Battery-less Audio Node Design
Table
| Function | MCU Pin | Net | Connected To | Direction | Notes |
|---|---|---|---|---|---|
| PDM clock | PC00 | PDM_CLK | MK1 CLOCK | Output | Clock to Knowles PDM microphone |
| PDM data | PC01 | PDM_DATA | MK1 DATA | Input | PDM data from MK1 |
| Harvest voltage sense | PA03 | HARV_SENSE | R3/R4 divider | Analog input | Divider ratio approximately 0.248 |
| SWCLK | PA01 | SWCLK | J2 Pin 4 | Debug | Datasheet debug function |
| SWDIO | PA02 | SWDIO | J2 Pin 2 | Debug | Datasheet debug function |
| RESETn | RESETn | RESET_N | R1, S1, J2 Pin 5 | Input | External reset button and debug reset |
| RF | RF2G4_IO | RF_MATCH_IC | L1/C11 match network | RF | 2.4 GHz RF path to SMA |
| HFXO input | HFXTAL_I | HFXTAL_I | Y1 OSC1 | Analog clock | 38.4 MHz crystal candidate |
| HFXO output | HFXTAL_O | HFXTAL_O | Y1 OSC2 | Analog clock | 38.4 MHz crystal candidate |
app.cC
#include "em_device.h" #include "em_chip.h" #include "em_cmu.h" #include "em_gpio.h" #include "em_iadc.h" #include "em_timer.h" #include <stdint.h> #include <stdbool.h> // Pin mapping from schematic #define PDM_CLK_PORT gpioPortC #define PDM_CLK_PIN 0 #define PDM_DATA_PORT gpioPortC #define PDM_DATA_PIN 1 #define HARV_ADC_PORT gpioPortA #define HARV_ADC_PIN 3 // Harvest divider: R3 = 1M, R4 = 330k #define HARV_DIVIDER_RATIO (330000.0f / (1000000.0f + 330000.0f)) #define IADC_VREF_MV 1210.0f #define IADC_MAX_COUNTS 4095.0f static volatile uint32_t g_pdm_edge_count = 0; static void initClocks(void) { CMU_ClockEnable(cmuClock_GPIO, true); CMU_ClockEnable(cmuClock_IADC0, true); CMU_ClockEnable(cmuClock_TIMER0, true); } static void initGpio(void) { // PDM clock output. TIMER0 route can be added after selecting final clock rate. GPIO_PinModeSet(PDM_CLK_PORT, PDM_CLK_PIN, gpioModePushPull, 0); // PDM data input from microphone. GPIO_PinModeSet(PDM_DATA_PORT, PDM_DATA_PIN, gpioModeInputPull, 0); // Harvest sense analog input. GPIO_PinModeSet(HARV_ADC_PORT, HARV_ADC_PIN, gpioModeDisabled, 0); } static void initHarvestAdc(void) { IADC_Init_t init = IADC_INIT_DEFAULT; IADC_AllConfigs_t allConfigs = IADC_ALLCONFIGS_DEFAULT; IADC_InitSingle_t initSingle = IADC_INITSINGLE_DEFAULT; IADC_SingleInput_t singleInput = IADC_SINGLEINPUT_DEFAULT; // Use internal reference; tune prescalers in production project using Clock Manager. allConfigs.configs[0].reference = iadcCfgReferenceInt1V2; allConfigs.configs[0].vRef = 1210; allConfigs.configs[0].analogGain = iadcCfgAnalogGain1x; // Port A pin 3 maps to iadcPosInputPortAPin3 on Series 2 devices. singleInput.posInput = iadcPosInputPortAPin3; singleInput.negInput = iadcNegInputGnd; IADC_init(IADC0, &init, &allConfigs); IADC_initSingle(IADC0, &initSingle, &singleInput); } static uint32_t readHarvestAdcCounts(void) { IADC_command(IADC0, iadcCmdStartSingle); while ((IADC0->STATUS & IADC_STATUS_SINGLEFIFODV) == 0) { // Wait for conversion complete. } IADC_Result_t result = IADC_pullSingleFifoResult(IADC0); return result.data; } static float readHarvestVoltage(void) { uint32_t counts = readHarvestAdcCounts(); float sense_mv = ((float)counts / IADC_MAX_COUNTS) * IADC_VREF_MV; float vharv_mv = sense_mv / HARV_DIVIDER_RATIO; return vharv_mv / 1000.0f; } static void initPdmClockTimer(void) { // This creates a simple firmware-visible PDM clock pin state for bring-up. // For production audio capture, replace this with the EFR32 PDM peripheral or // a TIMER/PRS route that generates the required 1.0 MHz to 4.8 MHz PDM clock. TIMER_Init_TypeDef timerInit = TIMER_INIT_DEFAULT; timerInit.enable = true; timerInit.prescale = timerPrescale1; TIMER_Init(TIMER0, &timerInit); } static void pdmBringupTick(void) { // Lightweight pin activity counter to prove the microphone DATA line is alive // while the final PDM peripheral/DMA capture path is being implemented. static uint8_t last = 0; uint8_t now = GPIO_PinInGet(PDM_DATA_PORT, PDM_DATA_PIN); if (now != last) { g_pdm_edge_count++; last = now; } } void app_init(void) { CHIP_Init(); initClocks(); initGpio(); initHarvestAdc(); initPdmClockTimer(); } void app_process_action(void) { static uint32_t loop_count = 0; pdmBringupTick(); if ((loop_count++ % 10000u) == 0u) { float vharv = readHarvestVoltage(); (void)vharv; // Add logging through RTT/SWO/USART if enabled in the project. // Add radio burst trigger here once the selected Silicon Labs stack is configured. } }
Welcome 👋
Flux helps you build PCBs faster with an AI teammate!
Create your account to collaborate, stay updated, fork your own version, and get instant answers from our AI agent.