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);
71 
72 typedef struct {
73  uint8_t BITRATE;
74  struct {
75  uint8_t X,Y;
76  } RATEUP;
77  struct {
78  uint8_t X,Y;
79  } RATEDOWN;
81 
83 #if defined(__LPC18XX__ )
84 
86 I2S_RATE_CONFIG I2S_SpeedConfig[] =
87 {
88  /* BITRATE RATE_Up(x,y) RATE_Down(x,y) */
89  /* 8000 */
90  {0x3F, {0x2D, 0xF7}, {0x02, 0x0B}},
91  /* 11025 */
92  {0x3F, {0x40, 0xFF}, {0x01, 0x04}},
93  /* 16000 unsupport */
94  {0, {0, 0}, {0, 0}},
95  /* 22050 */
96  {0x3F, {0x80, 0xFF}, {0x01, 0x02}},
97  /* 32000 unsupport */
98  {0, {0, 0}, {0, 0}},
99  /* 44100 */
100  {0x3E, {0xF4, 0xF7}, {0x51, 0x52}},
101  /* 48000 */
102  {0x39, {0x62, 0x63}, {0xC3, 0xC5}}
103 
104 };
105 #elif defined(__LPC43XX__ )
106 
108 I2S_RATE_CONFIG I2S_SpeedConfig[] =
109 {
110  /* BITRATE RATE_Up(x,y) RATE_Down(x,y) */
111  /* 8000 */
112  {0x3F, {0x20, 0xC1}, {0x16, 0x89}},
113  /* 11025 */
114  {0x3F, {0x1D, 0x83}, {0x38, 0xFD}},
115  /* 16000 unsupport */
116  {0, {0, 0}, {0, 0}},
117  /* 22050 */
118  {0x3F, {0x3A, 0x83}, {0x55, 0xC0}},
119  /* 32000 unsupport */
120  {0, {0, 0}, {0, 0}},
121  /* 44100 */
122  {0x3F, {0x74, 0x83}, {0xC9, 0xE3}},
123  /* 48000 */
124  {0x3F, {0xD5, 0xDD}, {0x85, 0x8A}}
125 
126 };
127 #endif
129 {
130  uint32_t pClk;
131  uint32_t x, y;
132  uint64_t divider;
133  uint16_t dif;
134  uint16_t x_divide = 0, y_divide_down = 0, y_divide_up = 0;
135  uint32_t N;
136  uint32_t err, ErrorOptimal_down = 0xFFFF, ErrorOptimal_up = 0xFFFF;
137 
138  pClk = (uint64_t)Chip_Clock_GetRate(CLK_APB1_I2S);
139 
140  /* find N that make x/y <= 1 -> divider <= 2^16 */
141  for (N = 64; N > 0; N--) {
142  /* divider is a fixed point number with 16 fractional bits */
143  divider = (((uint64_t)(audio_format->SampleRate) * 2 * (audio_format->WordWidth) * 2) << 16) * N / pClk;
144  if (divider < (1 << 16)) {
145  break;
146  }
147  }
148  if (N == 0) {
149  return ERROR;
150  }
151  //divider *= N;
152  for (y = 255; y > 0; y--) {
153  x = y * divider;
154  if (x & (0xFF000000)) {
155  continue;
156  }
157  dif = x & 0xFFFF;
158  if (dif > 0x8000) {
159  /* mark this case to plus 1 to x value */
160  err = (0x10000 - dif);
161  /* in this case x = 255 + 1 */
162  if((x & 0x00FF0000) == 0x00FF0000) continue;
163  if (err < ErrorOptimal_up ) {
164  ErrorOptimal_up = err;
165  y_divide_up = y;
166  }
167  }
168  else {
169  err = dif;
170  if (err < ErrorOptimal_down) {
171  ErrorOptimal_down = err;
172  y_divide_down = y;
173  }
174  }
175  }
176  I2S_Config->BITRATE = N - 1;
177  x_divide = ((uint64_t)y_divide_up * (audio_format->SampleRate) * 2 * (audio_format->WordWidth) * N * 2) / pClk;
178  x_divide += 1;
179  if (x_divide >= 256) {
180  x_divide = 0xFF;
181  }
182  if (x_divide == 0) {
183  x_divide = 1;
184  }
185  I2S_Config->RATEUP.X = x_divide;
186  I2S_Config->RATEUP.Y = y_divide_up;
187 
188  x_divide = ((uint64_t)y_divide_down * (audio_format->SampleRate) * 2 * (audio_format->WordWidth) * N * 2) / pClk;
189  if (x_divide >= 256) {
190  x_divide = 0xFF;
191  }
192  if (x_divide == 0) {
193  x_divide = 1;
194  }
195  I2S_Config->RATEDOWN.X = x_divide;
196  I2S_Config->RATEDOWN.Y = y_divide_down;
197  return SUCCESS;
198 }
199 
201 {
202  audio_buffer_count = 0;
205 }
206 
208 {
209  audio_buffer_wr_index += last_packet_size;
210  audio_buffer_count += last_packet_size;
213  }
215  memcpy(audio_buffer, &audio_buffer[audio_buffer_size], audio_buffer_wr_index - audio_buffer_size);
217  }
218  return (uint32_t) &audio_buffer[audio_buffer_wr_index];
219 }
220 
221 void Audio_Init(uint32_t samplefreq)
222 {
223  Chip_I2S_Audio_Format_T audio_Confg;
224  audio_Confg.SampleRate = samplefreq;
225  audio_Confg.ChannelNumber = 2; // 1 is mono, 2 is stereo
226  audio_Confg.WordWidth = 16; // 8, 16 or 32 bits
229  Chip_I2S_Config(LPC_I2S0, I2S_TX_MODE, &audio_Confg);
234  NVIC_EnableIRQ(I2S0_IRQn);
235 
237  switch (samplefreq) {
238  case 11025:
240  audio_buffer_size = 1764;
241  break;
242  case 22050:
244  audio_buffer_size = 1764;
245  break;
246  case 44100:
248  audio_buffer_size = 1764;
249  break;
250 
251  case 8000:
253  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
254  break;
255  case 16000:
257  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
258  break;
259  case 32000:
261  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
262  break;
263  case 48000:
265  default:
266  audio_buffer_size = samplefreq * 4 * AUDIO_MAX_PC / 1000;
267  break;
268  }
269  IP_I2S_SetBitRate(LPC_I2S0, I2S_TX_MODE, I2S_SpeedConfig[I2S_SpeedConfig_index].BITRATE);
271  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.X,
272  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.Y);
274 }
275 
276 void Audio_DeInit(void)
277 {
280  NVIC_DisableIRQ(I2S0_IRQn);
281 }
282 
283 void I2S0_IRQHandler(void)
284 {
285  uint32_t txlevel, i;
286  static bool double_speed = false;
287  static uint32_t sample = 0;
289  if (txlevel <= 4) {
290  for (i = 0; i < 8 - txlevel; i++) {
291  if (audio_buffer_count >= 4) { /*has enough data */
292  audio_buffer_count -= 4;
293  sample = *(uint32_t *) (audio_buffer + audio_buffer_rd_index);
297  }
298  }
299  Chip_I2S_Send(LPC_I2S0, sample);
300  }
301  /*Skip some samples if buffer run writting too fast. */
302  if(audio_buffer_size != 0)
303  {
305  if(!double_speed) {
307  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEUP.X,
308  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEUP.Y);
309  double_speed = true;
310  }
312  if(double_speed){
314  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.X,
315  I2S_SpeedConfig[I2S_SpeedConfig_index].RATEDOWN.Y);
316  double_speed = false;
317  }
318  }
319  }
320  }
321 }
322 
326 
327  /* Check if this is audio stream endpoint */
328  if (EPNum == AUDIO_STREAM_EPNUM) {
329  return Audio_Get_ISO_Buffer_Address(*last_packet_size);
330  }
331  else {return 0; }
332 }
333 
337 int main(void)
338 {
339  Chip_I2S_Audio_Format_T audio_Confg;
340 
341  SetupHardware();
342 
343  audio_Confg.ChannelNumber = 2; //stereo
344  audio_Confg.WordWidth = 16; //16 bits
345  /* Build I2S config table */
346  audio_Confg.SampleRate = 8000;
347  I2S_RateFind(LPC_I2S0, &audio_Confg, &I2S_SpeedConfig[0]);
348  audio_Confg.SampleRate = 11025;
349  I2S_RateFind(LPC_I2S0, &audio_Confg, &I2S_SpeedConfig[1]);
350  audio_Confg.SampleRate = 22050;
351  I2S_RateFind(LPC_I2S0, &audio_Confg, &I2S_SpeedConfig[3]);
352  /* Although the founded rate is very accuracy,
353  the XTAL doesn't always match its frequency.
354  Increase the sample rate a little bit will really meet the USB speed. */
355 #if defined(__LPC43XX__ )
356  audio_Confg.SampleRate = 44101; /* a bit higher for 204Mhz device */
357 #else
358  audio_Confg.SampleRate = 44100;
359 #endif
360  I2S_RateFind(LPC_I2S0, &audio_Confg, &I2S_SpeedConfig[5]);
361 #if defined(__LPC43XX__ )
362  audio_Confg.SampleRate = 48001; /* a bit higher for 204Mhz device */
363 #else
364  audio_Confg.SampleRate = 48000;
365 #endif
366  I2S_RateFind(LPC_I2S0, &audio_Confg, &I2S_SpeedConfig[6]);
367 
368 #if defined(USB_DEVICE_ROM_DRIVER)
369  UsbdAdc_Init(&Speaker_Audio_Interface);
370 #endif
371 
372  for (;; ) {
373 #if !defined(USB_DEVICE_ROM_DRIVER)
374  Audio_Device_USBTask(&Speaker_Audio_Interface);
375  USB_USBTask(Speaker_Audio_Interface.Config.PortNumber,USB_MODE_Device);
376 #endif
377  }
378 }
379 
381 void SetupHardware(void)
382 {
383  Board_Init();
384  USB_Init(Speaker_Audio_Interface.Config.PortNumber, USB_MODE_Device);
385 }
386 
387 #if !defined(USB_DEVICE_ROM_DRIVER)
388 
390 {}
391 
394 {}
395 
398 {
399  bool ConfigSuccess = true;
400 
401  ConfigSuccess &= Audio_Device_ConfigureEndpoints(&Speaker_Audio_Interface);
402 
403  // LEDs_SetAllLEDs(ConfigSuccess ? LEDMASK_USB_READY : LEDMASK_USB_ERROR);
404 }
405 
408 {
409  Audio_Device_ProcessControlRequest(&Speaker_Audio_Interface);
410 }
411 
413 {
414  /* reset audio buffer */
416 }
417 
422  const uint8_t EndpointProperty,
423  const uint8_t EndpointAddress,
424  const uint8_t EndpointControl,
425  uint16_t *const DataLength,
426  uint8_t *Data)
427 {
428  /* Check the requested endpoint to see if a supported endpoint is being manipulated */
429  if (EndpointAddress == (ENDPOINT_DIR_OUT | Speaker_Audio_Interface.Config.DataOUTEndpointNumber)) {
430  /* Check the requested control to see if a supported control is being manipulated */
431  if (EndpointControl == AUDIO_EPCONTROL_SamplingFreq) {
432  switch (EndpointProperty) {
434  /* Check if we are just testing for a valid property, or actually adjusting it */
435  if (DataLength != NULL) {
436  /* Set the new sampling frequency to the value given by the host */
438  (((uint32_t) Data[2] << 16) | ((uint32_t) Data[1] << 8) | (uint32_t) Data[0]);
440  return false;
441  }
442  Audio_DeInit();
444  }
445 
446  return true;
447 
449  /* Check if we are just testing for a valid property, or actually reading it */
450  if (DataLength != NULL) {
451  *DataLength = 3;
452 
453  Data[2] = (CurrentAudioSampleFrequency >> 16);
454  Data[1] = (CurrentAudioSampleFrequency >> 8);
455  Data[0] = (CurrentAudioSampleFrequency & 0xFF);
456  }
457 
458  return true;
459  }
460  }
461  }
462 
463  return false;
464 }
465 
466 #else
467 
468 #endif