#include "xc6xxx.h" #include "xc_drv_gpio.h" #include "xc_drv_clock.h" #include "xc_drv_i2s.h" #if XC_CHECK(XC_IIS_ENABLED) static I2s_Finish_Callback_t finish_callback; static void i2s_tx_finish_cb_register(void (*callback)(uint8_t status)) { finish_callback.i2s_trans_finish_callback = callback; } static void i2s_rx_finish_cb_register(void (*callback)(uint8_t status)) { finish_callback.i2s_receive_finish_callback = callback; } static void i2s_irq_enable(uint32_t irq) { uint32_t val = i2s_int_en_get(); val |= irq; i2s_int_en_set(val); } static void i2s_irq_disable(uint32_t irq) { uint32_t val = i2s_int_en_get(); val &= ~irq; i2s_int_en_set(val); } void i2s_clk_deinit(void) { cpr_rstctl_subrst_sw__i2s_rstn__setf(RSTCTL_ENABLE); // reset I2S model cpr_rstctl_subrst_sw__i2s_rstn__setf(RSTCTL_DISABLE); cpr_i2s_clk_ctl__i_2s_pclk_en__setf(DISABLE); cpr_i2s_clk_ctl__i_2s_mclk_en__setf(DISABLE); } void i2s_tx_dma_init(uint32_t saraddr, uint32_t transfsize, Audio_BitDept_e databit) { DMA_Chx_Cfg_t ch_cfg = { .sar = saraddr, .dar = (uint32_t)I2S_TXFIFO_DATA_ADDR, .ctl_src_msize = DMA_MSIZE_1, .ctl_dst_msize = DMA_MSIZE_1, .ctl_sinc = DMA_ADDR_INCREMENT, .ctl_dinc = DMA_ADDR_NOCHANGE, .ctl_src_tr_width = DMA_TRANS_WIDTH_32, .ctl_dst_tr_width = DMA_TRANS_WIDTH_32, .ctl_block_ts = transfsize, .ctl_tt_fc = DMA_MEM2PRF_DMA, .cfg_hs_sel_src = DMA_HS_HARDWARE, .cfg_hs_sel_dst = DMA_HS_HARDWARE, .cfg_fifo_mode = DMA_FIFO_MODE_SINGLE, .cfg_dst_per = I2S_DMA_TX_HS_IF5, }; if (databit == AUDIO_8BIT) { ch_cfg.ctl_src_tr_width = DMA_TRANS_WIDTH_8; ch_cfg.ctl_dst_tr_width = DMA_TRANS_WIDTH_8; } else if (databit == AUDIO_16BIT) { ch_cfg.ctl_src_tr_width = DMA_TRANS_WIDTH_16; ch_cfg.ctl_dst_tr_width = DMA_TRANS_WIDTH_16; } i2s_dma_config_iis_dma_tx_en_setf(ENABLE); xc_dma_init(); xc_dma_set_channel_config(I2S_TX_DMA_CHANNEL, &ch_cfg); xc_dma_set_listener(I2S_TX_DMA_CHANNEL, NULL); } void i2s_rx_dma_init(uint32_t daraddr, uint32_t transfsize, Audio_BitDept_e databit) { DMA_Chx_Cfg_t ch_cfg = { .sar = (uint32_t)I2S_RXFIFO_DATA_ADDR, .dar = daraddr, .ctl_src_msize = DMA_MSIZE_1, .ctl_dst_msize = DMA_MSIZE_1, .ctl_sinc = DMA_ADDR_NOCHANGE, .ctl_dinc = DMA_ADDR_INCREMENT, .ctl_src_tr_width = DMA_TRANS_WIDTH_32, .ctl_dst_tr_width = DMA_TRANS_WIDTH_32, .ctl_block_ts = transfsize, .ctl_tt_fc = DMA_PRF2MEM_DMA, .cfg_hs_sel_src = DMA_HS_HARDWARE, .cfg_hs_sel_dst = DMA_HS_HARDWARE, .cfg_fifo_mode = DMA_FIFO_MODE_SINGLE, .cfg_src_per = I2S_DMA_RX_HS_IF15, }; if (databit == AUDIO_8BIT) { ch_cfg.ctl_src_tr_width = DMA_TRANS_WIDTH_8; ch_cfg.ctl_dst_tr_width = DMA_TRANS_WIDTH_8; } else if (databit == AUDIO_16BIT) { ch_cfg.ctl_src_tr_width = DMA_TRANS_WIDTH_16; ch_cfg.ctl_dst_tr_width = DMA_TRANS_WIDTH_16; } i2s_dma_config_iis_dma_rx_en_setf(ENABLE); xc_dma_init(); xc_dma_set_channel_config(I2S_RX_DMA_CHANNEL, &ch_cfg); xc_dma_set_listener(I2S_RX_DMA_CHANNEL, NULL); } void xc_i2s_init(I2s_Cfg_t *cfg) { /* clock config */ uint16_t div; CLOCK_HFCLK_In_Typedef hf_clk = xc_clock_hfclk_in_get(); div = hf_clk / (AUDIO_DOUBLE_CHANNEL * cfg->audio_bit * cfg->samplerate) - 1; cpr_rstctl_subrst_sw__i2s_rstn__setf(RSTCTL_ENABLE); // reset I2S model cpr_rstctl_subrst_sw__i2s_rstn__setf(RSTCTL_DISABLE); cpr_i2s_clk_ctl__i_2s_pclk_en__setf(ENABLE); cpr_i2s_clk_ctl__i_2s_mclk_div__setf(div); /* gpio config */ xc_gpio_mux_ctl(cfg->bclk_pin, GPIO_Mux2); // i2s_sclk xc_gpio_mux_ctl(cfg->lrck_pin, GPIO_Mux2); // i2s_ws #if(I2S_TX_MODE == 1) xc_gpio_mux_ctl(cfg->tx_pin, GPIO_Mux2); // i2s_dout i2s_dma_config_iis_dma_txlvl_setf(I2S_TX_FIFO_LEN); #endif #if(I2S_RX_MODE == 1) xc_gpio_mux_ctl(cfg->rx_pin, GPIO_Mux2); // i2s_din i2s_dma_config_iis_dma_rxlvl_setf(I2S_RX_FIFO_LEN); #endif i2s_clock_gen_ws_polarity_i2s_setf(cfg->lrckpolarity); i2s_clock_gen_sclk_polarity_setf(cfg->bclkpolarity); i2s_clock_gen_ws_format_setf(cfg->interfacemode); /* i2s Transfer param config */ i2s_trans_en_i2s_enable_setf(DISABLE); // disable i2s Transfer i2s_config_slot_resolution_setf(cfg->slot_resolution); i2s_config_slot_width_setf(cfg->slot_width); #if(I2S_RX_MODE == 1) i2s_config_i2s_ch0en_setf(ENABLE); // enable i2s channel rx i2s_config_i2s_ch0txrx_setf(I2S_RX); // I2S Channel: Receive i2s_clock_gen_masteren_setf(DISABLE); #endif #if(I2S_TX_MODE == 1) i2s_config_i2s_ch1en_setf(ENABLE); // enable i2s channel tx i2s_config_i2s_ch1txrx_setf(I2S_TX); // I2S Channel: Transimit i2s_clock_gen_masteren_setf(ENABLE); #endif i2s_clock_gen_sclk_enable_setf(ENABLE); #ifdef USE_DMA #if(I2S_TX_MODE == 1) i2s_tx_dma_init((uint32_t)cfg->voice_tx_buffer, cfg->transf_size, cfg->audio_bit); #endif #if(I2S_RX_MODE == 1) i2s_rx_dma_init((uint32_t)cfg->voice_rx_buffer, cfg->transf_size, cfg->audio_bit); #endif #endif } void xc_i2s_deinit(void) { i2s_trans_en_i2s_enable_setf(DISABLE); // disable i2s Transfer #ifndef USE_DMA #if(I2S_TX_MODE == 1) i2s_irq_disable(I2S_TXFIFO_UNDERFLOW_EN | I2S_TXFIFO_OVERFLOW_EN | I2S_TXFIFO_DATA_READY_EN); #endif #if(I2S_RX_MODE == 1) i2s_irq_disable(I2S_RXFIFO_UNDERFLOW_EN | I2S_RXFIFO_OVERFLOW_EN | I2S_RXFIFO_DATA_READY_EN); #endif NVIC_DisableIRQ(I2S_IRQn); #else #if(I2S_TX_MODE == 1) xc_dma_disable_channel(I2S_TX_DMA_CHANNEL); #endif #if(I2S_RX_MODE == 1) xc_dma_disable_channel(I2S_RX_DMA_CHANNEL); #endif NVIC_DisableIRQ(DMA_IRQn); #endif i2s_fifo_status_iis_txfifo_flush_setf(1); // flush TX_FIFO for (int i = 0; i < 20; i++){__NOP();}; i2s_fifo_status_iis_txfifo_flush_setf(0); // flush TX_FIFO i2s_clk_deinit(); } void xc_i2s_start(void *tx_cb, void *rx_cb) { #ifndef USE_DMA #if(I2S_TX_MODE == 1) i2s_tx_finish_cb_register(tx_cb); i2s_irq_enable(I2S_TXFIFO_UNDERFLOW_EN | I2S_TXFIFO_OVERFLOW_EN | I2S_TXFIFO_DATA_READY_EN); #endif #if(I2S_RX_MODE == 1) i2s_rx_finish_cb_register(rx_cb); i2s_irq_enable(I2S_RXFIFO_UNDERFLOW_EN | I2S_RXFIFO_OVERFLOW_EN | I2S_RXFIFO_DATA_READY_EN); #endif NVIC_EnableIRQ(I2S_IRQn); #else NVIC_EnableIRQ(DMA_IRQn); xc_dma_enable(); #if(I2S_TX_MODE == 1) xc_dma_start_transfer(I2S_TX_DMA_CHANNEL, (DMA_Callback)tx_cb); #endif #if(I2S_RX_MODE == 1) xc_dma_start_transfer(I2S_RX_DMA_CHANNEL, (DMA_Callback)rx_cb); #endif #endif #if(I2S_TX_MODE == 1) i2s_fifo_status_iis_txfifo_flush_setf(1); // flush TX_FIFO for (int i = 0; i < 20; i++){__NOP();}; i2s_fifo_status_iis_txfifo_flush_setf(0); // flush TX_FIFO #endif #if(I2S_RX_MODE == 1) i2s_fifo_status_iis_rxfifo_flush_setf(1); // flush RX_FIFO for (int i = 0; i < 20; i++){__NOP();}; i2s_fifo_status_iis_rxfifo_flush_setf(0); // flush RX_FIFO #endif i2s_trans_en_i2s_enable_setf(ENABLE); // enable i2s Transfer cpr_i2s_clk_ctl__i_2s_mclk_en__setf(ENABLE); // enable i2s mclk } void xc_i2s_stop(void) { #if(I2S_TX_MODE == 1) i2s_fifo_status_iis_txfifo_flush_setf(1); // flush TX_FIFO for (int i = 0; i < 20; i++){__NOP();}; i2s_fifo_status_iis_txfifo_flush_setf(0); // flush TX_FIFO #endif #if(I2S_RX_MODE == 1) i2s_fifo_status_iis_rxfifo_flush_setf(1); // flush RX_FIFO for (int i = 0; i < 20; i++){__NOP();}; i2s_fifo_status_iis_rxfifo_flush_setf(0); // flush RX_FIFO #endif cpr_i2s_clk_ctl__i_2s_mclk_en__setf(DISABLE); // enable i2s mclk i2s_trans_en_i2s_enable_setf(DISABLE); // disable i2s Transfer } void I2S_Handler() { uint32_t val = i2s_int_get(); if (val & I2S_TXFIFO_UNDERFLOW_EN) { if (finish_callback.i2s_trans_finish_callback != NULL) { finish_callback.i2s_trans_finish_callback(I2S_TXFIFO_UNDERFLOW_EN); } } if (val & I2S_TXFIFO_OVERFLOW_EN) { if (finish_callback.i2s_trans_finish_callback != NULL) { finish_callback.i2s_trans_finish_callback(I2S_TXFIFO_OVERFLOW_EN); } } if (val & I2S_TXFIFO_DATA_READY_EN) { if (finish_callback.i2s_trans_finish_callback != NULL) { finish_callback.i2s_trans_finish_callback(I2S_TXFIFO_DATA_READY_EN); } } if (val & I2S_RXFIFO_UNDERFLOW_EN) { if (finish_callback.i2s_receive_finish_callback != NULL) { finish_callback.i2s_receive_finish_callback(I2S_RXFIFO_UNDERFLOW_EN); } } if (val & I2S_RXFIFO_OVERFLOW_EN) { if (finish_callback.i2s_receive_finish_callback != NULL) { finish_callback.i2s_receive_finish_callback(I2S_RXFIFO_OVERFLOW_EN); } } if (val & I2S_RXFIFO_DATA_READY_EN) { if (finish_callback.i2s_receive_finish_callback != NULL) { finish_callback.i2s_receive_finish_callback(I2S_RXFIFO_DATA_READY_EN); } } i2s_int_set(val); } #endif // XC_CHECK(XC_IIS_ENABLED)