This article provides detailed information on sampling audio signals and transferring the data to a PC for analysis.

Supporting Information



In a previous article, I presented a straightforward MEMS microphone circuit that can be included in a robot system or just about any other electronics project. If you’re undecided about how exactly to produce your analog audio, start with that article. If you already have a working microphone interface and now you want to sample and analyze the audio data, you’re ready for this article.

We all know the advantages of digital data when it comes to processing and storage. But why transfer the data to a PC? Well, the answer is obvious if your goal is simply to record sound and then analyze it or save it for future enjoyment. But what if the goal is in-system processing? PC analysis is valuable even when the end application requires the robot itself to process the audio data—the powerful and user-friendly software available for PCs can help you to develop and fine-tune the algorithms that will eventually be implemented in the robot’s processor.


Sampling and Timing

Once you have a buffered audio signal, there are two main tasks required for getting that audio data to a PC: analog-to-digital conversion and robot-to-PC data transfer.

Let’s first look at the analog-to-digital conversion, particularly the timing details involved. The following schematic excerpt shows the microphone circuit and the connection to the EFM8 microcontroller:



And here is the PCB layout, with the microphone output signal highlighted in blue:



Sample Rate

In general, the standard range of audible frequencies is 20 Hz to 20 kHz. That’s a maximum or optimal range; the real range varies greatly from person to person. Furthermore, for many types of sound reproduction, we do not have to represent the entire audible frequency range. For example, reliable voice communication is possible when the audio signals are restricted to frequencies below 4 kHz, and an upper limit of 10 kHz allows for decent (not great) music reproduction. A standard sampling rate for good-quality audio is 44.1 kHz—just enough to support frequencies up to 20 kHz.

My point here is that you are not bound to a 20 kHz bandwidth. You choose the bandwidth according to the audio quality that you want, then you configure your ADC for a sample rate that is about twice as high as the bandwidth. I’m running my 14-bit EFM8 ADC at 16 kHz, which allows me to capture frequencies up to almost 8 kHz.



Storing vs. Sending

Digital audio may seem like old technology, but audio data still requires a lot of memory in the context of a microcontroller. If you’re sampling at 14 bits and 16 thousand samples per second (i.e., 16 ksps), each second of audio requires 32 thousand bytes of data. If your MCU has only 4 kB of RAM, you’re limited to one-eighth of a second. There’s not much you can do with a 125-millisecond recording.

Thus, for this project, we will not store audio data. Instead, we will transfer it to the PC continuously, in real time: as soon as each 14-bit sample is generated by the ADC, we send both bytes out the serial port. You can use the same hardware-plus-software arrangement discussed in this article on incorporating microphones into robotics—i.e., a Pololu USB-to-UART converter board (see photo below) and YAT (“Yet Another Terminal”).



When the transfer is complete, we move the data from YAT to Excel.


Timing Conflict?

The primary concern here is ensuring that both bytes are successfully transferred before a new ADC sample arrives. An ADC running at 16 ksps will generate one sample every 62.5 µs. The UART hardware must transfer 10 bits per byte (8 data bits plus one start bit and one stop bit). That’s 20 bits total, and then we also need a small amount of time for interrupt handling and execution of the necessary instructions. So let’s include some margin and say that 25-bit periods must fit within the 62.5 µs between ADC samples.


$$\frac{62.5\ \mu s}{25\ bit\ periods}=\frac{2.5\ \mu s}{bit\ period}$$

$$baud\ rate=\frac{1}{bit\ period}=400\ kbaud$$


We’ll increase the baud rate to the closest standard value, which is 460800. The limitations of the EFM8’s divider hardware result in an actual baud rate of 453704. Is that close enough? My conclusion from this article is that UART communication will usually be reliable when the baud rates are not different by more than 3.75%. The difference between 460800 and 453704 is about 1.5%, so it should be fine.

Before we move on, let’s use a debug signal and a scope to confirm that we don’t have a timing conflict.


                    SI_INTERRUPT (ADC0EOC_ISR, ADC0EOC_IRQn)

	ADC0CN0_ADINT = 0;	//clear interrupt flag

	SFRPAGE = 0x00;	//this page works for both SBUF0 and ADC0H/L

	SCON0_TI = 0;

	SCON0_TI = 0;

	if(Num_Samples_Sent == 15999)
		//stop Timer5 (one more conversion will occur)
		TMR5CN0_TR5 = 0;


As you can see, C2ADAPTER_LEDGRN goes high at the beginning of the interrupt routine (i.e., when a new ADC sample becomes available) and low at the end of the interrupt routine, at which point the bytes have been transferred and the processor is ready to start idly waiting for the next sample. The cursors in this first scope capture confirm that the rising edges are separated by ~62.5 µs.



You can already see that there is ample time between the completion of the data transfer and the arrival of the next sample. To be precise, we have 18.8 µs of spare time, which is 30% of the ADC sampling period:



YAT and Excel

The bytes are sent using the code shown above (you can remove the C2ADAPTER_LEDGRN = HIGH and C2ADAPTER_LEDGRN = LOW statements if you want to). You can explore the firmware in detail by looking through the source files and the hardware configuration file:


  Source and Project Files  

Refer to this article for details on using YAT and Excel. However, be warned that YAT could give you problems if you’re dealing with large quantities of data. Apparently, it doesn’t like having lots of data in the terminal monitor, so the save-to-file technique becomes inconvenient.

An alternative approach is to use a log file, but I had serious difficulties with the logging functionality—so serious that I abandoned YAT and decided to write my own C# serial-port logging software that does exactly what I want. Here it is:



So far it’s working well. I’ll probably continue adding functionality until I have a general-purpose serial-port program that efficiently and reliably does (once again) exactly what I need it to do, and nothing more. I’ll make the logger available for download when I’m confident that it’s stable and can adequately handle error scenarios.     

You can use the following link to download my Excel file:


  Excel File  

It’s currently arranged for 16,000 audio samples, which corresponds to one second of recording time, and it does the following:

  • converts bytes to ADC counts and millivolts
  • generates two time-domain plots of the audio data
  • performs spectral analysis by calculating and plotting Fast Fourier Transform (FFT) data; click here for instructions on using Excel’s FFT functionality

In the following video, I am generating a single-tone audio signal using this website. The EFM8 gathers and transfers 16,000 audio samples, which are stored by my logger software and imported into Excel. You can see that the frequency of the spike in the Fourier plot corresponds to the frequency of the original signal. (I’m doing a 1024-point FFT, which results in a frequency resolution of 15.625 Hz. So, in general, the original and measured audio frequencies won’t be exactly the same.) 



We’ve discussed some important details related to the digitization of audio signals, and we used custom hardware in conjunction with Excel to visualize and analyze digital audio data. And I even developed some handy serial-port software along the way—a good reminder that projects don’t always follow the expected route.