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