Skip to main content
M.CHN
Associate III
August 11, 2020
Solved

Store ADC's data stream without losses

  • August 11, 2020
  • 7 replies
  • 3638 views

Hello,

I am working on a project in which I have to store the data from my ADC (in continuous mode with DMA) on a SD card (with FATFS and SDMMC1) without losses. I try to use a ping pong buffer but when I want to change the bufferinwhich the ADC store values I have to stop my adc and restart it with the good buffer in parameter. Thus I lose a lots of data because of that.

Do you have a better solution to this matter ?

I also use my SD card in 1 bit mode because when I want to use it in 4 bits mode I have the RXOverrun flag. Fatfs is not configure to work with DMA because I don't know how to do it.

***EDIT 1***

I tryed to use a pointer in second parameter of HAL_ADC_Start_DMA() but it never write in the second buffer enven if my pointer is set at the 2nd buffer's adress.

Thank you for your help.

Best regards

Mathieu

Here is my main function

res= f_mount(&fs, "0:", 1);
 if (res == FR_OK){
	 HAL_GPIO_TogglePin(LD1_GPIO_Port, LD1_Pin);
 }
 res = f_open(&SDFile, "test.bin", FA_CREATE_ALWAYS|FA_WRITE);
 HAL_ADC_Start_DMA(&hadc1, (uint32_t *)raw, LENGTH);
 /* USER CODE END 2 */
 
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 int i = 0, time = 0;
 while (1)
 {
	 if (flag1){ // this flag is set in Adc convcplt callback
		if (!time) {
			HAL_ADC_Stop_DMA(&hadc1);
			HAL_ADC_Start_DMA(&hadc1, (uint32_t*)baw, LENGTH);
			res = f_write(&SDFile, raw, sizeof(raw),(void * ) &wr);
			time = 1;
		}
		else {
			HAL_ADC_Stop_DMA(&hadc1);
			HAL_ADC_Start_DMA(&hadc1, (uint32_t * )raw, LENGTH);
			res = f_write(&SDFile, baw, sizeof(baw),(void * ) &wr);
			time = 0;
		}
		 i++;
		 flag1=0;
	 }
	 if (i ==3){
		 //res = f_write(&SDFile, raw, sizeof(raw), &wr);
		 f_close(&SDFile);
		 while(1){
			 HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
			 HAL_Delay (500);
		 }
	 }
 /* USER CODE END WHILE */
 
 /* USER CODE BEGIN 3 */
 }

This topic has been closed for replies.
Best answer by Tesla DeLorean

Needs to be large enough, and some multiple of sectors to write efficiently. Say 8192 bytes or 32768 as it flushes the inactive portion of the buffer.

Hard deadline is the time the ADC takes to fill the active half of the buffer.

Should get the SDMMC implementation working properly first, and 4-bit, and speed benchmarked.

Where using DMA to fill from ADC, and using polled writes from memory for SDMMC, need to watch cache coherency​

7 replies

waclawek.jan
Super User
August 11, 2020

Use circular DMA, store at half-complete and transfer-complete interrupts.

I have no idea whether this can be clicked in Cube.

JW

M.CHN
M.CHNAuthor
Associate III
August 11, 2020

Thank you for your help. DMA was already configured in circular mode and even if it is better than before, when I store at half-complete and transfer-complete interrupts I still lose datas when I change the buffer (in the black rectangles on the photo)0693W000003Ov0hQAC.jpg.

waclawek.jan
Super User
August 11, 2020

Using HAL_ADC_Stop_DMA() / HAL_ADC_Start_DMA() defeats the point of circular DMA. You don't want to stop/start ADC/DMA.

JW

M.CHN
M.CHNAuthor
Associate III
August 11, 2020

I agree, but this is the only way I found to make my ADC fill the the second buffer (as I said in edit It does not work when I use a pointer in 2nd parameter of HAL_ADC_Start_DMA() to simply set it on the good buffer after). I tryed to used the memcpy() function to avoid to stop/start the ADC/DMA but I didn't have much success.

Maybe there is another solution to send data from the adc directly on the sd card but I don't know it.

Here is the tests with memcpy() function, maybe I have done something wrong :

// try 1 : It does not use callback functions ; STEP<LENGTH
if (toto == LENGTH) toto = 0;
memcpy(baw, &raw[toto], STEP);
f_write(&SDFile, baw, STEP,(void*) &wr);
toto += STEP;
 
// try 2 It uses callback functions to set flag1
	 if (flag1){
		if (!time) {
			memcpy(baw, &raw[0],sizeof(baw));
			res = f_write(&SDFile, baw, sizeof(baw),(void * ) &wr);
			time = 1;
 
		}
		else {
			memcpy(baw, &raw[LENGTH/2],sizeof(baw)-sizeof(uint16_t));
			res = f_write(&SDFile, baw, sizeof(baw),(void * ) &wr);
			time = 0;
		}
		 i++;
		 flag1=0;
	 }

MM..1
Chief III
August 11, 2020

you dont swap buffers, you have one big circular and on half interrupt copy first half of buffer to sdram, on full complete interrupt copy second .

HW in same time continue ADC DMA neverend...

main code :

init circularadc dma

while(1) your ifs memcpy isnt need directly f_wwrite half buffer first and second by flags;

in irq half set flag 1

in irq full set flag 2

M.CHN
M.CHNAuthor
Associate III
August 12, 2020

This seems to be better, but I still have some losses like on the photo. I am wondering if it could come from the writing speed of my SD card which is to slow. More I don't use 4 bit mode for SDMMC1 because I always have Rx overrun error :grinning_face_with_sweat:.

***EDIT***

The "losses" seem to come from ADC because I have "glitches" like in the photo even in the middle of the half part of the buffer for exemple.

Thanks for your help :D 0693W000003P8BsQAK.jpg

prain
Visitor II
August 12, 2020

There is a good tutorial here:

​https://visualgdb.com/tutorials/arm/stm32/adc/

see section 27​

M.CHN
M.CHNAuthor
Associate III
August 12, 2020

Thank you for your help. I was already using HAL_ADC_ConvHalfCpltCallback and even with it I lose datas :downcast_face_with_sweat: .

prain
Visitor II
August 12, 2020

Maybe you need a bigger buffer​, buy enough time for cpu to process half of buffer while the other half fills

gregstm
Senior II
August 13, 2020

My suggestions-

Use circular buffer with HT and TC interrupts that is never stopped.

Use no calls, write only to registers, especially in interrupt handlers.

Use the GPIO BSRR register to set/reset IO pins to provide efficient accurate timing info within the interrupt routines eg. set a pin at start of routine and reset at end of routine

M.CHN
M.CHNAuthor
Associate III
August 18, 2020

I finally succeded in using my SD card in 4 bit mode. I was still loosing some datas but when I set my buffer length to 32768 as @Community member​ told me to do all work perfectly.

Thank you all for your help. :grinning_face: