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