DMA and sourceBuffer() issues with 8-bit transfers

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.

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;
}
 
Back
Top