cancel
Showing results for 
Search instead for 
Did you mean: 

Does DMA miss data while it is used by SAI interface?

Ltura.1
Associate

Hi everyone,

I work on Data Acquisition System project. Our main controller is STM32F765VG. We used ADS131A0x A/D converter (by SPI) to sample input signal in our previous version. Now we want to replace ADS131A0x with ADS1274 (because of its higher sampling rate).

I haven’t encountered any problem when I get data from ADS131A0x through SPI-DMA combination.

I couldn’t use SPI with ADS1274 because of its high sampling rate. So I decided to use SAI interface. It is completely suitable with ADS1274 and I didn’t have any problem (I could get interrupt from DMA and obtain SAI data that transferred by DMA). But when I plotted 1024 samples, I saw that some samples are absent. And then, I collected more samples by Saleae Logic Pro. and compared them.

0693W000000UhtJQAS.jpg

As you see from picture abowe, there are some absent samples (with STM32F765VG).

0693W000000UhuHQAS.jpg

As you see from picture abowe, there isn't any absent sample ( with Saleae Logic Pro.).

I think, my DMA gives me wrong data sometimes or it misses some samples.

I used CubeMX to generate codes for SAI-DMA. Here my settings :

volatile sint32_t 	adsRdBuf[1];
 
SAI_HandleTypeDef hsai_BlockA1;
DMA_HandleTypeDef hdma_sai1_a;
 
void initASAI1(void)
{
#if(!ADS1274_SAI1A_USE_DMA)
	IRQ_attach(ADS1274_SAI1A_SAI_IRQ, IRQ_RESOURCE_ADS1274_SAI1A_SAI, IRQ_ENABLE);
#endif
 
    // SAI1
	hsai_BlockA1.Instance 					= SAI1_Block_A;
	hsai_BlockA1.Init.Protocol 				= SAI_FREE_PROTOCOL;
	hsai_BlockA1.Init.AudioMode 			= SAI_MODEMASTER_RX;
	hsai_BlockA1.Init.DataSize 				= SAI_DATASIZE_24;
	hsai_BlockA1.Init.FirstBit 				= SAI_FIRSTBIT_MSB;
	hsai_BlockA1.Init.ClockStrobing 		= SAI_CLOCKSTROBING_RISINGEDGE;
	hsai_BlockA1.Init.Synchro	 			= SAI_ASYNCHRONOUS;
	hsai_BlockA1.Init.OutputDrive 			= SAI_OUTPUTDRIVE_DISABLE;
	hsai_BlockA1.Init.NoDivider 			= SAI_MASTERDIVIDER_ENABLE;
	hsai_BlockA1.Init.FIFOThreshold 		= SAI_FIFOTHRESHOLD_EMPTY;
	hsai_BlockA1.Init.AudioFrequency		= SAI_AUDIO_FREQUENCY_96K;
	hsai_BlockA1.Init.SynchroExt 			= SAI_SYNCEXT_DISABLE;
	hsai_BlockA1.Init.MonoStereoMode 		= SAI_STEREOMODE;
	hsai_BlockA1.Init.CompandingMode 		= SAI_NOCOMPANDING;
	hsai_BlockA1.FrameInit.FrameLength 		= 32;
	hsai_BlockA1.FrameInit.ActiveFrameLength= 1;
	hsai_BlockA1.FrameInit.FSDefinition 	= SAI_FS_STARTFRAME;
	hsai_BlockA1.FrameInit.FSPolarity 		= SAI_FS_ACTIVE_HIGH;
	hsai_BlockA1.FrameInit.FSOffset 		= SAI_FS_FIRSTBIT;
	hsai_BlockA1.SlotInit.FirstBitOffset	= 0;
	hsai_BlockA1.SlotInit.SlotSize 			= SAI_SLOTSIZE_DATASIZE;
	hsai_BlockA1.SlotInit.SlotNumber 		= 1;
	hsai_BlockA1.SlotInit.SlotActive 		= SAI_SLOTACTIVE_0;
 
	HAL_SAI_Init(&hsai_BlockA1);
}
 
void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai)
{
	GPIO_InitTypeDef gis;
 
	__HAL_RCC_GPIOE_CLK_ENABLE();
	__HAL_RCC_SAI1_CLK_ENABLE();
 
	/**SAI1_A_Block_A GPIO Configuration
	PE2     ------> SAI1_MCLK_A
	PE4     ------> SAI1_FS_A
	PE5     ------> SAI1_SCK_A
	PE6     ------> SAI1_SD_A
	*/
	gis.Pin 		= LL_GPIO_PIN_6| LL_GPIO_PIN_5| LL_GPIO_PIN_4| LL_GPIO_PIN_2;
	gis.Mode 		= GPIO_MODE_AF_PP;
	gis.Pull 		= GPIO_NOPULL;
	gis.Speed 		= GPIO_SPEED_FREQ_VERY_HIGH;
	gis.Alternate 	= GPIO_AF6_SAI1;
	HAL_GPIO_Init(GPIOE, &gis);
 
#if(ADS1274_SAI1A_USE_DMA)
	// Peripheral DMA init
	hdma_sai1_a.Instance 				= DMA2_Stream6;
	hdma_sai1_a.Init.Channel 			= LL_DMA_CHANNEL_10;
	hdma_sai1_a.Init.Direction 			= DMA_PERIPH_TO_MEMORY;
	hdma_sai1_a.Init.PeriphInc 			= DMA_PINC_DISABLE;
	hdma_sai1_a.Init.MemInc 			= DMA_MINC_ENABLE;
	hdma_sai1_a.Init.PeriphDataAlignment= DMA_PDATAALIGN_WORD;
	hdma_sai1_a.Init.MemDataAlignment 	= DMA_MDATAALIGN_WORD;
	hdma_sai1_a.Init.Mode 				= DMA_CIRCULAR;
	hdma_sai1_a.Init.Priority 			= DMA_PRIORITY_VERY_HIGH;
	hdma_sai1_a.Init.FIFOMode 			= DMA_FIFOMODE_DISABLE;
 
	HAL_DMA_Init(&hdma_sai1_a);
 
	__HAL_LINKDMA(hsai,hdmarx,hdma_sai1_a);
#endif
}
 
void startADS1274(void)
{
#if(ADS1274_SAI1A_USE_DMA)
	HAL_SAI_Receive_DMA(&hsai_BlockA1, (uint8_t *)&(adsRdBuf[0]), ADS1274_READ_LEN);
#else
	HAL_SAI_Receive_IT(&hsai_BlockA1, (uint8_t *)&(adsRdBuf[0]), 1);
#endif
 
}
 
void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
{
	sint32_t rd1;
 
	rd1 = adsRdBuf[0];
 
	if(rd1 >= ADS1274_VAL_LIM) {
		V = (float32_t)rd1 - (float32_t)ADS1274_VAL_MAX;
	} else {
		V = (float32_t)rd1;
	}
 
	vBuf[rdCtr] = V;
	rdCtr++;
	if(rdCtr == 1024) {
		rdCtr = 0;
	}
 
#if(!ADS1274_SAI1A_USE_DMA)
	HAL_SAI_Receive_IT(&hsai_BlockA1, (uint8_t *)&(adsRdBuf[0]), 1);
#endif
}

As you see in code below, I also tried to use SAI without DMA but the result was same.

Thanks for your comments and helps.

2 REPLIES 2
Piranha
Chief II

Most likely it's not the hardware, but something stupid in HAL code. Also make sure you have cache management and/or MPU configuration right. Try using FIFO on both - SAI and DMA.

Ltura.1
Associate

Thanks for your reply @Piranha. I solved it. The problem is related with adding break point while system runs. I did many different tests. So I realized that if I double clicked line 104 to add break point while system runs, vBuf is bad (as I mentioned before). But if I click pause button, I saw that vBuf is perfect (as I expected). As a result I decided that I won't double click to add break point while system runs.