I’m trying to write 24bit frames via DMA with LPSPI. The application is not important but for my example it is to send data from memory to an external DAC. I want to get this working with DMA because I will eventually use a link-list of TCD’s together with PIT to update the DAC continuously w/o CPU overhead. This is a common application with external ADC and DAC. It is also common that 16bit DAC/ADC’s have 24bit frame requirements (top byte is for command, lower bytes for data). I don’t want to use uint8_t data and split the transfer into 3 bytes, I want to use uint32_t data and send with 24bits frame size, the top byte to be ignored.
Now, onto the LPSPI and DMA configuration.
1. The lpspi_master_config_t structure of the imxRT1060 SDK’s API LPSPI_MasterInit function allows me to set bitsPerFrame to 24. This is no problem when doing a standard transfer w/o DMA.
2. However, when using DMA w/ the API's LPSPI_MasterTransferEDMA function, the case for 24-bits frame size is not handled or supported by the eDMA hardware? In LPSPI_MasterTransferEDMALite the DMA transfer width is set in the edma_transfer_config_t struct. Specifically, the srcTransferSize and destTransferSize fields are configured based on the bytesEachRead and bytesLastWrite values, which are derived from the SPI frame size (bytesPerFrame) by….
/* LPSPI_MasterTransferPrepareEDMALite */
uint32_t bytesPerFrame = ((base->TCR & LPSPI_TCR_FRAMESZ_MASK) >> LPSPI_TCR_FRAMESZ_SHIFT) / 8U + 1U;
if (bytesPerFrame <= 4U)
{
handle->bytesEachWrite = (uint8_t)bytesPerFrame; // for 24bit frames = 3
handle->bytesEachRead = (uint8_t)bytesPerFrame; // ....
handle->bytesLastRead = (uint8_t)bytesPerFrame; // ....
}
/* now back in LPSPI_MasterTransferEDMALite */
switch (handle->bytesEachRead) //bytes each transfer
{
case (1U):
transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
transferConfigRx.minorLoopBytes = 1;
if (handle->isByteSwap)
{
addrOffset = 3;
}
break;
case (2U):
transferConfigRx.srcTransferSize = kEDMA_TransferSize2Bytes;
transferConfigRx.minorLoopBytes = 2;
if (handle->isByteSwap)
{
addrOffset = 2;
}
break;
case (4U):
transferConfigRx.srcTransferSize = kEDMA_TransferSize4Bytes;
transferConfigRx.minorLoopBytes = 4;
break;
default:
transferConfigRx.srcTransferSize = kEDMA_TransferSize1Bytes;
transferConfigRx.minorLoopBytes = 1;
assert(false);
break;
}
We get the default case and an error as the case of 3 bytes is not handled. Does the EDMA hardware support 3-byte transfers? Basically I want to use uint32_t data and frame as 3 bytes and transfer via DMA, ignoring the most significant byte. Is it possible?