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-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 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 MI_InitNDmaConfig();
162
163 // DMA is not used in GX (the old DMA conflicts with camera DMA)
164 (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
165
166 // Clears VRAM
167 GX_SetBankForLCDC(GX_VRAM_LCDC_A);
168 GX_SetBankForLCDC(GX_VRAM_LCDC_B);
169 GX_SetBankForLCDC(GX_VRAM_LCDC_C);
170 GX_SetBankForLCDC(GX_VRAM_LCDC_D);
171 MI_CpuClearFast((void*)HW_LCDC_VRAM_A, 128 * 1024);
172 MI_CpuClearFast((void*)HW_LCDC_VRAM_B, 128 * 1024);
173 MI_CpuClearFast((void*)HW_LCDC_VRAM_C, 128 * 1024);
174 MI_CpuClearFast((void*)HW_LCDC_VRAM_D, 128 * 1024);
175
176 // Direct bitmap display mode and text display
177 GX_SetBankForBG(GX_VRAM_BG_512_ABCD); // Assign VRAM-A, B, C, and D banks to the background
178 GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D);
179 GX_SetVisiblePlane(GX_PLANEMASK_BG1 | GX_PLANEMASK_BG3);
180
181 G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16,
182 GX_BG_SCRBASE_0x0000, GX_BG_CHARBASE_0x04000, GX_BG_EXTPLTT_01);
183 G2_SetBG1Priority(1);
184 G2_BG1Mosaic(FALSE);
185
186 wp = 0;
187 rp = 2;
188 wp_pending = TRUE;
189 stabilizedCount = 0;
190 switchFlag = FALSE;
191 G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GetNextDispSrc());
192 G2_SetBG3Priority(3);
193 G2_BG3Mosaic(FALSE);
194
195 // Load text
196 {
197 static const GXRgb pal[16] = { GX_RGB(0, 0, 0), GX_RGB(31, 31, 31), };
198 GX_LoadBG1Char(DEMOAsciiChr, 0x00000, sizeof(DEMOAsciiChr));
199 GX_LoadBGPltt(pal, 0x0000, sizeof(pal));
200 }
201
202 // V-Blank interrupt settings
203 OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr);
204 (void)OS_EnableIrqMask(OS_IE_V_BLANK);
205 (void)OS_EnableIrq();
206 (void)GX_VBlankIntr(TRUE);
207 (void)OS_EnableInterrupts();
208
209 OS_WaitVBlankIntr();
210 GX_DispOn();
211
212 // Initialize camera
213 current = CAMERA_SELECT_IN;
214 (void)CameraInit();
215
216 // Configure DMA interrupt
217 (void)OS_EnableIrqMask(OS_IE_NDMA1);
218
219 // Camera VSYNC interrupt callback
220 CAMERA_SetVsyncCallback(CameraIntrVsync);
221
222 // Camera error interrupt callback
223 CAMERA_SetBufferErrorCallback(CameraIntrError);
224
225 // Camera restart completion callback
226 CAMERA_SetRebootCallback(CameraIntrReboot);
227
228 CAMERA_SetOutputFormat(CAMERA_OUTPUT_RGB);
229 CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(WIDTH));
230
231 // Start capturing
232 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
233 CAMERA_ClearBuffer();
234 CAMERA_StartCapture();
235 OS_TPrintf("Camera is shooting a movie...\n");
236
237 while (1)
238 {
239 u16 pad;
240 u16 trg;
241 static u16 old = 0xffff;
242 static BOOL standby = FALSE;
243
244 OS_WaitVBlankIntr();
245
246 pad = PAD_Read();
247 trg = (u16)(pad & ~old);
248 old = pad;
249
250 if (trg & PAD_BUTTON_A)
251 {
252 DebugReport();
253 }
254 if (trg & PAD_BUTTON_X)
255 {
256 switchFlag = TRUE;
257 }
258 if (trg & PAD_BUTTON_B)
259 {
260 standby ^= 1;
261 if (standby)
262 {
263 // 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"
264 CAMERA_StopCapture();
265 while(CAMERA_IsBusy())
266 {
267 }
268 MI_StopNDma(NDMA_NO);
269 result = CAMERA_I2CActivate(CAMERA_SELECT_NONE);
270 if(result == CAMERA_RESULT_FATAL_ERROR)
271 OS_Panic("CAMERA FATAL ERROR\n");
272 }
273 else
274 {
275 result = CAMERA_I2CActivate(current);
276 if(result == CAMERA_RESULT_FATAL_ERROR)
277 OS_Panic("CAMERA FATAL ERROR\n");
278 stabilizedCount = 0;
279 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
280 CAMERA_ClearBuffer();
281 CAMERA_StartCapture();
282 }
283 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
284 }
285 }
286 }
287
288 //--------------------------------------------------------------------------------
289 // V-Blank interrupt process
290 //
VBlankIntr(void)291 void VBlankIntr(void)
292 {
293 OS_SetIrqCheckFlag(OS_IE_V_BLANK);
294 G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GetNextDispSrc());
295 GX_LoadBG1Scr(text_buffer, 0, sizeof(text_buffer));
296 }
297
298 //--------------------------------------------------------------------------------
299 // Camera initialization (only the Init- and I2C-related initialization)
300 //
CameraInit(void)301 BOOL CameraInit(void)
302 {
303 CAMERAResult result;
304 result = CAMERA_Init();
305 if(result == CAMERA_RESULT_FATAL_ERROR)
306 OS_TPanic("CAMERA_Init was failed.");
307 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
308 return FALSE;
309
310 result = CAMERA_I2CActivate(current);
311 if (result == CAMERA_RESULT_FATAL_ERROR)
312 OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
313 if(result == CAMERA_RESULT_ILLEGAL_STATUS)
314 return FALSE;
315 stabilizedCount = 0;
316
317 return TRUE;
318 }
319 //--------------------------------------------------------------------------------
320 // Camera interrupt process (occurs both when there is an error and for Vsync)
321 //
322 #define FPS_SAMPLES 4
CameraIntrError(CAMERAResult result)323 void CameraIntrError(CAMERAResult result)
324 {
325 #pragma unused(result)
326 OS_TPrintf("Error was occurred.\n");
327 // Camera stop processing
328 CAMERA_StopCapture();
329 MI_StopNDma(NDMA_NO);
330 CAMERA_ClearBuffer();
331 PendingCapture(); // Also use same frame next time
332 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
333 CAMERA_StartCapture();
334 }
335
CameraIntrReboot(CAMERAResult result)336 void CameraIntrReboot(CAMERAResult result)
337 {
338 if(result == CAMERA_RESULT_FATAL_ERROR)
339 {
340 return; // Restore was not possible, even after restarting camera
341 }
342 CameraIntrError(result); // DMA synchronization might have drifted, so realign
343 }
344
CameraIntrVsync(CAMERAResult result)345 void CameraIntrVsync(CAMERAResult result)
346 {
347 #pragma unused(result)
348 if(stabilizedCount <= 30)
349 stabilizedCount++;
350 if(switchFlag)
351 {
352 current = (current == CAMERA_SELECT_IN ? CAMERA_SELECT_OUT : CAMERA_SELECT_IN);
353 OS_TPrintf("call CAMERA_I2CActivate(%s)... ", (current == CAMERA_SELECT_IN ? "CAMERA_SELECT_IN" : "CAMERA_SELECT_OUT"));
354 result = CAMERA_I2CActivate(current);
355 if(result == CAMERA_RESULT_FATAL_ERROR)
356 OS_Panic("CAMERA FATAL ERROR\n");
357 OS_TPrintf("%s\n", result == CAMERA_RESULT_SUCCESS ? "SUCCESS" : "FAILED");
358 stabilizedCount = 0;
359 switchFlag = FALSE;
360 }
361 }
362
CameraDmaRecvIntr(void * arg)363 void CameraDmaRecvIntr(void* arg)
364 {
365 #pragma unused(arg)
366 MI_StopNDma(NDMA_NO);
367
368 if (CAMERA_IsBusy() == TRUE)
369 {
370 if (MI_IsNDmaBusy(NDMA_NO)) // Check whether image transfer is complete
371 {
372 OS_TPrintf("DMA was not done until VBlank.\n");
373 MI_StopNDma(NDMA_NO);
374 }
375 // Start the next frame capture
376 CAMERA_DmaRecvAsync(NDMA_NO, GetNextCaptureAddr(), CAMERA_GetBytesAtOnce(WIDTH), CAMERA_GET_FRAME_BYTES(WIDTH, HEIGHT), CameraDmaRecvIntr, NULL);
377 }
378
379 // Display frame rate
380 {
381 static OSTick begin = 0;
382 static int uspf[FPS_SAMPLES] = { 0 };
383 static int count = 0;
384 int i;
385 int sum = 0;
386 OSTick end = OS_GetTick();
387 if (begin) // Leave out the first time
388 {
389 uspf[count] = (int)OS_TicksToMicroSeconds(end - begin);
390 count = (count + 1) % FPS_SAMPLES;
391 }
392 begin = end;
393 // Calculate average value
394 for (i = 0; i < FPS_SAMPLES; i++)
395 {
396 if (uspf[i] == 0) break;
397 sum += uspf[i];
398 }
399 if (sum)
400 {
401 int mfps = (int)(1000000000LL * i / sum);
402 PutString("%2d.%03d fps", mfps / 1000, mfps % 1000);
403 }
404 }
405 }
406