i.mx6ull 官方SDK学习与移植(3)

0.前言

i.mx6ull 官方SDK学习与移植(2)中已经搭建起了裸板学习的框架,剩下的就是按部就班,参照正点原子的裸板学习教程,试验每一个例子。

看完正点原子《IMX6U嵌入式Linux驱动开发指南》教程,对照NXP官方例程,就会发现裸板试验代码其实也并不复杂。在理解对时钟、IO控制、外设原理等的基础上,使用很少的代码就可以完成裸板试验。

1.其它例子

对按键试验、GPIO中断、高精度时延、定时中断、I2C读写就不做多写了,套路基本一致。

1.1按键控制代码

#include "fsl_gpio.h"
#include "fsl_debug_console.h"
#include "CommonHelper.h"
#include "board.h"
#include "key.h"

extern uint8_t led_cnt;
extern bool g_InputSignal;

/*按键初始化函数*/
void key_init(void)
{        
        /*添加中断服务函数到  "中断向量表"*/
    SystemInstallIrqHandler(BOARD_KEY_IRQ, (system_irq_handler_t)GPIO5_Combined_0_15_IRQHandler, NULL);

    gpio_pin_config_t gpio_config;
        
    gpio_config.direction = kGPIO_DigitalInput;
    gpio_config.outputLogic = 0;
    gpio_config.interruptMode = kGPIO_IntRisingEdge;

    /* Init input switch GPIO. */
    EnableIRQ(BOARD_KEY_IRQ);
    GPIO_PinInit(BOARD_KEY_GPIO, BOARD_KEY_GPIO_PIN, &gpio_config);

    /* Enable GPIO pin interrupt */  
    GPIO_EnableInterrupts(BOARD_KEY_GPIO, 1U << BOARD_KEY_GPIO_PIN);

    PRINTF("\r\nKey Interrupt installed.\r\n");
}


/*按键中断处理函数*/
void Key_GPIO_IRQHandler(void)
{
    GPIO_ClearPinsInterruptFlags(BOARD_KEY_GPIO,1U << BOARD_KEY_GPIO_PIN);

    /*按键引脚中断服务函数*/
    g_InputSignal = true;

    led_cnt++;
    
    PRINTF("\r\n %s Key Pressed %d.\r\n",BOARD_KEY_NAME,led_cnt);      
}

1.2 I2C控制(以I2C1为例)

I2C.h

#ifndef _I2C_H_
#define _I2C_H_

#include "fsl_common.h"
#include "fsl_clock.h"
#include "fsl_i2c.h"

#define I2C1_MASTER_BASEADDR I2C1
#define I2C1_MASTER_CLK_FREQ (CLOCK_GetFreq(kCLOCK_IpgClk) / \
                            (CLOCK_GetDiv(kCLOCK_PerclkDiv) + 1U))

#define I2C1_MASTER_SLAVE_ADDR_7BIT 0x7EU
#define I2C1_BAUDRATE 100000U
#define I2C1_DATA_LENGTH 32U

i2c_master_handle_t g_m_handle;
volatile bool g_MasterCompletionFlag = false;

void I2C1_Init();

#endif

I2C.c

#include "i2c.h"
#include "fsl_common.h"
#include "fsl_debug_console.h"
#include "fsl_i2c.h"

static void I2C1_Master_Callback(I2C_Type *base, i2c_master_handle_t *handle, status_t status, void *userData)
{
    /* Signal transfer success when received success status. */
    if (status == kStatus_Success)
    {
        g_MasterCompletionFlag = true;
    }
}

void I2C1_Init()
{
    i2c_master_config_t masterConfig;
    uint32_t sourceClock;
    /*
     * masterConfig->baudRate_Bps = 100000U;
     * masterConfig->enableHighDrive = false;
     * masterConfig->enableStopHold = false;
     * masterConfig->glitchFilterWidth = 0U;
     * masterConfig->enableMaster = true;
     */
    I2C_MasterGetDefaultConfig(&masterConfig);
    masterConfig.baudRate_Bps = I2C1_BAUDRATE;

    sourceClock = I2C1_MASTER_CLK_FREQ;

    I2C_MasterInit(I2C1_MASTER_BASEADDR, &masterConfig, sourceClock);

    memset(&g_m_handle, 0, sizeof(g_m_handle));

    I2C_MasterTransferCreateHandle(I2C1_MASTER_BASEADDR, &g_m_handle, I2C1_Master_Callback, NULL);
}

I2C回调函数暂时没有写其它的,完成一个状态重置。

1.3 读取AP3216C数据

I2C_AP3216C.h

#ifndef _I2C_AP3216C_H_
#define _I2C_AP3216C_H_

#include "fsl_common.h"

#define AP3216C_SLAVE_ADDR        0X1E    /* AP3216C器件地址 */

/*
 * AP3216C操作码定义
 */
typedef enum enAP3216C_OPCODE
{
    AP3216C_SYSTEMCONFIG = 0,          /* 配置寄存器  */
    AP3216C_INTSTATUS  = 1,             /* 中断状态寄存器 */
    AP3216C_INTCLEAR   = 2,               /* 中断清除寄存器 */
    AP3216C_START_ALL  = 3,            /* 开启全模式ALS/PS/IR */
    AP3216C_INIT       = 4,            /* 复位/初始化 */  
    AP3216C_IRDATALOW    = 10,           /* IR数据低字节    */
    AP3216C_IRDATAHIGH    = 11,           /* IR数据高字节    */
    AP3216C_ALSDATALOW    = 12,           /* ALS数据低字节   */
    AP3216C_ALSDATAHIGH    = 13,           /* ALS数据高字节   */
    AP3216C_PSDATALOW    = 14,           /* PS数据低字节    */
    AP3216C_PSDATAHIGH    = 15,           /* PS数据高字节    */
    AP3216C_DONOTHING_BULL
} AP3216C_OPCODE;


void AP3216C_Init_IO();

status_t AP3216C_Init(void);

status_t AP3216C_Translate(uint8_t regAddr,i2c_direction_t dr,uint8_t* pData);

status_t AP3216C_Read_IR(uint16_t *ir);

status_t AP3216C_Read_ALS(uint16_t *als);

status_t AP3216C_Read_PS(uint16_t *ps);

status_t AP3216C_Read_Data(uint16_t *ir, uint16_t *ps, uint16_t *als);

#endif

I2C_AP3216C.c

#include "CommonHelper.h"
#include "i2c.h"
#include "i2c_ap3216c.h"
#include "fsl_common.h"
#include "fsl_debug_console.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
#include "fsl_i2c.h"
#include "board.h"


void AP3216C_Init_IO()
{
    /*I2C1 复用UART4  SCL-TXD SDA-RXD  开启 AP3216C的中断,外接SNVS_TAMPER2*/
    /*设置 按键引脚的复用功能以及PAD属性*/
    IOMUXC_SetPinMux(AP3216C_INT_IOMUXC,0);     
    IOMUXC_SetPinConfig(AP3216C_INT_IOMUXC, button_PAD_CONFIG_DATA); 

    gpio_pin_config_t gpio_config;
        
    gpio_config.direction = kGPIO_DigitalInput;
    gpio_config.outputLogic = 0;
    gpio_config.interruptMode = kGPIO_NoIntmode; 
    //gpio_config.interruptMode = kGPIO_IntLowLevel;

    /* Init input switch GPIO. */
    //EnableIRQ(AP3216C_INT_IRQ);
    GPIO_PinInit(AP3216C_INT_GPIO, AP3216C_INT_GPIO_PIN, &gpio_config);

    /* Enable GPIO pin interrupt */  
    //GPIO_EnableInterrupts(AP3216C_INT_GPIO, 1U << AP3216C_INT_GPIO_PIN);

    //PRINTF("\r\nAP3216C Interrupt installed.\r\n");   

}

status_t AP3216C_Translate(uint8_t regAddr,i2c_direction_t dr,uint8_t* pData)
{
    i2c_master_transfer_t masterXfer;
    masterXfer.slaveAddress = AP3216C_SLAVE_ADDR;
    masterXfer.direction = dr;
    masterXfer.subaddress = regAddr;
    masterXfer.subaddressSize = 1;
    masterXfer.data = pData;
    masterXfer.dataSize = 1;
    masterXfer.flags = kI2C_TransferDefaultFlag;

    return I2C_MasterTransferBlocking(I2C1_MASTER_BASEADDR, &masterXfer);
}

status_t AP3216C_Init(void)
{
    AP3216C_Init_IO();

    status_t status = kStatus_Success;
    /*初始化/复位 AP3216C 软复位04*/
    uint8_t opcode = AP3216C_INIT;
    status = AP3216C_Translate(AP3216C_SYSTEMCONFIG,kI2C_Write,&opcode);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C Init Error!\r\n");
        return kStatus_Fail;
    }
    /*手册上写至少等待10ms*/
    delay(MSEC_TO_COUNT(15U, EPIT_CLK_FREQ) - 1);
    //开启ALS and PS+IR
    opcode = AP3216C_START_ALL;
    status = AP3216C_Translate(AP3216C_SYSTEMCONFIG,kI2C_Write,&opcode);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C Start All Error!\r\n");
        return kStatus_Fail;
    }
    return status;
}

status_t AP3216C_Read_IR(uint16_t *irData)
{
    uint8_t ucIrLow;
    uint8_t ucIrHigh;    

    status_t status = kStatus_Success;
    status = AP3216C_Translate(AP3216C_IRDATALOW,kI2C_Read,&ucIrLow);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C IR Data Low Error!\r\n");
        return kStatus_Fail;
    }
    status = AP3216C_Translate(AP3216C_IRDATAHIGH,kI2C_Read,&ucIrHigh);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C IR Data High Error!\r\n");
        return kStatus_Fail;
    }

    if(ucIrLow & 0x80)      //bit7 1:无效
    {        
        *irData = 0;            
    }
    else                   
    {
        *irData = ((uint16_t)ucIrHigh << 2) | (ucIrLow & 0X03);     
    }
    return status;
}

status_t AP3216C_Read_ALS(uint16_t *alsData)
{
    uint8_t ucAlsLow;
    uint8_t ucAlsHigh;    
    status_t status = kStatus_Success;

    status =AP3216C_Translate(AP3216C_ALSDATALOW,kI2C_Read,&ucAlsLow);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C ALS Data Low Error!\r\n");
        return kStatus_Fail;
    }
    status =AP3216C_Translate(AP3216C_ALSDATAHIGH,kI2C_Read,&ucAlsHigh);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C ALS Data High Error!\r\n");
        return kStatus_Fail;
    }

    *alsData = ((uint16_t)ucAlsHigh << 8) | ucAlsLow;

    return status;
}

status_t AP3216C_Read_PS(uint16_t *psData)
{
    uint8_t ucPsLow;
    uint8_t ucPsHigh;    
    status_t status = kStatus_Success;

    status = AP3216C_Translate(AP3216C_PSDATALOW,kI2C_Read,&ucPsLow);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C PS Data Low Error!\r\n");
        return kStatus_Fail;
    }
    status = AP3216C_Translate(AP3216C_PSDATAHIGH,kI2C_Read,&ucPsHigh);
    if(status == kStatus_Fail)
    {
        PRINTF("AP3216C PS Data High Error!\r\n");
        return kStatus_Fail;
    }

    if(ucPsLow & 0x40)      
    {
        *psData = 0;                
    }
    else                    
    {
        *psData = ((uint16_t)(ucPsHigh & 0X3F) << 4) | (ucPsLow & 0x0F);     
    }
    return status;
}


status_t AP3216C_Read_Data(uint16_t *ir, uint16_t *ps, uint16_t *als)
{
    return AP3216C_Read_IR(ir) &  AP3216C_Read_ALS(als) & AP3216C_Read_PS(ps);
}

在这里为了简便,没有使用AP3216C的中断功能。可以通过设置阈值,对超出阈值的事件引发中断再进行处理。后续可以继续尝试一下。

2.LCD移植

野火的开发板配套是5寸液晶屏,通过查阅野火的屏幕资料,可知其使用的屏幕通过LCD-FPC接口(开发板上J16接口)接入核心板。

LCD的驱动主要包括数据线、控制线(包含时钟)、背光等几部分。

i.mx6ull 官方SDK学习与移植(3)_第1张图片

LCD_DATA是数据总线。GPIO_8是背光控制总线。LCD_PCLK是时钟,LCD_HSYNC、LCD_VSYNC是行同步信号、帧同步信号,LCD_DE是数据使能。

2.1设置引脚

//LCD引脚
    IOMUXC_SetPinMux(IOMUXC_LCD_CLK_LCDIF_CLK, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_CLK_LCDIF_CLK, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA00_LCDIF_DATA00, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA00_LCDIF_DATA00, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA01_LCDIF_DATA01, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA01_LCDIF_DATA01, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA02_LCDIF_DATA02, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA02_LCDIF_DATA02, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA03_LCDIF_DATA03, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA03_LCDIF_DATA03, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA04_LCDIF_DATA04, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA04_LCDIF_DATA04, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA05_LCDIF_DATA05, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA05_LCDIF_DATA05, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA06_LCDIF_DATA06, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA06_LCDIF_DATA06, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA07_LCDIF_DATA07, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA07_LCDIF_DATA07, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA08_LCDIF_DATA08, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA08_LCDIF_DATA08, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA09_LCDIF_DATA09, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA09_LCDIF_DATA09, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA10_LCDIF_DATA10, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA10_LCDIF_DATA10, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA11_LCDIF_DATA11, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA11_LCDIF_DATA11, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA12_LCDIF_DATA12, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA12_LCDIF_DATA12, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA13_LCDIF_DATA13, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA13_LCDIF_DATA13, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA14_LCDIF_DATA14, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA14_LCDIF_DATA14, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA15_LCDIF_DATA15, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA15_LCDIF_DATA15, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA16_LCDIF_DATA16, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA16_LCDIF_DATA16, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA17_LCDIF_DATA17, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA17_LCDIF_DATA17, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA18_LCDIF_DATA18, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA18_LCDIF_DATA18, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA19_LCDIF_DATA19, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA19_LCDIF_DATA19, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA20_LCDIF_DATA20, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA20_LCDIF_DATA20, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA21_LCDIF_DATA21, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA21_LCDIF_DATA21, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA22_LCDIF_DATA22, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA22_LCDIF_DATA22, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_DATA23_LCDIF_DATA23, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_DATA23_LCDIF_DATA23, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_ENABLE_LCDIF_ENABLE, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_HSYNC_LCDIF_HSYNC, LCD_PAD_CONFIG_DATA);

    IOMUXC_SetPinMux(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, 0U);
    IOMUXC_SetPinConfig(IOMUXC_LCD_VSYNC_LCDIF_VSYNC, LCD_PAD_CONFIG_DATA);

引脚设置完成后,就可以按照野火、正点原子、官方例程来测试了。

2.2 设置LCD时钟。

/*
     * Initialize the Video PLL.
     * Video PLL output clock is OSC24M * (loopDivider + (denominator / numerator)) / postDivider = 93MHz.
     */
    clock_video_pll_config_t config = {
        .loopDivider = 31,
        .postDivider = 4,
        .numerator   = 0,
        .denominator = 0,
    };

    CLOCK_InitVideoPll(&config);

    /*
     * 000 derive clock from PLL2
     * 001 derive clock from PLL3 PFD3
     * 010 derive clock from PLL5
     * 011 derive clock from PLL2 PFD0
     * 100 derive clock from PLL2 PFD1
     * 101 derive clock from PLL3 PFD1
     */
    CLOCK_SetMux(kCLOCK_Lcdif1PreMux, 2);

    CLOCK_SetDiv(kCLOCK_Lcdif1PreDiv, 1);

    CLOCK_SetDiv(kCLOCK_Lcdif1Div, 1);

    /*
     * 000 derive clock from divided pre-muxed lcdif1 clock
     * 001 derive clock from ipp_di0_clk
     * 010 derive clock from ipp_di1_clk
     * 011 derive clock from ldb_di0_clk
     * 100 derive clock from ldb_di1_clk
     */
    CLOCK_SetMux(kCLOCK_Lcdif1Mux, 0);

2.3 配置 eLCDIF 接口

参照野火的5寸屏幕参数,

/* Macros for panel. */
#define LCD_HSW 41
#define LCD_HFP 4
#define LCD_HBP 8
#define LCD_VSW 10
#define LCD_VFP 4
#define LCD_VBP 2
#define LCD_WIDTH             800
#define LCD_HEIGHT            480

/* Initialize the display. */
    const elcdif_rgb_mode_config_t config = {
        .panelWidth    = LCD_WIDTH,
        .panelHeight   = LCD_HEIGHT,
        .hsw           = LCD_HSW,
        .hfp           = LCD_HFP,
        .hbp           = LCD_HBP,
        .vsw           = LCD_VSW,
        .vfp           = LCD_VFP,
        .vbp           = LCD_VBP,
        .polarityFlags = LCD_POL_FLAGS,
        /* lvgl starts render in frame buffer 0, so show frame buffer 1 first. */
        .bufferAddr  = (uint32_t)s_frameBuffer[1],
        .pixelFormat = kELCDIF_PixelFormatRGB888,
        .dataBus     = LCD_LCDIF_DATA_BUS,
    };

    ELCDIF_RgbModeInit(LCDIF, &config);
    SystemInstallIrqHandler(LCDIF_IRQn, (system_irq_handler_t)(uint32_t)LCDIF_IRQHandler, NULL);

    ELCDIF_EnableInterrupts(LCDIF, kELCDIF_CurFrameDoneInterruptEnable);
    EnableIRQ(LCDIF_IRQn);
    ELCDIF_RgbModeStart(LCDIF);

这样,LCD屏幕就初始化成功了。

2.4 测试

可以通过官方的例程进行测试了。

void APP_FillFrameBuffer(uint32_t frameBuffer[APP_IMG_HEIGHT][APP_IMG_WIDTH])
{
    /* Background color. */
    static const uint32_t bgColor = 0U;
    /* Foreground color. */
    static uint8_t fgColorIndex = 0U;
    static const uint32_t fgColorTable[] = {0x000000FFU, 0x0000FF00U, 0x0000FFFFU, 0x00FF0000U,
                                            0x00FF00FFU, 0x00FFFF00U, 0x00FFFFFFU};
    uint32_t fgColor = fgColorTable[fgColorIndex];

    /* Position of the foreground rectangle. */
    static uint16_t upperLeftX = 0U;
    static uint16_t upperLeftY = 0U;
    static uint16_t lowerRightX = (APP_IMG_WIDTH - 1U) / 2U;
    static uint16_t lowerRightY = (APP_IMG_HEIGHT - 1U) / 2U;

    static int8_t incX = 1;
    static int8_t incY = 1;

    /* Change color in next forame or not. */
    static bool changeColor = false;

    uint32_t i, j;

    /* Background color. */
    for (i = 0; i < APP_IMG_HEIGHT; i++)
    {
        for (j = 0; j < APP_IMG_WIDTH; j++)
        {
            frameBuffer[i][j] = bgColor;
        }
    }

    /* Foreground color. */
    for (i = upperLeftY; i < lowerRightY; i++)
    {
        for (j = upperLeftX; j < lowerRightX; j++)
        {
            frameBuffer[i][j] = fgColor;
        }
    }

    /* Update the format: color and rectangle position. */
    upperLeftX += incX;
    upperLeftY += incY;
    lowerRightX += incX;
    lowerRightY += incY;

    changeColor = false;

    if (0U == upperLeftX)
    {
        incX = 1;
        changeColor = true;
    }
    else if (APP_IMG_WIDTH - 1 == lowerRightX)
    {
        incX = -1;
        changeColor = true;
    }

    if (0U == upperLeftY)
    {
        incY = 1;
        changeColor = true;
    }
    else if (APP_IMG_HEIGHT - 1 == lowerRightY)
    {
        incY = -1;
        changeColor = true;
    }

    if (changeColor)
    {
        fgColorIndex++;

        if (ARRAY_SIZE(fgColorTable) == fgColorIndex)
        {
            fgColorIndex = 0U;
        }
    }
}

在主程序中调用,交替使用双缓冲进行显示输出。

while (1)
    {
        frameBufferIndex ^= 1U;

        APP_FillFrameBuffer(s_frameBuffer[frameBufferIndex]);

        ELCDIF_SetNextBufferAddr(APP_ELCDIF, (uint32_t)s_frameBuffer[frameBufferIndex]);

        s_frameDone = false;
        /* Wait for previous frame complete. */
        while (!s_frameDone)
        {
        }
    }

当看到一个蓝色的方块由左上角向右下角慢慢移动时,就说明屏幕驱动正常了。

你可能感兴趣的:(I.MX6ULL,mcu,arm开发,学习)