1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos.TWL - spi - pmAmpGainLevel
3 File: main.c
4
5 Copyright 2008 Nintendo. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Date:: 2008-09-06#$
14 $Rev: 8310 $
15 $Author: terui $
16 *---------------------------------------------------------------------------*/
17
18 /*---------------------------------------------------------------------------*
19 A sample that controls the amplifier gain for microphone input.
20
21 USAGE:
22 UP, DOWN: Control amplifier gain
23 LEFT: Minimize amplifier gain
24 RIGHT: Maximize amplifier gain
25
26 HOWTO:
27 1. Initialize MIC library.
28 2. Start auto sampling of MIC by default configuration.
29 3. When you change amplifier gain, you don't have to stop sampling.
30 *---------------------------------------------------------------------------*/
31
32 #include <twl.h>
33
34 /*---------------------------------------------------------------------------*
35 Constant Definitions
36 *---------------------------------------------------------------------------*/
37 #define TEST_BUFFER_SIZE (4 * 1024) // 4 KB
38 #define RETRY_MAX_COUNT 8
39
40 /*---------------------------------------------------------------------------*
41 Internal Function Definitions
42 *---------------------------------------------------------------------------*/
43 static void StepUpAmpGain(void);
44 static void StepDownAmpGain(void);
45 static void MaximizeAmpGain(void);
46 static void MinimizeAmpGain(void);
47 static u32 GetDefaultMicSamplingRate(void);
48 static SNDEXFrequency GetI2SFrequency(void);
49 static void StartMicSampling(const MICAutoParam* param);
50
51 static void SetDrawData(void *address, MICSamplingType type);
52
53 static void VBlankIntr(void);
54 static void Init3D(void);
55 static void Draw3D(void);
56 static void DrawLine(s16 sx, s16 sy, s16 ex, s16 ey);
57
58 /*---------------------------------------------------------------------------*
59 Internal Variable Definitions
60 *---------------------------------------------------------------------------*/
61 static MICAutoParam gMicAutoParam;
62 static u8 gDrawData[192];
63 static u8 gMicData[TEST_BUFFER_SIZE] ATTRIBUTE_ALIGN(HW_CACHE_LINE_SIZE);
64
65 /*---------------------------------------------------------------------------*
66 Name: TwlMain
67
68 Description: Initialization and main loop.
69
70 Arguments: None.
71
72 Returns: None.
73 *---------------------------------------------------------------------------*/
TwlMain(void)74 void TwlMain(void)
75 {
76 /* Various types of initialization */
77 OS_Init();
78 GX_Init();
79 GX_DispOff();
80 GXS_DispOff();
81
82 /* Initializes display settings */
83 GX_SetBankForLCDC(GX_VRAM_LCDC_ALL);
84 MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE);
85 (void)GX_DisableBankForLCDC();
86 MI_CpuFillFast((void *)HW_OAM, GX_LCD_SIZE_Y, HW_OAM_SIZE);
87 MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE);
88 MI_CpuFillFast((void *)HW_DB_OAM, GX_LCD_SIZE_Y, HW_DB_OAM_SIZE);
89 MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE);
90
91 /* 3D-related initialization */
92 Init3D();
93
94 /* Interrupt settings */
95 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
96 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
97 (void)OS_EnableIrq();
98 (void)OS_EnableInterrupts();
99 (void)GX_VBlankIntr(TRUE);
100
101 /* Initialize related libraries*/
102 {
103 (void)PM_SetAmp(PM_AMP_ON);
104 (void)PM_SetAmpGain(PM_AMPGAIN_80);
105
106 MIC_Init();
107 gMicAutoParam.type = MIC_SAMPLING_TYPE_8BIT;
108 gMicAutoParam.buffer = (void *)gMicData;
109 gMicAutoParam.size = TEST_BUFFER_SIZE;
110 gMicAutoParam.loop_enable = TRUE;
111 gMicAutoParam.full_callback = NULL;
112 gMicAutoParam.rate = GetDefaultMicSamplingRate();
113 StartMicSampling((const MICAutoParam *)&gMicAutoParam);
114 }
115
116 /* Initialize internal variables */
117 MI_CpuFill8(gDrawData, 0x80, sizeof(gDrawData));
118
119 /* LCD display start */
120 GX_DispOn();
121 GXS_DispOn();
122
123 /* Debug string output */
124 OS_Printf("pmAmpGainLevel demo started.\n");
125 OS_Printf(" up/down -> change amplifier gain\n");
126 OS_Printf(" left -> minimize amplifier gain\n");
127 OS_Printf(" right -> maximize amplifier gain\n");
128 OS_Printf("\n");
129
130 /* Empty call for getting key input data (strategy for pressing A Button in the IPL) */
131 (void)PAD_Read();
132
133 {
134 u16 keyOld = 0;
135 u16 keyTrg;
136 u16 keyNow;
137
138 /* Main loop */
139 while (TRUE)
140 {
141 /* Get key input data */
142 keyNow = PAD_Read();
143 keyTrg = (u16)((keyOld ^ keyNow) & keyNow);
144 keyOld = keyNow;
145
146 /* Change the amp gain*/
147 if (keyTrg & PAD_KEY_UP)
148 {
149 StepUpAmpGain();
150 }
151 if (keyTrg & PAD_KEY_DOWN)
152 {
153 StepDownAmpGain();
154 }
155 if (keyTrg & PAD_KEY_LEFT)
156 {
157 MinimizeAmpGain();
158 }
159 if (keyTrg & PAD_KEY_RIGHT)
160 {
161 MaximizeAmpGain();
162 }
163
164 /* Render waveform */
165 SetDrawData(MIC_GetLastSamplingAddress(), gMicAutoParam.type);
166 Draw3D();
167
168 /* Waiting for the V-Blank */
169 OS_WaitVBlankIntr();
170 }
171 }
172 }
173
174 /*---------------------------------------------------------------------------*
175 Name: StepDownAmpGain
176
177 Description: Raises the amp gain by one level.
178
179 Arguments: None.
180
181 Returns: None.
182 *---------------------------------------------------------------------------*/
183 static void
StepUpAmpGain(void)184 StepUpAmpGain(void)
185 {
186 u8 gain;
187
188 if (PM_GetAmpGainLevel(&gain) == PM_RESULT_SUCCESS)
189 {
190 if (OS_IsRunOnTwl() == TRUE)
191 {
192 gain ++;
193 if ((gain >= PM_AMPGAIN_LEVEL_MIN) && (gain <= PM_AMPGAIN_LEVEL_MAX))
194 {
195 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
196 {
197 OS_Printf("Amplifier gain level was changed to %d\n", gain);
198 }
199 }
200 }
201 else
202 {
203 switch (gain)
204 {
205 case PM_AMPGAIN_LEVEL_DS0:
206 gain = PM_AMPGAIN_LEVEL_DS1;
207 break;
208 case PM_AMPGAIN_LEVEL_DS1:
209 gain = PM_AMPGAIN_LEVEL_DS2;
210 break;
211 case PM_AMPGAIN_LEVEL_DS2:
212 gain = PM_AMPGAIN_LEVEL_DS3;
213 break;
214 default:
215 return;
216 }
217 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
218 {
219 OS_Printf("Amplifier gain level was changed to %d\n", gain);
220 }
221 }
222 }
223 }
224
225 /*---------------------------------------------------------------------------*
226 Name: StepDownAmpGain
227
228 Description: Lowers the amp gain by one level.
229
230 Arguments: None.
231
232 Returns: None.
233 *---------------------------------------------------------------------------*/
234 static void
StepDownAmpGain(void)235 StepDownAmpGain(void)
236 {
237 u8 gain;
238
239 if (PM_GetAmpGainLevel(&gain) == PM_RESULT_SUCCESS)
240 {
241 if (OS_IsRunOnTwl() == TRUE)
242 {
243 gain --;
244 if ((gain >= PM_AMPGAIN_LEVEL_MIN) && (gain <= PM_AMPGAIN_LEVEL_MAX))
245 {
246 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
247 {
248 OS_Printf("Amplifier gain level was changed to %d\n", gain);
249 }
250 }
251 }
252 else
253 {
254 switch (gain)
255 {
256 case PM_AMPGAIN_LEVEL_DS3:
257 gain = PM_AMPGAIN_LEVEL_DS2;
258 break;
259 case PM_AMPGAIN_LEVEL_DS2:
260 gain = PM_AMPGAIN_LEVEL_DS1;
261 break;
262 case PM_AMPGAIN_LEVEL_DS1:
263 gain = PM_AMPGAIN_LEVEL_DS0;
264 break;
265 default:
266 return;
267 }
268 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
269 {
270 OS_Printf("Amplifier gain level was changed to %d\n", gain);
271 }
272 }
273 }
274 }
275
276 /*---------------------------------------------------------------------------*
277 Name: MaximizeAmpGain
278
279 Description: Maximizes amp gain.
280
281 Arguments: None.
282
283 Returns: None.
284 *---------------------------------------------------------------------------*/
285 static void
MaximizeAmpGain(void)286 MaximizeAmpGain(void)
287 {
288 u8 gain;
289
290 if (PM_GetAmpGainLevel(&gain) == PM_RESULT_SUCCESS)
291 {
292 if (OS_IsRunOnTwl() == TRUE)
293 {
294 if (gain != PM_AMPGAIN_LEVEL_MAX)
295 {
296 gain = PM_AMPGAIN_LEVEL_MAX;
297 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
298 {
299 OS_Printf("Amplifier gain level was changed to %d\n", gain);
300 }
301 }
302 }
303 else
304 {
305 if (gain != PM_AMPGAIN_LEVEL_DS3)
306 {
307 gain = PM_AMPGAIN_LEVEL_DS3;
308 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
309 {
310 OS_Printf("Amplifier gain level was changed to %d\n", gain);
311 }
312 }
313 }
314 }
315 }
316
317 /*---------------------------------------------------------------------------*
318 Name: MinimizeAmpGain
319
320 Description: Minimizes amp gain.
321
322 Arguments: None.
323
324 Returns: None.
325 *---------------------------------------------------------------------------*/
326 static void
MinimizeAmpGain(void)327 MinimizeAmpGain(void)
328 {
329 u8 gain;
330
331 if (PM_GetAmpGainLevel(&gain) == PM_RESULT_SUCCESS)
332 {
333 if (OS_IsRunOnTwl() == TRUE)
334 {
335 if (gain != PM_AMPGAIN_LEVEL_MIN)
336 {
337 gain = PM_AMPGAIN_LEVEL_MIN;
338 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
339 {
340 OS_Printf("Amplifier gain level was changed to %d\n", gain);
341 }
342 }
343 }
344 else
345 {
346 if (gain != PM_AMPGAIN_LEVEL_DS0)
347 {
348 gain = PM_AMPGAIN_LEVEL_DS0;
349 if (PM_SetAmpGainLevel(gain) == PM_RESULT_SUCCESS)
350 {
351 OS_Printf("Amplifier gain level was changed to %d\n", gain);
352 }
353 }
354 }
355 }
356 }
357
358 /*---------------------------------------------------------------------------*
359 Name: GetDefaultMicSamplingRate
360
361 Description: Determines the sampling rate for the microphone's auto-sampling.
362
363 Arguments: None.
364
365 Returns: u32: Returns an appropriate sampling rate.
366 *---------------------------------------------------------------------------*/
367 static u32
GetDefaultMicSamplingRate(void)368 GetDefaultMicSamplingRate(void)
369 {
370 if ((OS_IsRunOnTwl() == TRUE) && (GetI2SFrequency() == SNDEX_FREQUENCY_47610))
371 {
372 return MIC_SAMPLING_RATE_15870;
373 }
374 else
375 {
376 return MIC_SAMPLING_RATE_16360;
377 }
378 }
379
380 #include <twl/ltdmain_begin.h>
381 /*---------------------------------------------------------------------------*
382 Name: GetI2SFrequency
383
384 Description: Gets the I2S operating frequency.
385
386 Arguments: None.
387
388 Returns: SNDEXFrequency: Returns the I2S operating frequency.
389 *---------------------------------------------------------------------------*/
390 static SNDEXFrequency
GetI2SFrequency(void)391 GetI2SFrequency(void)
392 {
393 SNDEXResult result;
394 SNDEXFrequency freq;
395 s32 retry = 0;
396
397 SNDEX_Init();
398 while (TRUE)
399 {
400 result = SNDEX_GetI2SFrequency(&freq);
401 switch (result)
402 {
403 case SNDEX_RESULT_SUCCESS: // Success
404 return freq;
405 case SNDEX_RESULT_EXCLUSIVE: // Exclusion error
406 case SNDEX_RESULT_PXI_SEND_ERROR: // PXI queue is full
407 if (++ retry <= RETRY_MAX_COUNT)
408 {
409 OS_Sleep(1);
410 continue;
411 }
412 OS_TWarning("%s: Retry count overflow.\n", __FUNCTION__);
413 break;
414 case SNDEX_RESULT_BEFORE_INIT: // Pre-initialization
415 case SNDEX_RESULT_ILLEGAL_STATE: // Abnormal state
416 OS_TWarning("%s: Illegal state to get I2S frequency.\n", __FUNCTION__);
417 break;
418 case SNDEX_RESULT_FATAL_ERROR: // Fatal error
419 default: // Other fatal error
420 OS_Panic("Fatal error (%d).\n", result);
421 /* Never return */
422 }
423 }
424 return SNDEX_FREQUENCY_32730;
425 }
426 #include <twl/ltdmain_end.h>
427
428 /*---------------------------------------------------------------------------*
429 Name: StartMicSampling
430
431 Description: Calls the microphone auto-sampling start function and performs error processing.
432
433 Arguments: param: Parameter passed to the microphone functions
434
435 Returns: None.
436 *---------------------------------------------------------------------------*/
437 static void
StartMicSampling(const MICAutoParam * param)438 StartMicSampling(const MICAutoParam* param)
439 {
440 MICResult result;
441 s32 retry = 0;
442
443 while (TRUE)
444 {
445 result = MIC_StartLimitedSampling(param);
446 switch (result)
447 {
448 case MIC_RESULT_SUCCESS: // Success
449 return;
450 case MIC_RESULT_BUSY: // Microphone in use by other thread
451 case MIC_RESULT_SEND_ERROR: // PXI queue is full
452 if (++retry <= RETRY_MAX_COUNT)
453 {
454 OS_Sleep(1);
455 continue;
456 }
457 OS_TWarning("%s: Retry count overflow.\n", __FUNCTION__);
458 return;
459 case MIC_RESULT_ILLEGAL_STATUS: // Auto-sampling is not currently paused
460 OS_TWarning("%s: Already started sampling.\n", __FUNCTION__);
461 return;
462 case MIC_RESULT_ILLEGAL_PARAMETER: // Unsupported parameter
463 OS_TWarning("%s: Illegal parameter to start automatic sampling.\n", __FUNCTION__);
464 return;
465 default: // Other fatal error
466 OS_Panic("Fatal error (%d).\n", result);
467 /* Never return */
468 }
469 }
470 }
471
472 /*---------------------------------------------------------------------------*
473 Name: SetDrawData
474
475 Description: Stores the current newest sampled data in the buffer that puts it on the display.
476
477
478 Arguments: address: Location in main memory where the most recent sampling data was stored by the component
479
480 type: Sampling type (bit width)
481
482 Returns: None.
483 *---------------------------------------------------------------------------*/
SetDrawData(void * address,MICSamplingType type)484 static void SetDrawData(void *address, MICSamplingType type)
485 {
486 s32 i;
487
488 /* If sampling has never been performed, do nothing and stop.
489 (Because it would delete memory cache(s) unrelated to the microphone) */
490 if ((address < gMicData) || (address >= (gMicData + TEST_BUFFER_SIZE)))
491 {
492 return;
493 }
494
495 switch (type)
496 {
497 case MIC_SAMPLING_TYPE_8BIT:
498 case MIC_SAMPLING_TYPE_SIGNED_8BIT:
499 /* In the case of 8-bit sampling */
500 {
501 u8 *p;
502
503 p = (u8 *)((u32)address - 191);
504 if (p < gMicData)
505 {
506 p = (u8 *)((u32)p + TEST_BUFFER_SIZE);
507 }
508 DC_InvalidateRange((void *)((u32)p & ~(HW_CACHE_LINE_SIZE - 1)), HW_CACHE_LINE_SIZE);
509 for (i = 0; i < 192; i++)
510 {
511 gDrawData[i] = *p;
512 p++;
513 if ((u32)p >= (u32)(gMicData + TEST_BUFFER_SIZE))
514 {
515 p -= TEST_BUFFER_SIZE;
516 }
517 if (((u32)p % HW_CACHE_LINE_SIZE) == 0)
518 {
519 DC_InvalidateRange(p, HW_CACHE_LINE_SIZE);
520 }
521 }
522 }
523 break;
524 case MIC_SAMPLING_TYPE_12BIT:
525 case MIC_SAMPLING_TYPE_SIGNED_12BIT:
526 case MIC_SAMPLING_TYPE_12BIT_FILTER_OFF:
527 case MIC_SAMPLING_TYPE_SIGNED_12BIT_FILTER_OFF:
528 /* For 12-bit sampling*/
529 {
530 u16 *p;
531
532 p = (u16 *)((u32)address - 382);
533 if ((u32)p < (u32)gMicData)
534 {
535 p = (u16 *)((u32)p + TEST_BUFFER_SIZE);
536 }
537 DC_InvalidateRange((void *)((u32)p & ~(HW_CACHE_LINE_SIZE - 1)), HW_CACHE_LINE_SIZE);
538 for (i = 0; i < 192; i++)
539 {
540 gDrawData[i] = (u8)((*p >> 8) & 0x00ff);
541 p++;
542 if ((u32)p >= (u32)(gMicData + TEST_BUFFER_SIZE))
543 {
544 p = (u16 *)((u32)p - TEST_BUFFER_SIZE);
545 }
546 if (((u32)p % HW_CACHE_LINE_SIZE) == 0)
547 {
548 DC_InvalidateRange(p, HW_CACHE_LINE_SIZE);
549 }
550 }
551 }
552 break;
553 }
554 }
555
556 /*---------------------------------------------------------------------------*
557 Name: VBlankIntr
558
559 Description: V-Blank interrupt vector.
560
561 Arguments: None.
562
563 Returns: None.
564 *---------------------------------------------------------------------------*/
VBlankIntr(void)565 static void VBlankIntr(void)
566 {
567 /* Sets the IRQ check flag */
568 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
569 }
570
571 /*---------------------------------------------------------------------------*
572 Name: Init3D
573
574 Description: Initialization for 3D display.
575
576 Arguments: None.
577
578 Returns: None.
579 *---------------------------------------------------------------------------*/
Init3D(void)580 static void Init3D(void)
581 {
582 G3X_Init();
583 G3X_InitMtxStack();
584 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_3D);
585 GX_SetVisiblePlane(GX_PLANEMASK_BG0);
586 G2_SetBG0Priority(0);
587 G3X_AlphaTest(FALSE, 0);
588 G3X_AntiAlias(TRUE);
589 G3X_EdgeMarking(FALSE);
590 G3X_SetFog(FALSE, (GXFogBlend)0, (GXFogSlope)0, 0);
591 G3X_SetClearColor(0, 0, 0x7fff, 63, FALSE);
592 G3_ViewPort(0, 0, 255, 191);
593 G3_MtxMode(GX_MTXMODE_POSITION_VECTOR);
594 }
595
596 /*---------------------------------------------------------------------------*
597 Name: Draw3D
598
599 Description: Displays waveforms in 3D.
600
601 Arguments: None.
602
603 Returns: None.
604 *---------------------------------------------------------------------------*/
Draw3D(void)605 static void Draw3D(void)
606 {
607 G3X_Reset();
608 G3_Identity();
609 G3_PolygonAttr(GX_LIGHTMASK_NONE, GX_POLYGONMODE_MODULATE, GX_CULL_NONE, 0, 31, 0);
610
611 {
612 s32 i;
613
614 if ((gMicAutoParam.type == MIC_SAMPLING_TYPE_SIGNED_8BIT) ||
615 (gMicAutoParam.type == MIC_SAMPLING_TYPE_SIGNED_12BIT) ||
616 (gMicAutoParam.type == MIC_SAMPLING_TYPE_SIGNED_12BIT_FILTER_OFF))
617 {
618 for (i = 0; i < 191; i++)
619 {
620 DrawLine((s16)((s8)gDrawData[i]),
621 (s16)i, (s16)((s8)gDrawData[i + 1]), (s16)(i + 1));
622 }
623 }
624 else
625 {
626 for (i = 0; i < 191; i++)
627 {
628 DrawLine((s16)(gDrawData[i]), (s16)i, (s16)(gDrawData[i + 1]), (s16)(i + 1));
629 }
630 }
631 }
632
633 G3_SwapBuffers(GX_SORTMODE_AUTO, GX_BUFFERMODE_W);
634 }
635
636 /*---------------------------------------------------------------------------*
637 Name: DrawLine
638
639 Description: Renders lines with triangular polygons.
640
641 Arguments: sx: X-coordinate of line's starting point
642 sy: Y-coordinate of line's starting point
643 ex: X-coordinate of line's ending point
644 ey: Y-coordinate of line's ending point
645
646 Returns: None.
647 *---------------------------------------------------------------------------*/
DrawLine(s16 sx,s16 sy,s16 ex,s16 ey)648 static void DrawLine(s16 sx, s16 sy, s16 ex, s16 ey)
649 {
650 fx16 fsx = (fx16)(((sx - 128) * 0x1000) / 128);
651 fx16 fsy = (fx16)(((96 - sy) * 0x1000) / 96);
652 fx16 fex = (fx16)(((ex - 128) * 0x1000) / 128);
653 fx16 fey = (fx16)(((96 - ey) * 0x1000) / 96);
654
655 G3_Begin(GX_BEGIN_TRIANGLES);
656 {
657 G3_Color(GX_RGB(31, 31, 31));
658 G3_Vtx(fsx, fsy, 0);
659 G3_Color(GX_RGB(31, 31, 31));
660 G3_Vtx(fex, fey, 0);
661 G3_Color(GX_RGB(31, 31, 31));
662 G3_Vtx(fsx, fsy, 1);
663 }
664 G3_End();
665 }
666