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