Mark B
/
i2s
Revision 0:6d43d111bdc1, committed 2010-01-20
- Comitter:
- macaba
- Date:
- Wed Jan 20 11:44:57 2010 +0000
- Commit message:
Changed in this revision
diff -r 000000000000 -r 6d43d111bdc1 i2s/dma.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2s/dma.cpp Wed Jan 20 11:44:57 2010 +0000 @@ -0,0 +1,151 @@ +/***************************************************************************** + * dma.c: DMA module file for NXP LPC17xx Family Microprocessors + * + * Copyright(C) 2009, NXP Semiconductor + * All rights reserved. + * + * History + * 2009.05.26 ver 1.00 Prelimnary version, first Release + * +******************************************************************************/ +#include "mbed.h" +#include "type.h" +#include "i2s.h" +#include "dma.h" + +#if I2S_DMA_ENABLED +volatile uint32_t DMATCCount = 0; +volatile uint32_t DMAErrCount = 0; +volatile uint32_t I2SDMA0Done = 0; +volatile uint32_t I2SDMA1Done = 0; + +/****************************************************************************** +** Function name: DMA_IRQHandler +** +** Descriptions: DMA interrupt handler +** +** parameters: None +** Returned value: None +** +******************************************************************************/ +void DMA_IRQHandler(void) +{ + uint32_t regVal; + + regVal = LPC_GPDMA->DMACIntTCStat; + if ( regVal ) + { + DMATCCount++; + LPC_GPDMA->DMACIntTCClear |= regVal; + if ( regVal & 0x01 ) + { + I2SDMA0Done = 1; + } + else if ( regVal & 0x02 ) + { + I2SDMA1Done = 1; + } + } + + regVal = LPC_GPDMA->DMACIntErrStat; + if ( regVal ) + { + DMAErrCount++; + LPC_GPDMA->DMACIntErrClr |= regVal; + } + +} + +/****************************************************************************** +** Function name: DMA_Init +** +** Descriptions: +** +** parameters: +** Returned value: +** +******************************************************************************/ +uint32_t DMA_Init( uint32_t ChannelNum, uint32_t DMAMode ) +{ + if ( ChannelNum == 0 ) + { + LPC_GPDMA->DMACIntTCClear = 0x01; + if ( DMAMode == M2P ) + { + /* Ch0 set for M2P transfer from mempry to I2S TX FIFO. */ + LPC_GPDMACH0->DMACCSrcAddr = DMA_SRC; + LPC_GPDMACH0->DMACCDestAddr = DMA_I2S_TX_FIFO; + /* The burst size is set to 1. Terminal Count Int enable */ + LPC_GPDMACH0->DMACCControl = (DMA_SIZE & 0x0FFF) | (0x00 << 12) | (0x00 << 15) + | (1 << 26) | 0x80000000; + } + else if ( DMAMode == P2M ) + { + /* Ch0 set for P2M transfer from I2S RX FIFO to memory. */ + LPC_GPDMACH0->DMACCSrcAddr = DMA_I2S_RX_FIFO; + LPC_GPDMACH0->DMACCDestAddr = DMA_DST; + /* The burst size is set to 1. Terminal Count Int enable. */ + LPC_GPDMACH0->DMACCControl = (DMA_SIZE & 0x0FFF) | (0x00 << 12) | (0x00 << 15) + | (1 << 27) | 0x80000000; + } + else if ( DMAMode == P2P ) + { + /* Ch0 set for P2P transfer from I2S DAO to I2S DAI. */ + LPC_GPDMACH0->DMACCSrcAddr = DMA_I2S_TX_FIFO; + LPC_GPDMACH0->DMACCDestAddr = DMA_I2S_RX_FIFO; + /* The burst size is set to 32. */ + LPC_GPDMACH0->DMACCControl = (DMA_SIZE & 0x0FFF) | (0x04 << 12) | (0x04 << 15) + | 0x80000000; + } + else + { + return ( FALSE ); + } + } + else if ( ChannelNum == 1 ) + { + LPC_GPDMA->DMACIntTCClear = 0x02; + if ( DMAMode == M2P ) + { + /* Ch1 set for M2P transfer from mempry to I2S TX FIFO. */ + LPC_GPDMACH1->DMACCSrcAddr = DMA_SRC; + LPC_GPDMACH1->DMACCDestAddr = DMA_I2S_TX_FIFO; + /* The burst size is set to 1. Terminal Count Int enable. */ + LPC_GPDMACH1->DMACCControl = (DMA_SIZE & 0x0FFF) | (0x00 << 12) | (0x00 << 15) + | (1 << 26) | 0x80000000; + } + else if ( DMAMode == P2M ) + { + /* Ch1 set for P2M transfer from I2S RX FIFO to memory. */ + LPC_GPDMACH1->DMACCSrcAddr = DMA_I2S_RX_FIFO; + LPC_GPDMACH1->DMACCDestAddr = DMA_DST; + /* The burst size is set to 1. Terminal Count Int enable. */ + LPC_GPDMACH1->DMACCControl = (DMA_SIZE & 0x0FFF) | (0x00 << 12) | (0x00 << 15) + | (1 << 27) | 0x80000000; + } + else if ( DMAMode == P2P ) + { + /* Ch1 set for P2P transfer from I2S DAO to I2S DAI. */ + LPC_GPDMACH1->DMACCSrcAddr = DMA_I2S_TX_FIFO; + LPC_GPDMACH1->DMACCDestAddr = DMA_I2S_RX_FIFO; + /* The burst size is set to 32. */ + LPC_GPDMACH1->DMACCControl = (DMA_SIZE & 0x0FFF) | (0x04 << 12) | (0x04 << 15) + | 0x80000000; + } + else + { + return ( FALSE ); + } + } + else + { + return ( FALSE ); + } + return( TRUE ); +} + +#endif /* end if DMA_ENABLED */ + +/****************************************************************************** +** End Of File +******************************************************************************/
diff -r 000000000000 -r 6d43d111bdc1 i2s/dma.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2s/dma.h Wed Jan 20 11:44:57 2010 +0000 @@ -0,0 +1,39 @@ +/***************************************************************************** + * dma.h: Header file for NXP LPC17xx Family Microprocessors + * + * Copyright(C) 2009, NXP Semiconductor + * All rights reserved. + * + * History + * 2009.05.26 ver 1.00 Prelimnary version, first Release + * +******************************************************************************/ +#ifndef __DMA_H +#define __DMA_H + +/* USB RAM is used for GPDMA operation. */ +//#define DMA_SRC 0x7FD00000 +//#define DMA_DST 0x7FD01000 +//#define DMA_I2S_TX_FIFO 0xE0088008 +//#define DMA_I2S_RX_FIFO 0xE008800C + +#define DMA_SRC 0x20080000 +#define DMA_DST 0x20081000 +#define DMA_I2S_TX_FIFO 0x400A8008 +#define DMA_I2S_RX_FIFO 0x400A800C + +#define DMA_SIZE 0x200 + +/* DMA mode */ +#define M2M 0x00 +#define M2P 0x01 +#define P2M 0x02 +#define P2P 0x03 + +extern void DMA_IRQHandler( void ); +extern uint32_t DMA_Init( uint32_t ChannelNum, uint32_t DMAMode ); + +#endif /* end __DMA_H */ +/**************************************************************************** +** End Of File +****************************************************************************/
diff -r 000000000000 -r 6d43d111bdc1 i2s/i2s.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2s/i2s.cpp Wed Jan 20 11:44:57 2010 +0000 @@ -0,0 +1,147 @@ +/***************************************************************************** + * i2s.c: I2S C file for NXP LPC17xx Family Microprocessors + * + * Copyright(C) 2009, NXP Semiconductor + * All rights reserved. + * + * History + * 2009.05.26 ver 1.00 Prelimnary version, first Release + * +*****************************************************************************/ +#include "mbed.h" +#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 +** +*****************************************************************************/ +uint32_t 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; + LPC_I2S->I2SRXRATE = 0x241; + + I2SStop(); + + NVIC_EnableIRQ(I2S_IRQn); + return( TRUE ); +} + +/****************************************************************************** +** End Of File +******************************************************************************/ +
diff -r 000000000000 -r 6d43d111bdc1 i2s/i2s.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2s/i2s.h Wed Jan 20 11:44:57 2010 +0000 @@ -0,0 +1,28 @@ +/***************************************************************************** + * i2s.h: Header file for NXP LPC17xx Family Microprocessors + * + * Copyright(C) 2009, NXP Semiconductor + * All rights reserved. + * + * History + * 2009.05.26 ver 1.00 Prelimnary version, first Release + * +******************************************************************************/ +#ifndef __I2S_H +#define __I2S_H + +#define I2S_DMA_ENABLED 1 + +#define BUFSIZE 0x200 +#define RXFIFO_EMPTY 0 +#define TXFIFO_FULL 8 + +extern void I2S_IRQHandler( void ); +extern void I2SStart( void ); +extern void I2SStop( void ); +extern uint32_t I2SInit( void ); + +#endif /* end __I2S_H */ +/**************************************************************************** +** End Of File +*****************************************************************************/
diff -r 000000000000 -r 6d43d111bdc1 i2s/type.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/i2s/type.h Wed Jan 20 11:44:57 2010 +0000 @@ -0,0 +1,33 @@ +/***************************************************************************** + * type.h: Type definition Header file for NXP LPC17xx Family + * Microprocessors + * + * Copyright(C) 2009, NXP Semiconductor + * All rights reserved. + * + * History + * 2009.05.25 ver 1.00 Prelimnary version, first Release + * +******************************************************************************/ +#include <stdint.h> + +#ifndef __TYPE_H__ +#define __TYPE_H__ + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (1) +#endif + + +typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus; +typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; + +#endif /* __TYPE_H__ */
diff -r 000000000000 -r 6d43d111bdc1 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Jan 20 11:44:57 2010 +0000 @@ -0,0 +1,80 @@ +#include "mbed.h" +#include "i2s.h" +#include "type.h" +#include "dma.h" + +extern volatile uint8_t *I2STXBuffer, *I2SRXBuffer; +extern volatile uint32_t I2SReadLength; +extern volatile uint32_t I2SWriteLength; +extern volatile uint32_t I2SRXDone, I2STXDone; +extern volatile uint32_t I2SDMA0Done, I2SDMA1Done; + +DigitalOut myled(LED1); + + +int main() { + uint32_t i; + /* Configure temp register before reading */ + for ( i = 0; i < BUFSIZE; i++ ) { /* clear buffer */ + I2STXBuffer[i] = i; + I2SRXBuffer[i] = 0; + } + + if ( I2SInit() == FALSE ) { /* initialize I2S */ + while ( 1 ); /* Fatal error */ + } + +#if I2S_DMA_ENABLED + /* USB RAM is used for test. + Please note, Ethernet has its own SRAM, but GPDMA can't access + that. GPDMA can access USB SRAM and IRAM. Ethernet DMA controller can + access both IRAM and Ethernet SRAM. */ + LPC_SC->PCONP |= (1 << 29); /* Enable GPDMA clock */ + + LPC_GPDMA->DMACIntTCClear = 0x03; + LPC_GPDMA->DMACIntErrClr = 0x03; + + LPC_GPDMA->DMACConfig = 0x01; /* Enable DMA channels, little endian */ + while ( !(LPC_GPDMA->DMACConfig & 0x01) ); + + /* on DMA channel 0, Source is memory, destination is I2S TX FIFO, + on DMA channel 1, source is I2S RX FIFO, Destination is memory */ + /* Enable channel and IE bit */ + DMA_Init( 0, M2P ); + LPC_GPDMACH0->DMACCConfig |= 0x18001 | (0x00 << 1) | (0x05 << 6) | (0x01 << 11); + DMA_Init( 1, P2M ); + LPC_GPDMACH1->DMACCConfig |= 0x08001 | (0x06 << 1) | (0x00 << 6) | (0x02 << 11); + + NVIC_EnableIRQ(DMA_IRQn); + + I2SStart(); + + LPC_I2S->I2SDMA2 = (0x01<<0) | (0x08<<8); /* Channel 2 is for RX, enable RX first. */ + LPC_I2S->I2SDMA1 = (0x01<<1) | (0x01<<16);/* Channel 1 is for TX. */ + + /* Wait for both DMA0 and DMA1 to finish before verifying. */ + while ( !I2SDMA0Done || !I2SDMA1Done ); +#else + /* Not DMA mode, enable I2S interrupts. */ + /* RX FIFO depth is 1, TX FIFO depth is 8. */ + I2SStart(); + LPC_I2S->I2SIRQ = (8 << 16) | (1 << 8) | (0x01 << 0); + + while ( I2SWriteLength < BUFSIZE ) { + while (((LPC_I2S->I2SSTATE >> 16) & 0xFF) == TXFIFO_FULL); + LPC_I2S->I2STXFIFO = I2STXBuffer[I2SWriteLength++]; + } + + I2STXDone = 1; + /* Wait for RX and TX complete before comparison */ + while ( !I2SRXDone || !I2STXDone ); +#endif + + /* Validate TX and RX buffer */ + for ( i=1; i<BUFSIZE; i++ ) { + if ( I2SRXBuffer[i] != I2STXBuffer[i-1] ) { + while ( 1 ); /* Validation error */ + } + } + return 0; +}
diff -r 000000000000 -r 6d43d111bdc1 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Jan 20 11:44:57 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0