1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos.TWL - camera - camera-1
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 WIDTH 256 // Image width
24 #define HEIGHT 192 // Image height
25
26 #define LINES_AT_ONCE CAMERA_GET_MAX_LINES(WIDTH) // Number of lines transferred in one cycle
27 #define BYTES_PER_LINE CAMERA_GET_LINE_BYTES(WIDTH) // Number of bytes in one line's transfer
28
29 static void VBlankIntr(void);
30 static BOOL CameraInit(void);
31 static void CameraIntrVsync(CAMERAResult result);
32 static void CameraIntrError(CAMERAResult result);
33 static void CameraIntrReboot(CAMERAResult result);
34 static void CameraDmaRecvIntr(void* arg);
35
36 static CAMERASelect current;
37 static CAMERAFlip flipIn, flipOut;
38 static BOOL flipFlag = FALSE;
39 static BOOL switchFlag = FALSE;
40 static u32 stabilizedCount;
41
42 static int wp; // Buffer while capturing data from camera
43 static int rp; // Buffer most recently copied to VRAM
44 static BOOL wp_pending; // Data capture was cancelled (recapture to same buffer)
45 static u16 buffer[2][WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
PendingCapture(void)46 static void PendingCapture(void)
47 {
48 wp_pending = TRUE;
49 }
50
51 // Character display
PutString(char * format,...)52 static void PutString( char *format, ... )
53 {
54 u16 *dest = G2_GetBG1ScrPtr();
55 char temp[32+1];
56 int i;
57 va_list va;
58
59 va_start(va, format);
60 (void)OS_VSNPrintf(temp, sizeof(temp), format, va);
61 va_end(va);
62
63 for (i = 0; i < 32 && temp[i]; i++)
64 {
65 dest[i] = (u16)((u8)temp[i] | (1 << 12));
66 }
67 }
68
69 /*---------------------------------------------------------------------------*
70 Name: TwlMain
71
72 Description: Main
73
74 Arguments: None.
75
76 Returns: None.
77 *---------------------------------------------------------------------------*/
TwlMain()78 void TwlMain()
79 {
80 CAMERAResult result;
81
82 // Initialization
83 OS_Init();
84 OS_InitThread();
85 GX_Init();
86 OS_InitTick();
87 OS_InitAlarm();
88
89 // When in NITRO mode, stopped by Panic
90 DEMOCheckRunOnTWL();
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 // Clears 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 and 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 flipIn = CAMERA_FLIP_HORIZONTAL;
139 flipOut = CAMERA_FLIP_NONE;
140 flipFlag = FALSE;
141
142 (void)CameraInit();
143
144 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
145 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
146
147 // Configure DMA interrupt
148 (void)OS_EnableIrqMask(OS_IE_NDMA1);
149
150 // Camera VSYNC interrupt callback
151 CAMERA_SetVsyncCallback(CameraIntrVsync);
152
153 // Camera error interrupt callback
154 CAMERA_SetBufferErrorCallback(CameraIntrError);
155
156 // Camera restart completion callback
157 CAMERA_SetRebootCallback(CameraIntrReboot);
158
159 // Prepare the DMA to use for the capture
160 MI_StopNDma(NDMA_NO);
161 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
162
163 // Camera start
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; // Ignore the trigger by first data
173 static int camera_end_flag = FALSE;
174 static int camera_stop_capture_flag = FALSE;
175 static int camera_notactivate_flag = FALSE;
176
177 OS_WaitVBlankIntr();
178
179 pad = PAD_Read();
180 trg = (u16)(pad & ~old);
181 old = pad;
182
183 if (camera_end_flag == FALSE)
184 {
185 if (trg & PAD_BUTTON_Y)
186 {
187 flipFlag = TRUE;
188 }
189 if (trg & PAD_BUTTON_X)
190 {
191 switchFlag = TRUE;
192 }
193 if (camera_stop_capture_flag == FALSE)
194 {
195 if (trg & PAD_BUTTON_B)
196 {
197 static BOOL standby = FALSE;
198 standby ^= 1;
199 if (standby)
200 {
201 // Temporarily halt use of the camera. If the camera will be used again in the next cycle, all you need to do is set "Activate NONE", instead of calling the CAMERA_End function.
202 // If you set Activate to NONE before StopCapture, there is a risk that IsBusy will be TRUE until the next time you set "Activate ON"
203 CAMERA_StopCapture();
204 while(CAMERA_IsBusy())
205 {
206 }
207 MI_StopNDma(NDMA_NO);
208 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
209 if(result == CAMERA_RESULT_FATAL_ERROR)
210 OS_Panic("CAMERA FATAL ERROR\n");
211
212 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
213 continue;
214
215 camera_notactivate_flag = TRUE;
216 }
217 else
218 {
219 result = CAMERA_I2CActivate(current);
220 if(result == CAMERA_RESULT_FATAL_ERROR)
221 OS_Panic("CAMERA FALTAL ERROR\n");
222 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
223 continue;
224 stabilizedCount = 0;
225
226 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
227 CAMERA_ClearBuffer();
228 CAMERA_StartCapture();
229 while (CAMERA_IsBusy() == FALSE)
230 {
231 }
232 camera_notactivate_flag = FALSE;
233 }
234 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
235 }
236 }
237 if (camera_notactivate_flag == FALSE)
238 {
239 if (trg & PAD_BUTTON_START)
240 {
241 if (CAMERA_IsBusy())
242 {
243 // If you want to change parameters, you need to first start up the camera and then stop capturing. This makes the CAMERA_IsBusy function return FALSE.
244 //
245 // If you are about to stop using the camera, then it's all right to stop capturing with the camera in standby mode.
246 result = CAMERA_I2CActivate(current);
247 if(result == CAMERA_RESULT_FATAL_ERROR)
248 OS_Panic("CAMERA FATAL ERROR\n");
249 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
250 continue;
251
252 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
253 OS_TPrintf("call CAMERA_Stop()... ");
254 CAMERA_StopCapture();
255 while (CAMERA_IsBusy())
256 {
257 }
258 OS_TPrintf("Camera was stopped.\n");
259 MI_StopNDma(NDMA_NO);
260 stabilizedCount = 0;
261 camera_stop_capture_flag = TRUE;
262 }
263 else
264 {
265 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
266 CAMERA_ClearBuffer();
267 CAMERA_StartCapture();
268 OS_TPrintf("Camera is shooting a movie...\n");
269 while (CAMERA_IsBusy() == FALSE)
270 {
271 }
272 camera_stop_capture_flag = FALSE;
273 }
274 }
275 }
276 }
277 // If you are not going to use the camera, just call CAMERA_I2CActivate(CAMERA_SELECT_NONE)
278 if (trg & PAD_BUTTON_SELECT)
279 {
280 if (camera_end_flag == FALSE)
281 {
282 OS_TPrintf("call CAMERA_End()... ");
283 CAMERA_StopCapture();
284 while(CAMERA_IsBusy())
285 {
286 }
287 MI_StopNDma(NDMA_NO);
288 CAMERA_End();
289 OS_TPrintf("Done.\n");
290 camera_stop_capture_flag = TRUE;
291 camera_notactivate_flag = TRUE;
292 camera_end_flag = TRUE;
293 }
294 else
295 {
296 if(CameraInit() == TRUE)
297 {
298 // Reregister the various callbacks that were registered at the first Init
299 CAMERA_SetVsyncCallback(CameraIntrVsync);
300 CAMERA_SetBufferErrorCallback(CameraIntrError);
301 CAMERA_SetRebootCallback(CameraIntrReboot);
302
303 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
304 CAMERA_ClearBuffer();
305 CAMERA_StartCapture();
306 OS_TPrintf("Camera is shooting a movie...\n");
307 while (CAMERA_IsBusy() == FALSE)
308 {
309 }
310 camera_end_flag = FALSE;
311 camera_notactivate_flag = FALSE;
312 camera_stop_capture_flag = FALSE;
313 }
314 }
315 }
316 }
317 }
318
319 //--------------------------------------------------------------------------------
320 // V-Blank interrupt process
321 //
VBlankIntr(void)322 void VBlankIntr(void)
323 {
324 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
325 if (wp == rp)
326 {
327 rp ^= 1;
328 GX_LoadBG3Scr(buffer[rp], 0, BYTES_PER_LINE * HEIGHT);
329 DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
330 }
331 }
332
333 //--------------------------------------------------------------------------------
334 // Camera initialization (only the Init- and I2C-related initialization)
335 //
CameraInit(void)336 BOOL CameraInit(void)
337 {
338 CAMERAResult result;
339 OSTick begin = OS_GetTick();
340
341 result = CAMERA_Init();
342 if(result == CAMERA_RESULT_FATAL_ERROR)
343 OS_TPanic("CAMERA_Init was failed.");
344 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
345 return FALSE;
346
347 OS_TPrintf("CAMERA_Init took %d msec\n", (int)OS_TicksToMilliSeconds(OS_GetTick()-begin));
348
349 result = CAMERA_I2CFlip(CAMERA_SELECT_IN, flipIn);
350 if (result == CAMERA_RESULT_FATAL_ERROR)
351 OS_TPanic("CAMERA_I2CFlip was failed. (%d)\n", result);
352 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
353 return FALSE;
354
355 result = CAMERA_I2CFlip(CAMERA_SELECT_OUT, flipOut);
356 if (result == CAMERA_RESULT_FATAL_ERROR)
357 OS_TPanic("CAMERA_I2CFlip was failed. (%d)\n", result);
358 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
359 return FALSE;
360
361 result = CAMERA_I2CActivate(current);
362 if (result == CAMERA_RESULT_FATAL_ERROR)
363 OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
364 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
365 return FALSE;
366 stabilizedCount = 0;
367
368 return TRUE;
369 }
370
371 //--------------------------------------------------------------------------------
372 // Camera interrupt process (Generated when there is an error and for Vsync)
373 //
CameraIntrError(CAMERAResult result)374 void CameraIntrError(CAMERAResult result)
375 {
376 #pragma unused(result)
377 OS_TPrintf("Error was occurred.\n");
378 // Camera stop processing
379 CAMERA_StopCapture();
380 MI_StopNDma(NDMA_NO);
381 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
382 CAMERA_ClearBuffer();
383 wp_pending = TRUE; // Also use same frame next time
384 CAMERA_StartCapture();
385 }
386
387 // Restart completion callback
CameraIntrReboot(CAMERAResult result)388 void CameraIntrReboot(CAMERAResult result)
389 {
390 if(result == CAMERA_RESULT_FATAL_ERROR)
391 {
392 return; // Recovery was not possible, even after restarting camera
393 }
394 CameraIntrError(result); // DMA synchronization might have drifted, so realign
395 }
396
DoneCallback(CAMERAResult result,void * arg)397 static void DoneCallback(CAMERAResult result, void* arg)
398 {
399 const char* str = arg;
400 if (result != CAMERA_RESULT_SUCCESS)
401 {
402 OS_TPrintf("%s was failed. (%d)\n", arg, result);
403 }
404 }
405
CameraIntrVsync(CAMERAResult result)406 void CameraIntrVsync(CAMERAResult result)
407 {
408 #pragma unused(result)
409 if(stabilizedCount <= 30)
410 stabilizedCount++;
411 }
412
413 #define FPS_SAMPLES 4
CameraDmaRecvIntr(void * arg)414 void CameraDmaRecvIntr(void* arg)
415 {
416 #pragma unused(arg)
417 CAMERAResult result;
418
419 MI_StopNDma(NDMA_NO);
420
421 if(flipFlag == TRUE)
422 {
423 CAMERAFlip *pFlip = (current == CAMERA_SELECT_IN ? &flipIn : &flipOut);
424 *pFlip = (CAMERAFlip)((*pFlip + 1) % CAMERA_FLIP_MAX);
425 result = CAMERA_I2CFlipAsync(current, *pFlip, DoneCallback, "CAMERA_I2CFlipAsync");
426 if (result == CAMERA_RESULT_FATAL_ERROR)
427 OS_TPanic("CAMERA_I2CFlipAsync was failed. (%d)\n", result);
428 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
429 return;
430
431 flipFlag = FALSE;
432 }
433 else if(switchFlag == TRUE)
434 {
435 current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
436 result = CAMERA_I2CActivateAsync(current, DoneCallback, "CAMERA_I2CActivateAsync");
437 if (result == CAMERA_RESULT_FATAL_ERROR)
438 OS_TPanic("CAMERA_I2CActivateAsync was failed. (%d)\n", result);
439 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
440 return;
441 stabilizedCount = 0;
442 switchFlag = FALSE;
443 }
444
445 // Start the next frame capture
446 if (wp_pending)
447 {
448 wp_pending = FALSE;
449 }
450 else
451 {
452 // Capture results are not displayed on screen until camera is stable
453 // 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.
454 //
455 if(stabilizedCount > 4)
456 {
457 wp ^= 1;
458 }
459 }
460 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
461
462 // Display frame rate
463 {
464 static OSTick begin = 0;
465 static int uspf[FPS_SAMPLES] = { 0 };
466 static int count = 0;
467 int i;
468 int sum = 0;
469 OSTick end = OS_GetTick();
470 if (begin) // Leave out the first time
471 {
472 uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
473 count = (count + 1) % FPS_SAMPLES;
474 }
475 begin = end;
476 // Calculate average value
477 for (i = 0; i < FPS_SAMPLES; i++)
478 {
479 if (uspf[i] == 0) break;
480 sum += uspf[i];
481 }
482 if (sum)
483 {
484 int mfps = (int)(1000000000LL * i / sum);
485 PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
486 }
487 }
488 }
489