1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos.TWL - camera - camera-4
3 File: main.c
4
5 Copyright 2007-2009 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 /////
37 // Sample configuration with double buffer in main memory and 1 layer of VRAM
38 /////
39
40 static int wp; // Buffer while capturing data from camera
41 static int rp; // Buffer most recently copied to VRAM
42 static BOOL wp_pending; // Data capture was cancelled (recapture to same buffer)
43 static u32 stabilizedCount;
44 static BOOL switchFlag;
45
46 static CAMERASelect current;
47 static CAMERAFlip flipIn, flipOut;
48 static u16 buffer[2][WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
DebugReport(void)49 static void DebugReport(void)
50 {
51 OS_TPrintf("\nCapture to No.%d\tDisplay from No.%d\n", wp, rp);
52 }
PendingCapture(void)53 static void PendingCapture(void)
54 {
55 wp_pending = TRUE;
56 }
57
58 // Display text (one row only)
59 static u16 text_buffer[ 32 ] ATTRIBUTE_ALIGN(32);
PutString(char * format,...)60 static void PutString( char *format, ... )
61 {
62 u16 *dest = text_buffer;
63 char temp[32+1];
64 int i;
65 va_list va;
66
67 va_start(va, format);
68 (void)OS_VSNPrintf(temp, sizeof(temp), format, va);
69 va_end(va);
70
71 MI_CpuClearFast(text_buffer, sizeof(text_buffer));
72 for (i = 0; i < 32 && temp[i]; i++)
73 {
74 dest[i] = (u16)((u8)temp[i] | (1 << 12));
75 }
76 DC_StoreRange(text_buffer, sizeof(text_buffer));
77 }
78
79 /*---------------------------------------------------------------------------*
80 Name: TwlMain
81
82 Description: Main.
83
84 Arguments: None.
85
86 Returns: None.
87 *---------------------------------------------------------------------------*/
TwlMain()88 void TwlMain()
89 {
90 CAMERAResult result;
91
92 // Initialization
93 OS_Init();
94 OS_InitThread();
95 GX_Init();
96 OS_InitTick();
97 OS_InitAlarm();
98
99 // DMA is not used in GX (the old DMA conflicts with camera DMA)
100 (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
101
102 // Clears VRAM
103 GX_SetBankForLCDC(GX_VRAM_LCDC_A);
104 GX_SetBankForLCDC(GX_VRAM_LCDC_B);
105 MI_CpuClearFast((void*)HW_LCDC_VRAM_A, 128 * 1024);
106 MI_CpuClearFast((void*)HW_LCDC_VRAM_B, 128 * 1024);
107
108 // Direct bitmap display mode and text display
109 GX_SetBankForBG(GX_VRAM_BG_256_AB); // Allocate VRAM-A and B banks to BG
110 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D);
111 GX_SetVisiblePlane(GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3);
112
113 G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
114 GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000, GX_BG_EXTPLTT_01);
115 G2_SetBG1Priority(1);
116 G2_BG1Mosaic(FALSE);
117
118 G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x20000);
119 G2_SetBG3Priority(3);
120 G2_BG3Mosaic(FALSE);
121
122 // Load text
123 {
124 static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
125 GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
126 GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
127 }
128 wp = 0;
129 rp = 1;
130 wp_pending = TRUE;
131 stabilizedCount = 0;
132 switchFlag = FALSE;
133
134 // V-Blank interrupt settings
135 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
136 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
137 (void)OS_EnableIrq();
138 (void)GX_VBlankIntr(TRUE);
139 (void)OS_EnableInterrupts();
140
141 OS_WaitVBlankIntr();
142 GX_DispOn();
143
144 // Initialize camera
145 current = CAMERA_SELECT_IN;
146 flipIn = CAMERA_FLIP_HORIZONTAL;
147 flipOut = CAMERA_FLIP_NONE;
148 (void)CameraInit();
149
150 // Configure DMA interrupt
151 (void)OS_EnableIrqMask(OS_IE_NDMA1);
152
153 // Camera VSYNC interrupt callback
154 CAMERA_SetVsyncCallback(CameraIntrVsync);
155
156 // Camera error interrupt callback
157 CAMERA_SetBufferErrorCallback(CameraIntrError);
158
159 // Camera restart completion callback
160 CAMERA_SetRebootCallback(CameraIntrReboot);
161
162 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
163 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
164
165 // Start capturing
166 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
167 CAMERA_ClearBuffer();
168 CAMERA_StartCapture();
169 OS_TPrintf("Camera is shooting a movie...\n");
170
171 while (1)
172 {
173 u16 pad;
174 u16 trg;
175 static u16 old = 0xffff;
176 static BOOL standby = FALSE;
177
178 OS_WaitVBlankIntr();
179
180 pad = PAD_Read();
181 trg = (u16)(pad & ~old);
182 old = pad;
183
184 if (trg & PAD_BUTTON_Y)
185 {
186 DebugReport();
187 }
188 if (trg & PAD_BUTTON_X)
189 {
190 switchFlag = TRUE;
191 }
192 if (trg & PAD_BUTTON_B)
193 {
194 standby ^= 1;
195 if (standby)
196 {
197 // 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"
198 CAMERA_StopCapture();
199 while(CAMERA_IsBusy())
200 {
201 }
202 MI_StopNDma(NDMA_NO);
203 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
204 if(result == CAMERA_RESULT_FATAL_ERROR)
205 OS_Panic("CAMERA FATAL ERROR\n");
206 }
207 else
208 {
209 result = CAMERA_I2CActivate(current);
210 if(result == CAMERA_RESULT_FATAL_ERROR)
211 OS_Panic("CAMERA FATAL ERROR\n");
212 stabilizedCount = 0;
213 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
214 CAMERA_ClearBuffer();
215 CAMERA_StartCapture();
216 }
217 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
218 }
219
220 if (trg & PAD_BUTTON_SELECT)
221 {
222 result = CAMERA_I2CFlip(current, CAMERA_FLIP_VERTICAL);
223 if (result != CAMERA_RESULT_SUCCESS)
224 {
225 OS_TPrintf("CAMERA_I2CEffect was failed. (%d)\n", result);
226 }
227 *(current == CAMERA_SELECT_IN ? &flipIn : &flipOut) = CAMERA_FLIP_VERTICAL;
228 }
229 if (trg & PAD_BUTTON_L)
230 {
231 result = CAMERA_I2CFlip(current, CAMERA_FLIP_HORIZONTAL);
232 if (result != CAMERA_RESULT_SUCCESS)
233 {
234 OS_TPrintf("CAMERA_I2CEffect was failed. (%d)\n", result);
235 }
236 *(current == CAMERA_SELECT_IN ? &flipIn : &flipOut) = CAMERA_FLIP_HORIZONTAL;
237 }
238 if (trg & PAD_BUTTON_R)
239 {
240 result = CAMERA_I2CFlip(current, CAMERA_FLIP_REVERSE);
241 if (result != CAMERA_RESULT_SUCCESS)
242 {
243 OS_TPrintf("CAMERA_I2CEffect was failed. (%d)\n", result);
244 }
245 *(current == CAMERA_SELECT_IN ? &flipIn : &flipOut) = CAMERA_FLIP_REVERSE;
246 }
247 if (trg & PAD_BUTTON_START)
248 {
249 result = CAMERA_I2CFlip(current, CAMERA_FLIP_NONE);
250 if (result != CAMERA_RESULT_SUCCESS)
251 {
252 OS_TPrintf("CAMERA_I2CEffect was failed. (%d)\n", result);
253 }
254 *(current == CAMERA_SELECT_IN ? &flipIn : &flipOut) = CAMERA_FLIP_NONE;
255 }
256 }
257 }
258
259 //--------------------------------------------------------------------------------
260 // V-Blank interrupt process
261 //
VBlankIntr(void)262 void VBlankIntr(void)
263 {
264 OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
265 if (wp == rp)
266 {
267 rp ^= 1;
268 // This is just a simple copy, but format conversion and so on could be included
269 GX_LoadBG3Scr(buffer[rp], 0, BYTES_PER_LINE * HEIGHT);
270 DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
271 }
272 GX_LoadBG1Scr(text_buffer, 0, sizeof(text_buffer));
273 }
274
275 //--------------------------------------------------------------------------------
276 // Camera initialization
277 //
CameraInit(void)278 BOOL CameraInit(void)
279 {
280 CAMERAResult result;
281
282 result = CAMERA_Init();
283 if(result == CAMERA_RESULT_FATAL_ERROR)
284 OS_TPanic("CAMERA_Init was failed.");
285 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
286 return FALSE;
287
288 result = CAMERA_I2CFlip(CAMERA_SELECT_IN, flipIn);
289 if (result != CAMERA_RESULT_SUCCESS)
290 {
291 OS_TPrintf("CAMERA_I2CFlip was failed. (%d)\n", result);
292 }
293 result = CAMERA_I2CFlip(CAMERA_SELECT_OUT, flipOut);
294 if (result != CAMERA_RESULT_SUCCESS)
295 {
296 OS_TPrintf("CAMERA_I2CFlip was failed. (%d)\n", result);
297 }
298 result = CAMERA_I2CActivate(current);
299 if (result == CAMERA_RESULT_FATAL_ERROR)
300 OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
301 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
302 return FALSE;
303 stabilizedCount = 0;
304
305 return TRUE;
306 }
307
308 //--------------------------------------------------------------------------------
309 // Camera interrupt process (occurs both when there is an error and for Vsync)
310 //
311 #define FPS_SAMPLES 4
CameraIntrError(CAMERAResult result)312 void CameraIntrError(CAMERAResult result)
313 {
314 #pragma unused(result)
315 OS_TPrintf("Error was occurred.\n");
316 // Camera stop processing
317 CAMERA_StopCapture();
318 MI_StopNDma(NDMA_NO);
319 CAMERA_ClearBuffer();
320 wp_pending = TRUE; // Also use same frame next time
321 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
322 CAMERA_StartCapture();
323 }
324
CameraIntrReboot(CAMERAResult result)325 void CameraIntrReboot(CAMERAResult result)
326 {
327 if(result == CAMERA_RESULT_FATAL_ERROR)
328 {
329 return; // Restore was not possible, even after restarting camera
330 }
331 CameraIntrError(result); // DMA synchronization might have drifted, so realign
332 }
333
CameraIntrVsync(CAMERAResult result)334 void CameraIntrVsync(CAMERAResult result)
335 {
336 #pragma unused(result)
337 if(stabilizedCount <= 30)
338 stabilizedCount++;
339 if(switchFlag)
340 {
341 current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
342 OS_TPrintf("call CAMERA_I2CActivate(%s)... ", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
343 result = CAMERA_I2CActivate(current);
344 if(result == CAMERA_RESULT_FATAL_ERROR)
345 OS_Panic("CAMERA FATAL ERROR\n");
346 stabilizedCount = 0;
347 switchFlag = FALSE;
348 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
349 }
350 }
351
CameraDmaRecvIntr(void * arg)352 void CameraDmaRecvIntr(void* arg)
353 {
354 #pragma unused(arg)
355 MI_StopNDma(NDMA_NO);
356
357 if (CAMERA_IsBusy() == TRUE)
358 {
359 if (MI_IsNDmaBusy(NDMA_NO)) // Check whether image transfer is complete
360 {
361 OS_TPrintf("DMA was not done until VBlank.\n");
362 MI_StopNDma(NDMA_NO);
363 }
364 // Start the next frame capture
365 if (wp_pending)
366 {
367 wp_pending = FALSE;
368 }
369 else
370 {
371 // Capture results are not displayed on screen until camera is stable
372 // 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.
373 //
374 if(stabilizedCount > 4)
375 {
376 wp ^= 1;
377 }
378 }
379 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
380 }
381
382 // Display frame rate
383 {
384 static OSTick begin = 0;
385 static int uspf[FPS_SAMPLES] = { 0 };
386 static int count = 0;
387 int i;
388 int sum = 0;
389 OSTick end = OS_GetTick();
390 if (begin) // Leave out the first time
391 {
392 uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
393 count = (count + 1) % FPS_SAMPLES;
394 }
395 begin = end;
396 // Calculate average value
397 for (i = 0; i < FPS_SAMPLES; i++)
398 {
399 if (uspf[i] == 0) break;
400 sum += uspf[i];
401 }
402 if (sum)
403 {
404 int mfps = (int)(1000000000LL * i / sum);
405 PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
406 }
407 }
408 }
409