esp-idf/examples/peripherals/i2s/i2s_basic/i2s_pdm/main/i2s_pdm_tx.c

114 wiersze
4.9 KiB
C

/*
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdint.h>
#include <math.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_pdm.h"
#include "driver/gpio.h"
#include "esp_check.h"
#include "sdkconfig.h"
#include "i2s_pdm_example.h"
#define EXAMPLE_PDM_TX_CLK_IO GPIO_NUM_4 // I2S PDM TX clock io number
#define EXAMPLE_PDM_TX_DOUT_IO GPIO_NUM_5 // I2S PDM TX data out io number
#define EXAMPLE_PDM_TX_FREQ_HZ 44100 // I2S PDM TX frequency
#define EXAMPLE_WAVE_AMPLITUDE (1000.0) // 1~32767
#define CONST_PI (3.1416f)
#define EXAMPLE_SINE_WAVE_LEN(tone) (uint32_t)((EXAMPLE_PDM_TX_FREQ_HZ / (float)tone) + 0.5) // The sample point number per sine wave to generate the tone
#define EXAMPLE_TONE_LAST_TIME_MS 500
#define EXAMPLE_BYTE_NUM_EVERY_TONE (EXAMPLE_TONE_LAST_TIME_MS * EXAMPLE_PDM_TX_FREQ_HZ / 1000)
/* The frequency of tones: do, re, mi, fa, so, la, si, in Hz. */
static const uint32_t tone[3][7] = {{262, 294, 330, 349, 392, 440, 494}, // bass
{523, 587, 659, 698, 784, 880, 988}, // alto
{1046, 1175, 1318, 1397, 1568, 1760, 1976}}; // treble
/* Numbered musical notation of 'twinkle twinkle little star' */
static const uint8_t song[28] = {1, 1, 5, 5, 6, 6, 5,
4, 4, 3, 3, 2, 2, 1,
5, 5, 4, 4, 3, 3, 2,
5, 5, 4, 4, 3, 3, 2};
/* Rhythm of 'twinkle twinkle little star', it's repeated in four sections */
static const uint8_t rhythm[7] = {1, 1, 1, 1, 1, 1, 2};
static const char *tone_name[3] = {"bass", "alto", "treble"};
static i2s_chan_handle_t i2s_example_init_pdm_tx(void)
{
i2s_chan_handle_t tx_chan; // I2S tx channel handler
/* Setp 1: Determine the I2S channel configuration and allocate TX channel only
* The default configuration can be generated by the helper macro,
* it only requires the I2S controller id and I2S role,
* but note that PDM channel can only be registered on I2S_NUM_0 */
i2s_chan_config_t tx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
tx_chan_cfg.auto_clear = true;
ESP_ERROR_CHECK(i2s_new_channel(&tx_chan_cfg, &tx_chan, NULL));
/* Step 2: Setting the configurations of PDM TX mode and initialize the TX channel
* The slot configuration and clock configuration can be generated by the macros
* These two helper macros is defined in 'i2s_pdm.h' which can only be used in PDM TX mode.
* They can help to specify the slot and clock configurations for initialization or re-configuring */
i2s_pdm_tx_config_t pdm_tx_cfg = {
.clk_cfg = I2S_PDM_TX_CLK_DEFAULT_CONFIG(EXAMPLE_PDM_TX_FREQ_HZ),
/* The data bit-width of PDM mode is fixed to 16 */
.slot_cfg = I2S_PDM_TX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.clk = EXAMPLE_PDM_TX_CLK_IO,
.dout = EXAMPLE_PDM_TX_DOUT_IO,
.invert_flags = {
.clk_inv = false,
},
},
};
ESP_ERROR_CHECK(i2s_channel_init_pdm_tx_mode(tx_chan, &pdm_tx_cfg));
/* Step 3: Enable the tx channel before writing data */
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
return tx_chan;
}
void i2s_example_pdm_tx_task(void *args)
{
int16_t *w_buf = (int16_t *)calloc(1, EXAMPLE_BUFF_SIZE);
assert(w_buf);
i2s_chan_handle_t tx_chan = i2s_example_init_pdm_tx();
size_t w_bytes = 0;
uint8_t cnt = 0; // The current index of the song
uint8_t tone_select = 0; // To selecting the tone level
printf("Playing %s `twinkle twinkle little star`\n", tone_name[tone_select]);
while (1) {
int tone_point = EXAMPLE_SINE_WAVE_LEN(tone[tone_select][song[cnt]-1]);
/* Generate the tone buffer */
for (int i = 0; i < tone_point; i++) {
w_buf[i] = (int16_t)((sin(2 * (float)i * CONST_PI / tone_point)) * EXAMPLE_WAVE_AMPLITUDE);
}
for (int tot_bytes = 0; tot_bytes < EXAMPLE_BYTE_NUM_EVERY_TONE * rhythm[cnt % 7]; tot_bytes += w_bytes) {
/* Play the tone */
if (i2s_channel_write(tx_chan, w_buf, tone_point * sizeof(int16_t), &w_bytes, 1000) != ESP_OK) {
printf("Write Task: i2s write failed\n");
}
}
cnt++;
/* If finished playing, switch the tone level */
if (cnt == sizeof(song)) {
cnt = 0;
tone_select++;
tone_select %= 3;
printf("Playing %s `twinkle twinkle little star`\n", tone_name[tone_select]);
}
/* Gap between the tones */
vTaskDelay(15);
}
free(w_buf);
vTaskDelete(NULL);
}