| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

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
41 USB_ClassInfo_Audio_Device_t Speaker_Audio_Interface = {
42 .Config = {
43 .StreamingInterfaceNumber = 1,
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
58 uint32_t CurrentAudioSampleFrequency = AUDIO_MAX_SAMPLE_FREQ;
59
64 #define AUDIO_MAX_PC 10
65 PRAGMA_ALIGN_4
66 uint8_t audio_buffer[2048*2] ATTR_ALIGNED(4) __BSS(USBRAM_SECTION);
67 uint32_t audio_buffer_size = 0;
68 uint32_t audio_buffer_rd_index = 0;
69 uint32_t audio_buffer_wr_index = 0;
70 uint32_t audio_buffer_count = 0;
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;
81 } I2S_RATE_CONFIG;
82
83 static uint32_t I2S_SpeedConfig_index;
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
185 uint32_t Audio_Get_ISO_Buffer_Address(uint32_t last_packet_size)
186 {
187 audio_buffer_wr_index += last_packet_size;
188 audio_buffer_count += last_packet_size;
189 if (audio_buffer_count > audio_buffer_size) {
190 Audio_Reset_Data_Buffer();
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
205 Board_Audio_Init(LPC_I2S, UDA1380_LINE_IN);
206 Chip_I2S_Init(LPC_I2S);
207 Chip_I2S_Config(LPC_I2S, I2S_TX_MODE, &audio_Confg);
208 Chip_I2S_Stop(LPC_I2S, I2S_TX_MODE);
209 Chip_I2S_DisableMute(LPC_I2S);
210 Chip_I2S_Start(LPC_I2S, I2S_TX_MODE);
211 Chip_I2S_Int_Cmd(LPC_I2S, I2S_TX_MODE, ENABLE, 4);
212 NVIC_EnableIRQ(I2S_IRQn);
213
214 Audio_Reset_Data_Buffer();
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);
248 IP_I2S_SetXYDivider(LPC_I2S, I2S_TX_MODE,
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;
254 Chip_DAC_Init(LPC_DAC);
255 Chip_Clock_SetPCLKDiv(SYSCTL_PCLK_DAC, SYSCTL_CLKDIV_1);
256 Chip_TIMER_Init(LPC_TIMER0);
257 Chip_TIMER_Reset(LPC_TIMER0);
258 Chip_TIMER_MatchEnableInt(LPC_TIMER0, 0);
259 pclk = Chip_Clock_GetPeripheralClockRate(SYSCTL_PCLK_TIMER0);
260 Chip_TIMER_SetMatch(LPC_TIMER0, 0, ((pclk / samplefreq) - 1));
261 Chip_TIMER_ResetOnMatchEnable(LPC_TIMER0, 0);
262 Chip_TIMER_Enable(LPC_TIMER0);
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;
295 txlevel = Chip_I2S_GetLevel(LPC_I2S, I2S_TX_MODE);
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) {
313 IP_I2S_SetXYDivider(LPC_I2S, I2S_TX_MODE,
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){
320 IP_I2S_SetXYDivider(LPC_I2S, I2S_TX_MODE,
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
330 void TIMER0_IRQHandler(void)
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);
347 Chip_DAC_UpdateValue(LPC_DAC, val);
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 }
355 Chip_TIMER_ClearMatch(LPC_TIMER0, 0);
356 }
357 #endif
358
361 uint32_t CALLBACK_HAL_GetISOBufferAddress(const uint32_t EPNum, uint32_t *last_packet_size) {
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
427 void EVENT_USB_Device_Connect(void)
428 {}
429
431 void EVENT_USB_Device_Disconnect(void)
432 {}
433
435 void EVENT_USB_Device_ConfigurationChanged(void)
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
445 void EVENT_USB_Device_ControlRequest(void)
446 {
447 Audio_Device_ProcessControlRequest(&Speaker_Audio_Interface);
448 }
449
450 void EVENT_Audio_Device_StreamStartStop(USB_ClassInfo_Audio_Device_t *const AudioInterfaceInfo)
451 {
452 /* reset audio buffer */
453 Audio_Reset_Data_Buffer();
454 }
455
459 bool CALLBACK_Audio_Device_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t *const AudioInterfaceInfo,
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) {
471 case AUDIO_REQ_SetCurrent:
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 */
475 CurrentAudioSampleFrequency =
476 (((uint32_t) Data[2] << 16) | ((uint32_t) Data[1] << 8) | (uint32_t) Data[0]);
477 if (CurrentAudioSampleFrequency > AUDIO_MAX_SAMPLE_FREQ) {
478 return false;
479 }
480 Audio_DeInit();
481 Audio_Init(CurrentAudioSampleFrequency);
482 }
483
484 return true;
485
486 case AUDIO_REQ_GetCurrent:
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