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