The purpose of this knowledge base article is to demonstrate the usage of the Giant Gecko GG11 started kit to implement a sound-based guitar and ukulele tuner. A small background on instrument tuners is provided followed by a brief description of the hardware used from the development board and its implementation through functional blocks. Lastly, the general description of the software workflow is discussed. The article includes the simplicity studio project (.sls), please refer to it and it’s readme file for details on the software implementation and how to run the application. The following KBA contains a series of steps on how to import .sls files into Simplicity Studio.
An electric tuner aims to measure the frequency of a note played by an instrument, this is then correlated to its associated musical note in a scale, and feedback is provided to the user of the “closeness” of the played note to the desired one, usually in a visual way.
Tuners may record the input note by different means, usually through direct connection by an input jack, by sound (using a microphone) or by vibration (using a piezoelectric sensor).
Lastly, a tuner may be classified as standard or chromatic, the former allows to tune an instrument to its standard notes and the later will display the tuning at any pitch on a 12-notes chromatic scale. This project follows a sound approach with standard tuning for guitar and ukulele.
This example is implemented in the SLSTK3701A starter kit for the EFM32GG11 MCU. Multiple on-board hardware elements are leveraged such as the MEMS microphones, push-buttons, and LCD screen; MCU peripherals such as the PRS, GPIO interrupts, USART (I2S mode), CMU and LDMA. Core-specific peripherals like the DSP, FPU, and NVIC are also utilized.
Figure 1 below shows a high-level functional block representation of the project, each block is marked by a green background.
The tuner interacts with 3 different inputs: one audio and two mechanical. The audio input is captured by the 2 MEMS microphones in the SLSTK and the mechanical ones by the two available push-buttons.
The on-board microphones generate a PDM (Pulse Density Modulation) signal as its output, given that the MCU has no specialized peripheral for this, an IC transducer/codec is implemented. The codec is routed to the USART 3 peripheral of the MCU that can be configured to operate in I2S mode. This implementation is observed in Figure 2 below.
According to the microphone’s datasheet, the microphone operates in 3 different states based on the VDD value and the frequency of the input clock. A high value in VDD and a frequency >= 1 Mhz will take the device to an active mode whereas a frequency < 1Khz will take it to a sleep mode.
The clock signal for the microphones (PDM_CLK) is generated by the codec which requires 2 clock inputs the “bit clock” (BCLK) and the “word select” or “left-right clock” (LRCLK).
- “Bit clock”: Pulses once for each data bit in the data line, relative to the baud rate of the I2S peripheral
- “Left-right clock”: Determines the sampling rate, and the channel that data comes from, generated by the CS (Chip select) of the peripheral
- High: Right channel
- Low: Left channel
According to the datasheet of the codec, BCLK should be at least 64x the LRCLK rate and the generated PDM_CLK will be 64x the LRCLK rate. Furthermore, it’s stated that the minimum sampling rate should be between 4 - 96 kHz leading to a PDM_CLK ranging from 256 kHz to 6.144 MHz.
Since the PDM_CLK should be at least 1 MHz, the LRCLK should be PDM_CLK/64 or 15.625 KHz. Still, during testing, it was determined that pushing the LRCLK rate as low as 2 kHz still rendered reliable results this is important for the resolution of the application as explained in the Frequency acquisition section.
Following the selected sampling rate as 2 kHz, word size of 32-bits, and 2 channels, the Bit clock or baud rate is determined to be 2000 x 32 x 2 or 128000 bits/s.
It’s important to note that the data from both channels (left and right) is transferred through the same data line, and the application should keep track of the source in the RX buffer, this is described in the Data transfer section.
The SLSTK has 2 push-buttons available for user interaction. Push-button 0 is used to initialize the tuner whereas push-button 1 is used to switch between target instrument (Guitar & Ukulele) once the tuner is operating. Each input is managed in different ways, button 0 is routed to the PRS (Peripheral Reflex System) peripheral, and button 1 is managed through the edge interrupt of the GPIO peripheral.
The PRS system allows routing an event in a peripheral (producer) towards another peripheral (consumer), in this case, the GPIO level change towards the USART peripheral enabling its RX and TX components. This is done without the CPU intervention allowing the system to stay in a low energy mode. Further details on the PRS and GPIO peripherals can be found in sections 15 and 34 of the EFM32GG11 reference manual.
Following the idea of low energy mode, the LDMA (Linked Direct Memory Access) peripheral is enabled to transfer the microphone data in the RX buffer of the USART to RAM without the need for the CPU. Upon a transfer request the LDMA uses the descriptor data in memory to perform its operations, an extra property is that descriptor may link to new ones with different properties allowing for different operations on each transfer or looped process, which is the case of this example.
The LDMA peripheral is configured to trigger peripheral to memory transfers based on the RXDATAV and RXDATAVRIGHT USART status flags, the former indicates that data is available in the buffer and the second that data from the right channel is available allowing to differentiate between channels. The DMASPLIT in the USART_I2SCTRL register should be enabled to allow channel differentiation.
For this application only the data from the left microphone is used, still, the transfers for both channels are implemented for scalability. The left channel transfer has two linked descriptors assigned each with its own target buffer and the following main properties:
- 1 byte-sized transfers
- Total transfers (in bytes) = 4 x buffer size (uint32_t buffers)
- Interrupt generated on descriptor completion (full buffer)
- Looped linkage between descriptors
The right channel transfer descriptor performs a single byte transfer to a dummy buffer with no interrupts generated.
Once data from the microphone has been captured and the CPU informed, the processing begins which can be divided into three main steps: raw data processing, frequency acquisition, and tuning algorithm.
This segment manages and adjusts the microphone data before it’s processed for frequency extraction.
- Determine the data buffer to process
- There’re 2 buffers available for the left channel in the application
- Match the endianness of the data and adjust the number of bits
- Incoming data is big-endian whereas the MCU is little-endian. Only 20 bits of data are >relevant according to the codec datasheet
This segment determines the main frequency component of the input signal leveraging the CMSIS-DSP library that provides a series of functions for signal processing.
- Apply a Hanning window to the data
- Non-integer periods of data generate undesired high-frequency components after FFT processing, more details can be found in the following link
- Hanning window coefficients are generated in code (arm_cos_f32)
- Perform an FFT on the data (arm_rfft_fast_f32)
- The resolution of the FFT will be dependent on the sampling frequency and the number of FFT elements. Also, the frequency bin range is half of the sampling frequency
- Get the magnitude of the real and imaginary pairs from the FFT (arm_cmplx_mag_f32)
- Determine the bin with the highest magnitude (arm_max_f32)
- Verify if a second harmonic was detected
- Magnitude comparison of the highest bin and that at half of the frequency
- Determine the frequency of the input
This is a simple heuristic algorithm that compares the detected frequency with a series of frequency brackets surrounding a target fundamental frequency. The targets are dependent on the selected instrument and correspond to the frequencies of each string when tuned, these values are hardcoded and adjusted to the nearest integer that can be detected based on the resolution of the FFT. For the example code, this resolution is 3.91 Hz per frequency bin. Figure 3 below shows a graphic representation of the frequency brackets.
Based on the bracket, the algorithm will determine the properties of the figures and text to be displayed on the LCD screen in the last functional block.
The LCD screen management is leveraged through the GLIB (Graphics Library) As mentioned before, depending on the bracket that the detected frequency falls, a different set of properties are defined and used to display specific figures related to the “tuning level” detected. Figure 4 below shows an example of the 3 cases portrayed in Figure 3.
Please refer to the following KBA for and introductory documentation on using the GLIB library.
The application begins by initializing the different MCU peripherals as well as the 3 flow control flags:
- “buffer_select” - Indicate the buffer to be processed
- “buffer_ready” - Indicate that a buffer is ready to be processed
- “instrument_toggle” – Indicate the instrument that is being tuned (guitar or ukulele)
An initial interface screen is displayed, and the processor goes to EM1 (Energy Mode 1). The data acquisition and processing begin until button 0 is pressed, from this point, the application will run continuously until the board is reset.
Once push-button 0 is pressed, a PRS signal enables the I2S RX and TX components allowing microphone data to be captured, this in terms begins the LDMA transfers and once a full transfer is complete (a buffer of data is ready) an interruption is generated toggling the “buffer_select” flag and making the system leave EM1. Pressing push-button 1 will also take the system out of EM1 although its real purpose is to control the “instrument_toggle” flag.
Once a buffer of data is ready, the filled buffer (out of the two available) is selected based on the “buffer_select” flag. Its contents are pre-processed and the frequency analysis is performed as described in the Processing section.
Once the frequency is known, based on the “instrument_toggle” flag, the adequate tuning algorithm is executed either guitar or ukulele. They both have the same heuristic nature each differing on the target frequencies. This algorithm will define a series of properties that are passed as a structure to the LCD updating routine.
After the LCD update, the “buffer_ready” flag is cleared indicating that a new buffer may be processed. It’s important to note that I2S data acquisition and LDMA transfers are still running in the background during the data processing cycle. Figure 5 below demonstrates the overall software operation in a graphical manner.