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