|
| 1 | +--- |
| 2 | +title: Microphone With LVGL Tutorial |
| 3 | +description: "Learn how to use the GIGA Display Shield's microphone together with LVGL." |
| 4 | +author: Benjamin Dannegård |
| 5 | +tags: [Display, microphone, LVGL] |
| 6 | +--- |
| 7 | + |
| 8 | +The GIGA Display Shield comes equipped with on-board microphone and with the help of LVGL the microphones readings can be visualized on the screen. This tutorial will show you how to create a sketch that ties together the microphones readings with visual elements on the screen. |
| 9 | + |
| 10 | +## Hardware & Software Needed |
| 11 | + |
| 12 | +- [Arduino GIGA R1 WiFi](/hardware/giga-r1) |
| 13 | +- [Arduino GIGA Display Shield](/hardware/giga-display-shield) |
| 14 | +- [Arduino IDE](https://www.arduino.cc/en/software) |
| 15 | +- [LVGL library](https://reference.arduino.cc/reference/en/libraries/lvgl/) |
| 16 | + |
| 17 | +## Downloading the Library and Core |
| 18 | + |
| 19 | +Make sure the latest GIGA core is installed in the Arduino IDE. **Tools > Board > Board Manager...**. Here you need to look for the **Arduino Mbed OS Giga Boards** and install it, the [Arduino_H7_Video library](https://github.com/arduino/ArduinoCore-mbed/tree/main/libraries/Arduino_H7_Video) and [PDM library](https://docs.arduino.cc/learn/built-in-libraries/pdm) are included in the core. Now you have to install the library needed for handling the visual component. Go to **Tools > Manage libraries..**, search for **LVGL**, and install it. |
| 20 | + |
| 21 | +## Microphone Readings With The Shield |
| 22 | + |
| 23 | +### Microphone Test Sketch |
| 24 | + |
| 25 | +To test the microphone we can use the **PDMSerialPlotter** example sketch. This sketch can be found in **File > Examples > PDM** in the Arduino IDE. This sketch will print readings in the serial monitor. Upload the sketch and check so that readings are appearing in the serial monitor. |
| 26 | + |
| 27 | + |
| 28 | + |
| 29 | +### Using the Microphone Readings |
| 30 | + |
| 31 | +Now let's create a sketch that combines the microphone readings with a visual component. First, the libraries we need are, `PDM.h` which will handle the microphone readings and `lvgl.h` will handle the visual elements on the screen. |
| 32 | + |
| 33 | +```arduino |
| 34 | +#include <PDM.h> |
| 35 | +#include "Arduino_H7_Video.h" |
| 36 | +#include "lvgl.h" |
| 37 | +``` |
| 38 | + |
| 39 | +In the `setup()` we can start the display with `Display.begin();` and the microphone with `PDM.onReceive(onPDMdata);`. This will call the `void onPDMdata()` function at the bottom of the sketch. This function handles collecting and storing the readings from the microphone. |
| 40 | + |
| 41 | +```arduino |
| 42 | +void setup() { |
| 43 | + Display.begin(); |
| 44 | +
|
| 45 | + PDM.onReceive(onPDMdata); |
| 46 | +
|
| 47 | + if (!PDM.begin(channels, frequency)) { |
| 48 | + Serial.println("Failed to start PDM!"); |
| 49 | + while (1); |
| 50 | + } |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +In the `setup()` we will also create our LVGL bar and animation for that bar. Make sure you also define the `lv_obj_t * obj;` and `lv_anim_t a;` variables outside of the `setup()` function so they can be used in the `loop()` function later. Now `obj` will be the name of bar object. These next lines will set the bar's position, size and values. After that we can initialize the animation and set the time for the animation. Then we set the animation to our bar with `lv_anim_set_var(&a, obj);`. |
| 55 | + |
| 56 | +```arduino |
| 57 | + // Create the bar |
| 58 | + obj = lv_bar_create(lv_scr_act()); |
| 59 | + lv_obj_set_size(obj, 600, 50); |
| 60 | + lv_obj_center(obj); |
| 61 | + lv_bar_set_value(obj, 500, LV_ANIM_OFF); |
| 62 | + |
| 63 | + // Create the animation for the bar |
| 64 | + lv_anim_init(&a); |
| 65 | + lv_anim_set_exec_cb(&a, set_slider_val); |
| 66 | + lv_anim_set_time(&a, 300); |
| 67 | + lv_anim_set_playback_time(&a, 300); |
| 68 | + lv_anim_set_var(&a, obj); |
| 69 | +``` |
| 70 | + |
| 71 | +The microphone readings will be put into a buffer, in the `loop()` we will need to go through all the samples in the buffer. We can do this with a simple `for()` loop. If you ran the previous mic test sketch you will know that the readings can get pretty high in value, to make it fit our LVGL component reduce that value. By assigning the value to our `micValue` variable we can make it fit the visual element and easily use it to set the end value of the animation with `lv_anim_set_values(&a, 0, micValue)`. |
| 72 | + |
| 73 | +```arduino |
| 74 | +void loop() { |
| 75 | + |
| 76 | + // Wait for samples to be read |
| 77 | + if (samplesRead) { |
| 78 | +
|
| 79 | + // Print samples to the serial monitor or plotter |
| 80 | + for (int i = 0; i < samplesRead; i++) { |
| 81 | + Serial.println(sampleBuffer[i]); |
| 82 | + micValue = sampleBuffer[i]; |
| 83 | + micValue = micValue / 100; |
| 84 | + if (micValue > 500) |
| 85 | + { |
| 86 | + micValue = 500; |
| 87 | + } |
| 88 | + lv_anim_set_values(&a, 0, micValue); |
| 89 | + lv_anim_start(&a); |
| 90 | + } |
| 91 | +
|
| 92 | + // Clear the read count |
| 93 | + samplesRead = 0; |
| 94 | + delay(10); |
| 95 | + } |
| 96 | + lv_timer_handler(); |
| 97 | +} |
| 98 | +``` |
| 99 | + |
| 100 | +In the section below you can find the full sketch. If you upload it to your GIGA Display Shield, you should see the same result as the GIF below is showing. |
| 101 | + |
| 102 | +[GIF of sketch running]() |
| 103 | + |
| 104 | +### Full Sketch |
| 105 | + |
| 106 | +```arduino |
| 107 | +#include <PDM.h> |
| 108 | +#include "Arduino_H7_Video.h" |
| 109 | +#include "lvgl.h" |
| 110 | +
|
| 111 | +Arduino_H7_Video Display(800, 480, GigaDisplayShield); |
| 112 | +
|
| 113 | +static void set_slider_val(void * bar, int32_t val) { |
| 114 | + lv_bar_set_value((lv_obj_t *)bar, val, LV_ANIM_ON); |
| 115 | +} |
| 116 | +
|
| 117 | +// default number of output channels |
| 118 | +static const char channels = 1; |
| 119 | +
|
| 120 | +// default PCM output frequency |
| 121 | +static const int frequency = 16000; |
| 122 | +
|
| 123 | +// Buffer to read samples into, each sample is 16-bits |
| 124 | +short sampleBuffer[512]; |
| 125 | +
|
| 126 | +// Number of audio samples read |
| 127 | +volatile int samplesRead; |
| 128 | +
|
| 129 | +lv_obj_t * obj; |
| 130 | +lv_anim_t a; |
| 131 | +int micValue; |
| 132 | +
|
| 133 | +void setup() { |
| 134 | + Display.begin(); |
| 135 | +
|
| 136 | + PDM.onReceive(onPDMdata); |
| 137 | +
|
| 138 | + if (!PDM.begin(channels, frequency)) { |
| 139 | + Serial.println("Failed to start PDM!"); |
| 140 | + while (1); |
| 141 | + } |
| 142 | +
|
| 143 | + // Create the bar |
| 144 | + obj = lv_bar_create(lv_scr_act()); |
| 145 | + lv_obj_set_size(obj, 600, 50); |
| 146 | + lv_obj_center(obj); |
| 147 | + lv_bar_set_value(obj, 500, LV_ANIM_OFF); |
| 148 | + |
| 149 | + // Create the animation for the bar |
| 150 | + lv_anim_init(&a); |
| 151 | + lv_anim_set_exec_cb(&a, set_slider_val); |
| 152 | + lv_anim_set_time(&a, 300); |
| 153 | + lv_anim_set_playback_time(&a, 300); |
| 154 | + lv_anim_set_var(&a, obj); |
| 155 | +} |
| 156 | +
|
| 157 | +void loop() { |
| 158 | + |
| 159 | + // Wait for samples to be read |
| 160 | + if (samplesRead) { |
| 161 | +
|
| 162 | + // Print samples to the serial monitor or plotter |
| 163 | + for (int i = 0; i < samplesRead; i++) { |
| 164 | + Serial.println(sampleBuffer[i]); |
| 165 | + micValue = sampleBuffer[i]; |
| 166 | + micValue = micValue / 100; |
| 167 | + if (micValue > 500) |
| 168 | + { |
| 169 | + micValue = 500; |
| 170 | + } |
| 171 | + lv_anim_set_values(&a, 0, micValue); |
| 172 | + lv_anim_start(&a); |
| 173 | + } |
| 174 | +
|
| 175 | + // Clear the read count |
| 176 | + samplesRead = 0; |
| 177 | + delay(10); |
| 178 | + } |
| 179 | + lv_timer_handler(); |
| 180 | +} |
| 181 | +
|
| 182 | +/** |
| 183 | + * Callback function to process the data from the PDM microphone. |
| 184 | + * NOTE: This callback is executed as part of an ISR. |
| 185 | + * Therefore using `Serial` to print messages inside this function isn't supported. |
| 186 | + * */ |
| 187 | +void onPDMdata() { |
| 188 | + // Query the number of available bytes |
| 189 | + int bytesAvailable = PDM.available(); |
| 190 | +
|
| 191 | + // Read into the sample buffer |
| 192 | + PDM.read(sampleBuffer, bytesAvailable); |
| 193 | +
|
| 194 | + // 16-bit, 2 bytes per sample |
| 195 | + samplesRead = bytesAvailable / 2; |
| 196 | +} |
| 197 | +``` |
| 198 | + |
| 199 | +## Conclusion |
| 200 | + |
| 201 | +Now you know how to get readings from the GIGA Display Shield's on-board microphone and how to create simple visual elements with LVGL. And lastly, how these two components could be put together in a sketch to utilize the shield's screen and on-board components. |
| 202 | + |
| 203 | +## Next Step |
| 204 | +Now that you know how to use the on-board microphone, feel free to explore the shield's other features, like the IMU with our [Orientation tutorial](/tutorials/image-orientation). Or if you rather dive deeper into LVGL, take a look at our [LVGL guide](tutorials/lvgl-guide). |
0 commit comments