I improved the code for ESP32 and tried voice sound communication with Chirp using M5StickC.
Sample code for ESP32Below are the Arm Cortex-M4 Arduino MCUs and the Chirp library for ESP32. https://github.com/chirp/chirp-arduino
It can also be installed from the library manager of the Android IDE.
For ESP32, sample code for sound (signal) transmission and reception is available. https://blog.chirp.io/chirp-for-arduino-esp32/
Here, customize the receiving code for M5StickC.
The sample code for receiving is as simple as connecting an I2S microphone SPH0645 to ESP32, receiving the audio signal, processing the signal with the algorithm by Chirp, and displaying the signal (character string) on the serial monitor.
Since Chirp's sound signal sending / receiving smartphone app is published, use a smartphone.
- Android:https://play.google.com/store/apps/details?id=io.chirp.messenger
- iOS;https://apps.apple.com/jp/app/chirp-messenger/id1438119896
Customize the receiving code for M5StickC.
The main changes are as follows.
- Changed the microphone from SPH0645 to SPM1423 with built-in M5StickC Corrected pin assignment and I2S settings
- The signal (character string) received by voice is displayed on the display.
Arduino code
#include <M5StickC.h>
#include <driver/i2s.h>
#include "efontEnableAll.h"
#include "efont.h"
#include "efontM5StickC.h"
#include "chirp_connect.h"
#include "credentials.h"
#define PIN_CLK 0
#define PIN_DATA 34
#define LED_PIN 10 // Pin number for on-board LED
#define BUFFER_SIZE 512 // Audio buffer size
#define SAMPLE_RATE 16000 // Audio sample rate
#define MIC_CALIBRATION 13125
#define CONVERT_INPUT(sample) (((int32_t)(sample) >> 14) + MIC_CALIBRATION)
// Global variables ------------------------------------------------------------
static chirp_connect_t *chirp = NULL;
static chirp_connect_state_t currentState = CHIRP_CONNECT_STATE_NOT_CREATED;
static bool startTasks = false;
// Function definitions --------------------------------------------------------
void setupChirp();
void chirpErrorHandler(chirp_connect_error_code_t code);
void setupAudioInput(int sample_rate);
// Function declarations -------------------------------------------------------
void setup()
{
M5.begin();
M5.Lcd.setRotation(1);
M5.Lcd.fillScreen(BLACK);
delay(500);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Serial.begin(115200);
Serial.printf("Heap size: %u\n", ESP.getFreeHeap());
xTaskCreate(initTask, "initTask", 16384, NULL, 1, NULL);
}
void loop()
{
esp_err_t audioError;
chirp_connect_error_code_t chirpError;
if (startTasks)
{
xTaskCreate(processInputTask, "processInputTask", 16384, NULL, 5, NULL);
startTasks = false;
}
}
// RTOS Tasks ------------------------------------------------------------------
void initTask(void *parameter)
{
setupChirp();
chirp_connect_error_code_t chirpError = chirp_connect_set_input_sample_rate(chirp, SAMPLE_RATE);
chirpErrorHandler(chirpError);
setupAudioInput(SAMPLE_RATE);
Serial.printf("Heap size: %u\n", ESP.getFreeHeap());
startTasks = true;
vTaskDelete(NULL);
}
void processInputTask(void *parameter)
{
esp_err_t audioError;
chirp_connect_error_code_t chirpError;
size_t bytesLength = 0;
float buffer[BUFFER_SIZE] = {0};
int32_t ibuffer[BUFFER_SIZE] = {0};
while (currentState >= CHIRP_CONNECT_STATE_RUNNING)
{
audioError = i2s_read(I2S_NUM_0, ibuffer, BUFFER_SIZE * 4, &bytesLength, portMAX_DELAY);
if (bytesLength)
{
for (int i = 0; i < bytesLength / 4; i++)
{
buffer[i] = (float) CONVERT_INPUT(ibuffer[i]);
}
chirpError = chirp_connect_process_input(chirp, buffer, bytesLength / 4);
chirpErrorHandler(chirpError);
}
}
vTaskDelete(NULL);
}
// Chirp -----------------------------------------------------------------------
void onStateChangedCallback(void *chirp, chirp_connect_state_t previous, chirp_connect_state_t current)
{
currentState = current;
Serial.printf("State changed from %d to %d\n", previous, current);
}
void onReceivingCallback(void *chirp, uint8_t *payload, size_t length, uint8_t channel)
{
Serial.println("Receiving data...");
digitalWrite(LED_PIN, HIGH);
}
void onReceivedCallback(void *chirp, uint8_t *payload, size_t length, uint8_t channel)
{
if (payload)
{
char *data = (char *)calloc(length + 1, sizeof(uint8_t));
memcpy(data, payload, length * sizeof(uint8_t));
Serial.print("Received data: ");
Serial.println(data);
// text print
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(2);
printEfont(data, 5, 10);
free(data);
}
else
{
Serial.println("Decode failed.");
}
}
void setupChirp()
{
chirp = new_chirp_connect(CHIRP_APP_KEY, CHIRP_APP_SECRET);
if (chirp == NULL)
{
Serial.println("Chirp initialisation failed.");
return;
}
chirp_connect_error_code_t err = chirp_connect_set_config(chirp, CHIRP_APP_CONFIG);
chirpErrorHandler(err);
chirp_connect_callback_set_t callbacks = {0};
callbacks.on_state_changed = onStateChangedCallback;
callbacks.on_receiving = onReceivingCallback;
callbacks.on_received = onReceivedCallback;
err = chirp_connect_set_callbacks(chirp, callbacks);
chirpErrorHandler(err);
err = chirp_connect_set_callback_ptr(chirp, chirp);
chirpErrorHandler(err);
err = chirp_connect_start(chirp);
chirpErrorHandler(err);
Serial.println("Chirp Connect initialised.");
}
void chirpErrorHandler(chirp_connect_error_code_t code)
{
if (code != CHIRP_CONNECT_OK)
{
const char *error_string = chirp_connect_error_code_to_string(code);
Serial.println(error_string);
exit(42);
}
}
// I2S Audio -------------------------------------------------------------------
void setupAudioInput(int sample_rate)
{
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM),
.sample_rate = sample_rate,
.bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // is fixed at 12bit, stereo, MSB
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 64,
};
i2s_pin_config_t pin_config;
pin_config.bck_io_num = I2S_PIN_NO_CHANGE;
pin_config.ws_io_num = PIN_CLK;
pin_config.data_out_num = I2S_PIN_NO_CHANGE;
pin_config.data_in_num = PIN_DATA;
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &pin_config);
i2s_set_sample_rates(I2S_NUM_0, sample_rate);
i2s_set_clk(I2S_NUM_0, sample_rate, I2S_BITS_PER_SAMPLE_32BIT, I2S_CHANNEL_MONO);
}
Surprisingly, Chirp's communication also supports Japanese, so we have introduced a library with reference to the following so that Japanese fonts can be displayed.https://github.com/tanakamasayuki/efont
In credentials.h, the APP_KEY, APP_SECRET, and APP_CONFIG issued during developer registration are described.Comment out # error ~ on the 15th line.
OperationThe sound is so cute like R2-D2!
There was news that the microcomputer will also support ultrasound in the future, so I would like to try ultrasound as well.
Comments