本帖最后由 qqlc 于 2025-8-17 19:39 编辑
gd32f4 进行使用iis驱动,完成录音实验,单纯接收录音数据 不保存为wav文件,但是发现接收到的数据有问题,频率一直为0,目前不知道是iis配置错了还是wm8978配置错了,wm8978用的是正点的例子改的
下面是我的iis驱动代码
void myi2s_init(uint32_t spi_periph, i2s_config_t *config,uint32_t TX_DMA_LENGTH,uint32_t RX_DMA_LENGTH)
{
current_config = *config;
if(spi_periph == SPI1) {
rcu_periph_clock_enable(RCU_SPI1);
} else if(spi_periph == SPI2) {
rcu_periph_clock_enable(RCU_SPI2);
}
spi_i2s_deinit(spi_periph);
//mode 主机
i2s_init(spi_periph, config->mode, config->standard, config->ckpl);
//mode从机
//i2s_psc_config(spi_periph, config->audio_sample,config->frame_format, config->mckout);
I2S1_SampleRate_Set(config->audio_sample,config->frame_format,config->mckout);
i2s_full_duplex_mode_config(I2S1_ADD, config->mode, config->standard, config->ckpl, config->frame_format);
i2s_dma_config(spi_periph,config,TX_DMA_LENGTH,RX_DMA_LENGTH);
i2s_enable(spi_periph);
i2s_enable(I2S1_ADD);
i2s_callback_init();
check_i2s_clock1(SPI1,I2S_FRAMEFORMAT_DT16B_CH16B,config->mckout);
}
void iis1_gpio_init(void){
/* 使能 GPIO 时钟 */
IIS1_MCK_GPIO_CLK_ENABLE();
IIS1_SCK_GPIO_CLK_ENABLE();
IIS1_WS_GPIO_CLK_ENABLE();
IIS1_SDA_GPIO_CLK_ENABLE();
IIS1_ADDSDA_GPIO_CLK_ENABLE();
/* 使能 SPI1/I2S1 时钟 */
rcu_periph_clock_enable(RCU_SPI1);
/* 配置 MCK (PC6) 为复用推挽输出 */
gpio_af_set(IIS1_MCK_GPIO_PORT, GPIO_AF_5, IIS1_MCK_GPIO_PIN); // AF5 = SPI1/I2S1
gpio_mode_set(IIS1_MCK_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, IIS1_MCK_GPIO_PIN);
gpio_output_options_set(IIS1_MCK_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, IIS1_MCK_GPIO_PIN);
/* 配置 SCK (PB13) 为复用推挽输出 */
gpio_af_set(IIS1_SCK_GPIO_PORT, GPIO_AF_5, IIS1_SCK_GPIO_PIN); // AF5 = SPI1/I2S1
gpio_mode_set(IIS1_SCK_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, IIS1_SCK_GPIO_PIN);
gpio_output_options_set(IIS1_SCK_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, IIS1_SCK_GPIO_PIN);
/* 配置 WS (PB12) 为复用推挽输出 */
gpio_af_set(IIS1_WS_GPIO_PORT, GPIO_AF_5, IIS1_WS_GPIO_PIN); // AF5 = SPI1/I2S1
gpio_mode_set(IIS1_WS_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, IIS1_WS_GPIO_PIN);
gpio_output_options_set(IIS1_WS_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, IIS1_WS_GPIO_PIN);
/* 配置 SDA (PB15) 为复用推挽输出 */
gpio_af_set(IIS1_SDA_GPIO_PORT, GPIO_AF_5, IIS1_SDA_GPIO_PIN); // AF5 = SPI1/I2S1
gpio_mode_set(IIS1_SDA_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, IIS1_SDA_GPIO_PIN);
gpio_output_options_set(IIS1_SDA_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, IIS1_SDA_GPIO_PIN);
// ADDSDA: PB14 → I2S1_SD_IN(接收数据,对应2S1_ADD_SD)
gpio_af_set(IIS1_ADDSDA_GPIO_PORT, GPIO_AF_6, IIS1_ADDSDA_GPIO_PIN); //
gpio_mode_set(IIS1_ADDSDA_GPIO_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, IIS1_ADDSDA_GPIO_PIN);
gpio_output_options_set(IIS1_ADDSDA_GPIO_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, IIS1_ADDSDA_GPIO_PIN);
}
void i2s_rx_dma_init(uint8_t *buf0, uint8_t *buf1, uint16_t num, i2s_config_t *config){
rcu_periph_clock_enable(RCU_DMA0);
dma_multi_data_parameter_struct dma_init;
dma_multi_data_para_struct_init(&dma_init);
// 公共配置
dma_deinit(DMA0, DMA_CH3);
dma_init.periph_inc = DMA_PERIPH_INCREASE_DISABLE; // 外设地址不递增(SPI数据寄存器地址固定)
dma_init.periph_width = DMA_PERIPH_WIDTH_16BIT; // 外设数据宽度:16位(音频数据常用16位采样)
dma_init.memory_width = DMA_MEMORY_WIDTH_16BIT; // 内存数据宽度:16位(与外设匹配)
dma_init.memory_inc = DMA_MEMORY_INCREASE_ENABLE; // 内存地址递增(数据连续存储到缓冲区)
dma_init.circular_mode = DMA_CIRCULAR_MODE_ENABLE; // 循环模式使能
dma_init.priority = DMA_PRIORITY_HIGH; // DMA优先级:高(音频传输需实时性)
dma_init.memory_burst_width=DMA_MEMORY_BURST_SINGLE;
dma_init.periph_burst_width=DMA_PERIPH_BURST_SINGLE;
if (config->dma_channel_rx != 0xFF) {
//dma_init.periph_addr = (uint32_t)&SPI_DATA(I2S1_ADD); // 外设地址:SPI数据寄存器
dma_init.periph_addr = (uint32_t)&I2S_ADD_DATA(I2S1_ADD);
dma_init.memory0_addr = (uint32_t)buf0;
dma_init.number = num;
dma_init.direction = DMA_PERIPH_TO_MEMORY;
dma_multi_data_mode_init(DMA0, (dma_channel_enum)config->dma_channel_rx, &dma_init);
dma_channel_subperipheral_select(DMA0, (dma_channel_enum)config->dma_channel_rx, DMA_SUBPERI3);
dma_switch_buffer_mode_config(DMA0, (dma_channel_enum)config->dma_channel_rx, (uint32_t)buf1, DMA_MEMORY_0);
dma_switch_buffer_mode_enable(DMA0, (dma_channel_enum)config->dma_channel_rx, ENABLE);
dma_interrupt_enable(DMA0, (dma_channel_enum)config->dma_channel_rx, DMA_CHXCTL_FTFIE);
nvic_irq_enable(DMA0_Channel3_IRQn, 2, 0);
spi_dma_enable(I2S1_ADD, SPI_DMA_RECEIVE);
delay_1us(10);
}
}
void i2s_tx_dma_init(uint8_t *buf0, uint8_t *buf1, uint16_t num, i2s_config_t *config){
rcu_periph_clock_enable(RCU_DMA0);
dma_multi_data_parameter_struct dma_init;
dma_multi_data_para_struct_init(&dma_init);
// 公共配置
dma_deinit(DMA0, DMA_CH4);
dma_init.periph_inc = DMA_PERIPH_INCREASE_DISABLE; // 外设地址不递增(SPI数据寄存器地址固定)
dma_init.periph_width = DMA_PERIPH_WIDTH_16BIT; // 外设数据宽度:16位(音频数据常用16位采样)
dma_init.memory_width = DMA_MEMORY_WIDTH_16BIT; // 内存数据宽度:16位(与外设匹配)
dma_init.memory_inc = DMA_MEMORY_INCREASE_ENABLE; // 内存地址递增(数据连续存储到缓冲区)
dma_init.circular_mode = DMA_CIRCULAR_MODE_ENABLE; // 循环模式使能
dma_init.priority = DMA_PRIORITY_HIGH; // DMA优先级:高(音频传输需实时性)
dma_init.memory_burst_width=DMA_MEMORY_BURST_SINGLE;
dma_init.periph_burst_width=DMA_PERIPH_BURST_SINGLE;
if (config->dma_channel_tx != 0xFF) {
dma_init.periph_addr = (uint32_t)&SPI_DATA(SPI1); // 外设地址:SPI数据寄存器
dma_init.memory0_addr = (uint32_t)buf0; // 内存缓冲区0地址
dma_init.number = num;
dma_init.direction = DMA_MEMORY_TO_PERIPH;
dma_multi_data_mode_init(DMA0, (dma_channel_enum)config->dma_channel_tx, &dma_init);
dma_channel_subperipheral_select(DMA0, (dma_channel_enum)config->dma_channel_tx, DMA_SUBPERI0);
dma_switch_buffer_mode_config(DMA0, (dma_channel_enum)config->dma_channel_tx, (uint32_t)buf1, DMA_MEMORY_0);//缓冲区1地址 激活当前的缓冲区DMA_MEMORY_0
dma_switch_buffer_mode_enable(DMA0, (dma_channel_enum)config->dma_channel_tx, ENABLE);
spi_dma_enable(SPI1, SPI_DMA_TRANSMIT);
dma_channel_disable(DMA0, (dma_channel_enum)current_config.dma_channel_tx);
dma_interrupt_enable(DMA0, (dma_channel_enum)config->dma_channel_tx, DMA_CHXCTL_FTFIE);
nvic_irq_enable(DMA0_Channel4_IRQn, 2, 0);
delay_1us(10);
}
}
/**
* @brief 配置I2S DMA传输
* @param spi_periph: SPI/I2S外设
* @param config: I2S配置结构体
*/
//SPI1 DMA RX CHANNEL 3 SP1 DMA TX CHANNEL 4
static void i2s_dma_config(uint32_t spi_periph, i2s_config_t *config,uint32_t TX_DMA_LENGTH,uint32_t RX_DMA_LENGTH)
{
i2s_rx_dma_init((u8*)iis1_info.rx_data_buf0,(u8*)iis1_info.rx_data_buf1,RX_DMA_LENGTH,config);
i2s_tx_dma_init((u8*)iis1_info.tx_data_buf0,(u8*)iis1_info.tx_data_buf1,TX_DMA_LENGTH,config);
}
void setI2Sconfig(i2s_config_t *config,u32 mode,u32 standard,u32 sample){
config->mode = mode;
config->standard = standard;
config->ckpl = I2S_CKPL_LOW;
config->audio_sample = sample;
config->frame_format = I2S_FRAMEFORMAT_DT16B_CH16B;
config->mckout = I2S_MCKOUT_ENABLE;
config->dma_channel_tx = DMA_CH4;
config->dma_channel_rx = DMA_CH3;
}
void wm8978_iis1_init(void)
{
u16 i = 0;
double fc = 5.0;
iis1_info.tx_done = 1;//初始化默认发送完成,保证下次可以直接开始发射
iis1_info.rx_done = 1;
setI2Sconfig(&config,I2S_MODE_MASTERTX,I2S_STD_PHILLIPS,I2S_AUDIOSAMPLE_16K);
iis1_info.tx_data_buf0 = (s16*)g_ABuff;//定义发送buf为26K
iis1_info.tx_data_buf1 = (s16*)mymalloc(SRAM2, MAX_ABUFF_SIZE);
iis1_info.rx_data_buf0 = (s16*)g_CBuff;//定义接收buf为MAX_CBUFF_SIZEk
iis1_info.rx_data_buf1 = (s16 *)(g_CBuff+MAX_CBUFF_SIZE);//(s16 *)g_DBuff;//定义发送buf为MAX_CBUFF_SIZEk
//iis1_info.rx_data_buf1 = (s16*)mymalloc(SRAM0, MAX_CBUFF_SIZE);
for(i = 0; i < MAX_ABUFF_SIZE/2; i++)
{
if(i %1024 == 0)
{
fc += 1;
}
//iis1_info.tx_data_buf0 = sin(fc*0.006132*i)*8192;
iis1_info.tx_data_buf0 = 0;
}
for(i = 0; i < MAX_ABUFF_SIZE/2; i++)
{
if(i %1024 == 0)
{
fc += 1;
}
//iis1_info.tx_data_buf1 = sin(fc*0.006132*i)*8192;
iis1_info.tx_data_buf0 = 0;
}
//MAX_CBUFF_SIZE 接收缓冲区的长度 MAX_ABUFF_SIZE 发送缓冲区的长度
myi2s_init(SPI1, &config,MAX_ABUFF_SIZE/2,MAX_CBUFF_SIZE/2);
I2S_Play_Stop();
I2S_Rec_Stop();
}
uint8_t I2S1_SampleRate_Set(uint32_t samplerate,u32 frame_format,u32 mck_en) {
uint8_t i = 0;
uint32_t tempreg = 0;
samplerate /= 10; // 与表中值对齐(采样率/10)
const u16 (*I2S_PSC_TBL)[5];
if(mck_en){
I2S_PSC_TBL=I2S_PSC_TBL_256;
}else if(frame_format==I2S_FRAMEFORMAT_DT16B_CH16B){
I2S_PSC_TBL=I2S_PSC_TBL_32;//16位
}else if(frame_format==I2S_FRAMEFORMAT_DT16B_CH32B){
I2S_PSC_TBL=I2S_PSC_TBL_64;
}
// 查找支持的采样率配置
size_t table_size = sizeof(I2S_PSC_TBL_256)/sizeof(I2S_PSC_TBL_256[0]);
for(i = 0; i < table_size; i++) {
if(samplerate == I2S_PSC_TBL[0]) {
break;
}
}
if(i == table_size) {
return 1; // 未找到匹配的采样率
}
//关闭PLLI2S
rcu_osci_off(RCU_PLLI2S_CK);
while((rcu_flag_get(RCU_FLAG_PLLI2SSTB) != RESET));
// 配置PLLI2S参数(PLLI2SN分频系数,PLLI2SR分频系数)
if(rcu_plli2s_config(I2S_PSC_TBL[1], I2S_PSC_TBL[2]) != SUCCESS) {
return 2; // PLLI2S参数配置失败(超出范围)
}
uint32_t plli2sm = (uint32_t)(RCU_PLL & RCU_PLL_PLLPSC);
uint32_t plli2sn = (uint32_t)((RCU_PLLI2S & RCU_PLLI2S_PLLI2SN) >> 6);
uint32_t plli2sr = (uint32_t)((RCU_PLLI2S & RCU_PLLI2S_PLLI2SR) >> 28);
printf("rcu_plli2s_config plli2sm1:%d plli2sn2: %d ,plli2sr3:%d,HXTAL_VALUE:%d, ishal:%d\r\n",plli2sm,plli2sn,plli2sr,HXTAL_VALUE,(RCU_PLL & RCU_PLL_PLLSEL) == RCU_PLLSRC_HXTAL);
rcu_osci_on(RCU_PLLI2S_CK);
// 等待PLLI2S稳定
if(rcu_osci_stab_wait(RCU_PLLI2S_CK) != SUCCESS) {
return 2; // PLLI2S启动超时
}
// 使I2S1外设时钟
rcu_periph_clock_enable(RCU_SPI1);
tempreg = I2S_PSC_TBL[3] << 0; // I2SDIV(位0-7):分频系数
tempreg |= I2S_PSC_TBL[4] << 8; // ODD(位8):奇数分频标志(0=偶数,1=奇数)
tempreg |= mck_en; // MCKOE(位9):主时钟输出使能(按需开启)
//printf("config tempreg:0x%08X\n", tempreg);
SPI_I2SPSC(SPI1) = tempreg; // 写入I2S预分频寄存器
//printf("after config SPL_I2SPSC:0x%08X\n", SPI_I2SPSC(SPI1));
// 配置帧格式
SPI_I2SCTL(SPI1) &= ~(SPI_I2SCTL_DTLEN | SPI_I2SCTL_CHLEN);
SPI_I2SCTL(SPI1) |= frame_format;
return 0;
}
另外我发射可以正常发射,但是接收收到的数据一直是下面的图
我不太懂是哪里出现了问题,理论上应该为白噪声的,而且我手机放单频信号靠近咪头,收到的数据也还是这样,各位大神能帮我看看我驱动写错了吗
|