mirror of
https://github.com/ggerganov/ggwave.git
synced 2026-02-06 08:37:59 +08:00
rp2040-rx : analog mic example
This commit is contained in:
@@ -92,6 +92,7 @@ else()
|
||||
add_subdirectory(arduino-tx)
|
||||
add_subdirectory(arduino-tx-obsolete)
|
||||
add_subdirectory(esp32-rx)
|
||||
add_subdirectory(rp2040-rx)
|
||||
endif()
|
||||
|
||||
if (GGWAVE_SUPPORT_SDL2)
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
|
||||
// Uncoment this line to enable long-range transmission
|
||||
// The used protocols are slower and use more memory to decode, but are much more robust
|
||||
//#define EXAMPLE_LONG_RANGE 1
|
||||
//#define LONG_RANGE 1
|
||||
|
||||
#include <ggwave.h>
|
||||
|
||||
@@ -129,7 +129,7 @@ void send_text(GGWave & ggwave, uint8_t pin, const char * text, GGWave::TxProtoc
|
||||
|
||||
void setup() {
|
||||
Serial.begin(57600);
|
||||
//while (!Serial);
|
||||
while (!Serial);
|
||||
|
||||
pinMode(kPinLED0, OUTPUT);
|
||||
pinMode(kPinSpeaker, OUTPUT);
|
||||
@@ -139,6 +139,8 @@ void setup() {
|
||||
|
||||
#ifdef DISPLAY_OUTPUT
|
||||
{
|
||||
Serial.println(F("Initializing display..."));
|
||||
|
||||
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
|
||||
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
|
||||
Serial.println(F("SSD1306 allocation failed"));
|
||||
@@ -175,12 +177,15 @@ void setup() {
|
||||
|
||||
// Adjust the "ggwave" parameters to your needs.
|
||||
// Make sure that the "payloadLength" parameter matches the one used on the transmitting side.
|
||||
#ifdef EXAMPLE_LONG_RANGE
|
||||
#ifdef LONG_RANGE
|
||||
// The "FAST" protocols require 2x more memory, so we reduce the payload length to compensate:
|
||||
p.payloadLength = 8;
|
||||
#else
|
||||
p.payloadLength = 16;
|
||||
#endif
|
||||
Serial.print(F("Using payload length: "));
|
||||
Serial.println(p.payloadLength);
|
||||
|
||||
p.sampleRateInp = sampleRate;
|
||||
p.sampleRateOut = sampleRate;
|
||||
p.sampleRate = sampleRate;
|
||||
@@ -204,12 +209,12 @@ void setup() {
|
||||
// Remove the ones that you don't need to reduce memory usage
|
||||
GGWave::Protocols::rx().disableAll();
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_NORMAL, true);
|
||||
#ifdef EXAMPLE_LONG_RANGE
|
||||
#ifdef LONG_RANGE
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_FAST, true);
|
||||
#endif
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_FASTEST, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_NORMAL, true);
|
||||
#ifdef EXAMPLE_LONG_RANGE
|
||||
#ifdef LONG_RANGE
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_FAST, true);
|
||||
#endif
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_FASTEST, true);
|
||||
@@ -249,7 +254,6 @@ void loop() {
|
||||
int but0Prev = HIGH;
|
||||
|
||||
GGWave::TxRxData result;
|
||||
GGWave::Spectrum rxSpectrum;
|
||||
|
||||
char resultLast[17];
|
||||
int tLastReceive = -10000;
|
||||
@@ -295,6 +299,7 @@ void loop() {
|
||||
#ifdef DISPLAY_OUTPUT
|
||||
const auto t = millis();
|
||||
|
||||
static GGWave::Spectrum rxSpectrum;
|
||||
if (ggwave.rxTakeSpectrum(rxSpectrum) && t > 2000) {
|
||||
const bool isNew = t - tLastReceive < 2000;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// Tested I2S microphones:
|
||||
// - Adafruit I2S SPH0645
|
||||
//
|
||||
// The ESP32 microcontroller has a built-int 12-bit ADC which is used to digitalize the analog signal
|
||||
// The ESP32 microcontroller has a built-in 12-bit ADC which is used to digitalize the analog signal
|
||||
// from the external analog microphone. When I2S microphone is used, the ADC is not used.
|
||||
//
|
||||
// The sketch optionally supports displaying the received "ggwave" data on an OLED display.
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
// Uncoment this line to enable long-range transmission
|
||||
// These protocols are slower and use more memory to decode, but are much more robust
|
||||
//#define EXAMPLE_LONG_RANGE 1
|
||||
//#define LONG_RANGE 1
|
||||
|
||||
#include <ggwave.h>
|
||||
|
||||
@@ -89,12 +89,13 @@ const int kPinLED0 = 2;
|
||||
GGWave ggwave;
|
||||
|
||||
// Audio capture configuration
|
||||
using TSample = int16_t;
|
||||
using TSample = int16_t;
|
||||
#if defined(MIC_ANALOG)
|
||||
using TSampleInput = int16_t;
|
||||
using TSampleInput = int16_t;
|
||||
#elif defined(MIC_I2S) || defined(MIC_I2S_SPH0645)
|
||||
using TSampleInput = int32_t;
|
||||
using TSampleInput = int32_t;
|
||||
#endif
|
||||
|
||||
const size_t kSampleSize_bytes = sizeof(TSample);
|
||||
|
||||
// High sample rate - better quality, but more CPU/Memory usage
|
||||
@@ -193,6 +194,8 @@ void setup() {
|
||||
|
||||
#ifdef DISPLAY_OUTPUT
|
||||
{
|
||||
Serial.println(F("Initializing display..."));
|
||||
|
||||
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
|
||||
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
|
||||
Serial.println(F("SSD1306 allocation failed"));
|
||||
@@ -229,12 +232,15 @@ void setup() {
|
||||
|
||||
// Adjust the "ggwave" parameters to your needs.
|
||||
// Make sure that the "payloadLength" parameter matches the one used on the transmitting side.
|
||||
#ifdef EXAMPLE_LONG_RANGE
|
||||
#ifdef LONG_RANGE
|
||||
// The "FAST" protocols require 2x more memory, so we reduce the payload length to compensate:
|
||||
p.payloadLength = 8;
|
||||
#else
|
||||
p.payloadLength = 16;
|
||||
#endif
|
||||
Serial.print(F("Using payload length: "));
|
||||
Serial.println(p.payloadLength);
|
||||
|
||||
p.sampleRateInp = sampleRate;
|
||||
p.sampleRateOut = sampleRate;
|
||||
p.sampleRate = sampleRate;
|
||||
@@ -254,12 +260,12 @@ void setup() {
|
||||
// Remove the ones that you don't need to reduce memory usage
|
||||
GGWave::Protocols::rx().disableAll();
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_NORMAL, true);
|
||||
#ifdef EXAMPLE_LONG_RANGE
|
||||
#ifdef LONG_RANGE
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_FAST, true);
|
||||
#endif
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_FASTEST, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_NORMAL, true);
|
||||
#ifdef EXAMPLE_LONG_RANGE
|
||||
#ifdef LONG_RANGE
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_FAST, true);
|
||||
#endif
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_FASTEST, true);
|
||||
@@ -315,7 +321,6 @@ int niter = 0;
|
||||
int tLastReceive = -10000;
|
||||
|
||||
GGWave::TxRxData result;
|
||||
GGWave::Spectrum rxSpectrum;
|
||||
|
||||
void loop() {
|
||||
// Read from i2s
|
||||
@@ -391,6 +396,7 @@ void loop() {
|
||||
#ifdef DISPLAY_OUTPUT
|
||||
const auto t = millis();
|
||||
|
||||
static GGWave::Spectrum rxSpectrum;
|
||||
if (ggwave.rxTakeSpectrum(rxSpectrum) && t > 2000) {
|
||||
const bool isNew = t - tLastReceive < 2000;
|
||||
|
||||
|
||||
2
examples/rp2040-rx/CMakeLists.txt
Normal file
2
examples/rp2040-rx/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
#
|
||||
# rp2040-rx
|
||||
@@ -1,5 +1,28 @@
|
||||
# rp2040-rx
|
||||
|
||||
WIP in progress
|
||||
This is a sample project for receiving audio data using [RP2040](https://www.espressif.com/en/products/socs/esp32) microcontroller.
|
||||
The chip has a built-in 12-bit ADC which is used to process the analog audio from the external microphone module in real-time.
|
||||
|
||||
## Setup
|
||||
|
||||
- Raspberry Pi Pico (or other RP2040 board)
|
||||
- Microphone, tested with the following, but others could be also supported:
|
||||
- Analog:
|
||||
- MAX9814
|
||||
- KY-037
|
||||
- KY-038
|
||||
- WS Sound sensor
|
||||
|
||||
## Pinout
|
||||
|
||||
### Analog Microphone
|
||||
|
||||
| MCU | Mic |
|
||||
| ------- | --------- |
|
||||
| GND | GND |
|
||||
| 3.3V | VCC / VDD |
|
||||
| GPIO 26 | Out |
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
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;
|
||||
}
|
||||
33
examples/rp2040-rx/mic-analog.h
Normal file
33
examples/rp2040-rx/mic-analog.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PICO_ANALOG_MICROPHONE_H_
|
||||
#define _PICO_ANALOG_MICROPHONE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void (*analog_samples_ready_handler_t)(void);
|
||||
|
||||
struct analog_microphone_config {
|
||||
uint32_t gpio;
|
||||
float bias_voltage;
|
||||
uint32_t sample_rate;
|
||||
uint32_t sample_buffer_size;
|
||||
};
|
||||
|
||||
int analog_microphone_init(const struct analog_microphone_config* config);
|
||||
void analog_microphone_deinit();
|
||||
|
||||
int analog_microphone_start();
|
||||
void analog_microphone_stop();
|
||||
|
||||
void analog_microphone_set_samples_ready_handler(analog_samples_ready_handler_t handler);
|
||||
|
||||
int analog_microphone_read(int16_t* buffer, size_t samples);
|
||||
|
||||
#endif
|
||||
242
examples/rp2040-rx/rp2040-rx.ino
Normal file
242
examples/rp2040-rx/rp2040-rx.ino
Normal file
@@ -0,0 +1,242 @@
|
||||
// rp2040-rx
|
||||
//
|
||||
// Sample sketch for receiving sound data using "ggwave"
|
||||
//
|
||||
// Tested MCU boards:
|
||||
// - Raspberry Pi Pico
|
||||
// - Arduino Nano RP2040 Connect
|
||||
//
|
||||
// Tested analog microphones:
|
||||
// - MAX9814
|
||||
// - KY-037
|
||||
// - KY-038
|
||||
// - WS Sound sensor
|
||||
//
|
||||
// The RP2040 microcontroller has a built-in 12-bit ADC which is used to digitalize the analog signal
|
||||
// from the external analog microphone. The MCU supports sampling rates up to 500kHz which makes it
|
||||
// capable of even recording audio in the ultrasound range, given that your microphone's sensitivity
|
||||
// supports it.
|
||||
//
|
||||
// If you want to perform a quick test, you can use the free "Waver" application:
|
||||
// - Web: https://waver.ggerganov.com
|
||||
// - Android: https://play.google.com/store/apps/details?id=com.ggerganov.Waver
|
||||
// - iOS: https://apps.apple.com/us/app/waver-data-over-sound/id1543607865
|
||||
//
|
||||
// Make sure to enable the "Fixed-length" option in "Waver"'s settings and set the number of
|
||||
// bytes to be equal to "payloadLength" used in the sketch. Also, select a protocol that is
|
||||
// listed as Rx in the current sketch.
|
||||
//
|
||||
// Sketch: https://github.com/ggerganov/ggwave/tree/master/examples/rp2040-rx
|
||||
//
|
||||
// ## Pinout
|
||||
//
|
||||
// ### Analog Microphone
|
||||
//
|
||||
// | MCU | Mic |
|
||||
// | ------- | --------- |
|
||||
// | GND | GND |
|
||||
// | 3.3V | VCC / VDD |
|
||||
// | GPIO 26 | Out |
|
||||
//
|
||||
|
||||
// Uncomment the line coresponding to your microhpone
|
||||
#define MIC_ANALOG
|
||||
|
||||
// Uncoment this line to enable long-range transmission
|
||||
// The used protocols are slower and use more memory to decode, but are much more robust
|
||||
//#define LONG_RANGE 1
|
||||
|
||||
#include <ggwave.h>
|
||||
|
||||
// Audio capture configuration
|
||||
using TSample = int16_t;
|
||||
|
||||
const size_t kSampleSize_bytes = sizeof(TSample);
|
||||
|
||||
// High sample rate - better quality, but more CPU/Memory usage
|
||||
const int sampleRate = 48000;
|
||||
const int samplesPerFrame = 1024;
|
||||
|
||||
// Low sample rate
|
||||
//const int sampleRate = 24000;
|
||||
//const int samplesPerFrame = 512;
|
||||
|
||||
TSample sampleBuffer[samplesPerFrame];
|
||||
|
||||
#if defined(MIC_ANALOG)
|
||||
|
||||
#include "mic-analog.h"
|
||||
|
||||
volatile int samplesRead = 0;
|
||||
|
||||
const struct analog_microphone_config config = {
|
||||
// GPIO to use for input, must be ADC compatible (GPIO 26 - 28)
|
||||
.gpio = 26,
|
||||
|
||||
// bias voltage of microphone in volts
|
||||
.bias_voltage = 1.25,
|
||||
|
||||
// sample rate in Hz
|
||||
.sample_rate = sampleRate,
|
||||
|
||||
// number of samples to buffer
|
||||
.sample_buffer_size = samplesPerFrame,
|
||||
};
|
||||
|
||||
void on_analog_samples_ready()
|
||||
{
|
||||
// callback from library when all the samples in the library
|
||||
// internal sample buffer are ready for reading
|
||||
samplesRead = analog_microphone_read(sampleBuffer, samplesPerFrame);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Global GGwave instance
|
||||
GGWave ggwave;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
|
||||
// Initialize "ggwave"
|
||||
{
|
||||
Serial.println(F("Trying to initialize the ggwave instance"));
|
||||
|
||||
ggwave.setLogFile(nullptr);
|
||||
|
||||
auto p = GGWave::getDefaultParameters();
|
||||
|
||||
// Adjust the "ggwave" parameters to your needs.
|
||||
// Make sure that the "payloadLength" parameter matches the one used on the transmitting side.
|
||||
#ifdef LONG_RANGE
|
||||
// The "FAST" protocols require 2x more memory, so we reduce the payload length to compensate:
|
||||
p.payloadLength = 8;
|
||||
#else
|
||||
p.payloadLength = 16;
|
||||
#endif
|
||||
Serial.print(F("Using payload length: "));
|
||||
Serial.println(p.payloadLength);
|
||||
|
||||
p.sampleRateInp = sampleRate;
|
||||
p.sampleRateOut = sampleRate;
|
||||
p.sampleRate = sampleRate;
|
||||
p.samplesPerFrame = samplesPerFrame;
|
||||
p.sampleFormatInp = GGWAVE_SAMPLE_FORMAT_I16;
|
||||
p.sampleFormatOut = GGWAVE_SAMPLE_FORMAT_U8;
|
||||
p.operatingMode = GGWAVE_OPERATING_MODE_RX | GGWAVE_OPERATING_MODE_TX | GGWAVE_OPERATING_MODE_USE_DSS | GGWAVE_OPERATING_MODE_TX_ONLY_TONES;
|
||||
|
||||
// Protocols to use for TX
|
||||
// Remove the ones that you don't need to reduce memory usage
|
||||
GGWave::Protocols::tx().disableAll();
|
||||
//GGWave::Protocols::tx().toggle(GGWAVE_PROTOCOL_MT_NORMAL, true);
|
||||
//GGWave::Protocols::tx().toggle(GGWAVE_PROTOCOL_MT_FAST, true);
|
||||
GGWave::Protocols::tx().toggle(GGWAVE_PROTOCOL_MT_FASTEST, true);
|
||||
|
||||
// Protocols to use for RX
|
||||
// Remove the ones that you don't need to reduce memory and CPU usage
|
||||
GGWave::Protocols::rx().disableAll();
|
||||
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_AUDIBLE_NORMAL, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_NORMAL, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_NORMAL, true);
|
||||
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_AUDIBLE_NORMAL, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_NORMAL, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_NORMAL, true);
|
||||
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_ULTRASOUND_NORMAL, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_ULTRASOUND_FAST, true);
|
||||
//GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_ULTRASOUND_FASTEST, true);
|
||||
|
||||
#ifdef LONG_RANGE
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_AUDIBLE_FAST, true);
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_FAST, true);
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_FAST, true);
|
||||
#endif
|
||||
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_AUDIBLE_FASTEST, true);
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_DT_FASTEST, true);
|
||||
GGWave::Protocols::rx().toggle(GGWAVE_PROTOCOL_MT_FASTEST, true);
|
||||
|
||||
// Print the memory required for the "ggwave" instance:
|
||||
ggwave.prepare(p, false);
|
||||
|
||||
Serial.print(F("Required memory by the ggwave instance: "));
|
||||
Serial.print(ggwave.heapSize());
|
||||
Serial.println(F(" bytes"));
|
||||
|
||||
// Initialize the "ggwave" instance:
|
||||
ggwave.prepare(p, true);
|
||||
Serial.print(F("Instance initialized successfully! Memory used: "));
|
||||
}
|
||||
|
||||
// initialize the analog microphone
|
||||
if (analog_microphone_init(&config) < 0) {
|
||||
Serial.println(F("analog microphone initialization failed!"));
|
||||
while (1) { tight_loop_contents(); }
|
||||
}
|
||||
|
||||
// set callback that is called when all the samples in the library
|
||||
// internal sample buffer are ready for reading
|
||||
analog_microphone_set_samples_ready_handler(on_analog_samples_ready);
|
||||
|
||||
// start capturing data from the analog microphone
|
||||
if (analog_microphone_start() < 0) {
|
||||
Serial.println(F("Analog microphone start failed!"));
|
||||
while (1) { tight_loop_contents(); }
|
||||
}
|
||||
|
||||
Serial.println(F("setup() done"));
|
||||
}
|
||||
|
||||
int niter = 0;
|
||||
int tLastReceive = -10000;
|
||||
|
||||
GGWave::TxRxData result;
|
||||
|
||||
void loop() {
|
||||
// wait for new samples
|
||||
while (samplesRead == 0) { tight_loop_contents(); }
|
||||
|
||||
// store and clear the samples read from the callback
|
||||
int nSamples = samplesRead;
|
||||
samplesRead = 0;
|
||||
|
||||
//// loop through any new collected samples
|
||||
//for (int i = 0; i < nSamples; i++) {
|
||||
// Serial.printf("%d\n", sampleBuffer[i]);
|
||||
//}
|
||||
|
||||
// Try to decode any "ggwave" data:
|
||||
auto tStart = millis();
|
||||
|
||||
if (ggwave.decode(sampleBuffer, samplesPerFrame*kSampleSize_bytes) == false) {
|
||||
Serial.println("Failed to decode");
|
||||
}
|
||||
|
||||
auto tEnd = millis();
|
||||
|
||||
if (++niter % 10 == 0) {
|
||||
// print the time it took the last decode() call to complete
|
||||
// should be smaller than samplesPerFrame/sampleRate seconds
|
||||
// for example: samplesPerFrame = 128, sampleRate = 6000 => not more than 20 ms
|
||||
Serial.println(tEnd - tStart);
|
||||
if (tEnd - tStart > 1000*(float(samplesPerFrame)/sampleRate)) {
|
||||
Serial.println(F("Warning: decode() took too long to execute!"));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have successfully decoded any data:
|
||||
int nr = ggwave.rxTakeData(result);
|
||||
if (nr > 0) {
|
||||
Serial.println(tEnd - tStart);
|
||||
Serial.print(F("Received data with length "));
|
||||
Serial.print(nr); // should be equal to p.payloadLength
|
||||
Serial.println(F(" bytes:"));
|
||||
|
||||
Serial.println((char *) result.data());
|
||||
|
||||
tLastReceive = tEnd;
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
# define GGWAVE_API
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO)
|
||||
#if defined(ARDUINO_UNO)
|
||||
#define GGWAVE_CONFIG_FEW_PROTOCOLS
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user