From 4b4c5bb3fa573c3c2f34605bbbc0936925d4360d Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Mon, 1 Sep 2014 19:58:25 +0200 Subject: More I2S driver work. --- firmware/drivers/i2s.c | 662 +++++++++++++++++++++++++++++++++++----------- firmware/drivers/i2s.h | 134 +++++++--- firmware/drivers/wm8523.c | 14 +- 3 files changed, 606 insertions(+), 204 deletions(-) diff --git a/firmware/drivers/i2s.c b/firmware/drivers/i2s.c index 0085e1d..7c87133 100644 --- a/firmware/drivers/i2s.c +++ b/firmware/drivers/i2s.c @@ -1,159 +1,503 @@ -/**************************************************************************** - * $Id:: i2s.c 5797 2010-12-03 00:27:00Z usb00423 $ - * Project: NXP LPC17xx I2S example - * - * Description: - * This file contains I2S code example which include I2S initialization, - * I2C interrupt handler, and APIs for I2S access. - * - **************************************************************************** - * Software that is described herein is for illustrative purposes only - * which provides customers with programming information regarding the - * products. This software is supplied "AS IS" without any warranties. - * NXP Semiconductors assumes no responsibility or liability for the - * use of the software, conveys no license or title under any patent, - * copyright, or mask work right to the product. NXP Semiconductors - * reserves the right to make changes in the software without - * notification. NXP Semiconductors also make no representation or - * warranty that such application will be suitable for the specified - * use without further testing or modification. -****************************************************************************/ -#include -//#include "type.h" -#include "i2s.h" -#include "dma.h" - -/* treat I2S TX and RX as a constant address, make the code and buffer -easier for both DMA and non-DMA test */ -volatile uint8_t *I2STXBuffer = (uint8_t *)(DMA_SRC); -volatile uint8_t *I2SRXBuffer = (uint8_t *)(DMA_DST); -volatile uint32_t I2SReadLength = 0; -volatile uint32_t I2SWriteLength = 0; -volatile uint32_t I2SRXDone = 0, I2STXDone = 0; - -/***************************************************************************** -** Function name: I2S_IRQHandler -** -** Descriptions: I2S interrupt handler, only RX interrupt is enabled -** for simplicity. -** -** parameters: None -** Returned value: None -** -*****************************************************************************/ -void I2S_IRQHandler (void) -{ - uint32_t RxCount = 0; - - if ( LPC_I2S->I2SSTATE & 0x01 ) - { - RxCount = (LPC_I2S->I2SSTATE >> 8) & 0xFF; - if ( (RxCount != RXFIFO_EMPTY) && !I2SRXDone ) - { - while ( RxCount > 0 ) - { - if ( I2SReadLength == BUFSIZE ) - { - LPC_I2S->I2SDAI |= ((0x01 << 3) | (0x01 << 4)); - LPC_I2S->I2SIRQ &= ~(0x01 << 0); /* Disable RX */ - I2SRXDone = 1; - break; - } - else - { - I2SRXBuffer[I2SReadLength++] = LPC_I2S->I2SRXFIFO; - } - RxCount--; - } - } - } - return; -} - -/***************************************************************************** -** Function name: I2SStart -** -** Descriptions: Start I2S DAI and DAO -** -** parameters: None -** Returned value: None -** -*****************************************************************************/ -void I2SStart( void ) -{ - uint32_t DAIValue, DAOValue; - - /* Audio output is the master, audio input is the slave, */ - /* 16 bit data, stereo, reset, master mode, not mute. */ - DAOValue = LPC_I2S->I2SDAO; - DAIValue = LPC_I2S->I2SDAI; - LPC_I2S->I2SDAO = DAOValue & (~((0x01 << 4)|(0x01 <<3))); - /* 16 bit data, stereo, reset, slave mode, not mute. */ - LPC_I2S->I2SDAI = DAIValue & (~((0x01 << 4)|(0x01 <<3))); - return; -} - -/***************************************************************************** -** Function name: I2SStop -** -** Descriptions: Stop I2S DAI and DAO -** -** parameters: None -** Returned value: None -** -*****************************************************************************/ -void I2SStop( void ) -{ - uint32_t DAIValue, DAOValue; - - /* Stop the I2S to start. Audio output is master, audio input is the slave. */ - /* 16 bit data, set STOP and RESET bits to reset the channels */ - DAOValue = LPC_I2S->I2SDAO; - /* Switch to master mode, TX channel, no mute */ - DAOValue &= ~((0x01 << 5)|(0x01 << 15)); - DAIValue = LPC_I2S->I2SDAI; - DAIValue &= ~(0x01 << 15); - LPC_I2S->I2SDAO = (0x01 << 4) | (0x01 << 3) | DAOValue; /* Master */ - LPC_I2S->I2SDAI = (0x01 << 4) | (0x01 << 3) | DAIValue; /* Slave */ - return; -} - -/***************************************************************************** -** Function name: I2SInit -** -** Descriptions: Initialize I2S controller -** -** parameters: None -** Returned value: true or false, return false if the I2S -** interrupt handler was not installed correctly -** -*****************************************************************************/ -void I2SInit( void ) -{ - - /*enable I2S in the PCONP register. I2S is disabled on reset*/ - LPC_SC->PCONP |= (1 << 27); - - /*connect the I2S sigals to port pins(P0.4-P0.9)*/ - LPC_PINCON->PINSEL0 &= ~0x000FFF00; - LPC_PINCON->PINSEL0 |= 0x00055500; - - /* Please note, in order to generate accurate TX/RX clock rate for I2S, - PCLK and CCLK needs to be carefully reconsidered. For this test - program, the TX is looped back to RX without external I2S device, - clock rate is not critical in this matter. */ - LPC_I2S->I2STXRATE = //0x241; - (100 << 0) | // Y - (49 << 8) // X - ; - - // LPC_I2S->I2SRXRATE = 0x241; - - I2SStop(); - return; -} - -/****************************************************************************** -** End Of File -******************************************************************************/ - +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * i2s.c + * + * Thu Aug 21 18:09:54 CEST 2014 + * Copyright 2014 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pedal2Metal. + * + * Pedal2Metal is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pedal2Metal is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pedal2Metal; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "i2s.h" + +static void i2s_set_power(int power) +{ + // 1. Enable I²S in PCONP register. Set PCI2S to 1 (see table 46, pg. 64) + // Remark: On reset, the I²S interface is disabled (PCI2S = 0). + uint32_t *pconp = (uint32_t *)0x400FC0C4; + *pconp &= ~(0b1 << 27); // Clear bit + *pconp |= ~( (power & 0b1) << 27); // Set bit +} + +typedef enum { + I2S_CCLK_4 = 0b00, // PCLK_peripheral = CCLK/4 + I2S_CCLK = 0b01, // PCLK_peripheral = CCLK + I2S_CCLK_2 = 0b10, // PCLK_peripheral = CCLK/2 + I2S_CCLK_8 = 0b11, // PCLK_peripheral = CCLK/8, except for CAN1, CAN2, and + // CAN filtering when 0b11 selects = CCLK/6. +} i2s_clksel_t; + +static void i2s_set_clksel(i2s_clksel_t sel) +{ + // 2. Clock: In PCLKSEL1 select PCLK_I2S. (see table 41, pg. 57) + uint32_t *pclksel1 = (uint32_t*)0x400FC1AC; + *pclksel1 &= ~(0b11 << 22); // Clear bits + *pclksel1 |= ( (sel & 0b11) << 22); // Set bits +} + +static void i2s_set_pinsel() +{ + //3. Pins: Select I²S pins and their modes in PINSEL0 to PINSEL4 and PINMODE0 + // to PINMODE4 (see Section 8.5). + + // See table 79, pg. 108 + uint32_t *pinsel0 = (uint32_t*)0x4002C000; + + // Reset ports + *pinsel0 &= + ~( + /* // We only do TX + (0b11 << 8) | // P0.4 + (0b11 << 10) | // P0.5 + (0b11 << 12) | // P0.6 + */ + (0b11 << 14) | // P0.7 + (0b11 << 16) | // P0.8 + (0b11 << 18)) // P0.9 + ; + + // Set ports + *pinsel0 |= + ( + /* // We only do TX + (0b01 << 8) | // P0.4: I2SRX_CLK + (0b01 << 10) | // P0.5: I2SRX_WS + (0b01 << 12) | // P0.6: I2SRX_SDA + */ + (0b01 << 14) | // P0.7: I2STX_CLK + (0b01 << 16) | // P0.8: I2STX_WS + (0b01 << 18)) // P0.9: I2STX_SDA + ; + + // See table 85, pg. 111 + uint32_t *pinsel9 = (uint32_t *)0x4002C024; + + // Reset + *pinsel9 &= + ~(0b11 << 26) // P4.28 + ; + + // Set port + *pinsel9 |= + (0b01 << 26) // P4.28: TX_MCLK + ; +} + +typedef enum { + WW_8_BIT = 0b00, // 8-bit data + WW_16_BIT = 0b01, // 16-bit data + WW_RESERVED = 0b10, // Reserved, do not use this setting + WW_32_BIT = 0b11, // 32-bit data +} wordwidth_t; + +typedef enum { + CH_MONO = 0b1, // Data is mono format + CH_STEREO = 0b0, // Data is stereo format +} channels_t; + +/** + * Sets DAO register values and stops/resets the bus. + */ +static void i2s_set_dao_register(wordwidth_t ww, + channels_t ch) +{ + // See table 405, pg. 476 + uint32_t *i2sdao = (uint32_t*)0x400A8000; + *i2sdao = + (ww << 0) | // Set bit word width + (ch << 2) | // stereo + (0b1 << 3) | // stop bit + (0b1 << 4) | // reset + (0b0 << 5) | // ws_sel in master mode + (0x1f << 6) | // ws_halfperiod ... default for now + (0b0 << 15) // no mute + ; +} + +/* +** + * Sets DAI register values and stops/resets the bus. + * +static void i2s_set_dai_register(wordwidth_t ww, + channels_t ch) +{ + // See table 406, pg. 477 + uint32_t *i2sdai = (uint32_t*)0x400A8004; + *i2sdai = + (ww << 0) | // Set bit word width + (ch << 2) | // stereo + (0b1 << 3) | // stop bit + (0b1 << 4) | // reset + (0b0 << 5) | // ws_sel in master mode + (0x1f << 6) | // ws_halfperiod ... default for now + (0b0 << 15) // no mute + ; +} +*/ + +/** + * I2STXMCLK = PCLK_I2S * (X/Y) /2 + */ +static void i2s_set_tx_rate(uint8_t y_div, uint8_t x_div) +{ + // See table 413, pg. 480 + uint32_t *i2stxrate = (uint32_t*)0x400A8020; + *i2stxrate = y_div | (x_div << 8); +} + +/* +static void i2s_set_rx_rate(uint8_t y_div, uint8_t x_div) +{ + // See table 414, pg. 481 + uint32_t *i2srxrate = (uint32_t*)0x400A8024; + *i2srxrate = y_div | (x_div << 8); +} +*/ + +/** + * I²S transmit bit rate. This value plus one is used to divide TX_MCLK to + * produce the transmit bit clock. + */ +static void i2s_set_tx_clock_bitrate(uint8_t bitrate) +{ + // See table 415, pg. 481 + uint32_t *i2stxbitrate = (uint32_t*)0x400A8028; + *i2stxbitrate = (bitrate & 0b111111); +} + +/* +static void i2s_set_rx_clock_bitrate(uint8_t bitrate) +{ + // See table 416, pg. 481 + uint32_t *i2srxbitrate = (uint32_t*)0x400A802C; + *i2srxbitrate = (bitrate & 0b111111); +} +*/ + +typedef enum { + CLK_TX_SRC = 0b00, // Select the TX fractional rate divider clock output as the source + CLK_RX_MCLK = 0b10, // Select the RX_MCLK signal as the TX_MCLK clock source +} clksel_t; + +static void i2s_set_tx_mode_control(clksel_t c, int _4pin, int mcena) +{ + // See table 417, pg 482 + uint32_t *i2stxmode = (uint32_t*)0x400A8030; + *i2stxmode = c | + ((_4pin & 0b1) << 2) | + ((mcena & 0b1) << 3) + ; +} + +/* +static void i2s_set_rx_mode_control(clksel_t c, int _4pin, int mcena) +{ + // See table 418, pg 483 + uint32_t *i2srxmode = (uint32_t*)0x400A8034; + *i2stxmode = c | + ((_4pin & 0b1) << 2) | + ((mcena & 0b1) << 3) + ; +} +*/ + +static void i2s_tx_reset() +{ + // See table 405, pg. 476 + uint32_t *i2sdao = (uint32_t*)0x400A8000; + *i2sdao |= + (0b1 << 4) // reset + ; +} + +void i2s_tx_stop() +{ + // See table 405, pg. 476 + uint32_t *i2sdao = (uint32_t*)0x400A8000; + *i2sdao |= + (0b1 << 3) // stop bit + ; +} + +void i2s_tx_start() +{ + // See table 405, pg. 476 + uint32_t *i2sdao = (uint32_t*)0x400A8000; + *i2sdao &= + ~((0b1 << 3) | // unset stop bit (start) + (0b1 << 15)) // unset mute bit (unmute) + ; +} + +/* +static void i2s_rx_reset() +{ + // See table 406, pg. 477 + uint32_t *i2sdai = (uint32_t*)0x400A8004; + *i2sdai |= + (0b1 << 4) // reset + ; +} +*/ + +/* +static void i2s_rx_stop() +{ + // See table 406, pg. 477 + uint32_t *i2sdai = (uint32_t*)0x400A8004; + *i2sdai |= + (0b1 << 3) // stop bit + ; +} +*/ +/* +static void i2s_rx_start() +{ + // See table 406, pg. 477 + uint32_t *i2sdai = (uint32_t*)0x400A8004; + *i2sdai &= + ~(0b1 << 3) // stop bit + ; +} + */ +/* + * A data sample in the FIFO consists of: + * - 1×32 bits in 8-bit or 16-bit stereo modes. + * - 1×32 bits in mono modes. + * - 2×32 bits, first left data, second right data, in 32-bit stereo modes. + * + * I2STXFIFO: 0x400A 8008 - 8 x 32 bit + * I2SRXFIFO: 0x400A 800C - 8 x 32 bit + * + * See figure 113, pg. 489, for examples. + */ + +/** + * This bit reflects the presence of Receive Interrupt or Transmit Interrupt. + * This is determined by comparing the current FIFO levels to the rx_depth_irq + * and tx_depth_irq fields in the I2SIRQ register. + */ +int i2s_get_state_irq() +{ + // See table 409, pg.478 + uint32_t *i2sstate = (uint32_t*)0x400A8010; + return (*i2sstate >> 0) & 0b1; // bit 0 +} + +/** + * This bit reflects the presence of Receive or Transmit DMA Request 1. This is + * determined by comparing the current FIFO levels to the rx_depth_dma1 and + * tx_depth_dma1 fields in the I2SDMA1 register. + */ +int i2s_get_state_dmareq1() +{ + // See table 409, pg.478 + uint32_t *i2sstate = (uint32_t*)0x400A8010; + return (*i2sstate >> 1) & 0b1; // bit 1 +} + +/** + * This bit reflects the presence of Receive or Transmit DMA Request 2. This is + * determined by comparing the current FIFO levels to the rx_depth_dma2 and + * tx_depth_dma2 fields in the I2SDMA2 register. + */ +int i2s_get_state_dmareq2() +{ + // See table 409, pg.478 + uint32_t *i2sstate = (uint32_t*)0x400A8010; + return (*i2sstate >> 2) & 0b1; // bit 2 +} + +/** + * Reflects the current level of the Receive FIFO. + */ +int i2s_get_state_rx_level() +{ + // See table 409, pg.478 + uint32_t *i2sstate = (uint32_t*)0x400A8010; + return (*i2sstate >> 8) & 0b1111; // bit 8-11 +} + +/** + * Reflects the current level of the Transmit FIFO. + */ +int i2s_get_state_tx_level() +{ + // See table 409, pg.478 + uint32_t *i2sstate = (uint32_t*)0x400A8010; + return (*i2sstate >> 16) & 0b1111; // bit 16-19 +} + +void i2s_init() +{ + i2s_set_power(1); + i2s_set_clksel(I2S_CCLK_2); + i2s_set_pinsel(); + i2s_set_dao_register(WW_16_BIT, CH_STEREO); + i2s_set_tx_rate(1, 1); + i2s_set_tx_clock_bitrate(7); + i2s_set_tx_mode_control(CLK_TX_SRC, 1, 1); + + i2s_tx_reset(); + i2s_tx_stop(); + + int i; + i = i2s_get_state_irq(); + i = i2s_get_state_dmareq1(); + i = i2s_get_state_dmareq2(); + i = i2s_get_state_rx_level(); + i = i2s_get_state_tx_level(); + (void)i; +} + +#if 0 +#include +//#include "type.h" +#include "dma.h" + +/* treat I²S TX and RX as a constant address, make the code and buffer +easier for both DMA and non-DMA test */ +volatile uint8_t *I2STXBuffer = (uint8_t *)(DMA_SRC); +volatile uint8_t *I2SRXBuffer = (uint8_t *)(DMA_DST); +volatile uint32_t I2SReadLength = 0; +volatile uint32_t I2SWriteLength = 0; +volatile uint32_t I2SRXDone = 0, I2STXDone = 0; + +/***************************************************************************** +** Function name: I2S_IRQHandler +** +** Descriptions: I²S interrupt handler, only RX interrupt is enabled +** for simplicity. +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void I2S_IRQHandler (void) +{ + uint32_t RxCount = 0; + + if ( LPC_I2S->I2SSTATE & 0x01 ) + { + RxCount = (LPC_I2S->I2SSTATE >> 8) & 0xFF; + if ( (RxCount != RXFIFO_EMPTY) && !I2SRXDone ) + { + while ( RxCount > 0 ) + { + if ( I2SReadLength == BUFSIZE ) + { + LPC_I2S->I2SDAI |= ((0x01 << 3) | (0x01 << 4)); + LPC_I2S->I2SIRQ &= ~(0x01 << 0); /* Disable RX */ + I2SRXDone = 1; + break; + } + else + { + I2SRXBuffer[I2SReadLength++] = LPC_I2S->I2SRXFIFO; + } + RxCount--; + } + } + } + return; +} + +/***************************************************************************** +** Function name: I2SStart +** +** Descriptions: Start I²S DAI and DAO +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void I2SStart( void ) +{ + uint32_t DAIValue, DAOValue; + + /* Audio output is the master, audio input is the slave, */ + /* 16 bit data, stereo, reset, master mode, not mute. */ + DAOValue = LPC_I2S->I2SDAO; + DAIValue = LPC_I2S->I2SDAI; + LPC_I2S->I2SDAO = DAOValue & (~((0x01 << 4)|(0x01 <<3))); + /* 16 bit data, stereo, reset, slave mode, not mute. */ + LPC_I2S->I2SDAI = DAIValue & (~((0x01 << 4)|(0x01 <<3))); + return; +} + +/***************************************************************************** +** Function name: I2SStop +** +** Descriptions: Stop I²S DAI and DAO +** +** parameters: None +** Returned value: None +** +*****************************************************************************/ +void I2SStop( void ) +{ + uint32_t DAIValue, DAOValue; + + /* Stop the I²S to start. Audio output is master, audio input is the slave. */ + /* 16 bit data, set STOP and RESET bits to reset the channels */ + DAOValue = LPC_I2S->I2SDAO; + /* Switch to master mode, TX channel, no mute */ + DAOValue &= ~((0x01 << 5)|(0x01 << 15)); + DAIValue = LPC_I2S->I2SDAI; + DAIValue &= ~(0x01 << 15); + LPC_I2S->I2SDAO = (0x01 << 4) | (0x01 << 3) | DAOValue; /* Master */ + LPC_I2S->I2SDAI = (0x01 << 4) | (0x01 << 3) | DAIValue; /* Slave */ + return; +} + +/***************************************************************************** +** Function name: I2SInit +** +** Descriptions: Initialize I²S controller +** +** parameters: None +** Returned value: true or false, return false if the I²S +** interrupt handler was not installed correctly +** +*****************************************************************************/ +void I2SInit( void ) +{ + + /*enable I²S in the PCONP register. I²S is disabled on reset*/ + LPC_SC->PCONP |= (1 << 27); + + /*connect the I²S sigals to port pins(P0.4-P0.9)*/ + LPC_PINCON->PINSEL0 &= ~0x000FFF00; + LPC_PINCON->PINSEL0 |= 0x00055500; + + /* Please note, in order to generate accurate TX/RX clock rate for I²S, + PCLK and CCLK needs to be carefully reconsidered. For this test + program, the TX is looped back to RX without external I²S device, + clock rate is not critical in this matter. */ + LPC_I2S->I2STXRATE = //0x241; + (100 << 0) | // Y + (49 << 8) // X + ; + + // LPC_I2S->I2SRXRATE = 0x241; + + I2SStop(); + return; +} +#endif diff --git a/firmware/drivers/i2s.h b/firmware/drivers/i2s.h index dbbb6f2..6e3acf2 100644 --- a/firmware/drivers/i2s.h +++ b/firmware/drivers/i2s.h @@ -1,41 +1,93 @@ -/**************************************************************************** - * $Id:: i2s.h 5797 2010-12-03 00:27:00Z usb00423 $ - * Project: NXP LPC17xx I2S example - * - * Description: - * This file contains I2S code header definition. - * - **************************************************************************** - * Software that is described herein is for illustrative purposes only - * which provides customers with programming information regarding the - * products. This software is supplied "AS IS" without any warranties. - * NXP Semiconductors assumes no responsibility or liability for the - * use of the software, conveys no license or title under any patent, - * copyright, or mask work right to the product. NXP Semiconductors - * reserves the right to make changes in the software without - * notification. NXP Semiconductors also make no representation or - * warranty that such application will be suitable for the specified - * use without further testing or modification. -****************************************************************************/ -#ifndef __I2S_H -#define __I2S_H - -//#include "../src/sample.h" - -#define I2S_DMA_ENABLED 1 - -#define BUFSIZE 0x200 -//(1097 * sizeof(short) * 2)/*stereo*/ -//((int)(sizeof(samples) * 2/*stereo*/)) -#define RXFIFO_EMPTY 0 -#define TXFIFO_FULL 8 - -extern void I2S_IRQHandler( void ); -extern void I2SStart( void ); -extern void I2SStop( void ); -extern void I2SInit( void ); - -#endif /* end __I2S_H */ -/**************************************************************************** -** End Of File -*****************************************************************************/ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * i2s.h + * + * Thu Aug 21 18:09:54 CEST 2014 + * Copyright 2014 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of Pedal2Metal. + * + * Pedal2Metal is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Pedal2Metal is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Pedal2Metal; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#ifndef __PEDAL2METAL_I2S_H__ +#define __PEDAL2METAL_I2S_H__ + +#include + +void i2s_init(); + +/** + * Enables accesses on FIFOs, places the transmit channel in unmute mode. + */ +void i2s_tx_start(); + +/** + * Disables accesses on FIFOs, places the transmit channel in mute mode. + */ +void i2s_tx_stop(); + +/** + * This bit reflects the presence of Receive Interrupt or Transmit Interrupt. + * This is determined by comparing the current FIFO levels to the rx_depth_irq + * and tx_depth_irq fields in the I2SIRQ register. + */ +int i2s_get_state_irq(); + +/** + * This bit reflects the presence of Receive or Transmit DMA Request 1. This is + * determined by comparing the current FIFO levels to the rx_depth_dma1 and + * tx_depth_dma1 fields in the I2SDMA1 register. + */ +int i2s_get_state_dmareq1(); + +/** + * This bit reflects the presence of Receive or Transmit DMA Request 2. This is + * determined by comparing the current FIFO levels to the rx_depth_dma2 and + * tx_depth_dma2 fields in the I2SDMA2 register. + */ +int i2s_get_state_dmareq2(); + +/** + * Reflects the current level of the Receive FIFO. + */ +int i2s_get_state_rx_level(); + +/** + * Reflects the current level of the Transmit FIFO. + */ +int i2s_get_state_tx_level(); + + +#if 0 + +#define I2S_DMA_ENABLED 1 + +#define BUFSIZE 0x200 +//(1097 * sizeof(short) * 2)/*stereo*/ +//((int)(sizeof(samples) * 2/*stereo*/)) +#define RXFIFO_EMPTY 0 +#define TXFIFO_FULL 8 + +extern void I2S_IRQHandler( void ); +extern void I2SStart( void ); +extern void I2SStop( void ); +extern void I2SInit( void ); + +#endif + +#endif/*__PEDAL2METAL_I2S_H__*/ diff --git a/firmware/drivers/wm8523.c b/firmware/drivers/wm8523.c index 96d5cae..e1711fd 100644 --- a/firmware/drivers/wm8523.c +++ b/firmware/drivers/wm8523.c @@ -113,6 +113,10 @@ void wm8523_init(uint8_t portnum, wm8523_samplerate_t fs) if(portnum == 0) SSP0Init(); else SSP1Init(); +#if 1 + i2s_init(); + (void)fs; +#else I2SInit(); // pg. 482 @@ -138,8 +142,8 @@ void wm8523_init(uint8_t portnum, wm8523_samplerate_t fs) // I2STXBITRATE 0x400A 8028 // bit 0-5 I2S transmit bit rate. This value plus one is used to divide TX_MCLK to produce the transmit bit clock. // set to 31 (divide by 32): stereo (2) * 16bit - uint32_t *i2stxbirate = (uint32_t *)0x400a8028; - *i2stxbirate = 7; + uint32_t *i2stxbitrate = (uint32_t *)0x400a8028; + *i2stxbitrate = 7; // bitclock = mclock / (divider+1) // samplerate = mclock / bitclock @@ -179,7 +183,8 @@ void wm8523_init(uint8_t portnum, wm8523_samplerate_t fs) (0b1111 << 4) | // Divide by 16 (0b1 << 8) // Enable ; - */ + */ +#endif } unsigned short wm8523_get_chip_id(uint8_t portnum) @@ -315,7 +320,8 @@ void wm8523_tone() NVIC_EnableIRQ(I2S_IRQn); // RX FIFO depth is 1, TX FIFO depth is 8. - I2SStart(); + //I2SStart(); + i2s_tx_start(); LPC_I2S->I2SIRQ = (8 << 16) | (1 << 8) | (0x01 << 0); //uint32_t val = 0; -- cgit v1.2.3