This is regarding the 9-bit DMA support on SPI interface.
We have a peripheral that requires 9-bit data transfer over SPI. 9-bit over SPI is working. However, the SPI DMA does not seem to support 9 bit (8-bit/16-bit/32 bits are supported). This requires us to use 16-bits for 9 bit data packaging which is not efficient in terms of memory usage and CPU cycles.
Please check if 9-bit DMA can be supported/any other implementation that can optimize the DMA flow.
Here are some possible configurations. Please check whether the SPI slave can accomodate the back-to-back frame timnig.
For 9-bit SPI transfers to be handled by the DMA the 9-bit data have to be stored in a 16-bit array; DMA transfers would have to be configured to be 16-bits wide and the destination address for DMA transfers would be the FIFO write data register as described in the highlighted section:.
In general it is a bit inefficient to use 16-bit storage to handle 9-bit data. If the SPI is used to send data only it looks as if using a 16-bit storage (half-words) to handle 9-bit data is inefficient but in case the SPI sends and receives 9-bit data then a 16-bit storage makes more sense especially for the received data.
Now, in case the SPI is used to send data only, the following is applicable:
Assuming customer’s application can tolerate back-to-back 9-bit frame transmissions (the SPI Delay register (DLY) FRAME_DELAY = 0) and the number of 9-bit frames sent in a transfer is a multiple of 8, then the data could be packed in the RAM so that 8x 9-bit data occupies 9 consecutive bytes, and the DMA can be configured to make 8-bit transfers. The SPI SCK output will look like a burst of 72 pulses but as long as the master and slave are synchronized (via the SSEL line) there should be no problems.
In case the customer send number of 9-bit frames that is a multiple of 16, then the SPI data length can be set to 16, the DMA transfers would also be 16-bit wide and the overall number of DMA transfers would be lower.
Config 1: number of 9-bit frames in the transfer is 8; frames are stored in 8 of 16-bit halfwords in the RAM, the DMA is set for 16-bit wide transfers and there is total of 8 DMA transfers
Config 2: number of 9-bit frames in the transfer is 8; frames are stored in 9 consecutive bytes in the RAM, the DMA is set for 8-bit wide transfers and there is total of 9 DMA transfers
The advantage of config 2 is a more efficient usage of the RAM (9 bytes in config 2 vs. 8 16-bit words (16 bytes total) in config 1); however, in there are fewer DMA transfers in config 1 than in config 2 (8 vs. 9) and config 1 is SPI received data friendly (in case of config 2 received 9-bit data would be packed back-to-back bitwise in consecutive bytes so some postprocessing might be needed to extract actual info).
Config 3: number of 9-bit frames in the transfer is 16; frames are stored in 18 consecutive bytes in the RAM, the DMA is set for 16-bit wide transfers and there is total of 9 DMA transfers; in case the DMA is set for 8-bit transfers there would be 16 of them.
In case of config 3 16-bit frames can be sent but this configuration is not SPI received data friendly either.
Overall configuration 2 and 3 can be used only in cases no rx data is expected and data to be sent are packed in the RAM, so some preprocessing might be needed but it’s only in case of the 3rd configuration the number of DMA transfers can be lower than number of 9-bit frames in the given SPI transfer.
The DMA transfer data size is not flexbile, which limited with 8-bit/16-bit/32-bit transfer size.
And DMA will reduce core workload when tranfer huge mount of data, if there only transfer less data, DMA effecitive maybe less than using software code.
If there with request to enhance the DMA effective, please consider to encode the 9-bit data to 8-bit or compress two 9-bit data to one 16-bit data.
I am thinking you can transfer all MSB = 0 Data together, then following transfer all MSB = 1 data.
For example, if you want to tranfer 1024 9-bit data, you can classfy those data to two groups: MSB = 0 & MSB = 1;
Then you can set a simple signal, MSB byte + data size (2 bytes);
The first byte is 0x55 means MSB = 0;
The first byte is 0xAA meas MSB = 1;
If there with 512 9-bit data with MSB = 0, then you can set DMA with 8-bit transfer size with following data:
0x55+0x02+0x00+(512 data without MSB);
After that, DMA with 8-bit transfer size to transfer left 512 9-bit data with MSB = 1:
0xAA+0x02+0x00+(512 data without MSB);
Wish it works for your application.