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