1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos.TWL - camera - camera-2
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:: 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 NDMA_IE OS_IE_NDMA1 // Corresponding interrupt
24 #define WIDTH 256 // Image width
25 #define HEIGHT 192 // Image height
26
27 #define LINES_AT_ONCE CAMERA_GET_MAX_LINES(WIDTH) // Number of lines transferred in one cycle
28 #define BYTES_PER_LINE CAMERA_GET_LINE_BYTES(WIDTH) // Number of bytes in one line's transfer
29
30 static void VBlankIntr(void);
31 static BOOL CameraInit(void);
32 static void CameraDmaIntr(void);
33 static void CameraIntrVsync(CAMERAResult result);
34 static void CameraIntrError(CAMERAResult result);
35 static void CameraIntrReboot(CAMERAResult result);
36
37 static int lineNumber = 0;
38 static BOOL effectFlag = FALSE;
39 static BOOL switchFlag = FALSE;
40 static BOOL standbyFlag = FALSE;
41 static u16 pipeBuffer[BYTES_PER_LINE * LINES_AT_ONCE / sizeof(u16)] ATTRIBUTE_ALIGN(32);
42 static CAMERASelect current;
43
44
45 static int wp; // Buffer while capturing data from camera
46 static int rp; // Buffer most recently copied to VRAM
47 static BOOL wp_pending; // Data capture was cancelled (recapture to same buffer)
48 static u32 stabilizedCount;
49 static u16 buffer[2][WIDTH*HEIGHT] ATTRIBUTE_ALIGN(32);
PendingCapture(void)50 static void PendingCapture(void)
51 {
52 wp_pending = TRUE;
53 }
54
55 // Character display
PutString(char * format,...)56 static void PutString( char *format, ... )
57 {
58 u16 *dest = G2_GetBG1ScrPtr();
59 char temp[32+1];
60 int i;
61 va_list va;
62
63 va_start(va, format);
64 (void)OS_VSNPrintf(temp, sizeof(temp), format, va);
65 va_end(va);
66
67 for (i = 0; i < 32 && temp[i]; i++)
68 {
69 dest[i] = (u16)((u8)temp[i] | (1 << 12));
70 }
71 }
72
73 /*---------------------------------------------------------------------------*
74 Name: TwlMain
75
76 Description: Main
77
78 Arguments: None.
79
80 Returns: None.
81 *---------------------------------------------------------------------------*/
TwlMain()82 void TwlMain()
83 {
84 // Initialization
85 OS_Init();
86 OS_InitThread();
87 GX_Init();
88 OS_InitTick();
89 OS_InitAlarm();
90
91 // When in NITRO mode, stopped by Panic
92 DEMOCheckRunOnTWL();
93
94 // DMA is not used in GX (the old DMA conflicts with camera DMA)
95 (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
96
97 // Clears VRAM
98 GX_SetBankForLCDC(GX_VRAM_LCDC_A);
99 GX_SetBankForLCDC(GX_VRAM_LCDC_B);
100 MI_CpuClearFast((void*)HW_LCDC_VRAM_A, 128 * 1024);
101 MI_CpuClearFast((void*)HW_LCDC_VRAM_B, 128 * 1024);
102
103 // Direct bitmap display mode and text display
104 GX_SetBankForBG(GX_VRAM_BG_256_AB); // Allocate VRAM-A and B banks to BG
105 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D);
106 GX_SetVisiblePlane(GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3);
107
108 G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
109 GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000, GX_BG_EXTPLTT_01);
110 G2_SetBG1Priority(1);
111 G2_BG1Mosaic(FALSE);
112
113 G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x20000);
114 G2_SetBG3Priority(3);
115 G2_BG3Mosaic(FALSE);
116
117 // Load text
118 {
119 static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
120 GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
121 GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
122 }
123 wp = 0;
124 rp = 1;
125 wp_pending = TRUE;
126 stabilizedCount = 0;
127
128 // V-Blank interrupt settings
129 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
130 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
131 (void)OS_EnableIrq();
132 (void)GX_VBlankIntr(TRUE);
133 (void)OS_EnableInterrupts();
134
135 OS_WaitVBlankIntr();
136 GX_DispOn();
137
138 // Initialize camera
139 current = CAMERA_SELECT_IN;
140 (void)CameraInit();
141
142 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
143 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
144
145 // Configure DMA interrupt
146 OS_SetIrqFunction(NDMA_IE, CameraDmaIntr);
147 (void)OS_EnableIrqMask(NDMA_IE);
148
149 // Camera VSYNC interrupt callback
150 CAMERA_SetVsyncCallback(CameraIntrVsync);
151
152 // Camera error interrupt callback
153 CAMERA_SetBufferErrorCallback(CameraIntrError);
154
155 // Camera restart completion callback
156 CAMERA_SetRebootCallback(CameraIntrReboot);
157
158 // DMA start (enabled forever unless explicitly stopped)
159 MI_StopNDma(NDMA_NO);
160 CAMERA_DmaPipeInfinity(NDMA_NO, pipeBuffer, CAMERA_GetBytesAtOnce(WIDTH), NULL, NULL);
161
162 // Camera start
163 lineNumber = 0;
164 CAMERA_ClearBuffer();
165 CAMERA_StartCapture();
166 OS_TPrintf("Camera is shooting a movie...\n");
167
168 while (1)
169 {
170 u16 pad;
171 u16 trg;
172 static u16 old = 0xffff;
173
174 OS_WaitVBlankIntr();
175
176 if (wp == rp)
177 {
178 rp ^= 1;
179 GX_LoadBG3Scr(buffer[rp], 0, BYTES_PER_LINE * HEIGHT);
180 DC_InvalidateRange(buffer[rp], BYTES_PER_LINE * HEIGHT);
181 }
182
183 pad = PAD_Read();
184 trg = (u16)(pad & ~old);
185 old = pad;
186
187 if (trg & PAD_BUTTON_A)
188 {
189 effectFlag ^= 1;
190 OS_TPrintf("Effect %s\n", effectFlag ? "ON" : "OFF");
191 }
192 if (trg & PAD_BUTTON_X)
193 {
194 current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
195 switchFlag = TRUE;
196 }
197 if (trg & PAD_BUTTON_B)
198 {
199 standbyFlag ^= 1;
200
201 if(standbyFlag)
202 {
203 switchFlag = TRUE;
204 }
205 else
206 {
207 CAMERAResult result;
208
209 OS_TPrintf("call CAMERA_I2CActivate(%s)\n", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
210 result = CAMERA_I2CActivateAsync(current, NULL, NULL);
211 if(result == CAMERA_RESULT_FATAL_ERROR)
212 OS_Panic("CAMERA FATAL ERROR\n");
213 stabilizedCount = 0;
214 }
215 }
216 }
217 }
218
219 //--------------------------------------------------------------------------------
220 // V-Blank interrupt process
221 //
VBlankIntr(void)222 void VBlankIntr(void)
223 {
224 OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
225 }
226
227 //--------------------------------------------------------------------------------
228 // Camera initialization (only the Init- and I2C-related initialization)
229 //
CameraInit(void)230 BOOL CameraInit(void)
231 {
232 CAMERAResult result;
233 result = CAMERA_Init();
234 if(result == CAMERA_RESULT_FATAL_ERROR)
235 OS_TPanic("CAMERA_Init was failed.");
236 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
237 return FALSE;
238
239 result = CAMERA_I2CActivate(current);
240 if (result == CAMERA_RESULT_FATAL_ERROR)
241 OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
242 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
243 return FALSE;
244 stabilizedCount = 0;
245
246 return TRUE;
247 }
248
249 //--------------------------------------------------------------------------------
250 // DMA interrupt process
251 //
252 #define FPS_SAMPLES 4
CameraDmaIntr(void)253 void CameraDmaIntr(void)
254 {
255 static BOOL effect = FALSE;
256 CAMERAResult result;
257
258 OS_SetIrqCheckFlag(NDMA_IE);
259 OS_SetIrqFunction(NDMA_IE, CameraDmaIntr);
260
261 // Process as required and copy to frame buffer
262 if (effect) // Invert negative/positive sign
263 {
264 int i;
265 u32 *src = (u32*)pipeBuffer;
266 u32 *dest = (u32*)buffer[wp] + lineNumber * WIDTH / 2;
267 for (i = 0; i < WIDTH * LINES_AT_ONCE / 2; i++)
268 {
269 dest[i] = ~src[i] | 0x80008000;
270 }
271 }
272 else
273 {
274 MI_CpuCopyFast(pipeBuffer, (u16*)buffer[wp] + lineNumber * WIDTH, sizeof(pipeBuffer));
275 }
276 DC_InvalidateRange(pipeBuffer, sizeof(pipeBuffer));
277
278 lineNumber += LINES_AT_ONCE;
279 if (lineNumber >= HEIGHT)
280 {
281 static OSTick begin = 0;
282 static int uspf[FPS_SAMPLES] = { 0 };
283 static int count = 0;
284 int i;
285 int sum = 0;
286 OSTick end = OS_GetTick();
287 if (begin) // Leave out the first time
288 {
289 uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
290 count = (count + 1) % FPS_SAMPLES;
291 }
292 begin = end;
293 // Calculate average value
294 for (i = 0; i < FPS_SAMPLES; i++)
295 {
296 if (uspf[i] == 0) break;
297 sum += uspf[i];
298 }
299 if (sum)
300 {
301 int mfps = (int)(1000000000LL * i / sum);
302 PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
303 }
304
305 if (switchFlag)
306 {
307 if (standbyFlag)
308 {
309 OS_TPrintf("call CAMERA_I2CActivate(CAMERA_SELECT_NONE)\n");
310 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
311 if(result == CAMERA_RESULT_FATAL_ERROR)
312 OS_Panic("CAMERA FATAL ERROR\n");
313 }
314 else
315 {
316 OS_TPrintf("call CAMERA_I2CActivate(%s)\n", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
317 result = CAMERA_I2CActivateAsync(current, NULL, NULL);
318 if(result == CAMERA_RESULT_FATAL_ERROR)
319 OS_Panic("CAMERA FATAL ERROR\n");
320 stabilizedCount = 0;
321 }
322 switchFlag = FALSE;
323 }
324 effect = effectFlag;
325
326 // Switch buffers
327 if (wp_pending)
328 {
329 wp_pending = FALSE;
330 }
331 else
332 {
333 // Capture results are not displayed on screen until camera is stable
334 // 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.
335 //
336 if(stabilizedCount > 4)
337 {
338 wp ^= 1;
339 }
340 }
341
342 lineNumber = 0;
343 }
344 }
345
CameraIntrVsync(CAMERAResult result)346 void CameraIntrVsync(CAMERAResult result)
347 {
348 #pragma unused(result)
349 if(stabilizedCount <= 30)
350 stabilizedCount++;
351 }
352
353 //--------------------------------------------------------------------------------
354 // Camera interrupt process (Generated when there is an error and for Vsync)
355 //
CameraIntrError(CAMERAResult result)356 void CameraIntrError(CAMERAResult result)
357 {
358 #pragma unused(result)
359 OS_TPrintf("Error was occurred.\n");
360
361 // Stop the camera
362 CAMERA_StopCapture();
363 lineNumber = 0;
364 wp_pending = TRUE; // Also use same frame next time
365 // Restart the camera
366 CAMERA_ClearBuffer();
367 CAMERA_StartCapture();
368 }
369
CameraIntrReboot(CAMERAResult result)370 void CameraIntrReboot(CAMERAResult result)
371 {
372 if(result == CAMERA_RESULT_FATAL_ERROR)
373 {
374 return; // Recovery was not possible, even after restarting camera
375 }
376 CameraIntrError(result); // DMA synchronization might have drifted, so realign
377 }
378