got it working, just a small bug left

This commit is contained in:
Ellen Arvidsson 2025-06-14 17:17:00 +02:00
parent 4ade3a5f00
commit f3a619decc
7 changed files with 356 additions and 178 deletions

View file

@ -1,15 +1,25 @@
#ifndef _AUDIOC_HPP
#define _AUDIOC_HPP
#include "daisy_seed.h"
#define AUDIOC_LOG (daisy_hw.PrintLine)
extern daisy::DaisySeed daisy_hw;
#define AUDIOC_DEBUG
#ifdef AUDIOC_DEBUG
#define AUDIOC_DBG_IND() (daisy_hw.SetLed(true))
#define AUDIOC_DBG_BRK() __asm("BKPT 234")
#define AUDIOC_PRECOND(cond) \
do { \
if (! (cond)) { \
AUDIOC_LOG("AC_PRECOND(" #cond ") @ %s: line %u failed\n", \
__FILE__, __LINE__); \
AUDIOC_DBG_IND(); \
AUDIOC_DBG_BRK(); \
} \
} while (0)
#define AUDIOC_POSTCOND(cond) \
@ -17,6 +27,8 @@
if (! (cond)) { \
AUDIOC_LOG("AC_POSTCOND(" #cond ") @ %s: line %u failed\n", \
__FILE__, __LINE__); \
AUDIOC_DBG_IND(); \
AUDIOC_DBG_BRK(); \
} \
} while (0)
#define AUDIOC_ASSERT(cond) \
@ -24,6 +36,8 @@
if (! (cond)) { \
AUDIOC_LOG("AC_ASSERT(" #cond ") @ %s: line %u failed\n", \
__FILE__, __LINE__); \
AUDIOC_DBG_IND(); \
AUDIOC_DBG_BRK(); \
} \
} while (0)
#else

View file

@ -309,47 +309,71 @@ int
osclsk_scope::render_block(void)
{
int res;
size_t render_idx;
static int async_id;
float block_norm;
float block_norm = 1.f;
res = 0;
switch (st) {
case osc_state::SAMPLE_DONE:
block_norm = 1.f;
for (render_idx = 0; render_idx < OSCLSK_BLOCK_LEN;
render_idx++) {
block_norm = std::max(
std::abs(block_y_max[render_idx]),
block_norm
);
block_norm = std::max(
std::abs(block_y_min[render_idx]),
block_norm
);
}
for (render_idx = 0; render_idx < OSCLSK_BLOCK_LEN;
render_idx++) {
block_y_max[render_idx] =
block_y_max[render_idx] / block_norm;
block_y_min[render_idx] =
block_y_min[render_idx] / block_norm;
}
for (render_idx = 0; render_idx < OSCLSK_BLOCK_LEN;
render_idx++) {
screen_px_y_max[render_idx] = 1u + (uint16_t)(
OSCLSK_Y_MAX_PX * (.5f + block_y_max[render_idx])
);
screen_px_y_min[render_idx] = (uint16_t)(
OSCLSK_Y_MAX_PX * (.5f + block_y_min[render_idx])
);
}
if (st != osc_state::SAMPLE_DONE)
return (-1);
tft.async_on_finish(render_finish_tft_cb, this);
st = osc_state::RENDER;
res = tft.async_start();
AC_ASSERT(res >= 0);
if (res < 0)
return (-1);
for (render_idx = 0; render_idx < OSCLSK_BLOCK_LEN; render_idx++) {
block_norm = std::max( std::abs(block_y_max[render_idx]),
block_norm);
block_norm = std::max( std::abs(block_y_min[render_idx]),
block_norm);
async_id = res;
render_idx = 0;
st = osc_state::RENDER;
__attribute__((fallthrough));
case osc_state::RENDER:
for (; render_idx < OSCLSK_BLOCK_LEN; render_idx++) {
res = tft.async_hline_row_bg_fill(async_id, &bg, &fg,
screen_px_y_min[render_idx],
screen_px_y_max[render_idx],
render_idx);
if (res < 0)
return (-1);
if (res > 0)
return (1);
}
tft.async_end();
break;
default:
break;
}
for (render_idx = 0; render_idx < OSCLSK_BLOCK_LEN; render_idx++) {
block_y_max[render_idx] = block_y_max[render_idx] / block_norm;
block_y_min[render_idx] = block_y_min[render_idx] / block_norm;
}
for (render_idx = 0; render_idx < OSCLSK_BLOCK_LEN; render_idx++) {
screen_px_y_max[render_idx] = 1u + (uint16_t)(
OSCLSK_Y_MAX_PX * (.5f + block_y_max[render_idx]));
screen_px_y_min[render_idx] = (uint16_t)(
OSCLSK_Y_MAX_PX * (.5f + block_y_min[render_idx]));
}
res = -1;
tft.async_on_finish(render_finish_tft_cb, this);
tft.async_start();
for (render_idx = 0; render_idx < OSCLSK_BLOCK_LEN; render_idx++) {
res = tft.async_hline_row_bg_fill(&bg, &fg,
screen_px_y_min[render_idx], screen_px_y_max[render_idx],
render_idx);
if (res == -1)
break;
}
tft.async_end();
return (res);
return (0);
}
void

View file

@ -79,6 +79,7 @@ struct osclsk_scope {
uint16_t screen_px_y_max[OSCLSK_SCREEN_XSZ];
uint16_t screen_px_y_min[OSCLSK_SCREEN_XSZ];
size_t render_idx;
osclsk_scope(void) : st(osc_state::INIT),
block_fill(0), block_fill_nsamp(0),
@ -87,7 +88,8 @@ struct osclsk_scope {
trig_margin(.05f), trig_num(0),
trig_num_req(2),
trig_state(osc_trig_state::INIT),
trig_mode(osc_trig_mode::RISING_EDGE) {};
trig_mode(osc_trig_mode::RISING_EDGE),
render_idx(0) {};
int init(uint8_t *dma_buf, size_t dma_sz);
int init_block(void);

View file

@ -7,7 +7,7 @@
using namespace daisy;
using namespace daisysp;
#define DMA_AREA_SIZE (3*(1 << 16))
#define DMA_AREA_SIZE (1 << 12)
#define SCOPE_RING_BUF_SIZE 1024
#define AUDIO_BLOCK_SIZE 2
@ -32,14 +32,14 @@ Switch kick, snare;
RingBuffer<float, SCOPE_RING_BUF_SIZE> scope_in;
static void
void
audio_cb(AudioHandle::InputBuffer in,
AudioHandle::OutputBuffer out, size_t sz)
{
float osc_out, noise_out, snr_env_out, kck_env_out;
float sig[AUDIO_BLOCK_SIZE];
load_meter.OnBlockStart();
// load_meter.OnBlockStart();
//Get rid of any bouncing
snare.Debounce();
kick.Debounce();
@ -81,15 +81,15 @@ audio_cb(AudioHandle::InputBuffer in,
sig[i] = .5 * noise_out + .5 * osc_out;
}
/* write to output */
for (size_t i = 0; i < sz; i++) {
out[0][i] = sig[i];
out[1][i] = sig[i];
}
scope_in.Overwrite(sig, sz);
load_meter.OnBlockEnd();
// load_meter.OnBlockEnd();
}
static void
@ -137,20 +137,20 @@ setup_drums(void)
}
#define LOAD_METER_TICKS (1 << 16)
#define LOAD_METER_TICKS (1 << 20)
int
main(void)
{
size_t read;
float s[AUDIO_BLOCK_SIZE];
int load_tick;
uint32_t load_tick;
daisy_hw.Configure();
daisy_hw.Init();
daisy_hw.StartLog(false); /* true = wait for usb connection */
daisy_hw.SetAudioBlockSize(AUDIO_BLOCK_SIZE);
load_meter.Init(daisy_hw.AudioSampleRate(), daisy_hw.AudioBlockSize());
load_tick = LOAD_METER_TICKS;
//load_meter.Init(daisy_hw.AudioSampleRate(), daisy_hw.AudioBlockSize());
//load_tick = LOAD_METER_TICKS;
if (scope.init(dma_area, sizeof(dma_area)) == -1)
daisy_hw.PrintLine("scope.init failed");
@ -175,6 +175,9 @@ main(void)
case osclsk_scope::osc_state::SAMPLE_DONE:
scope.render_block();
break;
case osclsk_scope::osc_state::RENDER:
scope.render_block();
break;
case osclsk_scope::osc_state::RENDER_DONE:
scope.prep();
break;
@ -185,18 +188,18 @@ main(void)
break;
}
if (--load_tick == 0) {
load_tick = LOAD_METER_TICKS;
// get the current load (smoothed value and peak values)
const float avgLoad = load_meter.GetAvgCpuLoad();
const float maxLoad = load_meter.GetMaxCpuLoad();
const float minLoad = load_meter.GetMinCpuLoad();
// print it to the serial connection (as percentages)
daisy_hw.PrintLine("Processing Load %:");
daisy_hw.PrintLine("Max: " FLT_FMT3, FLT_VAR3(maxLoad * 100.0f));
daisy_hw.PrintLine("Avg: " FLT_FMT3, FLT_VAR3(avgLoad * 100.0f));
daisy_hw.PrintLine("Min: " FLT_FMT3, FLT_VAR3(minLoad * 100.0f));
}
// if (--load_tick == 0) {
// load_tick = LOAD_METER_TICKS;
// // get the current load (smoothed value and peak values)
// const float avgLoad = load_meter.GetAvgCpuLoad();
// const float maxLoad = load_meter.GetMaxCpuLoad();
// const float minLoad = load_meter.GetMinCpuLoad();
// // print it to the serial connection (as percentages)
// daisy_hw.PrintLine("Processing Load %:");
// daisy_hw.PrintLine("Max: " FLT_FMT3, FLT_VAR3(maxLoad * 100.0f));
// daisy_hw.PrintLine("Avg: " FLT_FMT3, FLT_VAR3(avgLoad * 100.0f));
// daisy_hw.PrintLine("Min: " FLT_FMT3, FLT_VAR3(minLoad * 100.0f));
// }
}
}

View file

@ -2,10 +2,6 @@
#define _SCOPE_HPP
#include "daisy_seed.h"
extern daisy::DaisySeed daisy_hw;
#define AUDIOC_LOG (daisy_hw.PrintLine)
#include "audioc.hpp"
#endif /* _SCOPE_HPP */

View file

@ -43,8 +43,8 @@ tft_driver_ili9341::init(uint8_t *dma_buf, size_t dma_sz)
SpiHandle::Result res;
dcx_pin = daisy::seed::D12; // Pin(PORTB, 8);
dcx.Init(dcx_pin, GPIO::Mode::OUTPUT, GPIO::Pull::PULLUP,
GPIO::Speed::VERY_HIGH);
dcx.Init(dcx_pin, GPIO::Mode::OUTPUT, GPIO::Pull::NOPULL,
GPIO::Speed::HIGH);
spi_conf.datasize = 8;
@ -79,7 +79,9 @@ tft_driver_ili9341::init(uint8_t *dma_buf, size_t dma_sz)
_async_dma_buf = dma_buf;
_async_dma_sz = dma_sz;
_async_stat = async_status::READY;
_async_curr_rd = _async_curr_wr = (tft_dma_cmd *)dma_buf;
_async_id = 0;
_async_stat = async_status::INIT;
return (0);
}
@ -113,31 +115,81 @@ tft_driver_ili9341::async_on_finish(async_on_finish_f cb, void *ctx)
}
int
tft_driver_ili9341::async_start(void)
tft_driver_ili9341::async_ready(void)
{
if (_async_stat != async_status::READY &&
_async_stat != async_status::DONE)
async_status stat;
stat = (async_status)_async_stat;
switch (stat) {
case async_status::INIT:
case async_status::DONE:
if (_async_cb_fun == NULL ||
_async_cb_ctx == NULL ||
_async_id < 0)
return (-1);
_async_stat = async_status::READY;
__attribute__((fallthrough));
case async_status::READY:
return (0);
default:
break;
}
return (-1);
}
int
tft_driver_ili9341::dma_buf_reset(void)
{
async_status stat;
tft_dma_cmd *cmd;
if (dma_buf_sz_tx_pend() > 0)
return (-1);
if (_async_cb_fun == NULL)
stat = _async_stat;
switch (stat) {
case async_status::INIT:
case async_status::TX_NONE:
case async_status::TX_ACTIVE:
return (-1);
default:
break;
}
_async_curr_wr = (tft_dma_cmd *)_async_dma_buf;
_async_curr_rd = _async_curr_wr;
cmd = (tft_dma_cmd *)_async_dma_buf;
cmd->size = 0;
_async_curr_wr->size = 0;
_async_wr = async_wr::START;
_async_stat = async_status::NO_TX;
_async_curr_wr = cmd;
_async_curr_rd = cmd;
return (0);
}
int
tft_driver_ili9341::async_start(void)
{
if (async_ready() == -1)
return (-1);
if (dma_buf_reset() == -1)
return (-1);
_async_wr = async_wr::START;
_async_stat = async_status::TX_NONE;
return (async_id());
}
int
tft_driver_ili9341::async_end(void)
{
_async_wr = async_wr::END;
async_id_next();
async_flush();
return (0);
}
@ -147,57 +199,103 @@ tft_driver_ili9341::async_stat(void)
return (_async_stat);
}
void
tft_driver_ili9341::async_finalize(void)
{
AC_PRECOND(_async_cb_fun != NULL && _async_cb_ctx != NULL);
AC_PRECOND(_async_stat == async_status::TX_NONE ||
_async_stat == async_status::TX_INACTIVE ||
_async_stat == async_status::TX_ACTIVE);
AC_PRECOND(_async_wr == async_wr::END);
AC_PRECOND(dma_buf_sz_tx_pend() == 0);
_async_stat = async_status::DONE;
_async_cb_fun((void *)_async_cb_ctx);
}
void
tft_driver_ili9341::async_flush(void)
{
async_tx();
}
async_status stat;
async_wr wr;
int
tft_driver_ili9341::async_hline_row_bg_fill(tft_color *bg, tft_color *fg,
uint16_t hline_idx_st, uint16_t hline_idx_end, uint16_t row_idx)
{
if (render_dma_buf_hline_row_bg_fill(bg, fg, hline_idx_st,
hline_idx_end, row_idx) != 0) {
return (-1);
stat = _async_stat;
wr = _async_wr;
switch (stat) {
case async_status::TX_NONE:
case async_status::TX_INACTIVE:
if (dma_buf_sz_tx_pend() > 0) {
async_tx();
return;
}
if (wr == async_wr::END) {
async_finalize();
return;
}
dma_buf_reset();
break;
default:
break;
}
async_tx_try();
return (0);
}
#define TFT_ASYNC_TRY_TX_MIN 4096
#define TFT_ASYNC_TRY_TX_MIN 2048
void
tft_driver_ili9341::async_tx_try(void)
{
if (dma_buf_sz_tx_pend() > TFT_ASYNC_TRY_TX_MIN)
if (dma_buf_sz_tx_pend() < (_async_dma_sz / 2))
return;
async_tx();
async_flush();
}
void
tft_driver_ili9341::async_tx(void)
{
if (_async_wr == async_wr::END && _async_stat == async_status::NO_TX &&
dma_buf_sz_tx_pend() == 0) {
_async_stat = async_status::DONE;
_async_cb_fun((void *)_async_cb_ctx);
return;
}
async_status stat;
if (_async_stat != async_status::NO_TX)
return;
stat = _async_stat;
AC_ASSERT(stat == async_status::TX_NONE ||
stat == async_status::TX_INACTIVE);
AC_ASSERT(dma_buf_sz_tx_pend() > sizeof(tft_dma_cmd));
AC_ASSERT(_async_curr_rd->size > 0);
_async_stat = async_status::TX;
_async_stat = async_status::TX_ACTIVE;
async_send_raw((const uint8_t *)_async_curr_rd->buf, 1,
async_tx_cmd_scb, async_tx_cmd_ecb, this);
}
/* ret < 0: if error
* ret = 0: if success
* ret > 0: need reentrant call, ret == async_id that should be used in next
* call
*/
int
tft_driver_ili9341::async_hline_row_bg_fill(int id, tft_color *bg,
tft_color *fg, uint16_t hline_idx_st, uint16_t hline_idx_end,
uint16_t row_idx)
{
int ret;
if (id != _async_id)
return (-1);
ret = render_dma_buf_hline_row_bg_fill(bg, fg, hline_idx_st,
hline_idx_end, row_idx);
if (ret < 0)
return (ret);
if (ret > 0)
async_flush();
async_tx_try();
return (ret);
}
void
tft_driver_ili9341::async_tx_cmd_scb(void *ctx)
{
@ -205,7 +303,7 @@ tft_driver_ili9341::async_tx_cmd_scb(void *ctx)
tft = (tft_driver_ili9341 *)ctx;
AC_ASSERT(tft->_async_stat == async_status::TX);
AC_ASSERT(tft->_async_stat == async_status::TX_ACTIVE);
tft->dcx_low();
}
@ -219,6 +317,8 @@ tft_driver_ili9341::async_tx_cmd_ecb(void *ctx, SpiHandle::Result res)
tft = (tft_driver_ili9341 *)ctx;
cmd = tft->dma_buf_curr_rd();
AC_ASSERT(tft->_async_stat == async_status::TX_ACTIVE);
tft->async_send_raw(&cmd->buf[1], cmd->size, async_tx_param_scb,
async_tx_param_ecb, tft);
}
@ -229,6 +329,9 @@ tft_driver_ili9341::async_tx_param_scb(void *ctx)
tft_driver_ili9341 *tft;
tft = (tft_driver_ili9341 *)ctx;
AC_ASSERT(tft->_async_stat == async_status::TX_ACTIVE);
tft->dcx_high();
}
@ -240,20 +343,23 @@ tft_driver_ili9341::async_tx_param_ecb(void *ctx, SpiHandle::Result res)
tft = (tft_driver_ili9341 *)ctx;
AC_PRECOND(tft->_async_stat == async_status::TX_ACTIVE);
cmd = tft->dma_buf_next_rd();
AUDIOC_ASSERT(tft->async_stat() == async_status::TX);
if (cmd->size == 0) {
tft->_async_stat = async_status::NO_TX;
if (tft->dma_buf_sz_tx_pend() == 0 &&
tft->_async_wr == async_wr::END) {
tft->_async_stat = async_status::DONE;
tft->_async_cb_fun((void *)tft->_async_cb_ctx);
if (tft->_async_wr == async_wr::END) {
AC_ASSERT(tft->dma_buf_sz_tx_pend() == 0);
tft->async_finalize();
} else {
tft->_async_stat = async_status::TX_INACTIVE;
}
return;
}
AC_ASSERT(tft->dma_buf_sz_tx_pend() > sizeof(tft_dma_cmd));
tft->async_send_raw(cmd->buf, 1, async_tx_cmd_scb, async_tx_cmd_ecb,
tft);
}
@ -270,9 +376,8 @@ tft_driver_ili9341::dma_buf_sz_used(void)
{
size_t buf_fill;
buf_fill = (size_t)((uint8_t *)_async_curr_wr - _async_dma_buf);
if (_async_curr_wr->size > 0)
buf_fill += sizeof(tft_dma_cmd) + _async_curr_wr->size;
buf_fill = (size_t)((uint8_t *)_async_curr_wr - _async_dma_buf) +
sizeof(tft_dma_cmd);
return (buf_fill);
}
@ -284,19 +389,28 @@ tft_driver_ili9341::dma_buf_curr_wr(void)
}
tft_dma_cmd *
tft_driver_ili9341::dma_buf_next_wr(void)
tft_driver_ili9341::dma_buf_next_wr(size_t curr_sz)
{
size_t sz;
uint8_t *bytes;
tft_dma_cmd *tmp;
size_t tot_sz;
volatile tft_dma_cmd *curr, *next;
volatile uint8_t *bytes;
sz = sizeof(tft_dma_cmd) + _async_curr_wr->size;
bytes = (uint8_t *)_async_curr_wr;
AC_PRECOND(_async_dma_sz - dma_buf_sz_used() >=
curr_sz + sizeof(tft_dma_cmd));
tmp = (tft_dma_cmd *)&bytes[sz];
tmp->size = 0;
curr = (volatile tft_dma_cmd *)_async_curr_wr;
tot_sz = sizeof(*curr) + curr_sz;
return ((tft_dma_cmd *)(_async_curr_wr = tmp));
bytes = (volatile uint8_t *)curr;
bytes += tot_sz;
next = (volatile tft_dma_cmd *)bytes;
next->size = 0;
curr->size = curr_sz;
_async_curr_wr = next;
return ((tft_dma_cmd *)next);
}
const tft_dma_cmd *
@ -309,18 +423,26 @@ const tft_dma_cmd *
tft_driver_ili9341::dma_buf_next_rd(void)
{
size_t sz;
uint8_t *bytes;
volatile const tft_dma_cmd *cmd;
volatile const uint8_t *bytes;
sz = sizeof(tft_dma_cmd) + _async_curr_rd->size;
bytes = (uint8_t *)_async_curr_rd;
return ((const tft_dma_cmd *)
(_async_curr_rd = (tft_dma_cmd *)&bytes[sz]));
cmd = (volatile const tft_dma_cmd *)_async_curr_rd;
sz = sizeof(*cmd) + cmd->size;
bytes = (volatile const uint8_t *)cmd;
bytes += sz;
cmd = (volatile const tft_dma_cmd *)bytes;
_async_curr_rd = cmd;
return ((const tft_dma_cmd *)cmd);
}
#define SET_ADDR_WINDOW_SZ (sizeof(tft_dma_cmd) + 5 + \
sizeof(tft_dma_cmd) + 5)
int
tft_driver_ili9341::render_dma_buf_set_addr_window(uint16_t col_st,
uint16_t col_end, uint16_t row_st, uint16_t row_end)
@ -328,9 +450,8 @@ tft_driver_ili9341::render_dma_buf_set_addr_window(uint16_t col_st,
size_t n;
tft_dma_cmd *cmd;
if (_async_dma_sz - dma_buf_sz_used() <
2 * (sizeof(tft_dma_cmd) + sizeof(uint8_t) + 2 * sizeof(uint16_t)))
return (-1);
if (_async_dma_sz - dma_buf_sz_used() < SET_ADDR_WINDOW_SZ)
return (1);
cmd = dma_buf_curr_wr();
@ -341,9 +462,7 @@ tft_driver_ili9341::render_dma_buf_set_addr_window(uint16_t col_st,
cmd->buf[n++] = (uint8_t)((col_end >> 8) & 0xff);
cmd->buf[n++] = (uint8_t)(col_end & 0xff);
cmd->size = n;
cmd = dma_buf_next_wr();
cmd = dma_buf_next_wr(n);
n = 0;
cmd->buf[n++] = ILI9341_PASET;
@ -352,13 +471,12 @@ tft_driver_ili9341::render_dma_buf_set_addr_window(uint16_t col_st,
cmd->buf[n++] = (uint8_t)((row_end >> 8) & 0xff);
cmd->buf[n++] = (uint8_t)(row_end & 0xff);
cmd->size = n;
dma_buf_next_wr();
dma_buf_next_wr(n);
return (0);
}
#define MEMWR_SZ(num) (sizeof(tft_dma_cmd) + 1 + (num) * sizeof(uint16_t))
int
tft_driver_ili9341::render_dma_buf_memwr(const tft_color *col, size_t num)
{
@ -366,9 +484,8 @@ tft_driver_ili9341::render_dma_buf_memwr(const tft_color *col, size_t num)
uint16_t c16;
tft_dma_cmd *cmd;
if (_async_dma_sz - dma_buf_sz_used() <
sizeof(tft_dma_cmd) + sizeof(uint8_t) + num * sizeof(uint16_t))
return (-1);
if (_async_dma_sz - dma_buf_sz_used() < MEMWR_SZ(num))
return (1);
cmd = dma_buf_curr_wr();
@ -380,13 +497,12 @@ tft_driver_ili9341::render_dma_buf_memwr(const tft_color *col, size_t num)
cmd->buf[i++] = (uint8_t)(c16 & 0xff);
}
cmd->size = i;
dma_buf_next_wr();
dma_buf_next_wr(i);
return (0);
}
#define MEMWR_CONT_SZ(num) MEMWR_SZ(num)
int
tft_driver_ili9341::render_dma_buf_memwr_cont(const tft_color *col, size_t num)
{
@ -394,9 +510,9 @@ tft_driver_ili9341::render_dma_buf_memwr_cont(const tft_color *col, size_t num)
uint16_t c16;
tft_dma_cmd *cmd;
if (_async_dma_sz - dma_buf_sz_used() <
sizeof(tft_dma_cmd) + sizeof(uint8_t) + num * sizeof(uint16_t))
return (-1);
if (_async_dma_sz - dma_buf_sz_used() < MEMWR_CONT_SZ(num)) {
return (1);
}
cmd = dma_buf_curr_wr();
@ -408,43 +524,60 @@ tft_driver_ili9341::render_dma_buf_memwr_cont(const tft_color *col, size_t num)
cmd->buf[i++] = (uint8_t)(c16 & 0xff);
}
cmd->size = i;
dma_buf_next_wr();
dma_buf_next_wr(i);
return (0);
}
int
tft_driver_ili9341::render_dma_buf_hline(const tft_color *c, uint16_t col_s,
uint16_t col_e, uint16_t row)
{
if (render_dma_buf_set_addr_window(col_s, col_e, row, row + 1) == -1)
return (-1);
int ret;
if (render_dma_buf_memwr(c, (size_t)(col_e - col_s)) == -1)
return (-1);
AC_PRECOND(col_s <= col_e);
return (0);
if (_async_dma_sz - dma_buf_sz_used() <
SET_ADDR_WINDOW_SZ + MEMWR_SZ(col_e - col_s))
return (1);
ret = render_dma_buf_set_addr_window(col_s, col_e, row, row + 1);
if (ret != 0)
return (ret);
ret = render_dma_buf_memwr(c, (size_t)(col_e - col_s));
return (ret);
}
int
tft_driver_ili9341::render_dma_buf_hline_row_bg_fill(const tft_color *bg,
const tft_color *fg, uint16_t col_s, uint16_t col_e, uint16_t row)
{
if (col_e < col_s || width() < col_e)
return (-1);
int ret;
if (render_dma_buf_set_addr_window(0, width(), row, row+1) == -1)
return (-1);
AC_PRECOND(col_s <= col_s && col_e <= width());
if (render_dma_buf_memwr(bg, (size_t)col_s) == -1)
return (-1);
if (render_dma_buf_memwr_cont(fg, (size_t)(col_e - col_s)) == -1)
return (-1);
if (render_dma_buf_memwr_cont(bg, (size_t)(width() - col_e)) == -1)
return (-1);
if (_async_dma_sz - dma_buf_sz_used() <
SET_ADDR_WINDOW_SZ + MEMWR_SZ(col_s) + MEMWR_CONT_SZ(col_e - col_s))
return (1);
return (0);
ret = render_dma_buf_set_addr_window(0, width(), row, row+1);
if (ret != 0)
return (ret);
ret = render_dma_buf_memwr(bg, (size_t)col_s);
if (ret != 0)
return (ret);
ret = render_dma_buf_memwr_cont(fg, (size_t)(col_e - col_s));
if (ret != 0)
return (ret);
ret = render_dma_buf_memwr_cont(bg, (size_t)(width() - col_e));
return (ret);
}
#define TFT_N_PIXELS (ILI9341_TFTWIDTH * ILI9341_TFTHEIGHT)
@ -517,8 +650,8 @@ tft_driver_ili9341::send_raw_sync(const uint8_t *buf, size_t len)
SpiHandle::Result res;
res = SpiHandle::Result::OK;
for (block_st = 0; block_st < len; block_st += block_sz()) {
transfer_sz = std::min(block_sz(), len - block_st);
for (block_st = 0; block_st < len; block_st += TFT_BLOCK_SZ) {
transfer_sz = std::min(TFT_BLOCK_SZ, len - block_st);
res = spi.BlockingTransmit((uint8_t *)&buf[block_st],
transfer_sz);
}

View file

@ -157,8 +157,9 @@ struct tft_driver_ili9341 {
enum class async_status {
INIT,
READY,
TX,
NO_TX,
TX_NONE,
TX_ACTIVE,
TX_INACTIVE,
DONE
};
@ -176,8 +177,6 @@ struct tft_driver_ili9341 {
SpiHandle spi;
SpiHandle::Config spi_conf;
Logger<LOGGER_EXTERNAL> *lg;
Pin dcx_pin;
GPIO dcx;
@ -186,6 +185,7 @@ struct tft_driver_ili9341 {
volatile async_wr _async_wr;
volatile async_on_finish_f _async_cb_fun;
volatile void *_async_cb_ctx;
int _async_id;
uint8_t *_async_dma_buf;
size_t _async_dma_sz;
@ -196,17 +196,11 @@ struct tft_driver_ili9341 {
/* general */
inline uint16_t width(void) { return (ILI9341_TFTWIDTH); }
inline uint16_t height(void) { return (ILI9341_TFTHEIGHT); }
inline size_t block_rows(void) {
return (sizeof(tft_color) * height() /
TFT_DRIVER_ILI9341_NBLOCKS);
}
inline size_t block_sz(void) {
return (sizeof(tft_color) * width() * height() /
TFT_DRIVER_ILI9341_NBLOCKS);
}
tft_driver_ili9341(void) : _async_hint(async_hint::NONE),
_async_stat(async_status::INIT), _async_wr(async_wr::END),
_async_cb_fun(NULL), _async_cb_ctx(NULL),
_async_id(-1),
_async_dma_buf(NULL), _async_dma_sz(0),
_async_curr_wr(NULL), _async_curr_rd(NULL) {};
@ -233,9 +227,19 @@ struct tft_driver_ili9341 {
void async_flush(void);
void async_tx(void);
void async_tx_try(void);
void async_finalize(void);
int async_ready(void);
inline int async_id(void) { return (_async_id); }
inline int async_id_next(void) {
_async_id++;
_async_id &= 0xffff;
return (_async_id);
}
int async_cmd_hint(async_hint hint);
int async_hline_row_bg_fill(tft_color *bg, tft_color *fg,
int async_hline_row_bg_fill(int async_id, tft_color *bg, tft_color *fg,
uint16_t hline_idx_st, uint16_t hline_idx_end, uint16_t row_idx);
static void async_tx_cmd_scb(void *ctx);
@ -255,8 +259,10 @@ struct tft_driver_ili9341 {
size_t dma_buf_sz_tx_pend(void);
size_t dma_buf_sz_used(void);
int dma_buf_reset(void);
tft_dma_cmd *dma_buf_curr_wr(void);
tft_dma_cmd *dma_buf_next_wr(void);
tft_dma_cmd *dma_buf_next_wr(size_t curr_sz);
const tft_dma_cmd *dma_buf_curr_rd(void);
const tft_dma_cmd *dma_buf_next_rd(void);