293 lines
9.2 KiB
C
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)
|