This is an I2S library to allow people to take advantage of the I2S peripheral on the LPC1768. Ideally it will be included in future releases of the mbed.h file.

Files at this revision

API Documentation at this revision

Comitter:
Pinski1
Date:
Mon Dec 06 00:05:39 2010 +0000
Commit message:
An initial release, not fully tested.

Changed in this revision

I2S.cpp Show annotated file Show diff for this revision Revisions of this file
I2S.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2S.cpp	Mon Dec 06 00:05:39 2010 +0000
@@ -0,0 +1,228 @@
+#include "mbed.h"
+#include "LPC17xx.h"
+#include "core_cm3.h"
+#include "system_LPC17xx.h"
+#include "I2S.h"
+
+I2S::I2S(PinName bitTx = p7, PinName wdTx = p6, PinName daTx = p5, PinName bitRx = p30, PinName wdRx = p29, PinName daRx = p8) {
+    // assuming pins are correct
+
+    // assign pins - be nice to use mbed stuff for this
+	LPC_PINCON->PINSEL0 |= ((0x01 << 14) | (0x01 << 16) | (0x01 << 18)); // set p5,p6,p7 as I2S
+	LPC_PINCON->PINMODE0 |= ((0x02 << 14) | (0x02 << 16) | (0x02 << 18));
+	if(bitRx == p30)
+	{
+		LPC_PINCON->PINSEL0 |= (0x01 << 8);
+		LPC_PINCON->PINMODE0 |= (0x02 << 8);
+	}
+	else
+	{
+		LPC_PINCON->PINSEL1 |= (0x01 << 14);
+		LPC_PINCON->PINMODE1 |= (0x02 << 14);
+	}
+	if(wdRx == p29)
+	{
+		LPC_PINCON->PINSEL0 |= (0x01 << 10);
+		LPC_PINCON->PINMODE0 |= (0x02 << 10);
+	}
+	else
+	{
+		LPC_PINCON->PINSEL1 |= (0x01 << 16);
+		LPC_PINCON->PINMODE1 |= (0x02 << 16);
+	}
+	if(daRx == p8)
+	{
+		LPC_PINCON->PINSEL0 |= (0x01 << 12);
+		LPC_PINCON->PINMODE0 |= (0x02 << 12);
+	}
+	else
+	{
+		LPC_PINCON->PINSEL1 |= (0x01 << 18);
+		LPC_PINCON->PINMODE1 |= (0x02 << 18);
+	}
+
+    LPC_SC->PCONP |= (0x01 << 27); // turn on I2S periferal
+}
+
+I2S::~I2S() {
+    // release stuff
+    LPC_SC->PCONP &= (0 << 27); // turn off I2S periferal
+}
+
+
+void I2S::setClocks(uint8_t x, uint8_t y, uint8_t divider) {
+
+	if(divider == 1) LPC_SC->PCLKSEL1 &= (0x01 << 22);
+	else if(divider == 2) LPC_SC->PCLKSEL1 &= (0x02 << 22);
+	else if(divider == 4) LPC_SC->PCLKSEL1 &= (0x00 << 22);
+	else if(divider == 8) LPC_SC->PCLKSEL1 &= (0x03 << 22);
+
+	LPC_I2S->I2STXRATE = (x << 8) & y;
+	LPC_I2S->I2SRXRATE = (x << 8) & y;
+	
+	peripheralClock = SystemCoreClock/divider;
+	masterClock = (x * peripheralClock)/(2 * y);
+}
+
+
+void I2S::setTx(uint16_t resolution, uint16_t rate, bool stereo) {
+
+	if(resolution == 8) LPC_I2S->I2SDAO &= (0x00 << 4); // set to 00
+	else if(resolution == 16) LPC_I2S->I2SDAO |= (0x01 << 4); // set to 01
+	else if(resolution == 32) LPC_I2S->I2SDAO |= (0x03 << 4);// set to 11
+	
+    // rate limited to 16000, 22050, 32000, 44100, 48000 or 96000
+	
+	uint32_t bitClock = resolution * rate;
+	if(stereo == true) bitClock *= 2;
+	uint8_t bitDivider = masterClock / bitClock;	
+	LPC_I2S->I2STXBITRATE = bitDivider - 1;
+	
+    if(stereo == true) LPC_I2S->I2SDAO &= (0 << 2); // set to stereo
+	else LPC_I2S->I2SDAO |= (1 << 2);
+}
+
+void I2S::setRx(uint16_t resolution, uint16_t rate, bool stereo) {
+    
+	if(resolution == 8) LPC_I2S->I2SDAI &= (0x00 << 4); // set to 00
+	else if(resolution == 16) LPC_I2S->I2SDAI |= (0x01 << 4); // set to 01
+	else if(resolution == 32) LPC_I2S->I2SDAI |= (0x03 << 4);// set to 11
+	
+    // rate limited to 16000, 22050, 32000, 44100, 48000 or 96000
+	
+    uint32_t bitClock = resolution * rate;
+	if(stereo == true) bitClock *= 2;
+	uint8_t bitDivider = masterClock / bitClock;	
+	LPC_I2S->I2SRXBITRATE = bitDivider - 1;
+	
+	if(stereo == true) LPC_I2S->I2SDAI &= (0 << 2); // set to stereo
+	else LPC_I2S->I2SDAI |= (1 << 2);
+}
+
+void I2S::muteTx(void) {
+    // sets the channel into "stop" mode, TX sends zeros
+    if(LPC_I2S->I2SDAO & 0x08) LPC_I2S->I2SDAO |= (1 << 4);
+	else  LPC_I2S->I2SDAO &= (0 << 4);
+    return;
+}
+
+void I2S::muteRx(void) {
+    // sets the channel into "stop" mode, TX sends zeros
+    if(LPC_I2S->I2SDAI & 0x00008) LPC_I2S->I2SDAI |= (1 << 4);
+    else LPC_I2S->I2SDAI &= (0 << 4);
+    return;
+}
+
+void I2S::resetTx(void) {
+    // resets the channel
+    LPC_I2S->I2SDAO |= (1 << 5);
+    return;
+}
+
+void I2S::resetRx(void) {
+    // resets the channel
+    LPC_I2S->I2SDAI |= (1 << 5);
+    return;
+}
+
+void setTxMode(uint8_t mode) {
+	uint8_t modes[2][7] = {{0,0,0,0,1,1,1},{0,2,4,8,0,2,4}};
+	/*
+	0;0,0,0,0 // Typical transmitter master mode.
+	0;0,0,1,0 // Transmitter master mode sharing the receiver reference clock.
+	0;0,1,0,0 // 4-wire transmitter master mode sharing the receiver bit clock and WS.
+	0;1,0,0,0 // Transmitter master mode with TX_MCLK output.
+	1;0,0,0,0 // Typical transmitter slave mode.
+	1;0,0,1,0 // Transmitter slave mode sharing the receiver reference clock.
+	1;0,1,0,0 // 4-wire transmitter slave mode sharing the receiver bit clock and WS.
+	*/
+	LPC_I2S->I2SDAO &= (modes[0][mode] << 5);
+	LPC_I2S->I2STXMODE = modes[1][mode];
+}
+
+void setRxMode(uint8_t mode) {
+	uint8_t modes[2][7] = {{0,0,0,0,1,1,1},{0,2,4,8,0,2,4}};
+	/*
+	0;0,0,0,0 // Typical receiver master mode.
+	0;0,0,1,0 // Receiver master mode sharing the transmitter reference clock.
+	0;0,1,0,0 // 4-wire receiver master mode sharing the transmitter bit clock and WS.
+	0;1,0,0,0 // Receiver master mode with RX_MCLK output.
+	1;0,0,0,0 // Typical receiver slave mode.
+	1;0,0,1,0 // Receiver slave mode sharing the transmitter reference clock.
+	1;0,1,0,0 // 4-wire receiver slave mode sharing the transmitter bit clock and WS.
+	*/
+	LPC_I2S->I2SDAI &= (modes[0][mode] << 5);
+	LPC_I2S->I2SRXMODE = modes[1][mode];
+}
+
+void setIRQ(bool rxInterrupt, bool txInterrupt, uint8_t rxDepth, uint8_t txDepth) {
+	if(rxInterrupt == true)
+	{
+		LPC_I2S->I2SIRQ |= (0x01 << 0);
+		LPC_I2S->I2SIRQ |= (rxDepth << 8);
+	}
+	else
+	{
+		LPC_I2S->I2SIRQ &= ~(0x01 << 0);
+		LPC_I2S->I2SIRQ &= ~(0x0F << 8);
+	}
+	
+	if(rxInterrupt == true)
+	{
+		LPC_I2S->I2SIRQ |= (0x01 << 1);
+		LPC_I2S->I2SIRQ |= (txDepth << 16);
+	}
+	else
+	{
+		LPC_I2S->I2SIRQ &= ~(0x01 << 1);
+		LPC_I2S->I2SIRQ &= ~(0x0F << 16);
+	}
+}
+
+void setDMA1(bool rxDMA, bool txDMA, uint8_t rxDepth, uint8_t txDepth) {
+	if(rxDMA == true)
+	{
+		LPC_I2S->I2SDMA1 |= (0x01 << 0);
+		LPC_I2S->I2SDMA1 |= (rxDepth << 8);
+	}
+	else
+	{
+		LPC_I2S->I2SDMA1 &= ~(0x01 << 0);
+		LPC_I2S->I2SDMA1 &= ~(0x0F << 8);
+	}
+	
+	if(txDMA == true)
+	{
+		LPC_I2S->I2SDMA1 |= (0x01 << 1);
+		LPC_I2S->I2SDMA1 |= (txDepth << 16);
+	}
+	else
+	{
+		LPC_I2S->I2SDMA1 &= ~(0x01 << 1);
+		LPC_I2S->I2SDMA1 &= ~(0x0F << 16);
+	}
+}
+
+void setDMA2(bool rxDMA, bool txDMA, uint8_t rxDepth, uint8_t txDepth) {
+	if(rxDMA == true)
+	{
+		LPC_I2S->I2SDMA2 |= (0x01 << 0);
+		LPC_I2S->I2SDMA2 |= (rxDepth << 8);
+	}
+	else
+	{
+		LPC_I2S->I2SDMA2 &= ~(0x01 << 0);
+		LPC_I2S->I2SDMA2 &= ~(0x0F << 8);
+	}
+	
+	if(txDMA == true)
+	{
+		LPC_I2S->I2SDMA2 |= (0x01 << 1);
+		LPC_I2S->I2SDMA2 |= (txDepth << 16);
+	}
+	else
+	{
+		LPC_I2S->I2SDMA2 &= ~(0x01 << 1);
+		LPC_I2S->I2SDMA2 &= ~(0x0F << 16);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/I2S.h	Mon Dec 06 00:05:39 2010 +0000
@@ -0,0 +1,120 @@
+#ifndef MBED_I2S_H
+#define MBED_I2S_H
+
+#include "mbed.h"
+
+/** An I2S class
+ * It uses the I2S peripheral of the LPC1768
+ * @author Pinski1
+ * More details about the function goes here
+ * 
+ * An example:
+ * @code
+ * #include "I2S.h"
+ * #include "mbed.h"
+ * 
+ * I2S audioInterface (p7, p6, p5, p30, p29, p8);
+ *
+ * void main()
+ * {
+ * 		audioInterface.setClocks(,,,);
+ * 		audioInterface.setTx(32,9600000,true);
+ * 		audioInterface.setRx(32,9600000,true);
+ *
+ * 		// now print out registers out to prove it's set up correctly
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * 
+ * }
+ * @endcode
+ */
+class I2S
+{
+	private:
+		uint32_t masterClock;
+		uint32_t peripheralClock;
+		// fifoRx 0x400A800C
+		// LPC_I2S->I2SRXFIFO
+        // fifoTx 0x400A8008
+		// LPC_I2S->I2STXFIFO
+		
+    public:
+        /** Creates an I2S object to control the I2S peripheral.
+         *
+         * @param bitTx The bit clock pin used for transmitting I2S.
+         * @param wdTx The word clock pin used for transmitting I2S.
+         * @param daTx The data pin used for transmitting I2S.
+         * @param bitRx The bit clock pin used for recieving I2S.
+         * @param wdRx The word clock pin used for recieving I2S.
+         * @param daRx The data clock pin used for recieving I2S.
+         */
+        I2S(PinName, PinName, PinName, PinName, PinName, PinName);
+        
+        /** Destructs the I2S object and turns off the I2S peripheral. */
+        ~I2S();
+        
+        /** Sets up the clocks for the I2S peripheral.
+         * Currents sets up both recieve and transmit channels identically.
+		 *
+         * @param x The X divider for the perphieral clock which sets the I2S master clock.
+         * @param y The Y divider for the perphieral clock which sets the I2S master clock.
+         * @param divider The CPU clock divider that gives the peripheral clock.
+         */
+        void setClocks(uint8_t x, uint8_t y, uint8_t divider);
+        
+        /** Sets the bit clock and word clocks for the channels.
+		 *
+         * @param resolution The bits per sample (8, 16 or 32).
+         * @param rate The samples per second (16kHz to 96kHz).
+         * @param stereo Whether the stream was stereo or mono.
+         */
+        void setTx(uint16_t resolution, uint16_t rate, bool stereo);
+        void setRx(uint16_t resolution, uint16_t rate, bool stereo);
+
+		/** Mutes or unmutes the transmit I2S channel. */
+        void muteTx(void);
+		/** Mutes or unmutes the receive I2S channel. */
+        void muteRx(void);
+		
+		/** Resets the transmit I2S channel. */
+        void resetTx(void);
+		/** Resets the receive I2S channel. */
+        void resetRx(void);
+		
+		/** Sets the I2S mode of the transmit channel.
+		 *
+		 * @param mode Sets the typical mode.
+		 */
+		void setTxMode(uint8_t mode);
+		/** Sets the I2S mode of the receive channel.
+		 *
+		 * @param mode Sets the typical mode.
+		 */
+		void setRxMode(uint8_t mode);
+        
+		/** Sets up the Interrupt Requests
+		 *
+		 * @param rxInterrupt
+		 * @param txInterrupt
+		 * @param rxDepth
+		 * @param txDepth
+		 */
+		void setIRQ(bool rxInterrupt, bool txInterrupt, uint8_t rxDepth, uint8_t txDepth);
+		
+		/** Sets up the DMA requests
+		 *
+		 * @param rxDMA
+		 * @param txDMA
+		 * @param rxDepth
+		 * @param txDepth
+		 */
+		void setDMA1(bool rxDMA, bool txDMA, uint8_t rxDepth, uint8_t txDepth);
+		void setDMA2(bool rxDMA, bool txDMA, uint8_t rxDepth, uint8_t txDepth);
+};
+#endif
\ No newline at end of file