本帖最后由 可乐丸子 于 2017-9-12 21:21 编辑
下面介绍在NXP LPC54110开发板上实现语音电子书播放的方法,实现这个功能需要驱动SPI通讯的SD卡,另外需要MP3解码库,根据官方SDK修改,官方音频库是基于RT-THREAD操作系统首先介绍SPI驱动SD卡的方法,需要修改下面文件的第311行
- /lpc5411x_audio/Libraries/lpc_chip/chip_5410x/syscon_5411x.h
复制代码
将下面代码
改为
然后修改下面文件
- /lpc5411x_audio/drivers/drv_i2c.c
复制代码
将I2C_SCL_PORT、I2C_SCL_PIN、I2C_SDA_PORT数值设置为1,将I2C_SDA_PIN数值设置为2
- #define GPIO_PORT_I2C_SCL
- #define I2C_SCL_PORT 1
- #define I2C_SCL_PIN 1
- #define GPIO_PORT_I2C_SDA
- #define I2C_SDA_PORT 1
- #define I2C_SDA_PIN 2
复制代码
void rt_hw_i2c_init(void)函数中的iic 初始化修改如下
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 1, IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_FASTI2C_EN);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 2, IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_FASTI2C_EN);
复制代码
修改下面文件
- /lpc5411x_audio/drivers/drv_i2s_wm8904.c
复制代码
修改GPIO_Configuration为如下
- static void codec_gpio_config(void) //GPIO_Configuration(void)
- {
- rt_kprintf("codec_gpio_configrn");
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 5, IOCON_FUNC1 | IOCON_DIGITAL_EN);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 6, IOCON_FUNC1 | IOCON_DIGITAL_EN);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 7, IOCON_FUNC1 | IOCON_DIGITAL_EN);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 12, IOCON_FUNC4 | IOCON_DIGITAL_EN);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 13, IOCON_FUNC4 | IOCON_DIGITAL_EN);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 14, IOCON_FUNC4 | IOCON_DIGITAL_EN);
- }
复制代码
修改下面文件
- /lpc5411x_audio/drivers/drv_spi.c
复制代码
增加下面宏
- #define SPI2_FLEXCOMM 2
- #define MY_SPI LPC_SPI2
- #define MY_DMA_CH_RX DMA_CH4
- #define MY_DMA_CH_TX DMA_CH5
复制代码
SPI2 Defines定义如下
- /* SPI2 Defines */
- #define LPC_SPI2_BASE __APPEND3(LPC_FLEXCOMM,SPI2_FLEXCOMM,_BASE)
- #define LPC_SPI2 ((LPC_SPI_T *) LPC_SPI2_BASE)
- #define SPI2_IRQHandler __APPEND3(FLEXCOMM,SPI2_FLEXCOMM,_IRQHandler)
- #define SPI2_IRQn __APPEND3(FLEXCOMM,SPI2_FLEXCOMM,_IRQn)
- #define DMAREQ_SPI2_RX __APPEND3(DMAREQ_FLEXCOMM,SPI2_FLEXCOMM,_RX)
- #define DMAREQ_SPI2_TX __APPEND3(DMAREQ_FLEXCOMM,SPI2_FLEXCOMM,_TX)
复制代码
然后使用文本替换功能将LPC_SPI1全部替换为LPC_SPI1,将DMA_CH6全部替换为MY_DMA_CH_RX,将DMA_CH7全部替换为MY_DMA_CH_TX
最后将Connect the SPI1 signals to port pins部分做如下修改
- /* Connect the SPI1 signals to port pins */
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 10, (IOCON_FUNC1 | IOCON_MODE_PULLUP | IOCON_DIGITAL_EN)); /* SPI1_SCK */
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 8, (IOCON_FUNC1 | IOCON_MODE_PULLUP | IOCON_DIGITAL_EN)); /* SPI1_MOSI */
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 9, (IOCON_FUNC1 | IOCON_MODE_PULLUP | IOCON_DIGITAL_EN)); /* SPI1_MISO */
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 3, (IOCON_FUNC0 | IOCON_MODE_PULLUP | IOCON_DIGITAL_EN)); /* SPI1_SSEL0 */
-
- Chip_GPIO_SetPinDIROutput(LPC_GPIO, 0, 3);
- Chip_GPIO_SetPinState(LPC_GPIO, 0, 3, 1UL);
复制代码
所有的cs引脚都替换为P0_3
- if(message->cs_take)
- {
- Chip_GPIO_SetPinState(LPC_GPIO, 0, 3, 0UL);
- }
复制代码
- /* release CS */
- if(message->cs_release) {
- Chip_GPIO_SetPinState(LPC_GPIO, 0, 3, 1UL);
- }
复制代码
- void rt_hw_spi_init(void)
- {
- static struct lpc54110_spi_bus lpc_spi;
- static struct lpc54110_spi_cs spi_cs;
- static struct rt_spi_device spi_device;
-
- spi_cs.GPIOx = LPC_GPIO;
- spi_cs.GPIO_Port = 0;
- spi_cs.GPIO_Pin = 3;
- lpc_spi_register(MY_SPI, &lpc_spi, "spi1");
- rt_spi_bus_attach_device(&spi_device, "spi10", "spi1", (void*)&spi_cs);
- }
复制代码
然后是音频库的修改,修改外设管脚为1端口1、2脚
- void rt_hw_i2c_init(void)
- {
- rt_kprintf("install i2c1 rn");
- #ifdef RT_USING_I2C_BITOPS
- Chip_IOCON_PinMuxSet(LPC_IOCON, I2C_SDA_PORT, I2C_SDA_PIN, IOCON_FUNC0 | IOCON_DIGITAL_EN | IOCON_MODE_PULLUP);
- Chip_IOCON_PinMuxSet(LPC_IOCON, I2C_SCL_PORT, I2C_SCL_PIN, IOCON_FUNC0 | IOCON_DIGITAL_EN | IOCON_MODE_PULLUP);
-
- Chip_GPIO_SetPinDIROutput(LPC_GPIO, I2C_SDA_PORT, I2C_SDA_PIN);
- Chip_GPIO_SetPinState(LPC_GPIO, I2C_SDA_PORT, I2C_SDA_PIN, 1UL);
- Chip_GPIO_SetPinDIROutput(LPC_GPIO, I2C_SCL_PORT, I2C_SCL_PIN);
- Chip_GPIO_SetPinState(LPC_GPIO, I2C_SCL_PORT, I2C_SCL_PIN, 1UL);
-
- rt_memset((void *)&i2c_device, 0, sizeof(struct rt_i2c_bus_device));
- i2c_device.priv = (void *)&bit_ops;
- rt_i2c_bit_add_bus(&i2c_device, "i2c1");
- #else
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 25, IOCON_FUNC1 | IOCON_DIGITAL_EN | IOCON_FASTI2C_EN);
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 26, IOCON_FUNC1 | IOCON_DIGITAL_EN | IOCON_FASTI2C_EN);
-
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 1, IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_FASTI2C_EN);
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 2, IOCON_FUNC5 | IOCON_DIGITAL_EN | IOCON_FASTI2C_EN);
-
- Chip_I2C_Init(LPC_I2C0);
- Chip_I2C_SetClockDiv(LPC_I2C0, 20);
- Chip_I2CM_SetBusSpeed(LPC_I2C0, 100000);
- Chip_I2CM_Enable(LPC_I2C0);
-
- rt_memset((void *)&lpc54110_i2c1, 0, sizeof(struct rt_i2c_bus_device));
- lpc54110_i2c1.ops = &i2c1_ops;
- rt_i2c_bus_device_register(&lpc54110_i2c1, "i2c1");
- #endif
- }
复制代码
修改rt_err_t codec_hw_init使用使用i2c1初始化
- rt_err_t codec_hw_init(const char * i2c_bus_device_name)
- {
- struct rt_i2c_bus_device * i2c_device;
- uint32_t ret;
-
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 21, (IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGITAL_EN));
- Chip_Clock_SetCLKOUTSource(SYSCON_CLKOUTSRC_MAINCLK, 1);
-
- rt_kprintf("read file pagern");
- ret = Chip_Clock_GetMainClockRate();
- rt_kprintf("MainClk %d ", ret);
- ret = Chip_Clock_GetSystemClockRate();
- rt_kprintf("SysClk %d rn", ret);
-
- rt_kprintf("codec_hw_init_beginrn");
- i2c_device = rt_i2c_bus_device_find(i2c_bus_device_name);
- if(i2c_device == RT_NULL)
- {
- rt_kprintf("i2c bus device %s not found!rn", i2c_bus_device_name);
- return -RT_ENOSYS;
- }
- codec.i2c_device = i2c_device;
-
- /* Stop auto trimming of the FRO from USB */
- //Chip_USB_TrimOff(0);
- #if Magicoe
- LPC_SYSCON->FROCTRL = LPC_SYSCON->FROCTRL & ~(SYSCON_FROCTRL_MASK | SYSCON_FROCTRL_USBCLKADJ);
- Chip_Clock_SetMainClockSource(SYSCON_MAINCLKSRC_FRO12MHZ);
- Chip_Clock_SetSystemPLLSource(SYSCON_PLLCLKSRC_FRO12MHZ);
- Chip_Clock_SetPLLFreq(&pll_setup_48KHz);
- //Chip_Clock_SetPLLFreq(&pllSetup);
- Chip_Clock_SetMainClockSource(SYSCON_MAINCLKSRC_PLLOUT);
-
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 17, (IOCON_FUNC4 | IOCON_MODE_INACT | IOCON_DIGITAL_EN));
- Chip_Clock_SetMCLKDirOutput();
- Chip_Clock_SetMCLKClockSource(SYSCON_MCLKSRC_PLL, 2);
-
- Chip_SYSCON_SetFLASHAccess(SYSCON_FLASH_3CYCLE);
- #else
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 17, (IOCON_FUNC4 | IOCON_MODE_INACT | IOCON_DIGITAL_EN));
- Chip_Clock_SetMCLKDirOutput();
- Chip_Clock_SetMCLKClockSource(SYSCON_MCLKSRC_PLL, (1*LPC54110_IIS_MUL));
- #endif
- rt_kprintf("read file pagern");
- ret = Chip_Clock_GetMainClockRate();
- rt_kprintf("MainClk %d ", ret);
- ret = Chip_Clock_GetSystemClockRate();
- rt_kprintf("SysClk %d rn", ret);
- // Initial I2C here maybe
-
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 5, IOCON_FUNC1 | IOCON_DIGITAL_EN); // Flexcomm 6 / SDA
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 6, IOCON_FUNC1 | IOCON_DIGITAL_EN); // Flexcomm 6 / WS
- Chip_IOCON_PinMuxSet(LPC_IOCON, 0, 7, IOCON_FUNC1 | IOCON_DIGITAL_EN); // Flexcomm 6 / SCK
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 6, IOCON_FUNC2 | IOCON_DIGITAL_EN); // Flexcomm 7 / SCK
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 7, IOCON_FUNC2 | IOCON_DIGITAL_EN); // Flexcomm 7 / SDA
- // Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 8, IOCON_FUNC2 | IOCON_DIGITAL_EN); // Flexcomm 7 / WS
-
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 12, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / SCK */
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 13, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / SDA */
- Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 14, IOCON_FUNC4 | IOCON_DIGITAL_EN); /* Flexcomm 7 / WS */
-
- Chip_I2S_Init(I2S_PORT_TX, &audio_fmt_tx); // initialize I2S port
-
- Chip_Clock_SetFLEXCOMMClockSource(I2S7_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
-
- // Chip_I2S_Init(I2S_PORT_RX, &audio_fmt_rx); // initialize I2S port
- // Chip_Clock_SetFLEXCOMMClockSource(I2S6_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
-
- 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
-
- /* init codec */
- ret = wm8904_init();
- if (ret == LPC_OK) {
- //g_codec.cur_rate = DEF_SAMPLE_RATE;
- /* suspend codec after init to conserve power */
- //Codec_Suspend();
- }
-
- codec.parent.type = RT_Device_Class_Sound;
- codec.parent.rx_indicate = RT_NULL;
- codec.parent.tx_complete = RT_NULL;
- codec.parent.user_data = RT_NULL;
- codec.parent.control = codec_control;
- codec.parent.init = codec_init;
- codec.parent.open = codec_open;
- codec.parent.close = codec_close;
- codec.parent.read = RT_NULL;
- codec.parent.write = codec_write;
- /* set read_index and put index to 0 */
- codec.read_index = 0;
- codec.put_index = 0;
- // 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
- /* register the device */
- return rt_device_register(&codec.parent, "snd", RT_DEVICE_FLAG_WRONLY | RT_DEVICE_FLAG_DMA_TX);
- }
复制代码
修改好后编译,下载到开发板上电启动,串口打印如下
使用list()查看可以使用的命令
输入下面命令,播放TF卡里面Music文件夹里面语音电子书音频文件01.mp3
连接到开发板的耳机开始播放01.mp3语音电子书
工程文件如下
|