mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-05-03 05:27:24 +08:00
rp2040-rx : analog mic example
This commit is contained in:
208
examples/rp2040-rx/mic-analog.cpp
Normal file
208
examples/rp2040-rx/mic-analog.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mic-analog.h"
|
||||
|
||||
#include "hardware/adc.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ANALOG_RAW_BUFFER_COUNT 2
|
||||
|
||||
static struct {
|
||||
int dma_channel;
|
||||
uint16_t* raw_buffer[ANALOG_RAW_BUFFER_COUNT];
|
||||
uint32_t buffer_size;
|
||||
int16_t bias;
|
||||
uint32_t dma_irq;
|
||||
|
||||
volatile int raw_buffer_write_index;
|
||||
volatile int raw_buffer_read_index;
|
||||
|
||||
analog_microphone_config config;
|
||||
analog_samples_ready_handler_t samples_ready_handler;
|
||||
} analog_mic;
|
||||
|
||||
static void analog_dma_handler();
|
||||
|
||||
int analog_microphone_init(const struct analog_microphone_config* config) {
|
||||
memset(&analog_mic, 0x00, sizeof(analog_mic));
|
||||
memcpy(&analog_mic.config, config, sizeof(analog_mic.config));
|
||||
|
||||
if (config->gpio < 26 || config->gpio > 29) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t raw_buffer_size = config->sample_buffer_size * sizeof(analog_mic.raw_buffer[0][0]);
|
||||
|
||||
analog_mic.buffer_size = config->sample_buffer_size;
|
||||
analog_mic.bias = ((int16_t)((config->bias_voltage * 4095) / 3.3));
|
||||
|
||||
for (int i = 0; i < ANALOG_RAW_BUFFER_COUNT; i++) {
|
||||
analog_mic.raw_buffer[i] = (uint16_t* )malloc(raw_buffer_size);
|
||||
if (analog_mic.raw_buffer[i] == NULL) {
|
||||
analog_microphone_deinit();
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
analog_mic.dma_channel = dma_claim_unused_channel(true);
|
||||
if (analog_mic.dma_channel < 0) {
|
||||
analog_microphone_deinit();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
float clk_div = (clock_get_hz(clk_adc) / (1.0 * config->sample_rate)) - 1;
|
||||
|
||||
dma_channel_config dma_channel_cfg = dma_channel_get_default_config(analog_mic.dma_channel);
|
||||
|
||||
channel_config_set_transfer_data_size(&dma_channel_cfg, DMA_SIZE_16);
|
||||
channel_config_set_read_increment(&dma_channel_cfg, false);
|
||||
channel_config_set_write_increment(&dma_channel_cfg, true);
|
||||
channel_config_set_dreq(&dma_channel_cfg, DREQ_ADC);
|
||||
|
||||
analog_mic.dma_irq = DMA_IRQ_0;
|
||||
|
||||
dma_channel_configure(
|
||||
analog_mic.dma_channel,
|
||||
&dma_channel_cfg,
|
||||
analog_mic.raw_buffer[0],
|
||||
&adc_hw->fifo,
|
||||
analog_mic.buffer_size,
|
||||
false
|
||||
);
|
||||
|
||||
adc_gpio_init(config->gpio);
|
||||
|
||||
adc_init();
|
||||
adc_select_input(config->gpio - 26);
|
||||
adc_fifo_setup(
|
||||
true, // Write each completed conversion to the sample FIFO
|
||||
true, // Enable DMA data request (DREQ)
|
||||
1, // DREQ (and IRQ) asserted when at least 1 sample present
|
||||
false, // We won't see the ERR bit because of 8 bit reads; disable.
|
||||
false // Don't shift each sample to 8 bits when pushing to FIFO
|
||||
);
|
||||
|
||||
adc_set_clkdiv(clk_div);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void analog_microphone_deinit() {
|
||||
for (int i = 0; i < ANALOG_RAW_BUFFER_COUNT; i++) {
|
||||
if (analog_mic.raw_buffer[i]) {
|
||||
free(analog_mic.raw_buffer[i]);
|
||||
|
||||
analog_mic.raw_buffer[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (analog_mic.dma_channel > -1) {
|
||||
dma_channel_unclaim(analog_mic.dma_channel);
|
||||
|
||||
analog_mic.dma_channel = -1;
|
||||
}
|
||||
}
|
||||
|
||||
int analog_microphone_start() {
|
||||
irq_set_enabled(analog_mic.dma_irq, true);
|
||||
irq_set_exclusive_handler(analog_mic.dma_irq, analog_dma_handler);
|
||||
|
||||
if (analog_mic.dma_irq == DMA_IRQ_0) {
|
||||
dma_channel_set_irq0_enabled(analog_mic.dma_channel, true);
|
||||
} else if (analog_mic.dma_irq == DMA_IRQ_1) {
|
||||
dma_channel_set_irq1_enabled(analog_mic.dma_channel, true);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
analog_mic.raw_buffer_write_index = 0;
|
||||
analog_mic.raw_buffer_read_index = 0;
|
||||
|
||||
dma_channel_transfer_to_buffer_now(
|
||||
analog_mic.dma_channel,
|
||||
analog_mic.raw_buffer[0],
|
||||
analog_mic.buffer_size
|
||||
);
|
||||
|
||||
adc_run(true); // start running the adc
|
||||
//
|
||||
return 0;
|
||||
}
|
||||
|
||||
void analog_microphone_stop() {
|
||||
adc_run(false); // stop running the adc
|
||||
|
||||
dma_channel_abort(analog_mic.dma_channel);
|
||||
|
||||
if (analog_mic.dma_irq == DMA_IRQ_0) {
|
||||
dma_channel_set_irq0_enabled(analog_mic.dma_channel, false);
|
||||
} else if (analog_mic.dma_irq == DMA_IRQ_1) {
|
||||
dma_channel_set_irq1_enabled(analog_mic.dma_channel, false);
|
||||
}
|
||||
|
||||
irq_set_enabled(analog_mic.dma_irq, false);
|
||||
}
|
||||
|
||||
static void analog_dma_handler() {
|
||||
// clear IRQ
|
||||
if (analog_mic.dma_irq == DMA_IRQ_0) {
|
||||
dma_hw->ints0 = (1u << analog_mic.dma_channel);
|
||||
} else if (analog_mic.dma_irq == DMA_IRQ_1) {
|
||||
dma_hw->ints1 = (1u << analog_mic.dma_channel);
|
||||
}
|
||||
|
||||
// get the current buffer index
|
||||
analog_mic.raw_buffer_read_index = analog_mic.raw_buffer_write_index;
|
||||
|
||||
// get the next capture index to send the dma to start
|
||||
analog_mic.raw_buffer_write_index = (analog_mic.raw_buffer_write_index + 1) % ANALOG_RAW_BUFFER_COUNT;
|
||||
|
||||
// give the channel a new buffer to write to and re-trigger it
|
||||
dma_channel_transfer_to_buffer_now(
|
||||
analog_mic.dma_channel,
|
||||
analog_mic.raw_buffer[analog_mic.raw_buffer_write_index],
|
||||
analog_mic.buffer_size
|
||||
);
|
||||
|
||||
if (analog_mic.samples_ready_handler) {
|
||||
analog_mic.samples_ready_handler();
|
||||
}
|
||||
}
|
||||
|
||||
void analog_microphone_set_samples_ready_handler(analog_samples_ready_handler_t handler) {
|
||||
analog_mic.samples_ready_handler = handler;
|
||||
}
|
||||
|
||||
int analog_microphone_read(int16_t* buffer, size_t samples) {
|
||||
if (samples > analog_mic.config.sample_buffer_size) {
|
||||
samples = analog_mic.config.sample_buffer_size;
|
||||
}
|
||||
|
||||
if (analog_mic.raw_buffer_write_index == analog_mic.raw_buffer_read_index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t* in = analog_mic.raw_buffer[analog_mic.raw_buffer_read_index];
|
||||
int16_t* out = buffer;
|
||||
int16_t bias = analog_mic.bias;
|
||||
|
||||
analog_mic.raw_buffer_read_index++;
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
*out++ = *in++ - bias;
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
Reference in New Issue
Block a user