0
\$\begingroup\$

I use STM32F7 and I want to save Audio as ADC samples in SD card, continuously in 50K sample rate that is made by timer.(Same as voice recorder) I use DMA to save data in SD card. During read ADC, I put samples on the buffer and after 500000 sample ( about 10 seconds), I try to save them in ADC. My problem is during this process, I cant save any sample and I lost them. Please Help me! Thanks a lot!

uint8_t MIC_Voice_Store[200000];
    long int MIC_Store_Counter=0;
    int MIC_flag=0;
    
    
    char Name_buffer[30];
    int MIC_File_Counter=0;
    
    char buf[4];
    char try[4];
    int savecounter=0;
  extern char SDPath[4];  
  extern FATFS SDFatFS;   
  extern FIL SDFile;       
   UINT myBytes;
  FRESULT result;


sprintf(Name_buffer,"MIC_%d.TXT",MIC_File_Counter);     
result=f_mount(&SDFatFS,SDPath,1);

 while (1)
 {

            if(MIC_Ready==1)
                {

                    HAL_TIM_Base_Start_IT(&htim1);
                    if(MIC_flag==1)
                    {                                       
                        if(f_open(&SDFile,Name_buffer, FA_WRITE | FA_OPEN_APPEND) == FR_OK)
                            {
                                for (savecounter=0; savecounter<100000; savecounter++)
                                {
                                        buf[0]=((MIC_Voice_Store[savecounter]/100)%10)+48;
                                        buf[1]=((MIC_Voice_Store[savecounter]/10)%10)+48;
                                        buf[2]=(MIC_Voice_Store[savecounter]%10)+48;
                                        
                                        result=f_lseek(&SDFile,f_size(&SDFile));
                                        result=f_write(&SDFile,buf,sizeof(buf),&myBytes);

                                }
                                result=f_close(&SDFile);
                            }   
                        MIC_File_Counter++;
                        MIC_flag=0;
                        MIC_Store_Counter=0;
                    }
                MIC_Ready=0;
             }


}

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM1)
  {
      if(MIC_Ready==0)
      {
          HAL_ADC_Start(&hadc2);
          MIC_Voice=HAL_ADC_GetValue(&hadc2);
          if(MIC_Store_Counter<100000)
          {
              MIC_Voice_Store[MIC_Store_Counter]=MIC_Voice;
              MIC_Store_Counter++;
          }
          else
          {
            
            MIC_flag=1;
          } 
        
          MIC_Ready=1;
        }
   }
}

Thanks a lot. Because of sample rate is so important for me that have specific and constant value, I use timer to implement that. because of this I don't use DMA for ADC, and it doesn't cause any problem. But I use DMA for SD card and my main guidance for that, is this tutorial:

YouTube

And, Start DMA in this tutorial has ambiguity for me too. And I think it make problem. Can you help me more about that and start DMA with SD card?

Furthermore, you should not use f_open(), f_lseek() and f_close() on every write operation, they take an awful amount of time. Open file once at the beginning and keep writing data blocks until the end, then close file once. This way you have much better chance of keeping up with the incoming data flow.

Actually I use it at first, But this way change my sample rate because of f_write() slow response. That it related to use DMA with SD card, that I think is my problem now.

Finally, using f_printf() instead of f_write() may or may not be more efficient for writing bytes as text, but it sure will make your program more readable.

I will do that and tell you about that result.

\$\endgroup\$
5
  • 2
    \$\begingroup\$ Sorry, how should we know what goes wrong during this without a minimal,verifiable example of the code that doesn't work? It sounds like you're not actually making proper use of DMA, but that's just a guess without the code. \$\endgroup\$ Apr 11 at 12:29
  • \$\begingroup\$ I think so about DMA, and I don't have any idea about that. But I put the code in the Post. thank you \$\endgroup\$
    – Mohammad
    Apr 11 at 13:15
  • \$\begingroup\$ I don't know that specific MCU, but there's probably a DMA engine that can copy the data for you. If not or you don't want to use it, you're only acquiring 100KB/s of data on a fast cortex m7, so should be easy to do both the adc and sd copies in software. \$\endgroup\$ Apr 11 at 14:09
  • \$\begingroup\$ Thank you, I think so about use DMA with SD card in my code has wrong, but I can't find any suitable solution about that! \$\endgroup\$
    – Mohammad
    Apr 12 at 5:31
  • \$\begingroup\$ @Mohammad - Hi, What you wrote in the "Your Answer" box wasn't an answer to your original question, and therefore should not have been written there. I have moved it to the question as an edit i.e. an update. Unless you are writing the final answer to your own question (i.e. unless you have solved the problem yourself and no further help is needed), please don't use the "Your Answer" box below. Instead, please Edit the question to add new information. You can add a short comment below an answer, if your update affects that answer. See the tour and help center for more rules. Thanks! \$\endgroup\$
    – SamGibson
    Apr 12 at 10:52
2
\$\begingroup\$

I use DMA to save data in SD card

Are you sure about this? I don't see anything remotely related to DMA in your code.

You need to configure DMA for circular buffer and use HAL_ADC_Start_DMA() to begin regular transfer of ADC data into buffer.

Then you need to process HAL_ADC_ConvHalfCpltCallback() and HAL_ADC_ConvCpltCallback() to write accumulated data into file.

Furthermore, you should not use f_open(), f_lseek() and f_close() on every write operation, they take an awful amount of time. Open file once at the beginning and keep writing data blocks until the end, then close file once. This way you have much better chance of keeping up with the incoming data flow.

Checking myBytes after f_write() call is also a good idea - you need to know if something goes wrong.

Finally, using f_printf() instead of f_write() may or may not be more efficient for writing bytes as text, but it sure will make your program more readable.

UPDATE

Please, don't use answers to ask questions. Nevertheless, I'll answer your new questions here.

because of sample rate is so important for me that have specific and constant value, I use timer to implement that. because of this I don't use DMA for ADC

If sample rate is so important for you, why do you use heavy HAL timer code plus your own, instead of configuring ADC for continuous scan with fixed sampling rate and DMA for immediate transfer of results without software delays? You cannot beat hardware timing for sampling, so this approach just does not make any sense.

But I use DMA for SD card and my main guidance for that, is this tutorial...

That is another problem, right here. That tutorial uses DMA in worst possible way - they start DMA transaction and then enter a "while" loop until it completes (in BSP_SD_WriteBlocks_DMA function), effectively making DMA transfer into a blocking call.

Unfortunately that is a result of the way FatFS is written. Note, that this actually works more or less OK in preemptive mode RTOS, as other threads can continue working. For non-RTOS applications, however, it does not look good.

A lot of people are trying to come up with non-blocking ports or alternative implementations of FatFS, like AsyncFatFS for example. You can do a research and try some of them, I don't have any specific implementation I can endorse.

\$\endgroup\$
2
  • \$\begingroup\$ I tried a a lot about SD card with DMA. but non of them don't work. In all of tutorial, it has been said, that code is generated by CubeMX is incomplete, and they change that manually. in my CubeMx 5.2.1 some of their change is implemented. but all of them it seems don't work correctly! \$\endgroup\$
    – Mohammad
    Apr 14 at 6:15
  • \$\begingroup\$ @Mohammad As I said, the problem is not in SD card or DMA, the problem is in file system code. There are pretty fast SD cards and DMA can easily transfer data even faster than that. However when you insert generic file system code in between you usually kill the performance of both. You need to minimize software overhead as much as possible and hope it would be sufficient. If not, you'd have to either reduce sampling speed or write your own support for writing continuous stream to SD. \$\endgroup\$
    – Maple
    Apr 14 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.