gd32f4 配置i2s 驱动wm8978出现数据接收问题

[复制链接]
qqlc 发表于 2025-8-17 21:05 | 显示全部楼层 |阅读模式
本帖最后由 qqlc 于 2025-8-17 21:08 编辑

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;
}
另外我发射可以正常发射,但是接收收到的数据一直是下面的图

接收数据

接收数据

我不太懂是哪里出现了问题,理论上应该为白噪声的,而且我手机放单频信号靠近咪头,收到的数据也还是这样,各位大神能帮我看看我驱动写错了吗,同时 我示波器测量MCK引脚输出,有点失真了,频率是4M左右 倒是没错
内政奇才 发表于 2025-8-21 12:47 | 显示全部楼层
可能是由于硬件连接、时钟配置、I2S 模式设置或初始化顺序不正确导致的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

2

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部