LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
AudioOutput.c
Go to the documentation of this file.
1 /*
2  * @brief Make your board becomes a USB speaker
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * Copyright(C) Dean Camera, 2011, 2012
7  * All rights reserved.
8  *
9  * @par
10  * Software that is described herein is for illustrative purposes only
11  * which provides customers with programming information regarding the
12  * LPC products. This software is supplied "AS IS" without any warranties of
13  * any kind, and NXP Semiconductors and its licensor disclaim any and
14  * all warranties, express or implied, including all implied warranties of
15  * merchantability, fitness for a particular purpose and non-infringement of
16  * intellectual property rights. NXP Semiconductors assumes no responsibility
17  * or liability for the use of the software, conveys no license or rights under any
18  * patent, copyright, mask work right, or any other intellectual property rights in
19  * or to any products. NXP Semiconductors reserves the right to make changes
20  * in the software without notification. NXP Semiconductors also makes no
21  * representation or warranty that such application will be suitable for the
22  * specified use without further testing or modification.
23  *
24  * @par
25  * Permission to use, copy, modify, and distribute this software and its
26  * documentation is hereby granted, under NXP Semiconductors' and its
27  * licensor's relevant copyrights in the software, without fee, provided that it
28  * is used in conjunction with NXP Semiconductors microcontrollers. This
29  * copyright, permission, and disclaimer notice must appear in all copies of
30  * this code.
31  */
32 
33 #include "AudioOutput.h"
34 #if defined(USB_DEVICE_ROM_DRIVER)
35 //#include "usbd_adcuser.h"
36 #endif
37 
42  .Config = {
44 
45  .DataOUTEndpointNumber = AUDIO_STREAM_EPNUM,
46  .DataOUTEndpointSize = AUDIO_STREAM_EPSIZE,
47  .PortNumber = 0,
48  },
49 };
50 
52 #define AUDIO_MAX_SAMPLE_FREQ 48000
53 
54 #define AUDIO_SPEEP_UP_TRIGGER (audio_buffer_size*5/8)
55 
56 #define AUDIO_NORMAL_SPEED_TRIGGER (audio_buffer_size*3/8)
57 
59 
64 #define AUDIO_MAX_PC 10
66 uint8_t audio_buffer[2048*2] ATTR_ALIGNED(4) __BSS(USBRAM_SECTION);
71 
72 #if defined(__LPC177X_8X__) || defined(__LPC407X_8X__)
73 typedef struct {
74  uint8_t BITRATE;
75  struct {
76  uint8_t X,Y;
77  } RATEUP;
78  struct {
79  uint8_t X,Y;
80  } RATEDOWN;
82 
84 
85 I2S_RATE_CONFIG I2S_SpeedConfig[] =
86 {
87  /* BITRATE RATE_Up(x,y) RATE_Down(x,y) */
88  /* 8000 */
89  {0x3F, {0x2D, 0xF7}, {0x02, 0x0B}},
90  /* 11025 */
91  {0x3F, {0x40, 0xFF}, {0x01, 0x04}},
92  /* 16000 unsupport */
93  {0, {0, 0}, {0, 0}},
94  /* 22050 */
95  {0x3F, {0x80, 0xFF}, {0x01, 0x02}},
96  /* 32000 unsupport */
97  {0, {0, 0}, {0, 0}},
98  /* 44100 */
99  {0x3E, {0xF4, 0xF7}, {0x51, 0x52}},
100  /* 48000 */
101  {0x39, {0x62, 0x63}, {0xC3, 0xC5}}
102 
103 };
104 
105 Status I2S_RateFind(LPC_I2S_T *I2Sx, Chip_I2S_Audio_Format_T *audio_format, I2S_RATE_CONFIG *I2S_Config)
106 {
107  uint32_t pClk;
108  uint32_t x, y;
109  uint64_t divider;
110  uint16_t dif;
111  uint16_t x_divide = 0, y_divide_down = 0, y_divide_up = 0;
112  uint32_t N;
113  uint32_t err, ErrorOptimal_down = 0xFFFF, ErrorOptimal_up = 0xFFFF;
114 
115  pClk = (uint64_t)(Chip_Clock_GetPeripheralClockRate()*2);
116 
117  /* find N that make x/y <= 1 -> divider <= 2^16 */
118  for (N = 64; N > 0; N--) {
119  /* divider is a fixed point number with 16 fractional bits */
120  divider = (((uint64_t)(audio_format->SampleRate) * 2 * (audio_format->WordWidth) * 2) << 16) * N / pClk;
121  if (divider < (1 << 16)) {
122  break;
123  }
124  }
125  if (N == 0) {
126  return ERROR;
127  }
128  //divider *= N;
129  for (y = 255; y > 0; y--) {
130  x = y * divider;
131  if (x & (0xFF000000)) {
132  continue;
133  }
134  dif = x & 0xFFFF;
135  if (dif > 0x8000) {
136  /* mark this case to plus 1 to x value */
137  err = (0x10000 - dif);
138  /* in this case x = 255 + 1 */
139  if((x & 0x00FF0000) == 0x00FF0000) continue;
140  if (err < ErrorOptimal_up ) {
141  ErrorOptimal_up = err;
142  y_divide_up = y;
143  }
144  }
145  else {
146  err = dif;
147  if (err < ErrorOptimal_down) {
148  ErrorOptimal_down = err;
149  y_divide_down = y;
150  }
151  }
152  }
153  I2S_Config->BITRATE = N - 1;
154  x_divide = ((uint64_t)y_divide_up * (audio_format->SampleRate) * 2 * (audio_format->WordWidth) * N * 2) / pClk;
155  x_divide += 1;
156  if (x_divide >= 256) {
157  x_divide = 0xFF;
158  }
159  if (x_divide == 0) {
160  x_divide = 1;
161  }
162  I2S_Config->RATEUP.X = x_divide;
163  I2S_Config->RATEUP.Y = y_divide_up;
164 
165  x_divide = ((uint64_t)y_divide_down * (audio_format->SampleRate) * 2 * (audio_format->WordWidth) * N * 2) / pClk;
166  if (x_divide >= 256) {
167  x_divide = 0xFF;
168  }
169  if (x_divide == 0) {
170  x_divide = 1;
171  }
172  I2S_Config->RATEDOWN.X = x_divide;
173  I2S_Config->RATEDOWN.Y = y_divide_down;
174  return SUCCESS;
175 }
176 #endif
177 
178 void Audio_Reset_Data_Buffer(void)
179 {
180  audio_buffer_count = 0;
181  audio_buffer_wr_index = 0;
182  audio_buffer_rd_index = 0;
183 }
184 
186 {
187  audio_buffer_wr_index += last_packet_size;
188  audio_buffer_count += last_packet_size;
189  if (audio_buffer_count > audio_buffer_size) {
191  }
192  if (audio_buffer_wr_index >= audio_buffer_size) {
193  audio_buffer_wr_index -= audio_buffer_size;
194  }
195  return (uint32_t) &audio_buffer[audio_buffer_wr_index];
196 }
197 
198 void Audio_Init(uint32_t samplefreq)
199 {
200 #if defined(__LPC177X_8X__) || defined(__LPC407X_8X__)
201  Chip_I2S_Audio_Format_T audio_Confg;
202  audio_Confg.SampleRate = samplefreq;
203  audio_Confg.ChannelNumber = 2; // 1 is mono, 2 is stereo
204  audio_Confg.WordWidth = 16; // 8, 16 or 32 bits
207  Chip_I2S_Config(LPC_I2S, I2S_TX_MODE, &audio_Confg);
212  NVIC_EnableIRQ(I2S_IRQn);
213 
215  switch (samplefreq) {
216  case 11025:
217  I2S_SpeedConfig_index = 1;
218  audio_buffer_size = 1764;
219  break;
220  case 22050:
221  I2S_SpeedConfig_index = 3;
222  audio_buffer_size = 1764;
223  break;
224  case 44100:
225  I2S_SpeedConfig_index = 5;
226  audio_buffer_size = 1764;
227  break;
228 
229  case 8000:
230  I2S_SpeedConfig_index = 0;
231  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
232  break;
233  case 16000:
234  I2S_SpeedConfig_index = 2;
235  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
236  break;
237  case 32000:
238  I2S_SpeedConfig_index = 4;
239  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
240  break;
241  case 48000:
242  I2S_SpeedConfig_index = 6;
243  default:
244  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
245  break;
246  }
247  IP_I2S_SetBitRate(LPC_I2S, I2S_TX_MODE, I2S_SpeedConfig[I2S_SpeedConfig_index].BITRATE);
249  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.X,
250  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.Y);
251  audio_buffer_size*=2;
252 #else
253  volatile uint32_t pclk;
255  Chip_Clock_SetPCLKDiv(SYSCTL_PCLK_DAC, SYSCTL_CLKDIV_1);
259  pclk = Chip_Clock_GetPeripheralClockRate(SYSCTL_PCLK_TIMER0);
260  Chip_TIMER_SetMatch(LPC_TIMER0, 0, ((pclk / samplefreq) - 1));
263  NVIC_EnableIRQ(TIMER0_IRQn);
264  switch(samplefreq)
265  {
266  case 11025:
267  case 22050:
268  case 44100:
269  audio_buffer_size = 1764;
270  break;
271  case 8000:
272  case 16000:
273  case 32000:
274  case 48000:
275  default:
276  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
277  break;
278  }
279 #endif
280 }
281 
282 void Audio_DeInit(void)
283 {
284 #if defined(__LPC177X_8X__) || defined(__LPC407X_8X__)
285  NVIC_DisableIRQ(I2S_IRQn);
286 #endif
287 }
288 
289 #if defined(__LPC177X_8X__) || defined(__LPC407X_8X__)
290 void I2S_IRQHandler(void)
291 {
292  uint32_t txlevel, i;
293  static bool double_speed = false;
294  static uint32_t sample = 0;
296  if (txlevel <= 4) {
297  for (i = 0; i < 8 - txlevel; i++) {
298  if (audio_buffer_count >= 4) { /*has enough data */
299  audio_buffer_count -= 4;
300  sample = *(uint32_t *) (audio_buffer + audio_buffer_rd_index);
301  audio_buffer_rd_index += 4;
302  if (audio_buffer_rd_index >= audio_buffer_size) {
303  audio_buffer_rd_index -= audio_buffer_size;
304  }
305  }
306  Chip_I2S_Send(LPC_I2S, sample);
307  }
308  /*Skip some samples if buffer run writting too fast. */
309  if(audio_buffer_size != 0)
310  {
311  if(audio_buffer_count >= AUDIO_SPEEP_UP_TRIGGER){
312  if(!double_speed) {
314  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEUP.X,
315  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEUP.Y);
316  double_speed = true;
317  }
318  }else if(audio_buffer_count < AUDIO_NORMAL_SPEED_TRIGGER){
319  if(double_speed){
321  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.X,
322  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.Y);
323  double_speed = false;
324  }
325  }
326  }
327  }
328 }
329 #else
331 {
332  uint32_t val;
333  int32_t sample;
334  if(audio_buffer_count >= 2) /*has enough data */
335  {
336  audio_buffer_count -= 2;
337  sample = *(int16_t *)(audio_buffer + audio_buffer_rd_index);
338  audio_buffer_rd_index+=2;
339  if(audio_buffer_rd_index >= audio_buffer_size)
340  audio_buffer_rd_index -= audio_buffer_size;
341  }else{
342  sample = 0;
343  }
344  val = sample>>6;
345  val &= 0x3FF;
346  val += (0x01 << 9);
348  if((audio_buffer_size != 0) && (audio_buffer_count >= (audio_buffer_size/2)))
349  {
350  audio_buffer_count-=2;
351  audio_buffer_rd_index+=2;
352  if(audio_buffer_rd_index >= audio_buffer_size)
353  audio_buffer_rd_index -= audio_buffer_size;
354  }
356 }
357 #endif
358 
362 
363  /* Check if this is audio stream endpoint */
364  if (EPNum == AUDIO_STREAM_EPNUM) {
365  return Audio_Get_ISO_Buffer_Address(*last_packet_size);
366  }
367  else {return 0; }
368 }
369 
373 int main(void)
374 {
375 #if defined(__LPC177X_8X__) || defined(__LPC407X_8X__)
376  Chip_I2S_Audio_Format_T audio_Confg;
377 #endif
378  SetupHardware();
379 #if defined(__LPC177X_8X__) || defined(__LPC407X_8X__)
380  audio_Confg.ChannelNumber = 2; //stereo
381  audio_Confg.WordWidth = 16; //16 bits
382  /* Build I2S config table */
383  audio_Confg.SampleRate = 8000;
384  I2S_RateFind(LPC_I2S, &audio_Confg, &I2S_SpeedConfig[0]);
385  audio_Confg.SampleRate = 11025;
386  I2S_RateFind(LPC_I2S, &audio_Confg, &I2S_SpeedConfig[1]);
387  audio_Confg.SampleRate = 22050;
388  I2S_RateFind(LPC_I2S, &audio_Confg, &I2S_SpeedConfig[3]);
389  /* Although the founded rate is very accuracy,
390  the XTAL doesn't always match its frequency.
391  Increase the sample rate a little bit will really meet the USB speed. */
392 #if defined(__LPC43XX__ )
393  audio_Confg.SampleRate = 44101; /* a bit higher for 204Mhz device */
394 #else
395  audio_Confg.SampleRate = 44100;
396 #endif
397  I2S_RateFind(LPC_I2S, &audio_Confg, &I2S_SpeedConfig[5]);
398 #if defined(__LPC43XX__ )
399  audio_Confg.SampleRate = 48001; /* a bit higher for 204Mhz device */
400 #else
401  audio_Confg.SampleRate = 48000;
402 #endif
403  I2S_RateFind(LPC_I2S, &audio_Confg, &I2S_SpeedConfig[6]);
404 #endif
405 
406 #if defined(USB_DEVICE_ROM_DRIVER)
407  UsbdAdc_Init(&Speaker_Audio_Interface);
408 #endif
409 
410  for (;; ) {
411 #if !defined(USB_DEVICE_ROM_DRIVER)
412  Audio_Device_USBTask(&Speaker_Audio_Interface);
413  USB_USBTask(Speaker_Audio_Interface.Config.PortNumber,USB_MODE_Device);
414 #endif
415  }
416 }
417 
419 void SetupHardware(void)
420 {
421  Board_Init();
422  USB_Init(Speaker_Audio_Interface.Config.PortNumber, USB_MODE_Device);
423 }
424 
425 #if !defined(USB_DEVICE_ROM_DRIVER)
426 
428 {}
429 
432 {}
433 
436 {
437  bool ConfigSuccess = true;
438 
439  ConfigSuccess &= Audio_Device_ConfigureEndpoints(&Speaker_Audio_Interface);
440 
441  // LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
442 }
443 
446 {
447  Audio_Device_ProcessControlRequest(&Speaker_Audio_Interface);
448 }
449 
451 {
452  /* reset audio buffer */
454 }
455 
460  const uint8_t EndpointProperty,
461  const uint8_t EndpointAddress,
462  const uint8_t EndpointControl,
463  uint16_t *const DataLength,
464  uint8_t *Data)
465 {
466  /* Check the requested endpoint to see if a supported endpoint is being manipulated */
467  if (EndpointAddress == (ENDPOINT_DIR_OUT | Speaker_Audio_Interface.Config.DataOUTEndpointNumber)) {
468  /* Check the requested control to see if a supported control is being manipulated */
469  if (EndpointControl == AUDIO_EPCONTROL_SamplingFreq) {
470  switch (EndpointProperty) {
472  /* Check if we are just testing for a valid property, or actually adjusting it */
473  if (DataLength != NULL) {
474  /* Set the new sampling frequency to the value given by the host */
476  (((uint32_t) Data[2] << 16) | ((uint32_t) Data[1] << 8) | (uint32_t) Data[0]);
478  return false;
479  }
480  Audio_DeInit();
482  }
483 
484  return true;
485 
487  /* Check if we are just testing for a valid property, or actually reading it */
488  if (DataLength != NULL) {
489  *DataLength = 3;
490 
491  Data[2] = (CurrentAudioSampleFrequency >> 16);
492  Data[1] = (CurrentAudioSampleFrequency >> 8);
493  Data[0] = (CurrentAudioSampleFrequency & 0xFF);
494  }
495 
496  return true;
497  }
498  }
499  }
500 
501  return false;
502 }
503 
504 #else
505 
506 #endif