Skip to content

Instantly share code, notes, and snippets.

@justiceamoh
Created November 4, 2019 16:45
Show Gist options
  • Save justiceamoh/4c3033b2c5afbbe1d5c54cf4a1bf8235 to your computer and use it in GitHub Desktop.
Save justiceamoh/4c3033b2c5afbbe1d5c54cf4a1bf8235 to your computer and use it in GitHub Desktop.
Queued PDM Streaming on Artemis Boards
#define ARM_MATH_CM4 //ARM Math library needed for FFT
#include <arm_math.h>
#include "am_bsp.h"
#include <CircularBuffer.h>
#define ledPin LED_BUILTIN
// ----------------
// Global Variables
// ----------------
#define BUFFSIZE 512
#define FRMESIZE 128
uint32_t PDMDataBuffer[BUFFSIZE];
int16_t *pi16Buffer = (int16_t *) PDMDataBuffer;
int16_t FrameBuffer[FRMESIZE]={0};
// Audio Buffer
CircularBuffer<int16_t,2048> AudioQueue;
am_hal_pdm_transfer_t sTransfer;
// Global Vars
int fidx = 0; // Buffer read pointer
// -----------------
// PDM Configuration
// -----------------
void *PDMHandle = NULL;
am_hal_pdm_config_t newConfig = {
.eClkDivider = AM_HAL_PDM_MCLKDIV_1,
.eLeftGain = AM_HAL_PDM_GAIN_0DB,
.eRightGain = AM_HAL_PDM_GAIN_0DB,
.ui32DecimationRate = 24,
.bHighPassEnable = 0,
.ui32HighPassCutoff = 0xB,
.ePDMClkSpeed = AM_HAL_PDM_CLK_750KHZ, //we get 768,000 Hz using 49.152 MHz clock
.bInvertI2SBCLK = 0,
.ePDMClkSource = AM_HAL_PDM_INTERNAL_CLK,
.bPDMSampleDelay = 0,
.bDataPacking = 0,
.ePCMChannels = AM_HAL_PDM_CHANNEL_RIGHT,
.ui32GainChangeDelay = 1,
.bI2SEnable = 0,
.bSoftMute = 0,
.bLRSwap = 0,
};
// -----------------
// PDM Configuration
// -----------------
void pdm_init(void){
// Initialize, power-up and configure PDM
am_hal_pdm_initialize(0,&PDMHandle);
am_hal_pdm_power_control(PDMHandle, AM_HAL_PDM_POWER_ON,false);
am_hal_pdm_configure(PDMHandle,&newConfig);
am_hal_pdm_enable(PDMHandle);
// Configure PDM pins
am_hal_gpio_pinconfig(AM_BSP_PDM_DATA, g_AM_BSP_PDM_DATA);
am_hal_gpio_pinconfig(AM_BSP_PDM_CLOCK, g_AM_BSP_PDM_CLOCK);
// Configure PDM interrupts - set to trigger on DMA completion
am_hal_pdm_interrupt_enable(PDMHandle,(AM_HAL_PDM_INT_DERR
| AM_HAL_PDM_INT_DCMP
| AM_HAL_PDM_INT_UNDFL
| AM_HAL_PDM_INT_OVF));
// Enable PDM interrupt
NVIC_EnableIRQ(PDM_IRQn);
}
// ----------------------------
// Get Data from PDM Microphone
// ----------------------------
void pdm_data_start(void){
// Configure DMA and target address.
sTransfer.ui32TargetAddr = (uint32_t ) PDMDataBuffer;
sTransfer.ui32TotalCount = BUFFSIZE * 2;
// Start the data transfer.
am_hal_pdm_enable(PDMHandle);
am_util_delay_ms(100);
am_hal_pdm_fifo_flush(PDMHandle);
am_hal_pdm_dma_start(PDMHandle, &sTransfer);
}
void pdm_data_stop(void){
am_hal_pdm_disable(PDMHandle);
}
// -----------------------------
// PDM Interrupt Service Routine
// -----------------------------
extern "C" void am_pdm_isr(void){
uint32_t ui32Status;
// Read the interrupt status.
am_hal_pdm_interrupt_status_get(PDMHandle, &ui32Status, true);
am_hal_pdm_interrupt_clear(PDMHandle, ui32Status);
// Once DMA transaction completes, move to Queue & Start next conversion
if (ui32Status & AM_HAL_PDM_INT_DCMP){
for (int i=0; i<BUFFSIZE;i++){
AudioQueue.push(pi16Buffer[i]);
}
// Start next conversion
am_hal_pdm_dma_start(PDMHandle, &sTransfer);
}
}
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
delay(1000);
pdm_init();
pdm_data_start();
}
void loop() {
processFrame();
}
void processFrame(){
if(!AudioQueue.isEmpty()){
FrameBuffer[fidx] = AudioQueue.pop();
fidx+=1;
//When frame is full, dump to serial
if(fidx==FRMESIZE){
Serial.write((uint8_t*)FrameBuffer, sizeof(FrameBuffer));
fidx = 0;
delay(2);
}
}
}
// Blink n times
void blink(int n){
for (int i = 0; i < n; ++i) {
digitalWrite(ledPin, LOW);
delay(100);
digitalWrite(ledPin, HIGH);
delay(100);
digitalWrite(ledPin, LOW);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment