1 前言
本章实现了播放和录制功能。
2 硬件
3 代码
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_system.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s.h"
#include "driver/gpio.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "sdkconfig.h"
#include <dirent.h>
#include "esp_vfs.h"
#define DIR_NUM_MAX 10
static const char* TAG = "pdm_rec_example";
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#define SD_MOUNT_POINT "/sdcard"
#define I2S_REC_CHANNEL (1)
#define I2S_REC_BIT (16)
#define I2S_REC_SAMPLE_RATE (36000)
#define I2S_SAMPLE_SIZE (I2S_REC_BIT * 1024)
#define I2S_BYTE_RATE (I2S_REC_SAMPLE_RATE * (I2S_REC_BIT / 8)) * I2S_REC_CHANNEL
#define I2S_NUM 0
#define I2S_REC_TIME 5
#define I2S_PIN_BCK_GPIO 41
#define I2S_PIN_WS_GPIO 40
#define I2S_PIN_DATA_RECORD 42
#define I2S_PIN_DATA_PLAYBACK 45
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
sdmmc_card_t* card;
#define SPI_MOSI_GPIO 35
#define SPI_MISO_GPIO 37
#define SPI_SCLK_GPIO 36
#define SPI_CS_GPIO 34
static int16_t i2s_readraw_buff[I2S_SAMPLE_SIZE];
size_t bytes_read;
const int WAVE_HEADER_SIZE = 44;
struct wavinfo
{
char *name;
bool status;
int current_time;
int bit;
int channel;
int sample_rate;
int while_time;
int format;
struct wavinfo * next;
};
#define WAV_LIST_MAX 10
struct wavinfo *wav_list = NULL;
struct wavinfo list[WAV_LIST_MAX];
int current_list_num = 0;
struct wavinfo current_wav_msg;
struct wavinfo temp_wavinfo;
#define DIR_NAM_LEN_MAX 50
char dir_temp[DIR_NAM_LEN_MAX];
struct wavinfo get_wav_msg(char * wav_name)
{
for(int i=0;i<current_list_num;i++)
{
if(strstr(list[i].name,wav_name))
{
printf("has searched wav\n");
printf("name: %s\n",list[i].name);
return list[i];
}
}
printf("not find wav %s\n",wav_name);
return list[0];
}
char* char_change_A2a(char *raw_char)
{
char *temp = raw_char ;
int len = strlen(raw_char);
for(int a = 0; a<len; a++)
{
if('A'<=temp[a]&&temp[a]<='Z')
temp[a]=temp[a]+32;
}
return temp;
}
void dir_list(char *path)
{
char *dir_name;
if(path != NULL)
dir_name = path;
else
dir_name = SD_MOUNT_POINT;
ESP_LOGI(TAG, "Opening dir %s", dir_name);
DIR *dir_t1 = opendir(dir_name);
int count = 0;
char* names[DIR_NUM_MAX];
printf("DIR: %s\n",dir_name);
while(1) {
struct dirent* de = readdir(dir_t1);
if (!de) {
break;
}
names[count] = char_change_A2a(de->d_name);
printf("\t%s\n", de->d_name);
if(de->d_type == 2)
{
strcpy(dir_temp,dir_name);
strcat(dir_temp,"/");
strcat(dir_temp,de->d_name);
printf("this is dir:%s\n",dir_temp);
char * temp_cpr;
temp_cpr = "system~1";
if(strcmp(de->d_name,temp_cpr)==0)
printf("ignore this dir\n");
else
{
dir_list(dir_temp);
}
}
char* search_key = ".wav";
if(strstr(de->d_name,search_key) != NULL)
{
int file_name_len = strlen(dir_name)+strlen(de->d_name);
char *temp_path = (char *)malloc(sizeof(char) * (file_name_len+2));
strcpy(temp_path,dir_name);
strcat(temp_path,"/");
strcat(temp_path,de->d_name);
printf("file path = %s\n",temp_path);
struct wavinfo *p1 ;
p1 = &list[current_list_num];
current_list_num++;
p1->name = temp_path;
printf("p1->name = %s\n",p1->name);
}
++count;
}
closedir(dir_t1);
}
void print_wav_list()
{
printf("--------- wav list --------%d\n",current_list_num);
for(int i=0;i<current_list_num;i++)
{
printf("\twav%d: %s\n",i,list[i].name);
}
}
void test_sd_list()
{
char *temp_path = SD_MOUNT_POINT;
dir_list(temp_path);
print_wav_list();
}
void mount_sdcard(void)
{
esp_err_t ret;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 8 * 1024
};
ESP_LOGI(TAG, "Initializing SD card");
spi_bus_config_t bus_cfg = {
.mosi_io_num = SPI_MOSI_GPIO,
.miso_io_num = SPI_MISO_GPIO,
.sclk_io_num = SPI_SCLK_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize(host.slot, &bus_cfg, SPI_DMA_CHAN);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return;
}
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = SPI_CS_GPIO;
slot_config.host_id = host.slot;
ret = esp_vfs_fat_sdspi_mount(SD_MOUNT_POINT, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
}
return;
}
sdmmc_card_print_info(stdout, card);
}
void generate_wav_header(char* wav_header, uint32_t wav_size, uint32_t sample_rate){
uint32_t file_size = wav_size + WAVE_HEADER_SIZE - 8;
uint32_t byte_rate = I2S_BYTE_RATE;
const char set_wav_header[] = {
'R','I','F','F',
file_size, file_size >> 8, file_size >> 16, file_size >> 24,
'W','A','V','E',
'f','m','t',' ',
0x10, 0x00, 0x00, 0x00,
0x01, 0x00,
0x01, 0x00,
sample_rate, sample_rate >> 8, sample_rate >> 16, sample_rate >> 24,
byte_rate, byte_rate >> 8, byte_rate >> 16, byte_rate >> 24,
0x02, 0x00,
0x10, 0x00,
'd','a','t','a',
wav_size, wav_size >> 8, wav_size >> 16, wav_size >> 24,
};
memcpy(wav_header, set_wav_header, sizeof(set_wav_header));
}
void playback_wav(char *wav_name)
{
printf("wav name is %s\n",wav_name);
FILE* f_wav_play = fopen(wav_name, "r");
if (f_wav_play == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
char wav_header_fmt_play[WAVE_HEADER_SIZE];
fread(wav_header_fmt_play, 1, WAVE_HEADER_SIZE, f_wav_play);
char temp_cpr[8];
strncpy(temp_cpr,wav_header_fmt_play,4);
if(strstr(temp_cpr , "RIFF"))
{
strncpy(temp_cpr,wav_header_fmt_play+8,8);
if(strstr(temp_cpr , "WAVEfmt "))
{
printf("this is wav file \n");
current_wav_msg = get_wav_msg(wav_name);
printf("wav size = %02x, %02x, %02x, %02x\n",wav_header_fmt_play[40],wav_header_fmt_play[41],wav_header_fmt_play[42],wav_header_fmt_play[43]);
current_wav_msg.while_time = wav_header_fmt_play[40] + wav_header_fmt_play[41]* (1<<8) + wav_header_fmt_play[42]* (1<<16) + wav_header_fmt_play[43] * (1<<24);
printf("while_time = %d\n",current_wav_msg.while_time);
current_wav_msg.sample_rate = wav_header_fmt_play[24] + wav_header_fmt_play[25]* (1<<8) + wav_header_fmt_play[26]* (1<<16) + wav_header_fmt_play[27] * (1<<24);
printf("sample_rate = %d\n",current_wav_msg.sample_rate);
int temp_current_time = 0;
bytes_read = 0;
while (temp_current_time < current_wav_msg.while_time) {
fread(i2s_readraw_buff, 1, bytes_read, f_wav_play);
i2s_write(I2S_NUM, i2s_readraw_buff, I2S_SAMPLE_SIZE, &bytes_read, 100);
temp_current_time += bytes_read;
printf("temp_current_time = %d\n",temp_current_time);
}
}
}
fclose(f_wav_play);
ESP_LOGI(TAG, "File read from SDCard");
}
void record_wav(uint32_t rec_time)
{
int flash_wr_size = 0;
ESP_LOGI(TAG, "Opening file");
char wav_header_fmt[WAVE_HEADER_SIZE];
uint32_t flash_rec_time = I2S_BYTE_RATE * rec_time;
generate_wav_header(wav_header_fmt, flash_rec_time, I2S_REC_SAMPLE_RATE);
struct stat st;
if (stat(SD_MOUNT_POINT"/record.wav", &st) == 0) {
unlink(SD_MOUNT_POINT"/record.wav");
}
FILE* f = fopen(SD_MOUNT_POINT"/record.wav", "a");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
fwrite(wav_header_fmt, 1, WAVE_HEADER_SIZE, f);
while (flash_wr_size < flash_rec_time) {
i2s_read(I2S_NUM, i2s_readraw_buff, I2S_SAMPLE_SIZE, &bytes_read, 100);
fwrite(i2s_readraw_buff, 1, bytes_read, f);
flash_wr_size += bytes_read;
printf("flash_wr_size = %d\n",flash_wr_size);
}
ESP_LOGI(TAG, "Recording done!");
fclose(f);
ESP_LOGI(TAG, "File written on SDCard");
}
void init_i2s(void)
{
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX ,
.sample_rate = I2S_REC_SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL2,
.dma_buf_count = 8,
.dma_buf_len = 1024,
.use_apll = 0,
};
i2s_pin_config_t pin_config = {
.mck_io_num = I2S_PIN_NO_CHANGE,
.bck_io_num = I2S_PIN_BCK_GPIO,
.ws_io_num = I2S_PIN_WS_GPIO,
.data_out_num = I2S_PIN_DATA_PLAYBACK,
.data_in_num = I2S_PIN_DATA_RECORD,
};
ESP_ERROR_CHECK( i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL) );
ESP_ERROR_CHECK( i2s_set_pin(I2S_NUM, &pin_config) );
ESP_ERROR_CHECK( i2s_set_clk(I2S_NUM, I2S_REC_SAMPLE_RATE, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO) );
}
void app_main(void)
{
ESP_LOGI(TAG, "PDM microphone recording Example start");
mount_sdcard();
test_sd_list();
init_i2s();
ESP_LOGI(TAG, "Starting recording for %d seconds!", I2S_REC_TIME);
char * wav_play = "/sdcard/music60.wav";
wav_play = "/sdcard/music120.wav";
playback_wav(wav_play);
esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, card);
ESP_LOGI(TAG, "Card unmounted");
spi_bus_free(host.slot);
ESP_ERROR_CHECK( i2s_driver_uninstall(I2S_NUM) );
}
4 结果
|