1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - demos.TWL - camera - camera-2
3   File:     main.c
4 
5   Copyright 2007-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-06-15#$
14   $Rev: 10750 $
15   $Author: kitase_hirotake $
16  *---------------------------------------------------------------------------*/
17 
18 #include <twl.h>
19 #include <twl/camera.h>
20 #include "DEMOBitmap.h"
21 
22 #define NDMA_NO  1           // The NDMA number (0 to 3) to use
23 #define NDMA_IE  OS_IE_NDMA1  // Corresponding interrupt
24 #define WIDTH   256         // Image width
25 #define HEIGHT  192         // Image height
26 
27 #define LINES_AT_ONCE   CAMERA_GET_MAX_LINES(WIDTH)     // Number of lines transferred in one cycle
28 #define BYTES_PER_LINE  CAMERA_GET_LINE_BYTES(WIDTH)    // Number of bytes in one line's transfer
29 
30 static void VBlankIntr(void);
31 static BOOL CameraInit(void);
32 static void CameraDmaIntr(void);
33 static void CameraIntrVsync(CAMERAResult result);
34 static void CameraIntrError(CAMERAResult result);
35 static void CameraIntrReboot(CAMERAResult result);
36 
37 static int lineNumber = 0;
38 static BOOL effectFlag = FALSE;
39 static BOOL switchFlag = FALSE;
40 static BOOL standbyFlag = FALSE;
41 static u16 pipeBuffer[BYTES_PER_LINE * LINES_AT_ONCE / sizeof(u16)] ATTRIBUTE_ALIGN(32);
42 static CAMERASelect current;
43 
44 
45 static int wp;  // Buffer while capturing data from camera
46 static int rp;  // Buffer most recently copied to VRAM
47 static BOOL wp_pending; // Data capture was cancelled (recapture to same buffer)
48 static u32 stabilizedCount;
49 static u16 buffer[2][WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
PendingCapture(void)50 static void PendingCapture(void)
51 {
52     wp_pending = TRUE;
53 }
54 
55 // Character display
PutString(char * format,...)56 static void PutString( char *format, ... )
57 {
58     u16             *dest = G2_GetBG1ScrPtr();
59     char            temp[32+1];
60     int             i;
61     va_list         va;
62 
63     va_start(va, format);
64     (void)OS_VSNPrintf(temp, sizeof(temp), format, va);
65     va_end(va);
66 
67     for (i = 0; i < 32 && temp[i]; i++)
68     {
69         dest[i] = (u16)((u8)temp[i] | (1 << 12));
70     }
71 }
72 
73 /*---------------------------------------------------------------------------*
74   Name:         TwlMain
75 
76   Description:  Main
77 
78   Arguments:    None.
79 
80   Returns:      None.
81  *---------------------------------------------------------------------------*/
TwlMain()82 void TwlMain()
83 {
84     // Initialization
85     OS_Init();
86     OS_InitThread();
87     GX_Init();
88     OS_InitTick();
89     OS_InitAlarm();
90 
91     // DMA is not used in GX (the old DMA conflicts with camera DMA)
92     (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
93 
94     // Clear VRAM
95     GX_SetBankForLCDC(GX_VRAM_LCDC_A);
96     GX_SetBankForLCDC(GX_VRAM_LCDC_B);
97     MI_CpuClearFast((void*)HW_LCDC_VRAM_A, 128 * 1024);
98     MI_CpuClearFast((void*)HW_LCDC_VRAM_B, 128 * 1024);
99 
100     // Direct bitmap display mode and text display
101     GX_SetBankForBG(GX_VRAM_BG_256_AB);         // Allocate VRAM-A, B banks to BG
102     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D);
103     GX_SetVisiblePlane(GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3);
104 
105     G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
106                      GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000, GX_BG_EXTPLTT_01);
107     G2_SetBG1Priority(1);
108     G2_BG1Mosaic(FALSE);
109 
110     G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x20000);
111     G2_SetBG3Priority(3);
112     G2_BG3Mosaic(FALSE);
113 
114     // Load text
115     {
116         static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
117         GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
118         GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
119     }
120     wp = 0;
121     rp = 1;
122     wp_pending = TRUE;
123     stabilizedCount = 0;
124 
125     // V-Blank interrupt settings
126     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
127     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
128     (void)OS_EnableIrq();
129     (void)GX_VBlankIntr(TRUE);
130     (void)OS_EnableInterrupts();
131 
132     OS_WaitVBlankIntr();
133     GX_DispOn();
134 
135     // Initialize camera
136     current = CAMERA_SELECT_IN;
137     (void)CameraInit();
138 
139     CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
140     CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
141 
142     // Configure DMA interrupt
143     OS_SetIrqFunction(NDMA_IE, CameraDmaIntr);
144     (void)OS_EnableIrqMask(NDMA_IE);
145 
146     // Camera VSYNC interrupt callback
147     CAMERA_SetVsyncCallback(CameraIntrVsync);
148 
149     // Camera error interrupt callback
150     CAMERA_SetBufferErrorCallback(CameraIntrError);
151 
152     // Camera restart completion callback
153     CAMERA_SetRebootCallback(CameraIntrReboot);
154 
155     // DMA start (enabled forever unless explicitly stopped)
156     MI_StopNDma(NDMA_NO);
157     CAMERA_DmaPipeInfinity(NDMA_NO, pipeBuffer, CAMERA_GetBytesAtOnce(WIDTH), NULL, NULL);
158 
159     // Camera start
160     lineNumber = 0;
161     CAMERA_ClearBuffer();
162     CAMERA_StartCapture();
163     OS_TPrintf("Camera is shooting a movie...\n");
164 
165     while (1)
166     {
167         u16 pad;
168         u16 trg;
169         static u16 old = 0xffff;
170 
171         OS_WaitVBlankIntr();
172 
173         if (wp == rp)
174         {
175             rp ^= 1;
176             GX_LoadBG3Scr(buffer[rp], 0, BYTES_PER_LINE * HEIGHT);
177             DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
178         }
179 
180         pad = PAD_Read();
181         trg = (u16)(pad & ~old);
182         old = pad;
183 
184         if (trg & PAD_BUTTON_A)
185         {
186             effectFlag ^= 1;
187             OS_TPrintf("Effect %s\n", effectFlag ? "ON" : "OFF");
188         }
189         if (trg & PAD_BUTTON_X)
190         {
191             current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
192             switchFlag = TRUE;
193         }
194         if (trg & PAD_BUTTON_B)
195         {
196             standbyFlag ^= 1;
197 
198             if(standbyFlag)
199             {
200                 switchFlag = TRUE;
201             }
202             else
203             {
204                 CAMERAResult result;
205 
206                 OS_TPrintf("call CAMERA_I2CActivate(%s)\n", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
207                 result = CAMERA_I2CActivateAsync(current, NULL, NULL);
208                 if(result == CAMERA_RESULT_FATAL_ERROR)
209                     OS_Panic("CAMERA FATAL ERROR\n");
210                 stabilizedCount = 0;
211             }
212         }
213     }
214 }
215 
216 //--------------------------------------------------------------------------------
217 //    V-Blank interrupt process
218 //
VBlankIntr(void)219 void VBlankIntr(void)
220 {
221     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
222 }
223 
224 //--------------------------------------------------------------------------------
225 //    Camera initialization (only the Init- and I2C-related initialization)
226 //
CameraInit(void)227 BOOL CameraInit(void)
228 {
229     CAMERAResult result;
230     result = CAMERA_Init();
231     if(result == CAMERA_RESULT_FATAL_ERROR)
232         OS_TPanic("CAMERA_Init was failed.");
233     if(result == CAMERA_RESULT_ILLEGAL_STATUS)
234         return FALSE;
235 
236     result = CAMERA_I2CActivate(current);
237     if (result == CAMERA_RESULT_FATAL_ERROR)
238         OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
239     if(result == CAMERA_RESULT_ILLEGAL_STATUS)
240         return FALSE;
241     stabilizedCount = 0;
242 
243     return TRUE;
244 }
245 
246 //--------------------------------------------------------------------------------
247 //    DMA interrupt process
248 //
249 #define FPS_SAMPLES 4
CameraDmaIntr(void)250 void CameraDmaIntr(void)
251 {
252     static BOOL effect = FALSE;
253     CAMERAResult result;
254 
255     OS_SetIrqCheckFlag(NDMA_IE);
256     OS_SetIrqFunction(NDMA_IE, CameraDmaIntr);
257 
258     // Process as required and copy to frame buffer
259     if (effect) // Negative/positive inversion
260     {
261         int i;
262         u32 *src = (u32*)pipeBuffer;
263         u32 *dest = (u32*)buffer[wp] + lineNumber * WIDTH / 2;
264         for (i = 0; i < WIDTH * LINES_AT_ONCE / 2; i++)
265         {
266             dest[i] = ~src[i] | 0x80008000;
267         }
268     }
269     else
270     {
271         MI_CpuCopyFast(pipeBuffer, (u16*)buffer[wp] + lineNumber * WIDTH, sizeof(pipeBuffer));
272     }
273     DC_InvalidateRange(pipeBuffer, sizeof(pipeBuffer));
274 
275     lineNumber += LINES_AT_ONCE;
276     if (lineNumber >= HEIGHT)
277     {
278         static OSTick begin = 0;
279         static int uspf[FPS_SAMPLES] = { 0 };
280         static int count = 0;
281         int i;
282         int sum = 0;
283         OSTick end = OS_GetTick();
284         if (begin)  // Leave out the first time
285         {
286             uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
287             count = (count + 1) % FPS_SAMPLES;
288         }
289         begin = end;
290         // Calculate average value
291         for (i = 0; i < FPS_SAMPLES; i++)
292         {
293             if (uspf[i] == 0)  break;
294             sum +=  uspf[i];
295         }
296         if (sum)
297         {
298             int mfps = (int)(1000000000LL * i / sum);
299             PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
300         }
301 
302         if (switchFlag)
303         {
304             if (standbyFlag)
305             {
306                 OS_TPrintf("call CAMERA_I2CActivate(CAMERA_SELECT_NONE)\n");
307                 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
308                 if(result == CAMERA_RESULT_FATAL_ERROR)
309                     OS_Panic("CAMERA FATAL ERROR\n");
310             }
311             else
312             {
313                 OS_TPrintf("call CAMERA_I2CActivate(%s)\n", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
314                 result = CAMERA_I2CActivateAsync(current, NULL, NULL);
315                 if(result == CAMERA_RESULT_FATAL_ERROR)
316                     OS_Panic("CAMERA FATAL ERROR\n");
317                 stabilizedCount = 0;
318             }
319             switchFlag = FALSE;
320         }
321         effect = effectFlag;
322 
323         // Switch buffers
324         if (wp_pending)
325         {
326             wp_pending = FALSE;
327         }
328         else
329         {
330             // Capture results are not displayed on screen until camera is stable
331             // This demo waits the minimum of four camera frames required to avoid chromatic aberration, but if you want to wait until auto-exposure is stable, you need to wait 14 frames for an indoor shot or 30 for an outdoor one, as indicated in the Function Reference.
332             //
333             if(stabilizedCount > 4)
334             {
335                 wp ^= 1;
336             }
337         }
338 
339         lineNumber = 0;
340     }
341 }
342 
CameraIntrVsync(CAMERAResult result)343 void CameraIntrVsync(CAMERAResult result)
344 {
345 #pragma unused(result)
346     if(stabilizedCount <= 30)
347         stabilizedCount++;
348 }
349 
350 //--------------------------------------------------------------------------------
351 //    Camera interrupt process (Generated when there is an error and for Vsync)
352 //
CameraIntrError(CAMERAResult result)353 void CameraIntrError(CAMERAResult result)
354 {
355 #pragma unused(result)
356     OS_TPrintf("Error was occurred.\n");
357 
358     // Stop the camera
359     CAMERA_StopCapture();
360     lineNumber = 0;
361     wp_pending = TRUE;      // Also use same frame next time
362     // Restart the camera
363     CAMERA_ClearBuffer();
364     CAMERA_StartCapture();
365 }
366 
CameraIntrReboot(CAMERAResult result)367 void CameraIntrReboot(CAMERAResult result)
368 {
369     if(result == CAMERA_RESULT_FATAL_ERROR)
370     {
371         return; // Restore was not possible, even after restarting camera
372     }
373     CameraIntrError(result); // DMA synchronization might have drifted, so realign
374 }
375