honey_the_codewitch
Well-known member
Edit: Never mind. I solved it. My transfer buffers were too large
I'm trying to do DMA to an LCD using 8-bit instead of 16-bit transfers for a couple of reasons. Firstly, the color depth for IoT screens can usually be set to 18-bit "packed" into a 24-bit pixel. That's 3 bytes per pixel, not 2. Secondly, it can be desirable to avoid the byte swapping during transfer of color data.
The issue is this: I'm getting some weird behavior from sourceBuffer(). The pixel data is currently 2 bytes wide (16-bit) but when I set the sourceBuffer to the total number of bytes it fails with a hard freeze. If I halve the number of bytes it doesn't halt, but the updates aren't quite right.
I'd really like to know what I'm doing incorrectly here.
I'm trying to do DMA to an LCD using 8-bit instead of 16-bit transfers for a couple of reasons. Firstly, the color depth for IoT screens can usually be set to 18-bit "packed" into a 24-bit pixel. That's 3 bytes per pixel, not 2. Secondly, it can be desirable to avoid the byte swapping during transfer of color data.
The issue is this: I'm getting some weird behavior from sourceBuffer(). The pixel data is currently 2 bytes wide (16-bit) but when I set the sourceBuffer to the total number of bytes it fails with a hard freeze. If I halve the number of bytes it doesn't halt, but the updates aren't quite right.
I'd really like to know what I'm doing incorrectly here.
C++:
bool lcd_spi_driver_t4::flush8_async(int x1, int y1, int x2, int y2, const void* bitmap, bool flush_cache) {
// Don't start one if already active.
if (_dma_state & LCD_SPI_DMA_ACTIVE) {
Serial.println("DMA IN PROGRESS");
return false;
}
_buffer = (uint16_t*)bitmap;
int w = x2-x1+1;
int h = y2-y1+1;
_count_words = w*h;
_dma_pixel_index = 0;
// count pixels * 2 at 16-bit color
size_t bytes = _count_words * _color_width;
if(flush_cache) {
arm_dcache_flush((void*)_buffer,bytes);
}
init_dma_settings();
// if I don't do /2 it will crash
_dma_data[_spi_num]._dmasettings[0].sourceBuffer((const uint8_t*)_buffer, bytes/2);
// Start off remove disable on completion from both...
// it will be the ISR that disables it...
_dma_data[_spi_num]._dmasettings[0].TCD->CSR &= ~(DMA_TCD_CSR_DREQ);
_dma_data[_spi_num]._dmasettings[1].TCD->CSR &= ~(DMA_TCD_CSR_DREQ);
begin_transaction();
write_address_window(x1,y1,x2,y2);
_spi_fcr_save = _pimxrt_spi->FCR; // remember the FCR
_pimxrt_spi->FCR = 0; // clear water marks...
// Update TCR to 8 bit mode. .
maybe_update_tcr(LPSPI_TCR_PCS(1) | LPSPI_TCR_FRAMESZ(7) | LPSPI_TCR_RXMSK /*| LPSPI_TCR_CONT*/);
_pimxrt_spi->DER = LPSPI_DER_TDDE;
_pimxrt_spi->SR = 0x3f00; // clear out all of the other status...
_dma_data[_spi_num]._dmatx.triggerAtHardwareEvent(_spi_hardware->tx_dma_channel);
_dma_data[_spi_num]._dmatx = _dma_data[_spi_num]._dmasettings[0];
_dma_data[_spi_num]._dmatx.begin(false);
_dma_data[_spi_num]._dmatx.enable();
_dma_frame_count = 0; // Set frame count back to zero.
_dmaActiveDisplay[_spi_num] = this;
_dma_state &= ~LCD_SPI_DMA_CONT;
_dma_state |= LCD_SPI_DMA_ACTIVE;
return true;
}