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