cancel
Showing results for 
Search instead for 
Did you mean: 

Store ADC's data stream without losses

M.CHN
Associate III

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 */
  }

1 ACCEPTED SOLUTION

Accepted Solutions

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​

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

15 REPLIES 15

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
Associate III

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.

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
Associate III

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;
	  }

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

prain
Senior III

There is a good tutorial here:

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

​

see section 27​

M.CHN
Associate III

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 😅.

***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

M.CHN
Associate III

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

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