1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - DSP - demos - yuvToRgb
3   File:     main.c
4 
5   Copyright 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-08#$
14   $Rev: 9562 $
15   $Author: kitase_hirotake $
16 *---------------------------------------------------------------------------*/
17 
18 /*---------------------------------------------------------------------------
19     This demo gets an image in YUV422 format from the camera and uses the DSP to convert to RGB555 and display it on screen.
20 
21 
22     Exit with the START Button.
23  ----------------------------------------------------------------------------*/
24 
25 #include <twl.h>
26 #include <twl/dsp.h>
27 
28 #include <twl/camera.h>
29 
30 #include <DEMO.h>
31 #include <twl/dsp/common/graphics.h>
32 
33 /* Settings */
34 #define DMA_NO_FOR_FS          3    // For FS_Init
35 #define CAMERA_NEW_DMA_NO      1    // New DMA number used for CAMERA
36 
37 #define CAM_WIDTH   256            // Width of image the camera gets
38 #define CAM_HEIGHT  192            // Height of image the camera gets
39 
40 #define LINES_AT_ONCE   CAMERA_GET_MAX_LINES(CAM_WIDTH)     // Number of lines transferred in one cycle
41 #define BYTES_PER_LINE  CAMERA_GET_LINE_BYTES(CAM_WIDTH)    // Number of bytes in one line's transfer
42 
43 /*---------------------------------------------------------------------------*
44  Prototype Declarations
45 *---------------------------------------------------------------------------*/
46 void VBlankIntr(void);
47 static void CameraIntrVsync(CAMERAResult result);
48 static void CameraIntrError(CAMERAResult result);
49 static void CameraIntrReboot(CAMERAResult result);
50 static void InitializeGraphics(void);
51 static void InitializeCamera(void);
52 static void WriteScreenBuffer(u16 *data, u32 width, u32 height, u16 *scr);
53 static void ConvertCallbackFunc(void);
54 
55 /*---------------------------------------------------------------------------*
56  Internal Variable Definitions
57 *---------------------------------------------------------------------------*/
58 // Screen buffers for main and sub-screens
59 // Buffer that stores the image obtained by the camera as well as the DSP conversion results
60 static u16 TmpBuf[2][CAM_WIDTH * CAM_HEIGHT] ATTRIBUTE_ALIGN(32);
61 
62 static BOOL StartRequest = FALSE;
63 static OSTick StartTick;       // Variable for measuring DSP processing time
64 
65 static int wp;                  // Buffer while capturing data from camera
66 static int rp;                  // Buffer most recently copied to VRAM
67 static BOOL wp_pending;         // Data capture was cancelled (recapture to same buffer)
68 
69 static BOOL IsConvertNow = FALSE;      // Whether YUV to RGB conversion is underway
70 
71 /*---------------------------------------------------------------------------*
72  Name:         TwlMain
73 
74  Description:  Initialization and main loop.
75 
76  Arguments:    None.
77 
78  Returns:      None.
79 *---------------------------------------------------------------------------*/
TwlMain(void)80 void TwlMain(void)
81 {
82     FSFile file;
83 
84     DEMOInitCommon();
85     OS_InitThread();
86     OS_InitTick();
87     OS_InitAlarm();
88 
89     DEMOInitVRAM();
90     InitializeGraphics();
91     InitializeCamera();
92 
93     DEMOStartDisplay();
94 
95     // DMA is not used in GX (the old DMA conflicts with camera DMA)
96     (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
97 
98     // Because at first there is a possibility that WRAM might have been allocated to something as per the ROM header, clear it
99     (void)MI_FreeWram_B( MI_WRAM_ARM9 );
100     (void)MI_CancelWram_B( MI_WRAM_ARM9 );
101     (void)MI_FreeWram_C( MI_WRAM_ARM9 );
102     (void)MI_CancelWram_C( MI_WRAM_ARM9 );
103 
104     FS_Init(DMA_NO_FOR_FS);
105 
106     (void)OS_EnableInterrupts();
107 
108     // Load graphics component
109     DSP_OpenStaticComponentGraphics(&file);
110     if(!DSP_LoadGraphics(&file, 0xFF, 0xFF))
111     {
112         OS_TPanic("failed to load graphics DSP-component! (lack of WRAM-B/C)");
113     }
114 
115     // Camera start
116     wp = 0;
117     rp = 1;
118     wp_pending = TRUE;
119     StartRequest = TRUE;
120     CameraIntrVsync(CAMERA_RESULT_SUCCESS);
121     OS_TPrintf("Camera is shooting a movie...\n");
122     OS_TPrintf("Press A Button.\n");
123 
124     while (1)
125     {
126         DEMOReadKey();
127 
128         if (DEMO_IS_TRIG( PAD_BUTTON_START ))
129         {
130             break;    // Quit
131         }
132 
133         if (wp == rp && !IsConvertNow)
134         {
135             rp ^= 1;
136             DC_FlushRange(TmpBuf[rp], BYTES_PER_LINE * CAM_HEIGHT);
137             GX_LoadBG3Scr(TmpBuf[rp], 0, BYTES_PER_LINE * CAM_HEIGHT);
138         }
139 
140         OS_WaitVBlankIntr();           // Waiting for the end of the V-Blank interrupt
141     }
142 
143     OS_TPrintf("demo end.\n");
144 
145     // Unload graphics component
146     DSP_UnloadGraphics();
147     OS_Terminate();
148 }
149 
150 //--------------------------------------------------------------------------------
151 //    V-Blank interrupt process
152 //
VBlankIntr(void)153 void VBlankIntr(void)
154 {
155     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
156 }
157 
158 // Camera interrupt
CameraIntrError(CAMERAResult result)159 void CameraIntrError(CAMERAResult result)
160 {
161 #pragma unused(result)
162     OS_TPrintf("Error was occurred.\n");
163     // Stopping
164     CAMERA_StopCapture();           // Stop the camera
165     CAMERA_ClearBuffer();           // Clear
166     MI_StopNDma(CAMERA_NEW_DMA_NO); // Stop DMA
167     wp_pending = TRUE;              // Also use same frame next time
168     StartRequest = TRUE;            // Camera restart request
169 }
170 
CameraIntrReboot(CAMERAResult result)171 void CameraIntrReboot(CAMERAResult result)
172 {
173     if(result == CAMERA_RESULT_FATAL_ERROR)
174     {
175         return; // Restore was not possible, even after restarting camera
176     }
177     // Camera start
178     CAMERA_ClearBuffer();
179     MI_StopNDma(CAMERA_NEW_DMA_NO);
180     wp_pending = TRUE;              // Also use same frame next time
181     StartRequest = TRUE;            // Camera restart request
182 }
183 
184 
CameraIntrVsync(CAMERAResult result)185 void CameraIntrVsync(CAMERAResult result)
186 {
187 #pragma unused(result)
188     // The following is processing during V-sync
189     if (StartRequest)
190     {
191         CAMERA_ClearBuffer();
192         CAMERA_StartCapture();
193         StartRequest = FALSE;
194     }
195 
196     if (CAMERA_IsBusy() == FALSE)   // Done executing stop command?
197     {
198     }
199     else
200     {
201         if (MI_IsNDmaBusy(CAMERA_NEW_DMA_NO))    // NOT done capturing last frame?
202         {
203             OS_TPrintf("DMA was not done until VBlank.\n");
204             MI_StopNDma(CAMERA_NEW_DMA_NO);  // Stop DMA
205         }
206         // Start to capture for next frame
207         if (wp_pending)
208         {
209             wp_pending = FALSE;
210         }
211         else
212         {
213             // Change update buffer
214             wp ^= 1;
215             IsConvertNow = TRUE;
216             StartTick = OS_GetTick();
217             (void)DSP_ConvertYuvToRgbAsync(TmpBuf[rp ^1], TmpBuf[rp ^1], CAM_WIDTH * CAM_HEIGHT * sizeof(u16), ConvertCallbackFunc);
218         }
219 
220         CAMERA_DmaRecvAsync(CAMERA_NEW_DMA_NO, TmpBuf[wp], CAMERA_GetBytesAtOnce(CAM_WIDTH), CAMERA_GET_FRAME_BYTES(CAM_WIDTH, CAM_HEIGHT), NULL, NULL);
221     }
222 }
223 
InitializeGraphics()224 static void InitializeGraphics()
225 {
226     // VRAM allocation
227     GX_SetBankForBG(GX_VRAM_BG_128_A);
228     GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
229 
230     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_5, GX_BG0_AS_2D);
231     GX_SetVisiblePlane( GX_PLANEMASK_BG3 );
232     GXS_SetGraphicsMode( GX_BGMODE_4 );
233     GXS_SetVisiblePlane( GX_PLANEMASK_BG3 );
234 
235     GX_SetBGScrOffset(GX_BGSCROFFSET_0x00000);  // Set screen offset value
236     GX_SetBGCharOffset(GX_BGCHAROFFSET_0x20000);  // Configure character base offset value
237 
238     G2_BlendNone();
239     G2S_BlendNone();
240     GX_Power2DSub(TRUE);    // Turn the sub 2D graphic engine off
241 
242     // Main-BG
243     // BG3: scr 96KB
244     {
245         G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
246         G2_SetBG3Priority(2);
247         G2_BG3Mosaic(FALSE);
248     }
249 
250     // Sub-BG
251     // BG3: scr 96KB
252     {
253         G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
254         G2S_SetBG3Priority(2);
255         G2S_BG3Mosaic(FALSE);
256     }
257 }
258 
InitializeCamera(void)259 static void InitializeCamera(void)
260 {
261     CAMERAResult result;
262 
263     result = CAMERA_Init();
264     if(result == CAMERA_RESULT_FATAL_ERROR)
265         OS_TPanic("CAMERA_Init was failed.");
266 
267     result = CAMERA_I2CActivate(CAMERA_SELECT_IN);
268     if (result == CAMERA_RESULT_FATAL_ERROR)
269         OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
270 
271     // Camera VSYNC interrupt callback
272     CAMERA_SetVsyncCallback(CameraIntrVsync);
273 
274     // Camera error interrupt callback
275     CAMERA_SetBufferErrorCallback(CameraIntrError);
276 
277     // Camera restart completion callback
278     CAMERA_SetRebootCallback(CameraIntrReboot);
279 
280     CAMERA_SetOutputFormat(CAMERA_OUTPUT_YUV);
281     CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(CAM_WIDTH));
282 }
283 
284 /* Callback function called when YUV to RGB conversion is done*/
ConvertCallbackFunc(void)285 static void ConvertCallbackFunc(void)
286 {
287     OS_TPrintf("[Async]time: %d microsec.\n", OS_TicksToMicroSeconds(OS_GetTick() - StartTick));
288     IsConvertNow = FALSE;
289 }
290