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-09-24#$
14   $Rev: 11063 $
15   $Author: okubata_ryoma $
16  *---------------------------------------------------------------------------*/
17 
18 #include <twl.h>
19 #include <twl/camera.h>
20 #include "DEMO.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     // When in NITRO mode, stopped by Panic
92     DEMOCheckRunOnTWL();
93 
94     // DMA is not used in GX (the old DMA conflicts with camera DMA)
95     (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
96 
97     // Clears VRAM
98     GX_SetBankForLCDC(GX_VRAM_LCDC_A);
99     GX_SetBankForLCDC(GX_VRAM_LCDC_B);
100     MI_CpuClearFast((void*)HW_LCDC_VRAM_A, 128 * 1024);
101     MI_CpuClearFast((void*)HW_LCDC_VRAM_B, 128 * 1024);
102 
103     // Direct bitmap display mode and text display
104     GX_SetBankForBG(GX_VRAM_BG_256_AB);         // Allocate VRAM-A and B banks to BG
105     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D);
106     GX_SetVisiblePlane(GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3);
107 
108     G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
109                      GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000, GX_BG_EXTPLTT_01);
110     G2_SetBG1Priority(1);
111     G2_BG1Mosaic(FALSE);
112 
113     G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x20000);
114     G2_SetBG3Priority(3);
115     G2_BG3Mosaic(FALSE);
116 
117     // Load text
118     {
119         static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
120         GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
121         GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
122     }
123     wp = 0;
124     rp = 1;
125     wp_pending = TRUE;
126     stabilizedCount = 0;
127 
128     // V-Blank interrupt settings
129     OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
130     (void)OS_EnableIrqMask(OS_IE_V_BLANK);
131     (void)OS_EnableIrq();
132     (void)GX_VBlankIntr(TRUE);
133     (void)OS_EnableInterrupts();
134 
135     OS_WaitVBlankIntr();
136     GX_DispOn();
137 
138     // Initialize camera
139     current = CAMERA_SELECT_IN;
140     (void)CameraInit();
141 
142     CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
143     CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
144 
145     // Configure DMA interrupt
146     OS_SetIrqFunction(NDMA_IE, CameraDmaIntr);
147     (void)OS_EnableIrqMask(NDMA_IE);
148 
149     // Camera VSYNC interrupt callback
150     CAMERA_SetVsyncCallback(CameraIntrVsync);
151 
152     // Camera error interrupt callback
153     CAMERA_SetBufferErrorCallback(CameraIntrError);
154 
155     // Camera restart completion callback
156     CAMERA_SetRebootCallback(CameraIntrReboot);
157 
158     // DMA start (enabled forever unless explicitly stopped)
159     MI_StopNDma(NDMA_NO);
160     CAMERA_DmaPipeInfinity(NDMA_NO, pipeBuffer, CAMERA_GetBytesAtOnce(WIDTH), NULL, NULL);
161 
162     // Camera start
163     lineNumber = 0;
164     CAMERA_ClearBuffer();
165     CAMERA_StartCapture();
166     OS_TPrintf("Camera is shooting a movie...\n");
167 
168     while (1)
169     {
170         u16 pad;
171         u16 trg;
172         static u16 old = 0xffff;
173 
174         OS_WaitVBlankIntr();
175 
176         if (wp == rp)
177         {
178             rp ^= 1;
179             GX_LoadBG3Scr(buffer[rp], 0, BYTES_PER_LINE * HEIGHT);
180             DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
181         }
182 
183         pad = PAD_Read();
184         trg = (u16)(pad & ~old);
185         old = pad;
186 
187         if (trg & PAD_BUTTON_A)
188         {
189             effectFlag ^= 1;
190             OS_TPrintf("Effect %s\n", effectFlag ? "ON" : "OFF");
191         }
192         if (trg & PAD_BUTTON_X)
193         {
194             current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
195             switchFlag = TRUE;
196         }
197         if (trg & PAD_BUTTON_B)
198         {
199             standbyFlag ^= 1;
200 
201             if(standbyFlag)
202             {
203                 switchFlag = TRUE;
204             }
205             else
206             {
207                 CAMERAResult result;
208 
209                 OS_TPrintf("call CAMERA_I2CActivate(%s)\n", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
210                 result = CAMERA_I2CActivateAsync(current, NULL, NULL);
211                 if(result == CAMERA_RESULT_FATAL_ERROR)
212                     OS_Panic("CAMERA FATAL ERROR\n");
213                 stabilizedCount = 0;
214             }
215         }
216     }
217 }
218 
219 //--------------------------------------------------------------------------------
220 //    V-Blank interrupt process
221 //
VBlankIntr(void)222 void VBlankIntr(void)
223 {
224     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
225 }
226 
227 //--------------------------------------------------------------------------------
228 //    Camera initialization (only the Init- and I2C-related initialization)
229 //
CameraInit(void)230 BOOL CameraInit(void)
231 {
232     CAMERAResult result;
233     result = CAMERA_Init();
234     if(result == CAMERA_RESULT_FATAL_ERROR)
235         OS_TPanic("CAMERA_Init was failed.");
236     if(result == CAMERA_RESULT_ILLEGAL_STATUS)
237         return FALSE;
238 
239     result = CAMERA_I2CActivate(current);
240     if (result == CAMERA_RESULT_FATAL_ERROR)
241         OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
242     if(result == CAMERA_RESULT_ILLEGAL_STATUS)
243         return FALSE;
244     stabilizedCount = 0;
245 
246     return TRUE;
247 }
248 
249 //--------------------------------------------------------------------------------
250 //    DMA interrupt process
251 //
252 #define FPS_SAMPLES 4
CameraDmaIntr(void)253 void CameraDmaIntr(void)
254 {
255     static BOOL effect = FALSE;
256     CAMERAResult result;
257 
258     OS_SetIrqCheckFlag(NDMA_IE);
259     OS_SetIrqFunction(NDMA_IE, CameraDmaIntr);
260 
261     // Process as required and copy to frame buffer
262     if (effect) // Invert negative/positive sign
263     {
264         int i;
265         u32 *src = (u32*)pipeBuffer;
266         u32 *dest = (u32*)buffer[wp] + lineNumber * WIDTH / 2;
267         for (i = 0; i < WIDTH * LINES_AT_ONCE / 2; i++)
268         {
269             dest[i] = ~src[i] | 0x80008000;
270         }
271     }
272     else
273     {
274         MI_CpuCopyFast(pipeBuffer, (u16*)buffer[wp] + lineNumber * WIDTH, sizeof(pipeBuffer));
275     }
276     DC_InvalidateRange(pipeBuffer, sizeof(pipeBuffer));
277 
278     lineNumber += LINES_AT_ONCE;
279     if (lineNumber >= HEIGHT)
280     {
281         static OSTick begin = 0;
282         static int uspf[FPS_SAMPLES] = { 0 };
283         static int count = 0;
284         int i;
285         int sum = 0;
286         OSTick end = OS_GetTick();
287         if (begin)  // Leave out the first time
288         {
289             uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
290             count = (count + 1) % FPS_SAMPLES;
291         }
292         begin = end;
293         // Calculate average value
294         for (i = 0; i < FPS_SAMPLES; i++)
295         {
296             if (uspf[i] == 0)  break;
297             sum +=  uspf[i];
298         }
299         if (sum)
300         {
301             int mfps = (int)(1000000000LL * i / sum);
302             PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
303         }
304 
305         if (switchFlag)
306         {
307             if (standbyFlag)
308             {
309                 OS_TPrintf("call CAMERA_I2CActivate(CAMERA_SELECT_NONE)\n");
310                 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
311                 if(result == CAMERA_RESULT_FATAL_ERROR)
312                     OS_Panic("CAMERA FATAL ERROR\n");
313             }
314             else
315             {
316                 OS_TPrintf("call CAMERA_I2CActivate(%s)\n", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
317                 result = CAMERA_I2CActivateAsync(current, NULL, NULL);
318                 if(result == CAMERA_RESULT_FATAL_ERROR)
319                     OS_Panic("CAMERA FATAL ERROR\n");
320                 stabilizedCount = 0;
321             }
322             switchFlag = FALSE;
323         }
324         effect = effectFlag;
325 
326         // Switch buffers
327         if (wp_pending)
328         {
329             wp_pending = FALSE;
330         }
331         else
332         {
333             // Capture results are not displayed on screen until camera is stable
334             // 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.
335             //
336             if(stabilizedCount > 4)
337             {
338                 wp ^= 1;
339             }
340         }
341 
342         lineNumber = 0;
343     }
344 }
345 
CameraIntrVsync(CAMERAResult result)346 void CameraIntrVsync(CAMERAResult result)
347 {
348 #pragma unused(result)
349     if(stabilizedCount <= 30)
350         stabilizedCount++;
351 }
352 
353 //--------------------------------------------------------------------------------
354 //    Camera interrupt process (Generated when there is an error and for Vsync)
355 //
CameraIntrError(CAMERAResult result)356 void CameraIntrError(CAMERAResult result)
357 {
358 #pragma unused(result)
359     OS_TPrintf("Error was occurred.\n");
360 
361     // Stop the camera
362     CAMERA_StopCapture();
363     lineNumber = 0;
364     wp_pending = TRUE;      // Also use same frame next time
365     // Restart the camera
366     CAMERA_ClearBuffer();
367     CAMERA_StartCapture();
368 }
369 
CameraIntrReboot(CAMERAResult result)370 void CameraIntrReboot(CAMERAResult result)
371 {
372     if(result == CAMERA_RESULT_FATAL_ERROR)
373     {
374         return; // Recovery was not possible, even after restarting camera
375     }
376     CameraIntrError(result); // DMA synchronization might have drifted, so realign
377 }
378