下面介绍在NXP LPC54110上实现从DMIC数字话筒的音频流到开发板I2S,到WM8904,最后到CN7耳机孔的功能
实现下载开发板的Keil设备驱动包
https://keilpack.azureedge.net/pack/Keil.LPC54000_DFP.2.4.0.pack
双击安装后,打开如下目录的例程
- KeilARMPackKeilLPC54000_DFP2.4.0LPCOpenlpc5411xexamples_5411xperiph_i2s_dmic
复制代码
修改其中i2c_if.c文件为如下
- #include
- #include
- #include "board.h"
- #include "delay.h"
- #include "i2c_if.h"
- #define I2CM_STATUS_tiMEOUT 0x56
- #define I2C4_FLEXCOMM 4
- #define LPC_I2C_PORT LPC_I2C4
- #define LPC_I2C_INTHAND I2C4_IRQHandler
- #define LPC_IRQNUM I2C4_IRQn
- //#define I2C0_FLEXCOMM 4
- //#define LPC_I2C_PORT LPC_I2C0
- //#define LPC_I2C_INTHAND I2C0_IRQHandler
- //#define LPC_IRQNUM I2C0_IRQn
- #define I2C_CLK_DIVIDER 2
- #define I2C_BITRATE 400000
- static I2CM_XFER_T i2c_xfer;
- static const uint32_t i2c_spd_fast = IOCON_FUNC1 | IOCON_DIGITAL_EN | IOCON_FASTI2C_EN;
- static const uint32_t int_list = I2C_INTENSET_MSTPENDING | I2C_INTENSET_MSTRARBLOSS | I2C_INTENSET_MSTSTSTPERR;
- static void i2c_error(bool abbr, uint32_t i2c_error)
- {
- if (abbr == false) {
- DEBUGOUT("I2C error: ");
- }
- switch (i2c_error) {
- case I2CM_STATUS_ERROR:
- DEBUGOUT((abbr == true) ? " er" : "Unknown errorrn");
- break;
- case I2CM_STATUS_NAK_ADR:
- DEBUGOUT((abbr == true) ? " na" : "NAK addressrn");
- break;
- case I2CM_STATUS_BUS_ERROR:
- DEBUGOUT((abbr == true) ? " be" : "Bus errorrn");
- break;
- case I2CM_STATUS_NAK_DAT:
- DEBUGOUT((abbr == true) ? " nd" : "NAK datarn");
- break;
- case I2CM_STATUS_ARBLOST:
- DEBUGOUT((abbr == true) ? " al" : "Arbitration lostrn");
- break;
- case I2CM_STATUS_TIMEOUT:
- DEBUGOUT((abbr == true) ? " to" : "Timeoutrn");
- break;
- case I2CM_STATUS_BUSY:
- DEBUGOUT((abbr == true) ? " bs" : "Busyrn");
- break;
- default:
- DEBUGOUT(" --");
- }
- }
- static void WaitForI2cXferComplete(I2CM_XFER_T *xferRecPtr)
- {
- while (xferRecPtr->status == I2CM_STATUS_BUSY)
- __WFI();
- }
- void i2c_pinmux_init(void)
- {
- Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_IOCON);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 1, IOCON_MODE_PULLUP | IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 2, IOCON_MODE_PULLUP | IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_INPFILT_OFF);
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 23, i2c_spd_fast);
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 24, i2c_spd_fast);
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 25, i2c_spd_fast);
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 26, i2c_spd_fast);
- Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_IOCON);
- }
- void i2c_master_init(void)
- {
- Chip_I2C_Init(LPC_I2C_PORT);
- Chip_I2C_SetClockDiv(LPC_I2C_PORT, I2C_CLK_DIVIDER);
- Chip_I2CM_SetBusSpeed(LPC_I2C_PORT, I2C_BITRATE);
- Chip_I2CM_Enable(LPC_I2C_PORT);
- }
- static volatile uint32_t i2c_tick_ct = 0;
- bool i2c_io(I2CM_XFER_T *in)
- {
- bool ret_val;
- /* Setup I2C transfer */
- i2c_xfer = *in;
- i2c_tick_ct = 0;
- /* Execute I2C transfer */
- Chip_I2CM_Xfer(LPC_I2C_PORT, &i2c_xfer);
- Chip_I2C_EnableInt(LPC_I2C_PORT, int_list);
- WaitForI2cXferComplete(&i2c_xfer);
- Chip_I2C_DisableInt(LPC_I2C_PORT, int_list);
- in->status = i2c_xfer.status;
- if (i2c_xfer.status == I2CM_STATUS_OK) {
- ret_val = true;
- } else {
- i2c_error(false, i2c_xfer.status);
- ret_val = false;
- }
- return ret_val;
- }
- bool i2c_get_status(void) { return (i2c_xfer.status == I2CM_STATUS_BUSY) ? false : true; }
- void i2c_interrupt_enable(void) { NVIC_EnableIRQ(LPC_IRQNUM); }
- void i2c_interrupt_disable(void) { NVIC_DisableIRQ(LPC_IRQNUM); }
- void LPC_I2C_INTHAND(void)
- {
- uint32_t state = Chip_I2C_GetPendingInt(LPC_I2C_PORT);
- /* Error handling */
- if (state & (I2C_INTENSET_MSTRARBLOSS | I2C_INTENSET_MSTSTSTPERR)) {
- Chip_I2CM_ClearStatus(LPC_I2C_PORT, I2C_STAT_MSTRARBLOSS | I2C_STAT_MSTSTSTPERR);
- }
- /* Call I2CM ISR function with the I2C device and transfer rec */
- if (state & I2C_INTENSET_MSTPENDING) {
- Chip_I2CM_XferHandler(LPC_I2C_PORT, &i2c_xfer);
- if (i2c_xfer.status == I2CM_STATUS_OK) {
- Chip_I2C_DisableInt(LPC_I2C_PORT, I2C_INTENSET_MSTPENDING);
- } else {
- if (i2c_tick_ct++ > 200) {
- i2c_xfer.status = I2CM_STATUS_TIMEOUT;
- Chip_I2C_DisableInt(LPC_I2C_PORT, I2C_INTENSET_MSTPENDING);
- }
- }
- }
- }
复制代码
修改其中i2s.if.c文件为如下
- #include
- #include
- #include "board.h"
- #include "i2s_if.h"
- #define I2S6_FLEXCOMM 6
- #define I2S7_FLEXCOMM 7
- #define I2S_PORT_TX LPC_I2S7
- #define I2S_TX_ISR I2S7_IRQHandler
- #define I2S_TX_IRQNUM I2S7_IRQn
- #define I2S_TX_FLEXCOMM I2S7_FLEXCOMM
- #define I2S_PORT_RX LPC_I2S6
- #define I2S_RX_ISR I2S6_IRQHandler
- #define I2S_RX_IRQNUM I2S6_IRQn
- #define I2S_RX_FLEXCOMM I2S6_FLEXCOMM
- /*
- #define I2S_PORT_TX LPC_I2S6
- #define I2S_TX_ISR I2S6_IRQHandler
- #define I2S_TX_IRQNUM I2S6_IRQn
- #define I2S_TX_FLEXCOMM I2S6_FLEXCOMM
- #define I2S_PORT_RX LPC_I2S7
- #define I2S_RX_ISR I2S7_IRQHandler
- #define I2S_RX_IRQNUM I2S7_IRQn
- #define I2S_RX_FLEXCOMM I2S7_FLEXCOMM
- */
- #define BUFF_CT 6000
- static const uint32_t i2s_p1 = IOCON_FUNC1 | IOCON_DIGITAL_EN;
- static const uint32_t i2s_p2 = IOCON_FUNC2 | IOCON_DIGITAL_EN;
- static const uint32_t i2s_p4 = IOCON_FUNC4 | IOCON_DIGITAL_EN;
- static I2S_STATISTICS_T rx_stat;
- static I2S_STATISTICS_T tx_stat;
- static I2S_AUDIO_FORMAT_T audio_fmt_tx = {
- I2S_TX, /*!< Data direction: tx or rx */
- NORMAL_MASTER, /*!< Master / Slave configuration */
- I2S_CLASSIC, /*!< I2S mode */
- false, /*!< right channel data in low portion of FIFO */
- false, /*!< left justify data in FIFO */
- false, /*!< data source is the D-Mic subsystem */
- false, /*!< SCK polarity */
- false, /*!< WS polarity */
- 16, /*!< Flexcomm function clock divider */
- 2, /*!< Channel Number - 1 is mono, 2 is stereo */
- 16, /*!< Word Width */
- 32, /*!< Frame Width */
- 0, /*!< Data position in the frame */
- 4, /*!< FIFO depth (fifo config) */
- };
- static I2S_AUDIO_FORMAT_T audio_fmt_rx = {
- I2S_RX, /*!< Direction: Data direction: tx or rx */
- NORMAL_SLAVE, /*!< MSCfg: Master / Slave configuration */
- I2S_CLASSIC, /*!< Mode: I2S classic */
- false, /*!< RightLow: right channel data in low portion of FIFO */
- false, /*!< LeftJust: left justify data in FIFO */
- false, /*!< PDMData: data source is the D-Mic subsystem */
- false, /*!< SCKPol: SCK polarity */
- false, /*!< WSPol: WS polarity */
- 1, /*!< Divider: Flexcomm function clock divider */
- 2, /*!< ChannelNumber: Channel Number - 1 is mono, 2 is stereo */
- 16, /*!< WordWidth: Word Width */
- 32, /*!< FrameWidth: Frame Width */
- 0, /*!< DataPos: Data position in the frame */
- 4, /*!< FIFOdepth: FIFO depth (fifo config) */
- };
- static uint32_t io_buff_dmic[BUFF_CT]; // dmic buffer
- static uint32_t io_buff_i2s[BUFF_CT]; // i2s buffer
-
- extern const uint16_t sine_buff_arr[]; // pointer to the send buffer array
- extern const uint16_t sine_buff_ct; // number of entries in the array
- void i2s_pinmux_init(void)
- {
- Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_IOCON);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 5, i2s_p1); // Flexcomm 6 / SDA
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 6, i2s_p1); // Flexcomm 6 / WS
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 7, i2s_p1); // Flexcomm 6 / SCK
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 12, i2s_p4); // Flexcomm 7 / SCK
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 13, i2s_p4); // Flexcomm 7 / SDA
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 14, i2s_p4); // Flexcomm 7 / WS
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 12, i2s_p4); // Flexcomm 7 / SCK
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 7, i2s_p2); // Flexcomm 7 / SDA
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 8, i2s_p2); // Flexcomm 7 / WS
- Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_IOCON);
- }
- static void i2s_tx_init(void)
- {
- Chip_I2S_Init(I2S_PORT_TX, &audio_fmt_tx); // initialize I2S port
- Chip_Clock_SetFLEXCOMMClockSource(I2S_TX_FLEXCOMM, SYSCON_FLEXCOMMCLKSELSRC_PLL);
- Chip_I2S_Config(I2S_PORT_TX, &audio_fmt_tx); // configure I2S port
- Chip_I2S_FIFO_Config(I2S_PORT_TX, &audio_fmt_tx); // configure I2S FIFO
- Chip_I2S_FIFO_Control(I2S_PORT_TX, &audio_fmt_tx, I2S_FIFO_TXZ_ENABLE); // send zeros if no data is available
- Chip_I2S_FIFO_Control(I2S_PORT_TX, &audio_fmt_tx, I2S_FIFO_ENABLE); // enable FIFO
- }
- static void i2s_rx_init(void)
- {
- Chip_I2S_Init(I2S_PORT_RX, &audio_fmt_rx); // initialize I2S port
- Chip_Clock_SetFLEXCOMMClockSource(I2S_RX_FLEXCOMM, SYSCON_FLEXCOMMCLKSELSRC_PLL);
- Chip_I2S_Config(I2S_PORT_RX, &audio_fmt_rx); // configure I2S port
- Chip_I2S_FIFO_Config(I2S_PORT_RX, &audio_fmt_rx); // configure I2S FIFO
- Chip_I2S_FIFO_Control(I2S_PORT_RX, &audio_fmt_rx, I2S_FIFO_ENABLE); // enable FIFO
- }
- void i2s_port_init(void)
- {
- i2s_tx_init(); // init i2s tx port
- i2s_rx_init(); // init i2s rx port
- Chip_I2S_FIFO_SetInterrupt(I2S_PORT_TX, I2S_FIFO_INT_TXERR | I2S_FIFO_INT_TXLVL); // enable tx interrupts
- Chip_I2S_FIFO_SetInterrupt(I2S_PORT_RX, I2S_FIFO_INT_RXERR | I2S_FIFO_INT_RXLVL); // enable rx interrupts
- }
- void i2s_start(void)
- {
- NVIC_EnableIRQ(I2S_TX_IRQNUM); // enable tx interrupt
- Chip_I2S_Start(I2S_PORT_TX); // start tx I2S port
- NVIC_EnableIRQ(I2S_RX_IRQNUM); // enable rx interrupt
- Chip_I2S_Start(I2S_PORT_RX); // start rx I2S port
- }
- void i2s_stop(void)
- {
- Chip_I2S_Stop(I2S_PORT_RX); // stop rx I2S port
- NVIC_DisableIRQ(I2S_RX_IRQNUM); // disable rx interrupt
- Chip_I2S_Stop(I2S_PORT_TX); // stop tx I2S port
- NVIC_DisableIRQ(I2S_TX_IRQNUM); // disable tx interrupt
- }
- void i2s_get_rx_statistics(I2S_STATISTICS_T* s)
- {
- *s = rx_stat; // structure copy
- }
- void i2s_get_tx_statistics(I2S_STATISTICS_T* s)
- {
- *s = tx_stat; // structure copy
- }
-
- static volatile uint32_t tx_buff_idx = 1;
- static volatile uint16_t tx_idx_l=0, tx_idx_r=50;
- void i2s_buff_write(void)
- {
- while (Chip_I2S_GetFIFOStatus(I2S_PORT_TX) & I2S_FIFO_STAT_TXNOTFULL) { // if FIFO is not full
- Chip_I2S_Send(I2S_PORT_TX, io_buff_dmic[tx_buff_idx++]); // queue the data
- if (tx_buff_idx >= BUFF_CT) tx_buff_idx = 0; // wrap index pointer
- }
- }
- static uint32_t dmic_buff_idx = 0;
- static uint32_t i2s_buff_idx = 0;
- void i2s_buff_read(void)
- {
- while (Chip_I2S_GetFIFOStatus(I2S_PORT_RX) & I2S_FIFO_STAT_RXNOTEMPTY) { // if FIFO is not empty
- io_buff_i2s[i2s_buff_idx++] = Chip_I2S_Receive(I2S_PORT_RX); // read the data
- if (i2s_buff_idx >= BUFF_CT) i2s_buff_idx = 0; // wrap index pointer
- }
- }
- void i2s_buff_read_external(uint32_t data)
- {
- io_buff_dmic[dmic_buff_idx++] = data; // read the data
- if (dmic_buff_idx >= BUFF_CT) dmic_buff_idx = 0; // wrap index pointer
- }
- void I2S_TX_ISR(void) // I2S transmit interrupt
- {
- Chip_I2S_ErrorHandler(I2S_PORT_TX, &tx_stat); // Accumulate TX errors then, clear status
- i2s_buff_write(); // transmit data to I2S port
- }
- void I2S_RX_ISR(void) // I2S receive interrupt
- {
- Chip_I2S_ErrorHandler(I2S_PORT_RX, &rx_stat); // Accumulate RX errors then, clear status
- i2s_buff_read(); // read the data
- }
复制代码
修改dmic_if.c文件如下
- #define FIFO_DEPTH 8
- ALIGN(16) DMA_DUAL_DESCRIPTOR_T pingPongDescriptors0;
- ALIGN(16) DMA_DUAL_DESCRIPTOR_T pingPongDescriptors1;
- static DMIC_CHANNEL_CONFIG_T dmic_channel_cfg[2];
- static DMIC_STATISTICS_T stats[2];
- static const PINMUX_GRP_T dmic_io[] =
- {
- {1, 15, IOCON_FUNC1 | IOCON_DIGITAL_EN},//(IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGITAL_EN)}, /* PDM CLK */
- {1, 16, IOCON_FUNC1 | IOCON_DIGITAL_EN},//(IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGITAL_EN)}, /* PDM DATA */
- // {0, 31, (IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGITAL_EN)}, /* PDM CLK */
- // {1, 0, (IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGITAL_EN)}, /* PDM DATA */
- };
- static void read_data(uint32_t chan)
- {
- uint32_t data, i;
- for (i=0; i
- data = Chip_DMIC_FifoGetData(LPC_DMIC,chan) & 0xffff;
- i2s_buff_read_external(data);
- }
- }
- static void read_data_dummy(uint32_t chan)
- {
- uint32_t i;
- for (i=0; i
- Chip_DMIC_FifoGetData(LPC_DMIC,chan);
- }
- }
- void DMIC_IRQHandler()
- {
- uint32_t status;
- status = Chip_DMIC_FifoGetStatus(LPC_DMIC, DMIC_LEFT);
- if (status & DMIC_FIFO_INT) {
- Chip_DMIC_FifoClearStatus(LPC_DMIC, DMIC_LEFT, DMIC_FIFO_INT);
- stats[DMIC_LEFT].fifo_ints +=1;
- read_data(DMIC_LEFT);
- }
- if (status & DMIC_FIFO_OVERRUN) {
- Chip_DMIC_FifoClearStatus(LPC_DMIC, DMIC_LEFT, DMIC_FIFO_OVERRUN);
- stats[DMIC_LEFT].fifo_overrun +=1;
- }
- if (status & DMIC_FIFO_UNDERRUN) {
- Chip_DMIC_FifoClearStatus(LPC_DMIC, DMIC_LEFT, DMIC_FIFO_UNDERRUN);
- stats[DMIC_LEFT].fifo_underrun +=1;
- }
- status = Chip_DMIC_FifoGetStatus(LPC_DMIC, DMIC_RIGHT);
- if (status & DMIC_FIFO_INT) {
- Chip_DMIC_FifoClearStatus(LPC_DMIC, DMIC_RIGHT, DMIC_FIFO_INT);
- stats[DMIC_RIGHT].fifo_ints +=1;
- read_data_dummy(DMIC_RIGHT);
- }
- if (status & DMIC_FIFO_OVERRUN) {
- Chip_DMIC_FifoClearStatus(LPC_DMIC, DMIC_RIGHT, DMIC_FIFO_OVERRUN);
- stats[DMIC_RIGHT].fifo_overrun +=1;
- }
- if (status & DMIC_FIFO_UNDERRUN) {
- Chip_DMIC_FifoClearStatus(LPC_DMIC, DMIC_RIGHT, DMIC_FIFO_UNDERRUN);
- stats[DMIC_RIGHT].fifo_underrun +=1;
- }
- }
- void dmic_get_chan_statistics(DMIC_STATISTICS_T* s, uint16_t chan)
- {
- *s = stats[chan]; // structure copy
- }
- void HWVAD_IRQHandler()
- {
- volatile int i;
- Board_LED_Set(0, true);
- LPC_DMIC->HWVADST10 = 1; /* disable HWVAD */
- for (i=0;i<=500;i++); /* wait for HWVAD to settle */
- LPC_DMIC->HWVADST10 = 0; /* enable HWVAD */
- Board_LED_Set(0, false);
- };
- volatile uint32_t temp;
- void dmic_pinmux_init(void)
- {
- Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_IOCON);
- Chip_IOCON_SetPinMuxing(LPC_IOCON, dmic_io, sizeof(dmic_io) / sizeof(PINMUX_GRP_T));
- Chip_Clock_DisablePeriphClock(SYSCON_CLOCK_IOCON);
- }
- void dmic_cfg(void)
- {
- LPC_SYSCON->DMICCLKSEL = 0; // DMIC uses 12MHz FRO
- LPC_SYSCON->DMICCLKDIV = 4; // 12MHz divided by 5 = 2.4MHz PDM clock --> gives 48kHz sample rate
-
- dmic_channel_cfg[0].side = DMIC_LEFT;
- dmic_channel_cfg[0].divhfclk = DMIC_PDM_DIV1;
- dmic_channel_cfg[0].gainshft = 3;
- dmic_channel_cfg[0].osr = 25;
- dmic_channel_cfg[0].preac2coef = DMIC_COMP0_0;
- dmic_channel_cfg[0].preac4coef = DMIC_COMP0_0;
-
- dmic_channel_cfg[1].side = DMIC_RIGHT;
- dmic_channel_cfg[1].divhfclk = DMIC_PDM_DIV1;
- dmic_channel_cfg[1].gainshft = 3;
- dmic_channel_cfg[1].osr = 25;
- dmic_channel_cfg[1].preac2coef = DMIC_COMP0_0;
- dmic_channel_cfg[1].preac4coef = DMIC_COMP0_0;
-
- Chip_DMIC_Init(SYSCON_CLOCK_DMIC, RESET_DMIC);
- Chip_DMIC_CfgIO(LPC_DMIC, pdm_dual);
- Chip_DMIC_SetOpMode(LPC_DMIC, DMIC_OP_INTR);
- Chip_DMIC_Use2fs(LPC_DMIC, true);
- Chip_DMIC_CfgChannel(LPC_DMIC, DMIC_LEFT, &dmic_channel_cfg[0]);
- Chip_DMIC_CfgChannel(LPC_DMIC, DMIC_RIGHT, &dmic_channel_cfg[1]);
- Chip_DMIC_CfgChannelDc(LPC_DMIC, DMIC_LEFT, DMIC_DC_CUT155, 0, true);
- Chip_DMIC_CfgChannelDc(LPC_DMIC, DMIC_RIGHT, DMIC_DC_CUT155, 0, true);
-
- Chip_DMIC_FifoChannel(LPC_DMIC, DMIC_LEFT, FIFO_DEPTH, true, true);
- Chip_DMIC_FifoChannel(LPC_DMIC, DMIC_RIGHT, FIFO_DEPTH, true, true);
-
- LPC_DMIC->HWVADTHGN = 0;
- LPC_DMIC->HWVADTHGS = 1;
- Chip_SYSCON_EnableWakeup(SYSCON_STARTER_DMIC);
- Chip_SYSCON_EnableWakeup(SYSCON_STARTER_HWVAD);
- };
- void dmic_start(void)
- {
- NVIC_EnableIRQ(DMIC_IRQn);
- NVIC_EnableIRQ(HWVAD_IRQn);
- Chip_DMIC_EnableChannnel(LPC_DMIC, 0x3);
- }
- void dmic_stop(void)
- {
- NVIC_DisableIRQ(HWVAD_IRQn);
- Chip_DMIC_EnableChannnel(LPC_DMIC, 0x0);
- }
复制代码
工程源码如下
下载烧录后将耳机或者音箱插入开发板CN7然后对着开发板喊话可以立刻听到回音就表示成功
|