LPCOpen Platform for LPC18XX/43XX microcontrollers  18XX43XX
LPCOpen Platform for the NXP LPC18XX/43XX family of Microcontrollers
i2s_18xx_43xx.c
Go to the documentation of this file.
1 /*
2  * @brief LPC18xx/43xx I2S driver
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products. This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights. NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers. This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include "chip.h"
33 
34 /*****************************************************************************
35  * Private types/enumerations/variables
36  ****************************************************************************/
37 
38 /*****************************************************************************
39  * Public types/enumerations/variables
40  ****************************************************************************/
41 
42 /*****************************************************************************
43  * Private functions
44  ****************************************************************************/
45 
46 /* Get divider value */
47 STATIC Status getClkDiv(LPC_I2S_T *pI2S, I2S_AUDIO_FORMAT_T *format, uint16_t *pxDiv, uint16_t *pyDiv, uint32_t *pN)
48 {
49  uint32_t pClk;
50  uint32_t x, y;
51  uint64_t divider;
52  uint16_t dif;
53  uint16_t xDiv = 0, yDiv = 0;
54  uint32_t N;
55  uint16_t err, ErrorOptimal = 0xFFFF;
56 
58 
59  /* divider is a fixed point number with 16 fractional bits */
60  divider = (((uint64_t) (format->SampleRate) * 2 * (format->WordWidth) * 2) << 16) / pClk;
61  /* find N that make x/y <= 1 -> divider <= 2^16 */
62  for (N = 64; N > 0; N--) {
63  if ((divider * N) < (1 << 16)) {
64  break;
65  }
66  }
67  if (N == 0) {
68  return ERROR;
69  }
70  divider *= N;
71  for (y = 255; y > 0; y--) {
72  x = y * divider;
73  if (x & (0xFF000000)) {
74  continue;
75  }
76  dif = x & 0xFFFF;
77  if (dif > 0x8000) {
78  err = 0x10000 - dif;
79  }
80  else {
81  err = dif;
82  }
83  if (err == 0) {
84  yDiv = y;
85  break;
86  }
87  else if (err < ErrorOptimal) {
88  ErrorOptimal = err;
89  yDiv = y;
90  }
91  }
92  xDiv = ((uint64_t) yDiv * (format->SampleRate) * 2 * (format->WordWidth) * N * 2) / pClk;
93  if (xDiv >= 256) {
94  xDiv = 0xFF;
95  }
96  if (xDiv == 0) {
97  xDiv = 1;
98  }
99 
100  *pxDiv = xDiv;
101  *pyDiv = yDiv;
102  *pN = N;
103  return SUCCESS;
104 }
105 
106 /*****************************************************************************
107  * Public functions
108  ****************************************************************************/
109 
110 /* Initialize the I2S interface */
112 {
114 }
115 
116 /* Shutdown I2S */
118 {
119  pI2S->DAI = 0x07E1;
120  pI2S->DAO = 0x87E1;
121  pI2S->IRQ = 0;
122  pI2S->TXMODE = 0;
123  pI2S->RXMODE = 0;
124  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_1] = 0;
125  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_2] = 0;
127 }
128 
129 /* Configure I2S for Audio Format input */
131 {
132  uint32_t temp;
133  uint16_t xDiv, yDiv;
134  uint32_t N;
135 
136  if (getClkDiv(pI2S, format, &xDiv, &yDiv, &N) == ERROR) {
137  return ERROR;
138  }
139 
141  if (format->WordWidth <= 8) {
142  temp |= I2S_WORDWIDTH_8;
143  }
144  else if (format->WordWidth <= 16) {
145  temp |= I2S_WORDWIDTH_16;
146  }
147  else {
148  temp |= I2S_WORDWIDTH_32;
149  }
150 
151  temp |= (format->ChannelNumber) == 1 ? I2S_MONO : I2S_STEREO;
152  temp |= I2S_MASTER_MODE;
153  temp |= I2S_DAO_WS_HALFPERIOD(format->WordWidth - 1);
154  pI2S->DAO = temp;
155  pI2S->TXMODE = I2S_TXMODE_CLKSEL(0);
156  pI2S->TXBITRATE = N - 1;
157  pI2S->TXRATE = yDiv | (xDiv << 8);
158  return SUCCESS;
159 }
160 
161 /* Configure I2S for Audio Format input */
163 {
164  uint32_t temp;
165  uint16_t xDiv, yDiv;
166  uint32_t N;
167 
168  if (getClkDiv(pI2S, format, &xDiv, &yDiv, &N) == ERROR) {
169  return ERROR;
170  }
172  if (format->WordWidth <= 8) {
173  temp |= I2S_WORDWIDTH_8;
174  }
175  else if (format->WordWidth <= 16) {
176  temp |= I2S_WORDWIDTH_16;
177  }
178  else {
179  temp |= I2S_WORDWIDTH_32;
180  }
181 
182  temp |= (format->ChannelNumber) == 1 ? I2S_MONO : I2S_STEREO;
183  temp |= I2S_MASTER_MODE;
184  temp |= I2S_DAI_WS_HALFPERIOD(format->WordWidth - 1);
185  pI2S->DAI = temp;
186  pI2S->RXMODE = I2S_RXMODE_CLKSEL(0);
187  pI2S->RXBITRATE = N - 1;
188  pI2S->RXRATE = yDiv | (xDiv << 8);
189  return SUCCESS;
190 }
191 
192 /* Enable/Disable Interrupt with a specific FIFO depth */
193 void Chip_I2S_Int_TxCmd(LPC_I2S_T *pI2S, FunctionalState newState, uint8_t depth)
194 {
195  uint32_t temp;
196  depth &= 0x0F;
197  if (newState == ENABLE) {
198  temp = pI2S->IRQ & (~I2S_IRQ_TX_DEPTH_MASK);
199  pI2S->IRQ = temp | (I2S_IRQ_TX_DEPTH(depth));
200  pI2S->IRQ |= 0x02;
201  }
202  else {
203  pI2S->IRQ &= (~0x02);
204  }
205 }
206 
207 /* Enable/Disable Interrupt with a specific FIFO depth */
208 void Chip_I2S_Int_RxCmd(LPC_I2S_T *pI2S, FunctionalState newState, uint8_t depth)
209 {
210  uint32_t temp;
211  depth &= 0x0F;
212  if (newState == ENABLE) {
213  temp = pI2S->IRQ & (~I2S_IRQ_RX_DEPTH_MASK);
214  pI2S->IRQ = temp | (I2S_IRQ_RX_DEPTH(depth));
215  pI2S->IRQ |= 0x01;
216  }
217  else {
218  pI2S->IRQ &= (~0x01);
219  }
220 }
221 
222 /* Enable/Disable DMA with a specific FIFO depth */
224  I2S_DMA_CHANNEL_T dmaNum,
225  FunctionalState newState,
226  uint8_t depth)
227 {
228  /* Enable/Disable I2S transmit*/
229  if (newState == ENABLE) {
230  /* Set FIFO Level */
231  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_1] &= ~(0x0F << 16);
232  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_1] |= depth << 16;
233  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_1] |= 0x02;
234  }
235  else {
236  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_1] &= ~0x02;
237  }
238 }
239 
240 /* Enable/Disable DMA with a specific FIFO depth */
242  I2S_DMA_CHANNEL_T dmaNum,
243  FunctionalState newState,
244  uint8_t depth)
245 {
246 
247  /* Enable/Disable I2S Receive */
248  if (newState == ENABLE) {
249  /* Set FIFO Level */
250  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_2] &= ~(0x0F << 8);
251  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_2] |= depth << 8;
252  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_2] |= 0x01;
253  }
254  else {
255  pI2S->DMA[I2S_DMA_REQUEST_CHANNEL_2] &= ~0x01;
256  }
257 }
258