环境:ads2.2+ARM9 +s3c2410 注意:由于编译器(ads1.2或2.2)对全局变量初始化为0的不完全支持,有时必须手动初始化为0,切记!!! 一、ucos II移植到ARM9 s3c2410 可从官网下载移植代码,基本无需改动。 在os_cpu_a.s中的函数UCOS_IRQHandler中的bl OSIntEnter和bl C_IRQHandler之间插入如下代码(见邵贝贝,第2版,第104页的说明:L3.18(4) ): ldr r0, =OSIntNesting ldrb r0,[r0] cmp r0,#1 bne XX ldr r0,=OSTCBCur ldr r1,[r0] str sp,[r1] ; store sp in preempted tasks's TCB XX 二、ucGui 390移植到ARM9 s3c2410 1. Lcd驱动: 1) 画点函数: 对dm2410实验板上的lcd,左上为原点(0,0),函数如下: void LCD2410_SetPixel(int xp, int yp, U16 color, int dindex) { *(pLCDBuffer565 + SCREEN_WIDTH*yp + xp) = color; } 为了达到更快的显示速度,别忘了开启Cache!!! 2)LCD控制器的初始化,对2410函数如下: int LCD2410_Init(void) { if(!isLcdInit) { InitLcdPort(); InitLcdRegs(); isLcdInit = 1; return 0; } return 1; } void InitLcdPort(void) { // LCD port initialize. s2410IOP->GPCUP = 0xFFFFFFFF; s2410IOP->GPCCON = 0xAAAAAAAA; s2410IOP->GPDUP = 0xFFFFFFFF; s2410IOP->GPDCON = 0xAAAAAAAA; s2410IOP->GPGCON &= ~(3 << 8); /* Set LCD_PWREN as output */ s2410IOP->GPGCON |= (1 << 8); s2410IOP->GPGDAT |= (1 << 4); //* Backlight ON } void InitLcdRegs(void) { s2410LCD->LCDCON1 = (CLKVAL_TFT << 8) | //* VCLK = HCLK / ((CLKVAL + 1) * 2) -> About 7 Mhz (EACH_FRAME << 7) | //* 0 : Each Frame (3 << 5) | // TFT LCD Pannel (12 << 1) | //Y: // 16bpp Mode (0 << 0) ; // Disable LCD Output s2410LCD->LCDCON2 = (VBPD << 24) | //* VBPD : ((32-1)&0xff) = 0x1f (LINEVAL_TFT << 14) | //* LINEVAL_TFT : 480 - 1 (VFPD << 6) | //* VFPD : ((11-1)&0xff) = 0xa (VSPW << 0) ; //* VSPW : ((2-1) &0x3f) = 0x1 s2410LCD->LCDCON3 = (HBPD << 19) | //* HBPD : ((88-1)&0x7f) (HOZVAL_TFT << 8) | //* HOZVAL_TFT : 800 - 1 (HFPD << 0) ; //* HFPD : ((40-1)&0xff) s2410LCD->LCDCON4 = (MVAL << 8) | //* MVAL : 13 (HSPW << 0) ; //* HSPW : ((128-1)&0xff) s2410LCD->LCDCON5 = (0 << 12) | // BPP24BL : LSB valid (1 << 11) | // FRM565 MODE : 5:5:5:1 Format (0 << 10) | // INVVCLK : VCLK Falling Edge (1 << 9) | // INVVLINE : Inverted Polarity (1 << 8) | // INVVFRAME : Inverted Polarity (0 << 7) | // INVVD : Normal (0 << 6) | // INVVDEN : Normal (0 << 5) | // INVPWREN : Normal (0 << 4) | // INVENDLINE : Normal (1 << 3) | // PWREN : Disable PWREN (0 << 2) | // ENLEND : Disable LEND signal (0 << 1) | // BSWP : Swap Disable (1 << 0) ; // HWSWP : Swap Enable s2410LCD->LCDSADDR1 = ((FRAMEBUF_DMA_BASE >> 22) << 21) | ((M5D(FRAMEBUF_DMA_BASE >> 1)) << 0); s2410LCD->LCDSADDR2=M5D( (FRAMEBUF_DMA_BASE+(LCD_XSIZE_TFT*LCD_YSIZE_TFT*2))>>1 ); s2410LCD->LCDSADDR3=(((LCD_XSIZE_TFT-LCD_XSIZE_TFT)/1)<<11)|(LCD_XSIZE_TFT/1); s2410LCD->LCDINTMSK|=(3); // MASK LCD Sub Interrupt s2410LCD->LPCSEL&=(~7); // Disable LPC3600 s2410LCD->TPAL=0; // Disable Temp Palette s2410LCD->LCDCON1 |= 1; } 其中,部分变量、常量定义如下: #define LCD_XSIZE_TFT (800) #define LCD_YSIZE_TFT (480) #define HOZVAL_TFT (LCD_XSIZE_TFT-1) #define LINEVAL_TFT (LCD_YSIZE_TFT-1) #define MVAL (13) #define MVAL_USED (1) #define EACH_FRAME (0) //STN/CSTN timing parameter for LCBHBT161M(NANYA) #define WLH (3) #define WDLY (3) #define LINEBLANK (1 &0xff) #define VBPD ((32-1)&0xff) #define VFPD ((11-1)&0xff) #define VSPW ((2-1) &0x3f) #define HBPD ((88-1)&0x7f) #define HFPD ((40-1)&0xff) #define HSPW ((128-1)&0xff) #define CLKVAL_TFT (0) #define M5D(n) ((n) & 0x1fffff) #define SCREEN_WIDTH 800 //800 #define SCREEN_HEIGHT 480 //480 #define FRAMEBUF_DMA_BASE (0x35000000) U16* pLCDBuffer565=(U16*)FRAMEBUF_DMA_BASE; 3)填写配置文件LCDConf.h #define LCD_XSIZE (800) /* X-resolution of LCD, Logical coor. */ #define LCD_YSIZE (480) /* Y-resolution of LCD, Logical coor. */ #define LCD_BITSPERPIXEL (16) #define LCD_CONTROLLER 1 #define LCD_SWAP_RB_0 1 2.触摸屏驱动: 触摸屏驱动计算出触摸屏的坐标(x,y),对dm2410实验板上的触摸屏,左下为原点,但不一定是(0,0)。两个函数: 1) 设置中断向量,开中断: void SetTSInterrupt(void) { rADCDLY = (50000); rADCCON = (1<<14)|(ADCPRS<<6)|(7<<3)|(0<<2)|(0<<1)|(0); rADCTSC = (0<<8)|(1<<7)|(1<<6)|(0<<5)|(1<<4)|(0<<3)|(0<<2)|(3); pISR_ADC = (U32)TSIrqISR; // rINTMSK &= ~(BIT_ADC); rINTSUBMSK &= ~(BIT_SUB_TC); } 2) 中断处理函数: static void TSIrqISR(void) { int i; U32 Pt[6]; rINTSUBMSK |= (BIT_SUB_ADC|BIT_SUB_TC); if(rADCDAT0 & 0x8000) {//抬起 isDown = 0; rADCTSC &= 0xff; // Set stylus down interrupt TX = -1; TY = -1; //抬起触笔时,TX,TY要值成不大于0的数 } else //按下 { isDown = 1; rADCTSC=(0<<8)|(0<<7)|(0<<6)|(1<<5)|(1<<4)|(1<<3)|(0<<2)|(1); for(i=0;i<LOOP;i++); //delay to set up the next channel for(i=0;i<5;i++) //5 times { rADCCON|=0x1; // Start X-position conversion while(rADCCON & 0x1); // Check if Enable_start is low while(!(0x8000&rADCCON)); // Check ECFLG Pt[i]=(0x3ff&rADCDAT0); } Pt[5]=(Pt[0]+Pt[1]+Pt[2]+Pt[3]+Pt[4])/5;//多次采样取平均值 TX = Pt[5]; rADCTSC=(0<<8)|(0<<7)|(1<<6)|(1<<5)|(0<<4)|(1<<3)|(0<<2)|(2); for(i=0;i<LOOP;i++); //delay to set up the next channel for(i=0;i<5;i++) //5 times { rADCCON|=0x1; // Start Y-position conversion while(rADCCON & 0x1); // Check if Enable_start is low while(!(0x8000&rADCCON)); // Check ECFLG Pt[i]=(0x3ff&rADCDAT1); } Pt[5]=(Pt[0]+Pt[1]+Pt[2]+Pt[3]+Pt[4])/5;// 多次采样取平均值 TY = Pt[5]; rADCTSC=(1<<8)|(1<<7)|(1<<6)|(0<<5)|(1<<4)|(0<<3)|(0<<2)|(3); } //cprintf("%d,%d/n",TX,TY); OSMboxPost(TouchMbox, 0);//向处理触摸进程发消息 rSUBSRCPND |= BIT_SUB_TC; rINTSUBMSK &= ~(BIT_SUB_TC); // Unmask sub interrupt (TC) ClearPending(BIT_ADC); } 3) 需要的量: #define LOOP 1 #define ADCPRS 0x27 int TX=0;//触摸坐标x int TY=0;//触摸坐标y extern OS_EVENT *TouchMbox; int isDown; 4) 触摸屏校准: Ucgui390中,带有一校准程序(于TOUCH_Calibrate.c中),可以改写为我所用(见下文)。 也可设置默认值,测出左下最小坐标minX,minY和右上最大坐标maxX,maxY,注意是触摸坐标,不是lcd坐标,如下填写配置文件GUITouchConf.h: #define GUI_TOUCH_AD_LEFT minX #define GUI_TOUCH_AD_TOP maxY #define GUI_TOUCH_AD_RIGHT maxX #define GUI_TOUCH_AD_BOTTOM minY #define GUI_TOUCH_SWAP_XY 0 #define GUI_TOUCH_MIRROR_X 1 #define GUI_TOUCH_MIRROR_Y 1 #define TOUCH_NEED_CALIBRATE 0 3、如下填写GUIConf.h: #define GUI_OS (1) /* Compile with multitasking support */ #define GUI_SUPPORT_TOUCH (1) /* Support a touch screen (req. win-manager) */ #define GUI_SUPPORT_UNICODE (1) /* Support mixed ASCII/UNICODE strings */ #define GUI_SUPPORT_CHINESE (1) #define GUI_DEFAULT_FONT &GUI_Font6x8 #define GUI_ALLOC_SIZE 12500 /* Size of dynamic memory ... For WM and memory devices*/ #define GUI_WINSUPPORT 1 /* Window manager package available */ #define GUI_SUPPORT_MEMDEV 1 /* Memory devices available */ #define GUI_SUPPORT_AA 1 /* Anti aliasing available */ 4、ucgui与lcd驱动函数的连接,即修改LCDWin.c文件: 在LCDWin.c中,去掉无用的头文件包含。 #define SETPIXEL(x, y, c) LCD2410_SetPixel(x, y, c, LCD_DISPLAY_INDEX) #define GETPIXEL(x, y) LCD2410_GetPixel(x,y, LCD_DISPLAY_INDEX) 即将“LCDSIM_XX”改成“LCD2410_XX”,这两个函数位于lcd驱动文件中。 …………………………… #define SETPIXEL(x, y, c) / if (!_CheckBound(c)) { / LCD2410_SetPixel(x, y, c, LCD_DISPLAY_INDEX); / } #else #define SETPIXEL(x, y, c) LCD2410_SetPixel(x, y, c, LCD_DISPLAY_INDEX) #endif #define GETPIXEL(x, y) LCD2410_GetPixel(x,y,LCD_DISPLAY_INDEX) …………………………… static void _XorPixel(int x, int y) { unsigned int Index = LCD_L0_GetPixelIndex(x,y); LCD2410_SetPixel(x, y, LCD_NUM_COLORS-1-Index, LCD_DISPLAY_INDEX); } …………………………… int LCD_L0_Init(void) { return LCD2410_Init();//调用lcd初始化函数 } 5、某些编译器(如:ads1.2)不会初始化全局变量,因此做如下事: 1) 修改如下函数为:(位于GUICore.c) static void _InitContext(GUI_CONTEXT* pContext) { memset(pContext,0,sizeof(GUI_CONTEXT));//add #if GUI_SUPPORT_MEMDEV GUI_SelectLCD(); #else LCD_SetClipRectMax();//LCD_L0_GetRect #endif pContext->pLCD_HL = &LCD_HL_APIList; pContext->pAFont = GUI_DEFAULT_FONT; pContext->pClipRect_HL = &GUI_Context.ClipRect; pContext->PenSize = 1; pContext->DrawMode = GUI_DRAWMODE_NORMAL;//add pContext->TextMode = GUI_TEXTMODE_NORMAL;//add pContext->TextAlign = GUI_TA_LEFT|GUI_TA_TOP;//add pContext->AA_HiResEnable = 0;//add /* Variables in WM module */ #if GUI_WINSUPPORT pContext->hAWin = WM_GetDesktopWindow(); #endif /* Variables in GUI_AA module */ pContext->AA_Factor = 3; LCD_SetBkColor(GUI_DEFAULT_BKCOLOR); LCD_SetColor(GUI_DEFAULT_COLOR); } 修改如下函数为:(位于GUIAlloc.c) void GUI_ALLOC_Init(void) { ........ GUI_ALLOC.NumUsedBytes = 0; memset(&aBlock,0,sizeof(aBlock[0])*GUI_MAXBLOCKS);/////self aBlock[0].Size = (1<<GUI_BLOCK_ALIGN); /* occupy minimum for a block */ ....... } 修改如下函数为:(位于WM.c)( New) void WM_Init(void) { if (!_IsInited) { ………. memset(&_ClipContext,0,sizeof(WM_IVR_CONTEXT));//add NextDrawWin = WM__FirstWin = WM_HWIN_NULL; ………………. _IsInited =1; } } 2)自己编写如下函数(ads1.2): void MyInit() { IsInitialized = 0;//MemDev _IsInited = 0;//Win WM__CreateFlags = 0; GUI_CURSOR_pfTempHide = NULL; GUI_Context.hDevData = 0; WM__hCapture=0; WM__hWinFocus=0; WM_pfPollPID = 0; WM_pfHandlePID = 0; GUI_pfTimerExec = 0; _KeyMsgCnt = 0; } 该函数应在GUI_Init()调用之前调用。 6、改写GUI_Init()函数: int GUI_Init(void) { int r; GUI_DEBUG_LOG("/nGUI_Init()"); /* Init system wide globals first */ GUI_DecChar = '.'; /* Init context */ _InitContext(&GUI_Context); GUITASK_INIT(); r = LCD_Init(); #if GUI_WINSUPPORT WM_Init(); #endif GUITASK_COPY_CONTEXT(); GUI_Clear(); GUI_X_Init(); GUI_CURSOR_Show();//启动即显示鼠标 return r; } 三、ucGUI与ucOS的整合,主要修改GUI_X.c文件: 1、定义信号量及全局量: static OS_EVENT *DispSem; static OS_EVENT *EventMbox; static OS_EVENT *KeySem; static int KeyPressed; static char KeyIsInited; 2、实现结合函数: int GUI_X_GetTime(void) { return ((int)OSTimeGet()); } void GUI_X_Delay(int period) { INT32U ticks; ticks = (period * 1000) / OS_TICKS_PER_SEC; OSTimeDly((INT16U)ticks); } void GUI_X_Unlock(void) { OSSemPost(DispSem); } void GUI_X_Lock(void) { U8 err; OSSemPend(DispSem, 0, &err); } U32 GUI_X_GetTaskId(void) { return ((U32)(OSTCBCur->OSTCBPrio)); } void GUI_X_WaitEvent (void) { INT8U err; (void)OSMboxPend(EventMbox, 0, &err); } void GUI_X_SignalEvent (void) { (void)OSMboxPost(EventMbox, (void *)1); } void GUI_X_InitOS(void) { DispSem = OSSemCreate(1); EventMbox = OSMboxCreate((void *)0); } void GUI_X_ExecIdle(void) {GUI_X_Delay(1);} void GUI_X_Init(void) { SetTSInterrupt();//此处接入触摸屏的中断设置 GUI_TOUCH_SetDefaultCalibration();//用默认值校准触摸屏 } 四、与触摸屏有关的函数: 1、4个功能函数: void GUI_TOUCH_X_ActivateX(void) {//空} void GUI_TOUCH_X_ActivateY(void) {//空} int GUI_TOUCH_X_MeasureX(void) { return TX;//返回触摸坐标x } int GUI_TOUCH_X_MeasureY(void){ return TY; //返回触摸坐标y } 2、触摸屏校准任务(进程, 来自示例程序:TOUCH_Calibrate.c): #if TOUCH_NEED_CALIBRATE static const char * _acPos[] = { "(upper left position)", "(lower right position)" }; static void _WaitForPressedState(int Pressed) { GUI_PID_STATE State; /* Wait until touch is pressed */ do { GUI_TOUCH_GetState(&State); if (State.Pressed == Pressed) { break; } GUI_Delay (100); } while (1); } static void _DispStringCentered(const char * pString) { GUI_RECT Rect; Rect.x0 = Rect.y0 = 0; Rect.x1 = LCD_GetXSize() - 1; Rect.y1 = LCD_GetYSize() - 1; GUI_DispStringInRect(pString, &Rect, GUI_TA_HCENTER | GUI_TA_VCENTER); } static void _GetPhysValues(int LogX, int LogY, int * pPhysX, int * pPhysY, const char * pString) { char acText[] = "Press here"; GUI_RECT Rect; int FontSizeY, Align; FontSizeY = GUI_GetFontSizeY(); GUI_Clear(); GUI_SetColor(GUI_BLACK); _DispStringCentered("Runtime calibration,/n" "please touch the screen/n" "at the center of the ring."); /* Ask user to press the touch */ /* Calculate the rectangle for the string */ Rect.y0 = LogY - FontSizeY; Rect.y1 = LogY + FontSizeY; if (LogX < LCD_GetXSize() / 2) { Rect.x0 = LogX + 15; Rect.x1 = LCD_GetXSize(); Align = GUI_TA_LEFT; } else { Rect.x0 = 0; Rect.x1 = LogX - 15; Align = GUI_TA_RIGHT; } /* Show the text nearby the ring */ GUI_DispStringInRect(acText, &Rect, Align | GUI_TA_TOP); GUI_DispStringInRect(pString, &Rect, Align | GUI_TA_BOTTOM); /* Draw the ring */ GUI_FillCircle(LogX, LogY, 10); GUI_SetColor(GUI_WHITE); GUI_FillCircle(LogX, LogY, 5); GUI_SetColor(GUI_BLACK); /* Wait until touch is pressed */ _WaitForPressedState(1); *pPhysX = GUI_TOUCH_GetxPhys(); *pPhysY = GUI_TOUCH_GetyPhys(); /* Wait until touch is released */ _WaitForPressedState(0); } static void _Explain(void) { _DispStringCentered("This sample shows how/n" "a touch screen can be/n" "calibrated at run time./n" "Please press the touch/n" "screen to continue..."); GUI_DispStringHCenterAt("TOUCH_Calibrate", LCD_GetXSize() / 2, 5); _WaitForPressedState(1); _WaitForPressedState(0); } void CalibrateTask(void* pdata) {//触摸屏校准任务入口 int aPhysX[2], aPhysY[2], aLogX[2], aLogY[2], i; GUI_SetBkColor(GUI_WHITE); GUI_Clear(); GUI_SetColor(GUI_BLACK); GUI_SetFont(&GUI_Font13B_ASCII); _Explain(); /* Set the logical values */ aLogX[0] = 15; aLogY[0] = 15; aLogX[1] = LCD_GetXSize() - 20; aLogY[1] = LCD_GetYSize() - 20; /* Get the physical values of the AD converter for 2 positions */ for (i = 0; i < 2; i++) { _GetPhysValues(aLogX[i], aLogY[i], &aPhysX[i], &aPhysY[i], _acPos[i]); } /* Use the physical values to calibrate the touch screen */ GUI_TOUCH_Calibrate(0, aLogX[0], aLogX[1], aPhysX[0], aPhysX[1]); /* Calibrate X-axis */ GUI_TOUCH_Calibrate(1, aLogY[0], aLogY[1], aPhysY[0], aPhysY[1]); /* Calibrate Y-axis */ { /* calculate and display values for configuration file */ int calX0, calX1; int calY0, calY1; GUI_Clear(); GUI_TOUCH_GetCalData(GUI_COORD_X, &calX0, &calX1); GUI_TOUCH_GetCalData(GUI_COORD_Y, &calY0, &calY1); GUI_DispStringAt("calX0: ", 0, 0); GUI_DispDec(calX0, 4); GUI_DispNextLine(); GUI_DispString ("calX1: "); GUI_DispDec(calX1, 4); GUI_DispNextLine(); GUI_DispString ("calY0: "); GUI_DispDec(calY0, 4); GUI_DispNextLine(); GUI_DispString ("calY1: "); GUI_DispDec(calY1, 4); GUI_DispStringAt("lcdx0: ", 0, 200); GUI_DispDec(aLogX[0], 4); GUI_DispNextLine(); GUI_DispString ("lcdx1: "); GUI_DispDec(aLogX[1], 4); GUI_DispNextLine(); GUI_DispString ("lcdy0: "); GUI_DispDec(aLogY[0], 4); GUI_DispNextLine(); GUI_DispString ("lcdy1: "); GUI_DispDec(aLogY[1], 4); GUI_DispNextLine(); GUI_DispString ("tscX0: "); GUI_DispDec(aPhysX[0], 4); GUI_DispNextLine(); GUI_DispString ("tscX1: "); GUI_DispDec(aPhysX[1], 4); GUI_DispNextLine(); GUI_DispString ("tscY0: "); GUI_DispDec(aPhysY[0], 4); GUI_DispNextLine(); GUI_DispString ("tscY1: "); GUI_DispDec(aPhysY[1], 4); GUI_DispNextLine(); GUI_DispString ("Please touch display to continue..."); GUI_Delay(1000); _WaitForPressedState(1); _WaitForPressedState(0); } GUI_Clear(); SystemOn(); OSTaskSuspend(OS_PRIO_SELF); } 3、为了响应触摸屏,做如下事: 1)创建进程处理触摸事件,形式如下: void TouchTask(void* data) { INT8U err; while(1) { CONSOL_Printf("Waiting for Touch....../n"); OSMboxPend(TouchMbox, 0, &err); /* Acquire semaphore to perform random numbers */ CONSOL_Printf("Got a message/n"); GUI_TOUCH_Exec();// } } 2) 如下修改函数 GUI_TOUCH_Exec(): void GUI_TOUCH_Exec(void) { #ifndef WIN32 static U8 ReadState; int x,y; /* calculate Min / Max values */ if (xyMinMax[GUI_COORD_X].Min < xyMinMax[GUI_COORD_X].Max) { xMin = xyMinMax[GUI_COORD_X].Min; xMax = xyMinMax[GUI_COORD_X].Max; } else { xMax = xyMinMax[GUI_COORD_X].Min; xMin = xyMinMax[GUI_COORD_X].Max; } if (xyMinMax[GUI_COORD_Y].Min < xyMinMax[GUI_COORD_Y].Max) { yMin = xyMinMax[GUI_COORD_Y].Min; yMax = xyMinMax[GUI_COORD_Y].Max; } else { yMax = xyMinMax[GUI_COORD_Y].Min; yMin = xyMinMax[GUI_COORD_Y].Max; } /* Execute the state machine which reads the touch */ //switch (ReadState) { //case 0: yPhys = TOUCH_X_MeasureY(); // TOUCH_X_ActivateY(); /* Prepare X- measurement */ // ReadState++; // break; //default: xPhys = TOUCH_X_MeasureX(); // TOUCH_X_ActivateX(); /* Prepare Y- measurement */ /* Convert values into logical values */ #if !GUI_TOUCH_SWAP_XY /* Is X/Y swapped ? */ x = xPhys; y = yPhys; #else x = yPhys; y = xPhys; #endif if ((x <xMin) | (x>xMax) | (y <yMin) | (y>yMax)) { GUI_TOUCH_StoreUnstable(-1,-1); } else { x = AD2X(x); y = AD2Y(y); GUI_TOUCH_StoreUnstable(x,y); } /* Reset state machine */ //ReadState=0; // break; //} #endif /* WIN32 */ } 五、 GUI多任务测试: 测试程序:MT_MultiTasking.c 欢迎来信交流:hongyhm@hotmail.com
|