cancel
Showing results for 
Search instead for 
Did you mean: 

F7: SAI 24 bit audio samples to SRAM via DMA in bytes?

LCE
Principal

Hello,

I'm trying to get some audio samples with 24 bit resolution from the SAI (RX, connected to an external ADC) into SRAM via DMA.

When DMA data sizes / alignments are set to WORD (32bit) for peripheral and memory everything works fine.

To save some SRAM (and later on bandwidth) I tried to get only the 3 bytes (24 bits) from the SAI output into SRAM, so I set the DMA data sizes / alignments to BYTE.

Now the data in SRAM is crap... (looks like some bytes from somewhere within the ADC data).

The F7 ref manual (RM0410) made me think that the DMA is smart enough to get data bytewise from the SAI FIFO, although the SAI writes only 3 bytes per sample to the FIFO.

My questions are:

1) Is it possible to get only the 3 bytes via DMA into SRAM?

2) If yes, then how?

1 ACCEPTED SOLUTION

Accepted Solutions

Try 8-bit slots in SAI, three times that many slots per frame, DMA set to byte on SAI side and word on memory side (which implies DMA FIFO on). This may or may not work well depending on endianness.

JW

View solution in original post

6 REPLIES 6

From RM0410:

Each read or write operation from/to the FIFO targets one

word FIFO location whatever the access size. Each FIFO word contains one audio slot.

FIFO pointers are incremented by one word after each access to the SAI_xDR register.

In other words, no, there's no way to automatically extract using DMA only 3 bytes out of the word, which is the FIFO's unit.

OTOH, you are going to process those samples, don't you. For that, you need to pick them from memory where DMA placed them; and then you can do whatever you want with them.

JW

LCE
Principal

Hello JW,

thanks for your reply!

Now I found that paragraph in the ref manual, what bugs me most is not that it's not working as I hoped, but that I have overseen this.

And no, no data processing whatsoever (not enough CPU power for 8 channels at 192kHz sampling rate), so data path is

SAI -> DMA -> SRAM -> DMA -> interface

I have to check that, but I guess even re-ordering of data and throwing out the unused byte / sample might take to much processing time.

Try 8-bit slots in SAI, three times that many slots per frame, DMA set to byte on SAI side and word on memory side (which implies DMA FIFO on). This may or may not work well depending on endianness.

JW

LCE
Principal

Thanks again, interesting idea, I'll try that.

I'm curious how data will look...

So this at least gives some "interesting" results, could be good.

I have to work on my test input signal for final evaluation.

Right now I'm just putting a LRCK / FrameSync triggered PWM signal to the SAI data inputs, as I was playing with the timers anyway.

But now I guess I should reconfigure one SAI to transmit and let it output some counter value to get some exact data into the SAI RX under test.

LCE
Principal

So... mainly to Mr. Jan Waclawek:

it works, BIG THANKS for that idea!

Here's what I did:

F767 has 2 SAIs.

Right now I'm using SAI 1 A and SAI 1 B for stereo ADCs (not yet but soon).

SAI 1 A is sync master, sampling rate is 200kHz.

SAI 2 A should be used for an additional stereo ADC, but I use it now as a test output

to produce some serial data (simple up counter) in sync with SAI 1.

So SAI 2 A serial data output goes to SAI 1 A serial data input (via wire on a Nucleo-144 board).

So I set SAI 1 into receive mode (24 bit, MSB left justified) via HAL stuff (lazy me...),

then I fiddled directly with the registers:

As Jan proposed, I set the number of slots to 6 (3x stereo), and data size to 8 bit:

#define AUDIO2IP_DMA_BUF_WORD32   0
 
/* SAI 1 A, SYNC master, I2S INput --> ADC */
	/* creates SCLK, LRCK */
 
	hSai_1_A.Instance = SAI1_Block_A;
 
	hSai_1_A.Init.AudioMode 	= SAI_MODEMASTER_RX;
	hSai_1_A.Init.Synchro 		= SAI_ASYNCHRONOUS;
	hSai_1_A.Init.OutputDrive 	= SAI_OUTPUTDRIVE_DISABLE;
	hSai_1_A.Init.NoDivider 	= SAI_MASTERDIVIDER_ENABLE;
	hSai_1_A.Init.FIFOThreshold 	= SAI_FIFOTHRESHOLD_EMPTY;
	hSai_1_A.Init.AudioFrequency 	= SAI_AUDIO_FREQUENCY_MCKDIV;
	hSai_1_A.Init.Mckdiv 		= 0;
	hSai_1_A.Init.SynchroExt 	= SAI_SYNCEXT_OUTBLOCKA_ENABLE;	/* <-- IMPORTANT!, Not in Cube! */
	hSai_1_A.Init.MonoStereoMode 	= SAI_STEREOMODE;
	hSai_1_A.Init.CompandingMode 	= SAI_NOCOMPANDING;
	if (HAL_SAI_InitProtocol(&hSai_1_A, SAI_I2S_MSBJUSTIFIED, SAI_PROTOCOL_DATASIZE_24BIT, SAI_SLOTS_PER_SAI_2) != HAL_OK)
	{
		Error_Handler_FL(__FILE__, __LINE__);
	}
 
#if( AUDIO2IP_DMA_BUF_WORD32 )
	/* no changes to above settings */
#else
	SAI1_Block_A->CR1   = 0x00000241;	// datasize 8 bit
	SAI1_Block_A->FRCR  = 0x00031F3F;	// frame stuff: same
	SAI1_Block_A->SLOTR = 0xFFFF0500;	// 6 slots, data size same as CR1 -> 8 bit
#endif

Then I changed the DMA settings on the peripheral / SAI side to BYTE:

	/* Peripheral DMA init */
 
		hDMA_Sai_1_A.Instance = DMA2_Stream1;
 
		hDMA_Sai_1_A.Init.Channel 	= DMA_CHANNEL_0;
		hDMA_Sai_1_A.Init.Direction 	= DMA_PERIPH_TO_MEMORY;
		hDMA_Sai_1_A.Init.PeriphInc 	= DMA_PINC_DISABLE;
		hDMA_Sai_1_A.Init.MemInc 	= DMA_MINC_ENABLE;
#if( AUDIO2IP_DMA_BUF_WORD32 )
		hDMA_Sai_1_A.Init.PeriphDataAlignment 	= DMA_PDATAALIGN_WORD;
		hDMA_Sai_1_A.Init.MemDataAlignment 	= DMA_MDATAALIGN_WORD;
#else
		hDMA_Sai_1_A.Init.PeriphDataAlignment 	= DMA_PDATAALIGN_BYTE;
		hDMA_Sai_1_A.Init.MemDataAlignment 	= DMA_MDATAALIGN_WORD;
#endif
		hDMA_Sai_1_A.Init.Mode 		= DMA_CIRCULAR;
		hDMA_Sai_1_A.Init.Priority 	= DMA_PRIORITY_VERY_HIGH;
		hDMA_Sai_1_A.Init.FIFOMode 	= DMA_FIFOMODE_ENABLE;
		hDMA_Sai_1_A.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
		hDMA_Sai_1_A.Init.MemBurst 	= DMA_MBURST_SINGLE;
		hDMA_Sai_1_A.Init.PeriphBurst = DMA_PBURST_SINGLE;
 

In a test function I reconstructed the 24 bit samples from the bytes and checked that their content increases with each sample, as the input signal from SAI 2 A does.