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