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