1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - demos.TWL - camera - camera-3
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-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 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 u32 stabilizedCount;
37
38 static BOOL switchFlag;
39
40 /////
41 // Triple buffer sequence that assumes the display FPS rate is larger than that for rendering
42 /////
43
44 static int wp; // Buffer while capturing data from camera
45 static int rp; // The buffer being displayed
46 static BOOL wp_pending; // Data capture was cancelled (recapture to same buffer)
47 static GXBGBmpScrBase dispSrc[] =
48 {
49 GX_BG_BMPSCRBASE_0x20000,
50 GX_BG_BMPSCRBASE_0x40000,
51 GX_BG_BMPSCRBASE_0x60000,
52 };
53 static void* dispAddr[] =
54 {
55 (void*)(HW_BG_VRAM + 0x20000),
56 (void*)(HW_BG_VRAM + 0x40000),
57 (void*)(HW_BG_VRAM + 0x60000),
58 };
59 static CAMERASelect current;
DebugReport(void)60 static void DebugReport(void)
61 {
62 const char* const str[] =
63 {
64 "HW_BG_VRAM + 0x20000",
65 "HW_BG_VRAM + 0x40000",
66 "HW_BG_VRAM + 0x60000"
67 };
68 OSIntrMode enabled = OS_DisableInterrupts();
69 int wp_bak = wp;
70 int rp_bak = rp;
71 (void)OS_RestoreInterrupts(enabled);
72 OS_TPrintf("\nCapture to %s\tDisplay from %s\n", str[wp_bak], str[rp_bak]);
73 }
GetNextDispSrc(void)74 static GXBGBmpScrBase GetNextDispSrc(void)
75 {
76 OSIntrMode enabled = OS_DisableInterrupts();
77 GXBGBmpScrBase base;
78 int next = (rp + 1) % 3;
79 if (next != wp) // Next buffer is not in the middle of a write
80 {
81 rp = next;
82 }
83 base = dispSrc[rp];
84 (void)OS_RestoreInterrupts(enabled);
85 //DebugReport();
86 return base;
87 }
GetNextCaptureAddr(void)88 static void* GetNextCaptureAddr(void)
89 {
90 OSIntrMode enabled = OS_DisableInterrupts();
91 void* addr;
92 int next = (wp + 1) % 3;
93 if (wp_pending) // Recapture to the same buffer
94 {
95 wp_pending = FALSE;
96 }
97 else if (next != rp) // Next buffer is not in the middle of a load
98 {
99 // Capture results are not displayed on screen until camera is stable
100 // 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.
101 //
102 if(stabilizedCount > 4)
103 {
104 wp = next;
105 }
106 }
107 else // No buffer exists that can be captured (which is not possible from the FPS perspective)
108 {
109 OS_TPrintf("ERROR: there is no unused frame to capture.\n");
110 }
111 addr = dispAddr[wp];
112 (void)OS_RestoreInterrupts(enabled);
113 //DebugReport();
114 return addr;
115 }
PendingCapture(void)116 static void PendingCapture(void)
117 {
118 wp_pending = TRUE;
119 }
120
121 // Display text (one row only)
122 static u16 text_buffer[ 32 ] ATTRIBUTE_ALIGN(32);
PutString(char * format,...)123 static void PutString( char *format, ... )
124 {
125 u16 *dest = text_buffer;
126 char temp[32+1];
127 int i;
128 va_list va;
129
130 va_start(va, format);
131 (void)OS_VSNPrintf(temp, sizeof(temp), format, va);
132 va_end(va);
133
134 MI_CpuClearFast(text_buffer, sizeof(text_buffer));
135 for (i = 0; i < 32 && temp[i]; i++)
136 {
137 dest[i] = (u16)((u8)temp[i] | (1 << 12));
138 }
139 DC_StoreRange(text_buffer, sizeof(text_buffer));
140 }
141
142 /*---------------------------------------------------------------------------*
143 Name: TwlMain
144
145 Description: Main.
146
147 Arguments: None.
148
149 Returns: None.
150 *---------------------------------------------------------------------------*/
TwlMain()151 void TwlMain()
152 {
153 CAMERAResult result;
154
155 // Initialization
156 OS_Init();
157 OS_InitThread();
158 GX_Init();
159 OS_InitTick();
160 OS_InitAlarm();
161
162 // DMA is not used in GX (the old DMA conflicts with camera DMA)
163 (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
164
165 // Clears VRAM
166 GX_SetBankForLCDC(GX_VRAM_LCDC_A);
167 GX_SetBankForLCDC(GX_VRAM_LCDC_B);
168 GX_SetBankForLCDC(GX_VRAM_LCDC_C);
169 GX_SetBankForLCDC(GX_VRAM_LCDC_D);
170 MI_CpuClearFast((void*)HW_LCDC_VRAM_A, 128 * 1024);
171 MI_CpuClearFast((void*)HW_LCDC_VRAM_B, 128 * 1024);
172 MI_CpuClearFast((void*)HW_LCDC_VRAM_C, 128 * 1024);
173 MI_CpuClearFast((void*)HW_LCDC_VRAM_D, 128 * 1024);
174
175 // Direct bitmap display mode and text display
176 GX_SetBankForBG(GX_VRAM_BG_512_ABCD); // Assign VRAM-A, B, C, and D banks to the background
177 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D);
178 GX_SetVisiblePlane(GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3);
179
180 G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
181 GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000, GX_BG_EXTPLTT_01);
182 G2_SetBG1Priority(1);
183 G2_BG1Mosaic(FALSE);
184
185 wp = 0;
186 rp = 2;
187 wp_pending = TRUE;
188 stabilizedCount = 0;
189 switchFlag = FALSE;
190 G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GetNextDispSrc());
191 G2_SetBG3Priority(3);
192 G2_BG3Mosaic(FALSE);
193
194 // Load text
195 {
196 static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
197 GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
198 GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
199 }
200
201 // V-Blank interrupt settings
202 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
203 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
204 (void)OS_EnableIrq();
205 (void)GX_VBlankIntr(TRUE);
206 (void)OS_EnableInterrupts();
207
208 OS_WaitVBlankIntr();
209 GX_DispOn();
210
211 // Initialize camera
212 current = CAMERA_SELECT_IN;
213 (void)CameraInit();
214
215 // Configure DMA interrupt
216 (void)OS_EnableIrqMask(OS_IE_NDMA1);
217
218 // Camera VSYNC interrupt callback
219 CAMERA_SetVsyncCallback(CameraIntrVsync);
220
221 // Camera error interrupt callback
222 CAMERA_SetBufferErrorCallback(CameraIntrError);
223
224 // Camera restart completion callback
225 CAMERA_SetRebootCallback(CameraIntrReboot);
226
227 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
228 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
229
230 // Start capturing
231 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
232 CAMERA_ClearBuffer();
233 CAMERA_StartCapture();
234 OS_TPrintf("Camera is shooting a movie...\n");
235
236 while (1)
237 {
238 u16 pad;
239 u16 trg;
240 static u16 old = 0xffff;
241 static BOOL standby = FALSE;
242
243 OS_WaitVBlankIntr();
244
245 pad = PAD_Read();
246 trg = (u16)(pad & ~old);
247 old = pad;
248
249 if (trg & PAD_BUTTON_A)
250 {
251 DebugReport();
252 }
253 if (trg & PAD_BUTTON_X)
254 {
255 switchFlag = TRUE;
256 }
257 if (trg & PAD_BUTTON_B)
258 {
259 standby ^= 1;
260 if (standby)
261 {
262 // 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"
263 CAMERA_StopCapture();
264 while(CAMERA_IsBusy())
265 {
266 }
267 MI_StopNDma(NDMA_NO);
268 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
269 if(result == CAMERA_RESULT_FATAL_ERROR)
270 OS_Panic("CAMERA FATAL ERROR\n");
271 }
272 else
273 {
274 result = CAMERA_I2CActivate(current);
275 if(result == CAMERA_RESULT_FATAL_ERROR)
276 OS_Panic("CAMERA FATAL ERROR\n");
277 stabilizedCount = 0;
278 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
279 CAMERA_ClearBuffer();
280 CAMERA_StartCapture();
281 }
282 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
283 }
284 }
285 }
286
287 //--------------------------------------------------------------------------------
288 // V-Blank interrupt process
289 //
VBlankIntr(void)290 void VBlankIntr(void)
291 {
292 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
293 G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GetNextDispSrc());
294 GX_LoadBG1Scr(text_buffer, 0, sizeof(text_buffer));
295 }
296
297 //--------------------------------------------------------------------------------
298 // Camera initialization (only the Init- and I2C-related initialization)
299 //
CameraInit(void)300 BOOL CameraInit(void)
301 {
302 CAMERAResult result;
303 result = CAMERA_Init();
304 if(result == CAMERA_RESULT_FATAL_ERROR)
305 OS_TPanic("CAMERA_Init was failed.");
306 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
307 return FALSE;
308
309 result = CAMERA_I2CActivate(current);
310 if (result == CAMERA_RESULT_FATAL_ERROR)
311 OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
312 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
313 return FALSE;
314 stabilizedCount = 0;
315
316 return TRUE;
317 }
318 //--------------------------------------------------------------------------------
319 // Camera interrupt process (occurs both when there is an error and for Vsync)
320 //
321 #define FPS_SAMPLES 4
CameraIntrError(CAMERAResult result)322 void CameraIntrError(CAMERAResult result)
323 {
324 #pragma unused(result)
325 OS_TPrintf("Error was occurred.\n");
326 // Camera stop processing
327 CAMERA_StopCapture();
328 MI_StopNDma(NDMA_NO);
329 CAMERA_ClearBuffer();
330 PendingCapture(); // Also use same frame next time
331 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
332 CAMERA_StartCapture();
333 }
334
CameraIntrReboot(CAMERAResult result)335 void CameraIntrReboot(CAMERAResult result)
336 {
337 if(result == CAMERA_RESULT_FATAL_ERROR)
338 {
339 return; // Restore was not possible, even after restarting camera
340 }
341 CameraIntrError(result); // DMA synchronization might have drifted, so realign
342 }
343
CameraIntrVsync(CAMERAResult result)344 void CameraIntrVsync(CAMERAResult result)
345 {
346 #pragma unused(result)
347 if(stabilizedCount <= 30)
348 stabilizedCount++;
349 if(switchFlag)
350 {
351 current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
352 OS_TPrintf("call CAMERA_I2CActivate(%s)... ", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
353 result = CAMERA_I2CActivate(current);
354 if(result == CAMERA_RESULT_FATAL_ERROR)
355 OS_Panic("CAMERA FATAL ERROR\n");
356 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
357 stabilizedCount = 0;
358 switchFlag = FALSE;
359 }
360 }
361
CameraDmaRecvIntr(void * arg)362 void CameraDmaRecvIntr(void* arg)
363 {
364 #pragma unused(arg)
365 MI_StopNDma(NDMA_NO);
366
367 if (CAMERA_IsBusy() == TRUE)
368 {
369 if (MI_IsNDmaBusy(NDMA_NO)) // Check whether image transfer is complete
370 {
371 OS_TPrintf("DMA was not done until VBlank.\n");
372 MI_StopNDma(NDMA_NO);
373 }
374 // Start the next frame capture
375 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
376 }
377
378 // Display frame rate
379 {
380 static OSTick begin = 0;
381 static int uspf[FPS_SAMPLES] = { 0 };
382 static int count = 0;
383 int i;
384 int sum = 0;
385 OSTick end = OS_GetTick();
386 if (begin) // Leave out the first time
387 {
388 uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
389 count = (count + 1) % FPS_SAMPLES;
390 }
391 begin = end;
392 // Calculate average value
393 for (i = 0; i < FPS_SAMPLES; i++)
394 {
395 if (uspf[i] == 0) break;
396 sum += uspf[i];
397 }
398 if (sum)
399 {
400 int mfps = (int)(1000000000LL * i / sum);
401 PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
402 }
403 }
404 }
405