1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos.TWL - camera - camera-4
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: 9736 $
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 BOOL startRequest = FALSE;
37
38 /////
39 // Sample configuration with double buffer in main memory and 1 layer of VRAM
40 /////
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 u32 stabilizedCount;
46 static BOOL switchFlag;
47
48 static CAMERASelect current;
49 static CAMERAFlip flipIn, flipOut;
50 static u16 buffer[2][WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
DebugReport(void)51 static void DebugReport(void)
52 {
53 OS_TPrintf("\nCapture to No.%d\tDisplay from No.%d\n", wp, rp);
54 }
PendingCapture(void)55 static void PendingCapture(void)
56 {
57 wp_pending = TRUE;
58 }
59
60 // Display text (one line only)
61 static u16 text_buffer[ 32 ] ATTRIBUTE_ALIGN(32);
PutString(char * format,...)62 static void PutString( char *format, ... )
63 {
64 u16 *dest = text_buffer;
65 char temp[32+1];
66 int i;
67 va_list va;
68
69 va_start(va, format);
70 (void)OS_VSNPrintf(temp, sizeof(temp), format, va);
71 va_end(va);
72
73 MI_CpuClearFast(text_buffer, sizeof(text_buffer));
74 for (i = 0; i < 32 && temp[i]; i++)
75 {
76 dest[i] = (u16)((u8)temp[i] | (1 << 12));
77 }
78 DC_StoreRange(text_buffer, sizeof(text_buffer));
79 }
80
81 /*---------------------------------------------------------------------------*
82 Name: TwlMain
83
84 Description: Main
85
86 Arguments: None.
87
88 Returns: None.
89 *---------------------------------------------------------------------------*/
TwlMain()90 void TwlMain()
91 {
92 CAMERAResult result;
93
94 // Initialization
95 OS_Init();
96 OS_InitThread();
97 GX_Init();
98 OS_InitTick();
99 OS_InitAlarm();
100 MI_InitNDmaConfig();
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 // Clear 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, 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 // Camera start (substituted for by interrupt handler)
169 startRequest = TRUE;
170 CameraIntrVsync(CAMERA_RESULT_SUCCESS);
171 OS_TPrintf("Camera is shooting a movie...\n");
172
173 while (1)
174 {
175 u16 pad;
176 u16 trg;
177 static u16 old = 0xffff;
178 static BOOL standby = FALSE;
179
180 OS_WaitVBlankIntr();
181
182 pad = PAD_Read();
183 trg = (u16)(pad & ~old);
184 old = pad;
185
186 if (trg & PAD_BUTTON_Y)
187 {
188 DebugReport();
189 }
190 if (trg & PAD_BUTTON_X)
191 {
192 switchFlag = TRUE;
193 }
194 if (trg & PAD_BUTTON_B)
195 {
196 standby ^= 1;
197 if (standby)
198 {
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 else
210 {
211 result = CAMERA_I2CActivate(current);
212 if(result == CAMERA_RESULT_FATAL_ERROR)
213 OS_Panic("CAMERA FATAL ERROR\n");
214 stabilizedCount = 0;
215 startRequest = TRUE; // Camera restart request
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 startRequest = TRUE; // Camera restart request
322 }
323
CameraIntrReboot(CAMERAResult result)324 void CameraIntrReboot(CAMERAResult result)
325 {
326 if(result == CAMERA_RESULT_FATAL_ERROR)
327 {
328 return; // Restore was not possible, even after restarting camera
329 }
330 CameraIntrError(result); // DMA synchronization might have drifted, so realign
331 }
332
CameraIntrVsync(CAMERAResult result)333 void CameraIntrVsync(CAMERAResult result)
334 {
335 #pragma unused(result)
336 if(stabilizedCount <= 30)
337 stabilizedCount++;
338 if(switchFlag)
339 {
340 current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
341 OS_TPrintf("call CAMERA_I2CActivate(%s)... ", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
342 result = CAMERA_I2CActivate(current);
343 if(result == CAMERA_RESULT_FATAL_ERROR)
344 OS_Panic("CAMERA FATAL ERROR\n");
345 stabilizedCount = 0;
346 switchFlag = FALSE;
347 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
348 }
349 if (startRequest)
350 {
351 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
352 CAMERA_ClearBuffer();
353 CAMERA_StartCapture(); // The CAMERA_IsBusy function will immediately return TRUE because it is being called during a camera VSYNC
354 startRequest = FALSE;
355 }
356 }
357
CameraDmaRecvIntr(void * arg)358 void CameraDmaRecvIntr(void* arg)
359 {
360 #pragma unused(arg)
361 MI_StopNDma(NDMA_NO);
362
363 if (CAMERA_IsBusy() == TRUE)
364 {
365 if (MI_IsNDmaBusy(NDMA_NO)) // Check whether image transfer is complete
366 {
367 OS_TPrintf("DMA was not done until VBlank.\n");
368 MI_StopNDma(NDMA_NO);
369 }
370 // Start the next frame capture
371 if (wp_pending)
372 {
373 wp_pending = FALSE;
374 }
375 else
376 {
377 // Capture results are not displayed on screen until camera is stable
378 // 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.
379 //
380 if(stabilizedCount > 4)
381 {
382 wp ^= 1;
383 }
384 }
385 CAMERA_DmaRecvAsync(NDMA_NO, buffer[wp], CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
386 }
387
388 // Display frame rate
389 {
390 static OSTick begin = 0;
391 static int uspf[FPS_SAMPLES] = { 0 };
392 static int count = 0;
393 int i;
394 int sum = 0;
395 OSTick end = OS_GetTick();
396 if (begin) // Leave out the first time
397 {
398 uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
399 count = (count + 1) % FPS_SAMPLES;
400 }
401 begin = end;
402 // Calculate average value
403 for (i = 0; i < FPS_SAMPLES; i++)
404 {
405 if (uspf[i] == 0) break;
406 sum += uspf[i];
407 }
408 if (sum)
409 {
410 int mfps = (int)(1000000000LL * i / sum);
411 PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
412 }
413 }
414 }
415