Files
hpw421/component/xc6xx_drivers/Drivers/xc_driver/xc_drv_i2s.c
T
2026-07-03 18:08:25 +08:00

293 lines
9.2 KiB
C

#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)