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-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 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 // DMA is not used in GX (the old DMA conflicts with camera DMA)
90 (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
91
92 // Clear VRAM
93 GX_SetBankForLCDC(GX_VRAM_LCDC_A);
94 GX_SetBankForLCDC(GX_VRAM_LCDC_B);
95 MI_CpuClearFast((void*)HW_LCDC_VRAM_A, 128 * 1024);
96 MI_CpuClearFast((void*)HW_LCDC_VRAM_B, 128 * 1024);
97
98 // Direct bitmap display mode and text display
99 GX_SetBankForBG(GX_VRAM_BG_256_AB); // Allocate VRAM-A, B banks to BG
100 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D);
101 GX_SetVisiblePlane(GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3);
102
103 G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
104 GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000, GX_BG_EXTPLTT_01);
105 G2_SetBG1Priority(1);
106 G2_BG1Mosaic(FALSE);
107
108 G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x20000);
109 G2_SetBG3Priority(3);
110 G2_BG3Mosaic(FALSE);
111
112 // Load text
113 {
114 static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
115 GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
116 GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
117 }
118 wp = 0;
119 rp = 1;
120 wp_pending = TRUE;
121 stabilizedCount = 0;
122
123 // V-Blank interrupt settings
124 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
125 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
126 (void)OS_EnableIrq();
127 (void)GX_VBlankIntr(TRUE);
128 (void)OS_EnableInterrupts();
129
130 OS_WaitVBlankIntr();
131 GX_DispOn();
132
133 // Initialize camera
134 current = CAMERA_SELECT_IN;
135 flipIn = CAMERA_FLIP_HORIZONTAL;
136 flipOut = CAMERA_FLIP_NONE;
137 flipFlag = FALSE;
138
139 (void)CameraInit();
140
141 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
142 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
143
144 // Configure DMA interrupt
145 (void)OS_EnableIrqMask(OS_IE_NDMA1);
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 // Prepare the DMA to use for the capture
157 MI_StopNDma(NDMA_NO);
158 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
159
160 // Camera start
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; // Ignore the trigger by first data
170 static int camera_end_flag = FALSE;
171 static int camera_stop_capture_flag = FALSE;
172 static int camera_notactivate_flag = FALSE;
173
174 OS_WaitVBlankIntr();
175
176 pad = PAD_Read();
177 trg = (u16)(pad & ~old);
178 old = pad;
179
180 if (camera_end_flag == FALSE)
181 {
182 if (trg & PAD_BUTTON_Y)
183 {
184 flipFlag = TRUE;
185 }
186 if (trg & PAD_BUTTON_X)
187 {
188 switchFlag = TRUE;
189 }
190 if (camera_stop_capture_flag == FALSE)
191 {
192 if (trg & PAD_BUTTON_B)
193 {
194 static BOOL standby = FALSE;
195 standby ^= 1;
196 if (standby)
197 {
198 // 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.
199 // If you set Activate to NONE prior to StopCapture, there is a risk that IsBusy will be TRUE until the next time you set "Activate ON".
200 CAMERA_StopCapture();
201 while(CAMERA_IsBusy())
202 {
203 }
204 MI_StopNDma(NDMA_NO);
205 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
206 if(result == CAMERA_RESULT_FATAL_ERROR)
207 OS_Panic("CAMERA FATAL ERROR\n");
208
209 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
210 continue;
211
212 camera_notactivate_flag = TRUE;
213 }
214 else
215 {
216 result = CAMERA_I2CActivate(current);
217 if(result == CAMERA_RESULT_FATAL_ERROR)
218 OS_Panic("CAMERA FALTAL ERROR\n");
219 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
220 continue;
221 stabilizedCount = 0;
222
223 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
224 CAMERA_ClearBuffer();
225 CAMERA_StartCapture();
226 while (CAMERA_IsBusy() == FALSE)
227 {
228 }
229 camera_notactivate_flag = FALSE;
230 }
231 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
232 }
233 }
234 if (camera_notactivate_flag == FALSE)
235 {
236 if (trg & PAD_BUTTON_START)
237 {
238 if (CAMERA_IsBusy())
239 {
240 // 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.
241 //
242 // If you are about to stop using the camera, then it's all right to stop capturing with the camera in standby mode.
243 result = CAMERA_I2CActivate(current);
244 if(result == CAMERA_RESULT_FATAL_ERROR)
245 OS_Panic("CAMERA FATAL ERROR\n");
246 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
247 continue;
248
249 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
250 OS_TPrintf("call CAMERA_Stop()... ");
251 CAMERA_StopCapture();
252 while (CAMERA_IsBusy())
253 {
254 }
255 OS_TPrintf("Camera was stopped.\n");
256 MI_StopNDma(NDMA_NO);
257 stabilizedCount = 0;
258 camera_stop_capture_flag = TRUE;
259 }
260 else
261 {
262 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
263 CAMERA_ClearBuffer();
264 CAMERA_StartCapture();
265 OS_TPrintf("Camera is shooting a movie...\n");
266 while (CAMERA_IsBusy() == FALSE)
267 {
268 }
269 camera_stop_capture_flag = FALSE;
270 }
271 }
272 }
273 }
274 // If you are not going to use the camera, just call CAMERA_I2CActivate(CAMERA_SELECT_NONE)
275 if (trg & PAD_BUTTON_SELECT)
276 {
277 if (camera_end_flag == FALSE)
278 {
279 OS_TPrintf("call CAMERA_End()... ");
280 CAMERA_StopCapture();
281 while(CAMERA_IsBusy())
282 {
283 }
284 MI_StopNDma(NDMA_NO);
285 CAMERA_End();
286 OS_TPrintf("Done.\n");
287 camera_stop_capture_flag = TRUE;
288 camera_notactivate_flag = TRUE;
289 camera_end_flag = TRUE;
290 }
291 else
292 {
293 if(CameraInit() == TRUE)
294 {
295 // Reregister the various callbacks that were registered at the first Init
296 CAMERA_SetVsyncCallback(CameraIntrVsync);
297 CAMERA_SetBufferErrorCallback(CameraIntrError);
298 CAMERA_SetRebootCallback(CameraIntrReboot);
299
300 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
301 CAMERA_ClearBuffer();
302 CAMERA_StartCapture();
303 OS_TPrintf("Camera is shooting a movie...\n");
304 while (CAMERA_IsBusy() == FALSE)
305 {
306 }
307 camera_end_flag = FALSE;
308 camera_notactivate_flag = FALSE;
309 camera_stop_capture_flag = FALSE;
310 }
311 }
312 }
313 }
314 }
315
316 //--------------------------------------------------------------------------------
317 // V-Blank interrupt process
318 //
VBlankIntr(void)319 void VBlankIntr(void)
320 {
321 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
322 if (wp == rp)
323 {
324 rp ^= 1;
325 GX_LoadBG3Scr(buffer[rp], 0, BYTES_PER_LINE * HEIGHT);
326 DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
327 }
328 }
329
330 //--------------------------------------------------------------------------------
331 // Camera initialization (only the Init- and I2C-related initialization)
332 //
CameraInit(void)333 BOOL CameraInit(void)
334 {
335 CAMERAResult result;
336 OSTick begin = OS_GetTick();
337
338 result = CAMERA_Init();
339 if(result == CAMERA_RESULT_FATAL_ERROR)
340 OS_TPanic("CAMERA_Init was failed.");
341 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
342 return FALSE;
343
344 OS_TPrintf("CAMERA_Init took %d msec\n", (int)OS_TicksToMilliSeconds(OS_GetTick()-begin));
345
346 result = CAMERA_I2CFlip(CAMERA_SELECT_IN, flipIn);
347 if (result == CAMERA_RESULT_FATAL_ERROR)
348 OS_TPanic("CAMERA_I2CFlip was failed. (%d)\n", result);
349 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
350 return FALSE;
351
352 result = CAMERA_I2CFlip(CAMERA_SELECT_OUT, flipOut);
353 if (result == CAMERA_RESULT_FATAL_ERROR)
354 OS_TPanic("CAMERA_I2CFlip was failed. (%d)\n", result);
355 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
356 return FALSE;
357
358 result = CAMERA_I2CActivate(current);
359 if (result == CAMERA_RESULT_FATAL_ERROR)
360 OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
361 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
362 return FALSE;
363 stabilizedCount = 0;
364
365 return TRUE;
366 }
367
368 //--------------------------------------------------------------------------------
369 // Camera interrupt process (Generated when there is an error and for Vsync)
370 //
CameraIntrError(CAMERAResult result)371 void CameraIntrError(CAMERAResult result)
372 {
373 #pragma unused(result)
374 OS_TPrintf("Error was occurred.\n");
375 // Camera Stop processing
376 CAMERA_StopCapture();
377 MI_StopNDma(NDMA_NO);
378 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
379 CAMERA_ClearBuffer();
380 wp_pending = TRUE; // Also use same frame next time
381 CAMERA_StartCapture();
382 }
383
384 // Restart completion callback
CameraIntrReboot(CAMERAResult result)385 void CameraIntrReboot(CAMERAResult result)
386 {
387 if(result == CAMERA_RESULT_FATAL_ERROR)
388 {
389 return; // Restore was not possible, even after restarting camera
390 }
391 CameraIntrError(result); // DMA synchronization might have drifted, so realign
392 }
393
DoneCallback(CAMERAResult result,void * arg)394 static void DoneCallback(CAMERAResult result, void* arg)
395 {
396 const char* str = arg;
397 if (result != CAMERA_RESULT_SUCCESS)
398 {
399 OS_TPrintf("%s was failed. (%d)\n", arg, result);
400 }
401 }
402
CameraIntrVsync(CAMERAResult result)403 void CameraIntrVsync(CAMERAResult result)
404 {
405 #pragma unused(result)
406 if(stabilizedCount <= 30)
407 stabilizedCount++;
408 }
409
410 #define FPS_SAMPLES 4
CameraDmaRecvIntr(void * arg)411 void CameraDmaRecvIntr(void* arg)
412 {
413 #pragma unused(arg)
414 CAMERAResult result;
415
416 MI_StopNDma(NDMA_NO);
417
418 if(flipFlag == TRUE)
419 {
420 CAMERAFlip *pFlip = (current == CAMERA_SELECT_IN ? &flipIn : &flipOut);
421 *pFlip = (CAMERAFlip)((*pFlip + 1) % CAMERA_FLIP_MAX);
422 result = CAMERA_I2CFlipAsync(current, *pFlip, DoneCallback, "CAMERA_I2CFlipAsync");
423 if (result == CAMERA_RESULT_FATAL_ERROR)
424 OS_TPanic("CAMERA_I2CFlipAsync was failed. (%d)\n", result);
425 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
426 return;
427
428 flipFlag = FALSE;
429 }
430 else if(switchFlag == TRUE)
431 {
432 current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
433 result = CAMERA_I2CActivateAsync(current, DoneCallback, "CAMERA_I2CActivateAsync");
434 if (result == CAMERA_RESULT_FATAL_ERROR)
435 OS_TPanic("CAMERA_I2CActivateAsync was failed. (%d)\n", result);
436 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
437 return;
438 stabilizedCount = 0;
439 switchFlag = FALSE;
440 }
441
442 // Start the next frame capture
443 if (wp_pending)
444 {
445 wp_pending = FALSE;
446 }
447 else
448 {
449 // Capture results are not displayed on screen until camera is stable
450 // 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.
451 //
452 if(stabilizedCount > 4)
453 {
454 wp ^= 1;
455 }
456 }
457 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
458
459 // Display frame rate
460 {
461 static OSTick begin = 0;
462 static int uspf[FPS_SAMPLES] = { 0 };
463 static int count = 0;
464 int i;
465 int sum = 0;
466 OSTick end = OS_GetTick();
467 if (begin) // Leave out the first time
468 {
469 uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
470 count = (count + 1) % FPS_SAMPLES;
471 }
472 begin = end;
473 // Calculate average value
474 for (i = 0; i < FPS_SAMPLES; i++)
475 {
476 if (uspf[i] == 0) break;
477 sum += uspf[i];
478 }
479 if (sum)
480 {
481 int mfps = (int)(1000000000LL * i / sum);
482 PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
483 }
484 }
485 }
486