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:: 2009-09-24#$
14   $Rev: 11063 $
15   $Author: okubata_ryoma $
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     // When in NITRO mode, stopped by Panic
90     DEMOCheckRunOnTWL();
91 
92     DEMOInitVRAM();
93     InitializeGraphics();
94     InitializeCamera();
95 
96     DEMOStartDisplay();
97 
98     // DMA is not used in GX (the old DMA conflicts with camera DMA)
99     (void)GX_SetDefaultDMA(GX_DMA_NOT_USE);
100 
101     // Because at first there is a possibility that WRAM might have been allocated to something as per the ROM header, clear it
102     (void)MI_FreeWram_B( MI_WRAM_ARM9 );
103     (void)MI_CancelWram_B( MI_WRAM_ARM9 );
104     (void)MI_FreeWram_C( MI_WRAM_ARM9 );
105     (void)MI_CancelWram_C( MI_WRAM_ARM9 );
106 
107     FS_Init(DMA_NO_FOR_FS);
108 
109     (void)OS_EnableInterrupts();
110 
111     // Load graphics component
112     DSP_OpenStaticComponentGraphics(&file);
113     if(!DSP_LoadGraphics(&file, 0xFF, 0xFF))
114     {
115         OS_TPanic("failed to load graphics DSP-component! (lack of WRAM-B/C)");
116     }
117 
118     // Camera start
119     wp = 0;
120     rp = 1;
121     wp_pending = TRUE;
122     StartRequest = TRUE;
123     CameraIntrVsync(CAMERA_RESULT_SUCCESS);
124     OS_TPrintf("Camera is shooting a movie...\n");
125     OS_TPrintf("Press A Button.\n");
126 
127     while (1)
128     {
129         DEMOReadKey();
130 
131         if (DEMO_IS_TRIG( PAD_BUTTON_START ))
132         {
133             break;    // Quit
134         }
135 
136         if (wp == rp && !IsConvertNow)
137         {
138             rp ^= 1;
139             DC_FlushRange(TmpBuf[rp], BYTES_PER_LINE * CAM_HEIGHT);
140             GX_LoadBG3Scr(TmpBuf[rp], 0, BYTES_PER_LINE * CAM_HEIGHT);
141         }
142 
143         OS_WaitVBlankIntr();           // Waiting for the end of the V-Blank interrupt
144     }
145 
146     OS_TPrintf("demo end.\n");
147 
148     // Unload graphics component
149     DSP_UnloadGraphics();
150     OS_Terminate();
151 }
152 
153 //--------------------------------------------------------------------------------
154 //    V-Blank interrupt process
155 //
VBlankIntr(void)156 void VBlankIntr(void)
157 {
158     OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Checking V-Blank interrupt
159 }
160 
161 // Camera interrupt
CameraIntrError(CAMERAResult result)162 void CameraIntrError(CAMERAResult result)
163 {
164 #pragma unused(result)
165     OS_TPrintf("Error was occurred.\n");
166     // Stopping
167     CAMERA_StopCapture();           // Stop the camera
168     CAMERA_ClearBuffer();           // Clear
169     MI_StopNDma(CAMERA_NEW_DMA_NO); // Stop DMA
170     wp_pending = TRUE;              // Also use same frame next time
171     StartRequest = TRUE;            // Camera restart request
172 }
173 
CameraIntrReboot(CAMERAResult result)174 void CameraIntrReboot(CAMERAResult result)
175 {
176     if(result == CAMERA_RESULT_FATAL_ERROR)
177     {
178         return; // Restore was not possible, even after restarting camera
179     }
180     // Camera start
181     CAMERA_ClearBuffer();
182     MI_StopNDma(CAMERA_NEW_DMA_NO);
183     wp_pending = TRUE;              // Also use same frame next time
184     StartRequest = TRUE;            // Camera restart request
185 }
186 
187 
CameraIntrVsync(CAMERAResult result)188 void CameraIntrVsync(CAMERAResult result)
189 {
190 #pragma unused(result)
191     // The following is processing during V-sync
192     if (StartRequest)
193     {
194         CAMERA_ClearBuffer();
195         CAMERA_StartCapture();
196         StartRequest = FALSE;
197     }
198 
199     if (CAMERA_IsBusy() == FALSE)   // Done executing stop command?
200     {
201     }
202     else
203     {
204         if (MI_IsNDmaBusy(CAMERA_NEW_DMA_NO))    // NOT done capturing last frame?
205         {
206             OS_TPrintf("DMA was not done until VBlank.\n");
207             MI_StopNDma(CAMERA_NEW_DMA_NO);  // Stop DMA
208         }
209         // Start to capture for next frame
210         if (wp_pending)
211         {
212             wp_pending = FALSE;
213         }
214         else
215         {
216             // Change update buffer
217             wp ^= 1;
218             IsConvertNow = TRUE;
219             StartTick = OS_GetTick();
220             (void)DSP_ConvertYuvToRgbAsync(TmpBuf[rp ^1], TmpBuf[rp ^1], CAM_WIDTH * CAM_HEIGHT * sizeof(u16), ConvertCallbackFunc);
221         }
222 
223         CAMERA_DmaRecvAsync(CAMERA_NEW_DMA_NO, TmpBuf[wp], CAMERA_GetBytesAtOnce(CAM_WIDTH), CAMERA_GET_FRAME_BYTES(CAM_WIDTH, CAM_HEIGHT), NULL, NULL);
224     }
225 }
226 
InitializeGraphics()227 static void InitializeGraphics()
228 {
229     // VRAM allocation
230     GX_SetBankForBG(GX_VRAM_BG_128_A);
231     GX_SetBankForSubBG(GX_VRAM_SUB_BG_128_C);
232 
233     GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_5, GX_BG0_AS_2D);
234     GX_SetVisiblePlane( GX_PLANEMASK_BG3 );
235     GXS_SetGraphicsMode( GX_BGMODE_4 );
236     GXS_SetVisiblePlane( GX_PLANEMASK_BG3 );
237 
238     GX_SetBGScrOffset(GX_BGSCROFFSET_0x00000);  // Set screen offset value
239     GX_SetBGCharOffset(GX_BGCHAROFFSET_0x20000);  // Configure character base offset value
240 
241     G2_BlendNone();
242     G2S_BlendNone();
243     GX_Power2DSub(TRUE);    // Turn the sub 2D graphic engine off
244 
245     // Main-BG
246     // BG3: scr 96KB
247     {
248         G2_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
249         G2_SetBG3Priority(2);
250         G2_BG3Mosaic(FALSE);
251     }
252 
253     // Sub-BG
254     // BG3: scr 96KB
255     {
256         G2S_SetBG3ControlDCBmp(GX_BG_SCRSIZE_DCBMP_256x256, GX_BG_AREAOVER_XLU, GX_BG_BMPSCRBASE_0x00000);
257         G2S_SetBG3Priority(2);
258         G2S_BG3Mosaic(FALSE);
259     }
260 }
261 
InitializeCamera(void)262 static void InitializeCamera(void)
263 {
264     CAMERAResult result;
265 
266     result = CAMERA_Init();
267     if(result == CAMERA_RESULT_FATAL_ERROR)
268         OS_TPanic("CAMERA_Init was failed.");
269 
270     result = CAMERA_I2CActivate(CAMERA_SELECT_IN);
271     if (result == CAMERA_RESULT_FATAL_ERROR)
272         OS_TPanic("CAMERA_I2CActivate was failed. (%d)\n", result);
273 
274     // Camera VSYNC interrupt callback
275     CAMERA_SetVsyncCallback(CameraIntrVsync);
276 
277     // Camera error interrupt callback
278     CAMERA_SetBufferErrorCallback(CameraIntrError);
279 
280     // Camera restart completion callback
281     CAMERA_SetRebootCallback(CameraIntrReboot);
282 
283     CAMERA_SetOutputFormat(CAMERA_OUTPUT_YUV);
284     CAMERA_SetTransferLines(CAMERA_GET_MAX_LINES(CAM_WIDTH));
285 }
286 
287 /* Callback function called when YUV to RGB conversion is done */
ConvertCallbackFunc(void)288 static void ConvertCallbackFunc(void)
289 {
290     OS_TPrintf("[Async]time: %d microsec.\n", OS_TicksToMicroSeconds(OS_GetTick() - StartTick));
291     IsConvertNow = FALSE;
292 }
293 
294