element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
RoadTests & Reviews
  • Products
  • More
RoadTests & Reviews
Review Blogs GIGA VU Meter and Spectrum Analyzer
  • Blogs
  • RoadTest Forum
  • Documents
  • RoadTests
  • Reviews
  • Polls
  • Files
  • Members
  • Sub-Groups
  • More
  • Cancel
  • New
Join RoadTests & Reviews to participate - click to join for free!
  • Share
  • More
  • Cancel
  • Author Author: dougw
  • Date Created: 26 Oct 2025 6:13 PM Date Created
  • Views 1418 views
  • Likes 14 likes
  • Comments 10 comments
Related
Recommended
  • RoadTest
  • dougw
  • VU Meter
  • arduino giga r1
  • pdm microphone

GIGA VU Meter and Spectrum Analyzer

dougw
dougw
26 Oct 2025

Intro

The Arduino GIGA R1 kit I am road testing has a display with built in microphone. To test the microphone I am starting with using it to create a VU meter (volume unit meter). All the hardware necessary for this VU meter is included in this plug-and-play kit. It just needed a little adaptation of some example firmware.

image

Here is a short video demonstrating VU meter capability:

VU Meter Video

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

This demo used the LVGL library (light and versatile graphics library). Unfortunately this instance of the library would not accept larger fonts, so the label is pretty small.

VU Meter Firmware

/*
  VU Meter - Arduino GIGA Display - Microphone Demo
  Requires PDM, Arduino_H7_Video and lvgl libraries
  Code modified from code provided by Arduino
  By Doug Wong 2025
*/

// Include libraries
#include <PDM.h>
#include "Arduino_H7_Video.h"
#include "lvgl.h"

// Create display object
Arduino_H7_Video Display(800, 480, GigaDisplayShield);

// Slider
static void set_slider_val(void *bar, int32_t val) {
  lv_bar_set_value((lv_obj_t *)bar, val, LV_ANIM_ON);
}

// Default number of output channels
static const char channels = 1;

// Default PCM output frequency
static const int frequency = 16000;

// Buffer to read samples into, each sample is 16-bits
short sampleBuffer[512];

// Number of audio samples read
volatile int samplesRead;

lv_obj_t *obj;
lv_anim_t a;
int micValue;
long tot = 0;
float av;

void setup() {
  // Initialize Display
  Display.begin();

  // Setup callback
  PDM.onReceive(onPDMdata);

  // Start PDM
  if (!PDM.begin(channels, frequency)) {
    Serial.println("Failed to start PDM!");
    while (1)
      ;
  }

  // Create the bar
  obj = lv_bar_create(lv_scr_act());
  lv_obj_set_size(obj, 600, 50);
  lv_obj_center(obj);
  lv_bar_set_value(obj, 500, LV_ANIM_OFF);

  // Create the animation for the bar
  lv_anim_init(&a);
  lv_anim_set_exec_cb(&a, set_slider_val);
  lv_anim_set_time(&a, 300);
  lv_anim_set_playback_time(&a, 300);
  lv_anim_set_var(&a, obj);

// add title
  create_title(lv_scr_act());

}

void loop() {

  // Wait for samples to be read
  if (samplesRead > 256) {
    micValue = 0;
    for (int i = 0; i < 129; i++) {
      if (micValue < sampleBuffer[i]) micValue = sampleBuffer[i];
    }
      int dv = micValue / 4 - 20;
      if (dv > 0) {
        micValue = 20 + dv/4;
      } 
      else {
        micValue = 20 - 18 / micValue;
      }
      micValue = micValue;
      if (micValue > 500) {
        micValue = 500;
      }
      lv_anim_set_values(&a, 0, micValue);
      lv_anim_start(&a);

    // Clear the read count
    samplesRead = 0;
    delay(80);
  }
  lv_timer_handler();
}

// Callback function to process the data from the PDM microphone.

void onPDMdata() {
  // Query the number of available bytes
  int bytesAvailable = PDM.available();

  // Read into the sample buffer
  PDM.read(sampleBuffer, bytesAvailable);

  // 16-bit, 2 bytes per sample
  samplesRead = bytesAvailable / 2;
}

void create_title(lv_obj_t *parent) {
  // Create a label
  lv_obj_t *label = lv_label_create(parent);

  // Set the label text
  lv_label_set_text(label, "VU Meter");

  // Set a large font (make sure the font is available in your project)
  lv_obj_set_style_text_font(label, &lv_font_montserrat_14, LV_PART_MAIN);

  // Align the label to the top center of the screen
  lv_obj_align(label, LV_ALIGN_TOP_MID, 0, 60); // 60 pixels from the top
}

Spectrum Analyzer

image

Another microphone application I want to demonstrate is an audio spectrum analyzer, because the kit has all the hardware as well as the computing horsepower needed.

Here is an even shorter video demonstrating a simple spectrum analyzer:

Spectrum Analyzer Demo Video

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

The green bars are showing up as white in the video. The software is a long way from good, but the objective is to show that the hardware is capable.

Spectrum Analyzer Firmware

/*
	Example of an audio spectrum analyzer display using the Arduino Giga Display and its microphone
  by Doug Wong 2025
  This program uses th FFT library by Enrique Condes
*/

#include "Arduino_GigaDisplay.h"
#include "arduinoFFT.h"
#include "Arduino_GigaDisplay_GFX.h"
#include <PDM.h>

GigaDisplay_GFX display; // Create the display object

#define SAMPLES 128           // Number of audio samples
#define BARS 16               // Number of spectrum bars
#define SAMPLING_FREQUENCY 16000  // Hz
#define GREEN 0x07E0
#define BLACK 0x0000
#define BLUE 0x001E

/*
These values can be changed in order to evaluate the functions
*/
const uint16_t samples = 128; //This value MUST ALWAYS be a power of 2
const double signalFrequency = 1000;
const double sampleFrequency = 16000;
static const int frequency = 16000;
static const char channels = 1;
const uint8_t amplitude = 100;
// static const int channels = 1;

short sampleBuffer[samples];

double vReal[samples];      //audio samples array
double vImag[samples];      //spectrum amplitudes
int iBar = SAMPLES / BARS;  //number of data points per bar
int barWidth = 2 * display.width() / BARS;  //number of pixels per bar
int barHeight;
int BarAmp;

int bytesAvailable = 128;   //in microphone buffer

/* Create FFT object */
ArduinoFFT<double> FFT = ArduinoFFT<double>(vReal, vImag, samples, sampleFrequency);

#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02
#define SCL_PLOT 0x03

void setup()
{
  delay (400);
 // Serial.begin(115200);
  display.begin();
  display.setRotation(1);
  PDM.setBufferSize(samples);
  delay (400);
  display.fillScreen(BLACK);
  PDM.onReceive(onPDMdata);
    // Start PDM microphone
  if (!PDM.begin(channels, frequency)) {
    //Serial.println("Failed to start PDM!");
    while (1)
      ;
  }
}

void loop()
{
//  PDM.read(sampleBuffer, bytesAvailable);
  for (int i = 0; i < SAMPLES; i++) {
    vReal[i] = sampleBuffer[i];
    vImag[i] = 0.0;
  }

  FFT.windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);	/* Weigh data */
  FFT.compute(vReal, vImag, SAMPLES, FFT_FORWARD); /* Compute FFT */
  FFT.complexToMagnitude(vReal, vImag, SAMPLES); /* Compute magnitudes */

// Draw spectrum bars
  for (int i = 0; i < BARS; i++) {
    BarAmp = 0;
    for(int j = 0; j < iBar; j++) {
//       if (BarAmp < vImag[i * BARS + j]) BarAmp = vImag[i * BARS + j];
      BarAmp = BarAmp + vImag[i * BARS + j];    // total amplitude in each bar
    }
    if (i == 8) BarAmp = BarAmp / 20;           // to reduce an anomolously high bar
    BarAmp =  BarAmp / BARS;                    // average amplitube in this bar
    barHeight = BarAmp / 16;                    // adjustment for overall volume
    if (barHeight > display.height()) barHeight = display.height(); 
    display.fillRect(i * barWidth, 0, barWidth - 2, display.height() - barHeight, BLACK);
    display.fillRect(i * barWidth, display.height() - barHeight, barWidth - 2, barHeight, GREEN);
  }
  delay(80);
}

void onPDMdata() {
  // query the number of bytes available
  int bytesAvailable = PDM.available();

  // read into the sample buffer
  int bytesRead = PDM.read(sampleBuffer, bytesAvailable);

  // 16-bit, 2 bytes per sample
  int samplesRead = bytesRead / 2;
}

Discussion

The Arduino Giga  kit has so many features these applications can be implemented with no extra hardware. The VU meter uses the MCU, the PDM microphone and the Giga Display. The Spectrum analyzer uses the same set of hardware but also uses the arduinoFFT library. This GIGA and display kit not only allows an extensive array of applications to be implemented with little or no extra hardware, the fact that so many features are built-in allows standard demo software to be developed that does all the heavy lifting in making features work together. This kit by itself could be the basis for an extensive course on microcontrollers.

Links:

Unboxing and display demo

Touch Screen and USB memory demo

GIGA display of an Arducam video camera

GIGA VU Meter and Spectrum Analyzer

GIGA WAV Player

GIGA HID Touch Keyboard

GIGA MQTT Client

Giga Paint

Giga Scope

Final Giga Road Test Blog

Giga R1 Road Test page

  • Sign in to reply
  • dang74
    dang74 1 month ago in reply to dougw

    I think when C targets hardware it's essentially serving the role of  a more readable assembly.  In the assembly I've written aside from a few subroutine calls everything is flat... so I kind of extend that outlook to C.  Also I think a variable or pointer that is mapped to a specific hardware address should be a global.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dang74
    dang74 1 month ago in reply to beacon_dave

    I forgot that there was a goto.  I took that C course in the late 90s... and a bunch of us grew up on BASIC in the 80s so we were yearning for goto... and yes one of the guys in the class did tell us that it was supported by C... but I never used it though.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • beacon_dave
    beacon_dave 1 month ago in reply to dang74

    "...I remember the instructor telling us that globals are bad and should be avoided..."

    Lucky for us then that Kernighan and Ritchie gave us the 'goto' statement to distract the instructor's attention with... Slight smile

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dougw
    dougw 1 month ago in reply to dang74

    I was similarly indoctrinated into how bad globals are. I use them because I find it simpler for my small programs, but I don't claim it is good practice. People should be aware, I have a lot of bad programming habits....Sunglasses

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dang74
    dang74 1 month ago in reply to dougw

    When I was first learning C I remember the instructor telling us that globals are bad and should be avoided.  In the last couple of years I've said, "to hell with that" and now I let loose with the globals.  These days I think my code has more instances of the word extern than it does if.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube