diff --git a/daisy/scope/audioc.hpp b/daisy/scope/audioc.hpp index c55b5ec..b7dccd1 100644 --- a/daisy/scope/audioc.hpp +++ b/daisy/scope/audioc.hpp @@ -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 diff --git a/daisy/scope/osclsk.cpp b/daisy/scope/osclsk.cpp index cf8570f..dc585b8 100644 --- a/daisy/scope/osclsk.cpp +++ b/daisy/scope/osclsk.cpp @@ -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 diff --git a/daisy/scope/osclsk.hpp b/daisy/scope/osclsk.hpp index ce0c37f..1814d28 100644 --- a/daisy/scope/osclsk.hpp +++ b/daisy/scope/osclsk.hpp @@ -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); diff --git a/daisy/scope/scope.cpp b/daisy/scope/scope.cpp index e4c779e..ec55604 100644 --- a/daisy/scope/scope.cpp +++ b/daisy/scope/scope.cpp @@ -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 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)); +// } } } diff --git a/daisy/scope/scope.hpp b/daisy/scope/scope.hpp index dcb7e30..4a22158 100644 --- a/daisy/scope/scope.hpp +++ b/daisy/scope/scope.hpp @@ -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 */ diff --git a/daisy/scope/tft.cpp b/daisy/scope/tft.cpp index ab05de4..76ca46b 100644 --- a/daisy/scope/tft.cpp +++ b/daisy/scope/tft.cpp @@ -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); } diff --git a/daisy/scope/tft.hpp b/daisy/scope/tft.hpp index a7ed2b0..d2fbc3a 100644 --- a/daisy/scope/tft.hpp +++ b/daisy/scope/tft.hpp @@ -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 *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);