AnsweredAssumed Answered

DAC/ADC/SPI Comm. - Timing Analysis

Question asked by miller.mike.003 on Apr 3, 2014
Latest reply on Apr 5, 2014 by miller.mike.003

We are using the STM32F051C8T6

I have some comments and questions below but I mainly wanted to get a thumbs up to make sure I was on the right track with some of my conclusions.  Thank you for taking the time to read this.

We are following the ST application note AN3126. Which is titled “Audio and waveform generation using the DAC”.  

The goal is to read data from external SPI flash, moving this data into memory and using the DMA controller to push the data out to the DAC to play the audio.  This will be very similar to when we will be using the ADC to sample the data, use the DMA controller to move into memory and have the CPU record the audio to the SPI flash.



What I would like to confirm that the STM32F051C8T6 will work correctly for this application and that I am not missing something huge!

16 kHz Playback / Record


We would like to play the audio back at a sample rate of 16 kHz. This should be that each data point that is used for the DAC is updated every 6.25E-5 seconds. (.0000625 seconds).  For a 12-bit value that will take 2 bytes each of memory so let’s call this 128 data points. This also applies for recording and using the ADC.




128 (12-bit data points) x .0000625 seconds = 0.008 seconds.




Does this look correct?






Transferring data to/from external SPI Flash




Looking at page 16 of the application note there is an example on how to do the buffering.


While the first buffer from memory is being used to play data out to the DAC via DMA the CPU needs to be busy preparing the next buffer.  This will be handed over to the DMA so the DAC has continuous playback.  To do this correctly I believe that I need to be able to pull 256 bytes from the serial flash in less than 0.008 seconds. 

It’s 256 bytes because I need to read 2 bytes for each 12-bit DAC value.  I can only write 256 bytes at a time for the serial flash but I am able to do a continuous read.

I did some timing testing to see how long it would take to read and write a page of data on the SPI flash.

Below I show an image that shows the total write time (write enable, page program, check for write in progress)  of 210 us for a page (256 bytes) of the SPI flash.  The total read time (image not shown) is 334 us that surprised me. I was expecting the write to take longer.


But based on this I have 0.008 seconds to either push or pull data to my SPI flash.  This would be if I am either playing data out to the DAC (read from flash) or sampling the microphone to record audio with the ADC (write to flash).

Based on these initial results:


For the write 210 us =   0.000210 seconds

0.000210 seconds < 0.008 seconds  (The write is a factor of 38 times faster than the sampling time )

The worst case situation is when the page program command just by itself might take up to 3 ms. (0.003 seconds + 0.000210 seconds = .00321 seconds)

0.00321 seconds < 0.008 seconds (The write is a factor of 2.49 times faster than the sampling time )


For the read 334 us = 0.000334 seconds


0.000334 seconds < 0.008 (The read is a factor of about 23 times faster than the playback interval)



Polling vs Interrupts


Looking at the SPI transfer more closely I see delays between each byte of data.


The gaps in between the bytes of data being sent out look to be longer than the data itself. 


Gaps are about 944 ns between the read bytes and about 432 ns for the write bytes.


For each byte that I send out I poll to check that the transmit buffer is empty then I send the byte:


   // Wait until transmit buffer is empty than continue

        while(  !(SPI1->SR & 0x02)  );


SPI_SendData8(SPI1, data);


For the read I send the data out and then wait to receive a byte clocked in:


SPI_SendData8(SPI1, 0X00);


         // Wait to receive the first byte back. 

        while(  !(SPI1->SR & 0x01)  );


Is there a more optimal way to do this? Should I be using the RXFIFO/ TXFIFO?  What  about if I use interrupts to check the status instead of polling? How much faster would this be?



For audio playback I need to use a timer to drive the sample time of 16 kHz of the DAC.  In the other direction using this same timer when using the ADC.  I am planning on using Timer2 (TIM2_TRGO) to do this for both the ADC and DAC. Not at the same time.  For the datasheet botht he ADC and DAC are abled to be triggered with TIMER 2.

Will there be any problems with doing this?

Thank you.