久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

STemWin如何啟用Multiple Buffering功能

 yxz1212_bao 2018-07-19

1. Multiple Buffering的工作原理
多緩沖是一種使用多個(gè)幀緩沖器的方法。其基本原理如下:在啟用多個(gè)緩沖器的情況下,,由顯示控制器所使用的前置緩沖器(front buffer)會(huì)在屏幕上產(chǎn)生圖像,,同時(shí),一個(gè)或多個(gè)后置緩沖器(back buffers)則用于繪圖操作,。繪圖操作完成后,,后置緩沖器成為可見的前置緩沖器。

如果使用兩個(gè)緩沖器 (即一個(gè)前置緩沖器和一個(gè)后置緩沖器),,通常稱之為 “雙緩沖”,;如果使用兩個(gè)后置緩沖器和一個(gè)前置緩沖器,則稱之為 “三緩沖”,。

由于多緩沖方法使用多個(gè)幀緩沖器,,因此,即便繪圖操作仍在進(jìn)行中,,屏幕畫面也是完全渲染的結(jié)果,。啟動(dòng)繪圖過程時(shí),前置緩沖器的當(dāng)前內(nèi)容會(huì)被復(fù)制到一個(gè)后置緩沖器中,。在該操作完成后,,所有繪圖操作只對(duì)該后置緩沖器起作用。繪圖操作完成后,,后置緩沖器成為前置緩沖器,。如果要使后置緩沖器成為可見的前置緩沖器,通常只需修改顯示控制器的幀緩沖器起始地址寄存器即可,。

可以認(rèn)為,,顯示器的持續(xù)刷新是通過顯示控制器的應(yīng)用程序得以實(shí)現(xiàn)的。每秒60次,。每個(gè)周期完成之后有一個(gè)垂直同步信號(hào),通常稱之為VSYNC信號(hào),。使后置緩沖器成為前置緩沖器的最佳時(shí)機(jī)是該信號(hào)出現(xiàn)之時(shí),。如果不考慮VSYNC信號(hào),則可能產(chǎn)生撕裂效果(如圖1.1所示):
 
圖1.1 撕裂效果
2. 開發(fā)環(huán)境

硬件:STM32F429Discovery開發(fā)板,,主板芯片是STM32F429ZI,,外部64Mb的SDRAM,LCD是LG的LD050WV1,。

軟件:基于ST官方提供的STemWin_Library_V1.0.0固件庫和例程進(jìn)行移植,,操作系統(tǒng)是FreeRTOS,emWin版本為5.22,。

3. 如何啟用Multiple Buffering
?
3.1Multiple Buffering功能的工作流程
?
圖3.1 Multiple Buffering的工作流程
如圖3.1所示,,Multiple Buffering機(jī)制的工作順序?yàn)椋涸?/span>void LCD_X_Config(void)時(shí)進(jìn)行配置,;調(diào)用GUI_MULTIBUF_Begin()或GUI_MULTIBUF_BeginEx()對(duì)繪圖進(jìn)行緩沖,此時(shí)emWin會(huì)將front buffer的內(nèi)容拷貝到back buffer中,;進(jìn)行繪圖工作,,此時(shí)所有的繪圖工作都將在back buffer中進(jìn)行;調(diào)用GUI_MULTIBUF_End()或GUI_MULTIBUF_EndEX()結(jié)束緩沖,,此時(shí)emWin會(huì)將back buffer切換到front,。
3.2 官方代碼修改、實(shí)現(xiàn)以及實(shí)現(xiàn)原理解說
?主要修改STemWinLibrary555_4x9i目錄下的GUIDRV_stm32f429i_discovery.c文件,。由于該文件已經(jīng)對(duì)Multiple Buffering功能進(jìn)行了支持,,所以重點(diǎn)修改此處即可:

//
// Buffers / VScreens
//
#define NUM_BUFFERS 2 // Number of multiple buffers to be used

即使用兩個(gè)buffer,也就是雙緩沖,。后續(xù)的內(nèi)容官方代碼已經(jīng)寫好了,,這里指進(jìn)行介紹說明,同時(shí)捋清e(cuò)mWin進(jìn)行雙緩沖功能的工作流程,。
開啟雙緩沖后,,在void LCD_X_Config(void)函數(shù)中,預(yù)編譯條件被打開:

#if (NUM_BUFFERS > 1)
for (i = 0; i < GUI_NUM_LAYERS; i++) {
    GUI_MULTIBUF_ConfigEx(i, NUM_BUFFERS);
}
#endif

這是對(duì)多緩沖功能進(jìn)行配置,,由于NUM_BUFFERS的值是2,,所以多緩沖功能被打開。

前面提及開啟雙緩沖后,,所有的繪圖操作將在back buffer里進(jìn)行,,為了確保繪圖的正確性,emWin需要一個(gè)copy函數(shù)將front buffer中的數(shù)據(jù)首先拷貝到back buffer中,,然后再進(jìn)行繪圖,。ST官方代碼使用了用戶自定義的buffer copy程序,這樣可使使用DMA進(jìn)行內(nèi)存拷貝,,以提高工作效率,。使用自定義buffer copy程序,需要在void LCD_X_Config(void)函數(shù)中添加下面內(nèi)容:

LCD_SetDevFunc(i, LCD_DEVFUNC_COPYBUFFER, (void(*)(void))_LCD_CopyBuffer);
下面是官方給出的“_LCD_CopyBuffer”函數(shù)代碼:

/*********************************************************************
*
* _LCD_CopyBuffer
*/
static void _LCD_CopyBuffer(int LayerIndex, int IndexSrc, int IndexDst) {
    U32 BufferSize, AddrSrc, AddrDst;
    BufferSize = _GetBufferSize(LayerIndex);
    AddrSrc = _aAddr[LayerIndex] + BufferSize * IndexSrc;
    AddrDst = _aAddr[LayerIndex] + BufferSize * IndexDst;
    _DMA_Copy(LayerIndex, (void *)AddrSrc, (void *)AddrDst, _axSize[LayerIndex], _aySize[LayerIndex], 0);
}
在繪制完圖形后,,用戶調(diào)用GUI_MULTIBUF_End()函數(shù),,此時(shí)emWin將back buffer切換到前臺(tái)顯示出來。這個(gè)切換動(dòng)作最好在LCD進(jìn)行第一行的行掃描時(shí)進(jìn)行,,否則容易出現(xiàn)撕裂效果,。因此這段代碼被寫在LTDC的中斷處理程序中。
/*********************************************************************
*
* LTDC_ISR_Handler
*
* Purpose:
* End-Of-Frame-Interrupt for managing multiple buffering
*/
void LTDC_ISR_Handler(void) {
    U32 Addr;
    int i;
    LTDC->ICR = (U32)LTDC_IER_LIE;
    for (i = 0; i < GUI_NUM_LAYERS; i++) {
        if (_aPendingBuffer[i] >= 0) {
            //
            // Calculate address of buffer to be used as visible frame buffer
            //
            Addr = _aAddr[i] + _axSize[i] * _aySize[i] * _aPendingBuffer[i] * _aBytesPerPixels[i];
            //
            // Store address into SFR
            //
            _apLayer[i]->CFBAR &= ~(LTDC_LxCFBAR_CFBADD);
            _apLayer[i]->CFBAR = Addr;
            //
            // Reload configuration
            //
            LTDC_ReloadConfig(LTDC_SRCR_IMR);
            //
            // Tell emWin that buffer is used
            //
            GUI_MULTIBUF_ConfirmEx(i, _aPendingBuffer[i]);
            //
            // Clear pending buffer flag of layer
            //
            _aBufferIndex[i] = _aPendingBuffer[i];
            _aPendingBuffer[i] = -1;
        }
    }
}
從以上程序可以看出,,back buffer到front buffer的切換,,只是將back buffer的首地址賦值給了LTDC的CFBAR寄存器。這樣的切換時(shí)很迅速的,,因此用戶看不到圖像的繪制過程,,避免了由繪圖工作帶來的屏幕閃爍問題,。
那么,emWin如何知道何時(shí)需要進(jìn)行buffer的切換工作呢,?實(shí)際上,,當(dāng)用戶調(diào)用GUI_MULTIBUF_End()等函數(shù)的時(shí)候,會(huì)發(fā)出LCD_X_SHOWBUFFER信號(hào)給“LCD_X_DisplayDriver”函數(shù),。

int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData)
{
switch (Cmd) {
    case LCD_X_SHOWBUFFER: {
    //
    // Required if multiple buffers are used. The 'Index' element of p contains the buffer index.
    //
    LCD_X_SHOWBUFFER_INFO * p;
    p = (LCD_X_SHOWBUFFER_INFO *)pData;
    _aPendingBuffer[LayerIndex] = p->Index;
    break;
}
在需要進(jìn)行buffer切換時(shí),,傳入的p->Index為1,這樣,,在“LTDC_ISR_Handler”函數(shù)里就滿足了“_aPendingBuffer[i] >= 0”的條件,。

3.3 官方代碼中存在的bug

如果按上述方法進(jìn)行修改和配置,并啟用Multiple Buffering功能,,那你可能發(fā)現(xiàn),,屏幕上能夠出現(xiàn)文字,但是卻沒有方塊,、水平直線和豎直直線,。如果仿真調(diào)試,會(huì)發(fā)現(xiàn),,其實(shí)矩形,、水平直線和豎直直線被畫在了front buffer里。

這是由于官方示例代碼中存在一個(gè)bug,,導(dǎo)致用戶自定義的“LCD_DEVFUNC_FILLRECT”功能函數(shù)使用了錯(cuò)誤地址,。該示例代碼中配置使用了自定義“LCD_DEVFUNC_FILLRECT”函數(shù):

if (_GetPixelformat(i) <= LTDC_Pixelformat_ARGB4444) {
    LCD_SetDevFunc(i, LCD_DEVFUNC_FILLRECT, (void(*)(void))_LCD_FillRect);
}
而“ _LCD_FillRect"函數(shù)的實(shí)現(xiàn)如下:
/*********************************************************************
*
* _LCD_FillRect
*/
static void _LCD_FillRect(int LayerIndex, int x0, int y0, int x1, int y1, U32 PixelIndex) {
    U32 BufferSize, AddrDst;
    int xSize, ySize;
    if (GUI_GetDrawMode() == GUI_DM_XOR) {
        LCD_SetDevFunc(LayerIndex, LCD_DEVFUNC_FILLRECT, NULL);
        LCD_FillRect(x0, y0, x1, y1);
       LCD_SetDevFunc(LayerIndex, LCD_DEVFUNC_FILLRECT, (void(*) (void))_LCD_FillRect);
    } else {
        xSize = x1 - x0 + 1;
        ySize = y1 - y0 + 1;
        BufferSize = _GetBufferSize(LayerIndex);
        AddrDst = _aAddr[LayerIndex] + BufferSize * _aBufferIndex[LayerIndex] + (y0 * _axSize[LayerIndex] + x0) * _aBytesPerPixels[LayerIndex];
        _DMA_Fill(LayerIndex, (void *)AddrDst, xSize, ySize, _axSize[LayerIndex] - xSize, PixelIndex);
    }
}

該代碼將在繪制矩形、水平直線和豎直直線時(shí)進(jìn)行調(diào)用,,將繪制的圖形拷貝到相應(yīng)的buffer中,。如果對(duì)該處代碼進(jìn)行調(diào)試,會(huì)發(fā)現(xiàn)“AddrDst的值始終都是front buffer的值,。而在啟用雙緩沖時(shí),,AddrDst”應(yīng)該指向back buffer。進(jìn)一步會(huì)發(fā)現(xiàn)“_aBufferIndex[LayerIndex]”的值是錯(cuò)誤的,。這是因?yàn)椴粦?yīng)該在LTDC的中斷服務(wù)程序中對(duì)"_aBufferIndex[LayerIndex]"進(jìn)行賦值,。因?yàn)橹袛喾?wù)程序中的賦值只有在用戶調(diào)用GUI_MULTIBUF_End()時(shí)才執(zhí)行,這個(gè)時(shí)候繪圖工作都已經(jīng)完成了,。正確的方式應(yīng)該在GUI_MULTIBUF_Begin()后立即對(duì)"_aBufferIndex[LayerIndex]"進(jìn)行賦值。
那么,,應(yīng)該在代碼的何處進(jìn)行賦值呢,?答案是“_LCD_CopyBuffer”函數(shù),因?yàn)檎{(diào)用GUI_MULTIBUF_Begin()后,,emWin會(huì)調(diào)用該函數(shù)將front buffer中的內(nèi)容拷貝的back buffer,,然后才繪圖,。
因此,修改后的代碼為:

/*********************************************************************
*
* _LCD_CopyBuffer
*/
static void _LCD_CopyBuffer(int LayerIndex, int IndexSrc, int IndexDst) {
    U32 BufferSize, AddrSrc, AddrDst;
    BufferSize = _GetBufferSize(LayerIndex);
    AddrSrc = _aAddr[LayerIndex] + BufferSize * IndexSrc;
    AddrDst = _aAddr[LayerIndex] + BufferSize * IndexDst;
    _aBufferIndex[LayerIndex] = IndexDst;
    _DMA_Copy(LayerIndex, (void *)AddrSrc, (void *)AddrDst, _axSize[LayerIndex], _aySize[LayerIndex], 0);
}
/*********************************************************************
*
* LTDC_ISR_Handler
*
* Purpose:
* End-Of-Frame-Interrupt for managing multiple buffering
*/
void LTDC_ISR_Handler(void) {
    U32 Addr;
    int i;
    LTDC->ICR = (U32)LTDC_IER_LIE;
    for (i = 0; i < GUI_NUM_LAYERS; i++) {
        if (_aPendingBuffer[i] >= 0) {
            //
            // Calculate address of buffer to be used as visible frame buffer
            //
            Addr = _aAddr[i] + _axSize[i] * _aySize[i] * _aPendingBuffer[i] * _aBytesPerPixels[i];
            //
            // Store address into SFR
            //
            // _apLayer[i]->CFBAR &= ~(LTDC_LxCFBAR_CFBADD);    // 沒發(fā)現(xiàn)這句有什么用,,一起注掉了吧,!
            _apLayer[i]->CFBAR = Addr;
            //
            // Reload configuration
            //
            LTDC_ReloadConfig(LTDC_SRCR_IMR);
            //
            // Tell emWin that buffer is used
            //
            GUI_MULTIBUF_ConfirmEx(i, _aPendingBuffer[i]);
            //
            // Clear pending buffer flag of layer
            //
            _aPendingBuffer[i] = -1;
        }
    }

}

這個(gè)bug在STemWin_Library_V1.0.1中仍然存在。但是1.0.1的官方例程中沒有使用Multiple Buffering功能,,而1.0.0中的demo明顯使用了該功能(如圖3.2):


圖3.2 官方例程明顯開啟了Multiple Buffering功能

看起來似乎ST方面發(fā)現(xiàn)了Multiple Buffering功能不好用,,但是沒有從根本上解決問題,所以官方例程就不使用該功能了,。這種治標(biāo)不治本的處理方式,,讓我對(duì)st的工作態(tài)度表示懷疑。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多