整个LCD驱动主要由LCD初始化、LCD底层函数、framebuf实例、framebuf IO操作内联文件及其头文件自动生成文件等4部分组成。上节介绍了LCD驱动的前面3个部分。

本节介绍LCD驱动的framebuf IO操作内联文件及其头文件自动生成文件这个部分。本章最后会展示一个简单的应用测试程序。

CDL文件

LCD驱动的CDL文件是framebuf_stm32.cdl,相比其它设备的CDL文件,它稍微显得有点复杂。我们需要注意下面这一段代码:

        active_if { CYGPKG_DEVS_FRAMEBUF_STM32_FB0}
        make -priority=1 {
            <PREFIX>/include/cyg/io/framebufs/stm32_fb.h :      \
                <PACKAGE>/src/gen_stm32fb.tcl                   \
                <PREFIX>/include/pkgconf/devs_framebuf_stm32.h
            tclsh $< $(PREFIX)
        }
        compile stm32fb.c
        compile -library=libextras.a stm32fb_init.cxx

这段CDL代码大概的意思是会执行gen_stm32fb.tcl脚本,产生一个stm32_fb.h的头文件。这从驱动编译后可以在生成目录树中看到这个头文件。

tcl脚本文件

gen_stm32fb.tcl脚本文件有点复杂,它是一个tcl语言脚本,主要用于自动生成一个stm32_fb.h的头文件,生成后,这个头文件会自动包含到<cyg/io/framebufs/framebufs.h>头文件中,而它又会被<cyg/io/framebuf.h>头文件包含。

gen_stm32fb.tcl脚本文件有点多,下面截取其一部分:

extern cyg_fb cyg_stm32_fb[set fb];

#define CYG_FB_fb[set fb]_STRUCT            cyg_stm32_fb[set fb]
#define CYG_FB_fb[set fb]_DEPTH             $depth
#define CYG_FB_fb[set fb]_FORMAT            $format
#define CYG_FB_fb[set fb]_WIDTH             $width
#define CYG_FB_fb[set fb]_HEIGHT            $height
#define CYG_FB_fb[set fb]_VIEWPORT_WIDTH    $viewport_width
#define CYG_FB_fb[set fb]_VIEWPORT_HEIGHT   $viewport_height

#define CYG_FB_fb[set fb]_STRIDE            $stride
#define CYG_FB_fb[set fb]_FLAGS0            $flags0
#define CYG_FB_fb[set fb]_FLAGS1            0
#define CYG_FB_fb[set fb]_FLAGS2            0
#define CYG_FB_fb[set fb]_FLAGS3            0

#ifdef CYG_PLF_FB_fb[set fb]_BASE
# define CYG_FB_fb[set fb]_BASE            (void *) CYG_PLF_FB_fb[set fb]_BASE
#else
# define CYG_FB_fb[set fb]_BASE            0
#endif

#if CYG_FB_fb[set fb]_WIDTH > CYG_FB_fb[set fb]_HEIGHT
# define CYG_FB_fb[set fb]_ORIENTATION     landscape
# else
# define CYG_FB_fb[set fb]_ORIENTATION     portrait
#endif

#if CYG_FB_fb[set fb]_WIDTH == CYG_FB_fb[set fb]_HEIGHT
# error \"Framebuffer width and height cannot be configured equal\"
#endif

上面代码中,“set_fb”取0,因此上面的“fb[set fb]”实际上等效于“fb0”。等效后再看这些代码,是不是很熟悉?它就是上节我们用宏CYG_FB_FRAMEBUFFER定义LCD设备对象时一些使用的定义,看下面:

#define FB_STM32_MAKE_FN1(_fn_, _orientation_, _suffix_)  \
                    stm32_fb_ ## _fn_ ## _ ## _orientation_ ## _ ##_suffix_
#define FB_STM32_MAKE_FN( _fn_, _orientation_, _suffix_)  \
                    FB_STM32_MAKE_FN1(_fn_, _orientation_, _suffix_)

#define FB_STM32_COLOUR_FN1(_fn_, _suffix_)  cyg_fb_dev_ ## _fn_ ## _ ## _suffix_
#define FB_STM32_COLOUR_FN( _fn_, _suffix_)  FB_STM32_COLOUR_FN1(_fn_, _suffix_)

#ifdef CYGPKG_DEVS_FRAMEBUF_STM32_FB0

CYG_FB_FRAMEBUFFER(CYG_FB_fb0_STRUCT,
                    CYG_FB_fb0_DEPTH,
                    CYG_FB_fb0_FORMAT,
                    CYG_FB_fb0_WIDTH,
                    CYG_FB_fb0_HEIGHT,
                    CYG_FB_fb0_VIEWPORT_WIDTH,
                    CYG_FB_fb0_VIEWPORT_HEIGHT,
                    CYG_FB_fb0_BASE,
                    CYG_FB_fb0_STRIDE,
                    CYG_FB_fb0_FLAGS0,
                    CYG_FB_fb0_FLAGS1,
                    CYG_FB_fb0_FLAGS2,
                    CYG_FB_fb0_FLAGS3,
                    (CYG_ADDRWORD) 0,
                    (CYG_ADDRWORD) 0,
                    (CYG_ADDRWORD) 0,
                    (CYG_ADDRWORD) 0,
                    &stm32_fb_on,
                    &stm32_fb_off,
                    &stm32_fb_ioctl,
                    &cyg_fb_nop_synch,
                    &cyg_fb_nop_read_palette,
                    &cyg_fb_nop_write_palette,
      &FB_STM32_COLOUR_FN(make_colour, 16bpp_true_565),
      &FB_STM32_COLOUR_FN(break_colour, 16bpp_true_565),
      FB_STM32_MAKE_FN(write_pixel, CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
      FB_STM32_MAKE_FN(read_pixel,  CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
      FB_STM32_MAKE_FN(write_hline, CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
      FB_STM32_MAKE_FN(write_vline, CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
      FB_STM32_MAKE_FN(fill_block,  CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
      FB_STM32_MAKE_FN(write_block, CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
      FB_STM32_MAKE_FN(read_block,  CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
      FB_STM32_MAKE_FN(move_block,  CYG_FB_fb0_ORIENTATION, CYG_FB_fb0_DEPTH),
                    0, 0, 0, 0
    );
#endif

如果上节没弄明白这些定义来自哪里,到这里应该就可以看得懂了。 原来它们定义在由gen_stm32fb.tcl脚本生成的stm32_fb.h头文件中。

再看gen_stm32fb.tcl脚本文件的下面:

        if { $landscape == 1 } {
        append data \
            "
# define CYG_FB_fb0_WRITE_PIXEL(_x_, _y_, _colour_)                          \\
    CYG_MACRO_START                                                          \\
    stm32_fb_write_pixel_landscape_16_inl(CYG_FB_fb0_BASE,             \\
           CYG_FB_fb0_STRIDE,                                                \\
           _x_, _y_, _colour_);                                              \\
    CYG_MACRO_END

# define CYG_FB_fb0_READ_PIXEL(_x_, _y_)                                     \\
    stm32_fb_read_pixel_landscape_16_inl(CYG_FB_fb0_BASE,              \\
           CYG_FB_fb0_STRIDE,                                                \\
           _x_, _y_);

# define CYG_FB_fb0_WRITE_HLINE(_x_, _y_, _len_, _colour_)                   \\
    CYG_MACRO_START                                                          \\
    stm32_fb_write_hline_landscape_16_inl(CYG_FB_fb0_BASE,             \\
           CYG_FB_fb0_STRIDE,                                                \\
           _x_, _y_, _len_, _colour_);                                       \\
    CYG_MACRO_END

# define CYG_FB_fb0_WRITE_VLINE(_x_, _y_, _len_, _colour_)                   \\
    CYG_MACRO_START                                                          \\
    stm32_fb_write_vline_landscape_16_inl(CYG_FB_fb0_BASE,             \\
           CYG_FB_fb0_STRIDE,                                                \\
           _x_, _y_, _len_, _colour_);                                       \\
    CYG_MACRO_END

这里定义了一些函数的宏,在定义LCD设备对象时,LCD基本操作函数也是使用这些函数的。它们都是framebuf IO操作的内联函数。这些定义的宏都会原封不动的呈现到stm32_fb.h头文件中。

framebuf IO操作内联文件

stm32fb.inl文件中定义了framebuf IO操作的内联函数。

// The always_inline attribute must be a applied to a declaration, not a
// definition, so combine the two via a single macro.
#define CYG_FB_DEVS_FRAMEBUF_INLINE_FN(_type_, _name_, _args_)                        \
static __inline__ _type_ _name_ _args_ __attribute__((__always_inline__));            \
static __inline__ _type_ _name_ _args_

/* 设置显示窗口 WINDOWS */
# define CYG_FB_DEFAULT_WINDOW_AREA( _fbaddr_ )                 \
    CYG_MACRO_START                                             \
    cyg_stm32_lcd_t * _lcd = (cyg_stm32_lcd_t *)_fbaddr_;       \
    if ( _lcd->width > _lcd->height ) {                         \
       lcd_set_disp_win(_lcd, 0, 0, _lcd->width, _lcd->height); \
    } else {                                                    \
       lcd_set_disp_win(_lcd, 0, 0, _lcd->height, _lcd->width); \
    }                                                           \
    CYG_MACRO_END

// ----------------------------------------------------------------------------
// LCD in landscape mode

CYG_FB_DEVS_FRAMEBUF_INLINE_FN(void,
                         stm32_fb_write_pixel_landscape_16_inl,
                        (void* _fbaddr_, cyg_ucount16 _stride_, cyg_ucount16 _x_, cyg_ucount16 _y_, cyg_fb_colour _colour_))
{
    lcd_put_pixel(_x_,_y_,_colour_);
}

CYG_FB_DEVS_FRAMEBUF_INLINE_FN(cyg_fb_colour,
                         stm32_fb_read_pixel_landscape_16_inl,
                        (void* _fbaddr_, cyg_ucount16 _stride_, cyg_ucount16 _x_, cyg_ucount16 _y_))
{
    return  lcd_get_pixel(_x_,_y_);
}

CYG_FB_DEVS_FRAMEBUF_INLINE_FN(void,
                         stm32_fb_write_hline_landscape_16_inl,
                        (void* _fbaddr_, cyg_ucount16 _stride_, cyg_ucount16 _x_, cyg_ucount16 _y_, cyg_ucount16 _len_, cyg_fb_colour _colour_))
{
    cyg_uint32 pixels;

    lcd_set_cursor(_x_,_y_);
    /* 先横向扫描,再纵向扫描 */
    lcd_write_ir(LCDR_GRAM);
    for (pixels = 0; pixels < _len_; pixels++) {
        lcd_write_ram(_colour_);
    }
}

目前,stm32fb.inl文件中只实现了landscape(宽屏) LCD的一些操作IO,portrait(竖屏)LCD操作还没有实现。

到现在,应该大概明白LCD驱动的架构是怎样实现的了。像stm32fb.inl文件中实现的内联函数,以及stm32fb_lcd.inl中LCD底层函数,这些都会被gen_stm32fb.tcl脚本自动生成到stm32_fb.h头文件中。

最终,应用程序中只需包含<cyg/io/framebuf.h>头文件,就可以使用framebuf提供的API了。从这层来看,eCos中LCD应用程序与LCD驱动实际是一种API调用关系,只是被framebuf IO层封装化了。当然,这种封装是必要的,它实现了LCD应用程序与具体LCD设备的独立性。

应用实例

注意:要使用framebuf,需要包含CYGPKG_IO_FRAMEBUF软件包。在实际使用中发现,如果要使用标准颜色值,还需要包含FILE IO包:CYGPKG_IO_FILEIO,否则下面代码中宏定义的颜色会不起作用。

#include <unistd.h>
#include <fcntl.h>

#define STRING1(_a_) # _a_
#define STRING(_a_) STRING1(_a_)

// The colours used by this test code. Default to the standard palette
// but if running on a true colour display then adjust.
static cyg_ucount32 colours[16]  = {
    CYG_FB_DEFAULT_PALETTE_BLACK,
    CYG_FB_DEFAULT_PALETTE_BLUE,
    CYG_FB_DEFAULT_PALETTE_GREEN,
    CYG_FB_DEFAULT_PALETTE_CYAN,
    CYG_FB_DEFAULT_PALETTE_RED,
    CYG_FB_DEFAULT_PALETTE_MAGENTA,
    CYG_FB_DEFAULT_PALETTE_BROWN,
    CYG_FB_DEFAULT_PALETTE_LIGHTGREY,
    CYG_FB_DEFAULT_PALETTE_DARKGREY,
    CYG_FB_DEFAULT_PALETTE_LIGHTBLUE,
    CYG_FB_DEFAULT_PALETTE_LIGHTGREEN,
    CYG_FB_DEFAULT_PALETTE_LIGHTCYAN,
    CYG_FB_DEFAULT_PALETTE_LIGHTRED,
    CYG_FB_DEFAULT_PALETTE_LIGHTMAGENTA,
    CYG_FB_DEFAULT_PALETTE_YELLOW,
    CYG_FB_DEFAULT_PALETTE_WHITE
};

#define BLACK        colours[0x00]
#define BLUE         colours[0x01]
#define GREEN        colours[0x02]
#define CYAN         colours[0x03]
#define RED          colours[0x04]
#define MAGENTA      colours[0x05]
#define BROWN        colours[0x06]
#define LIGHTGREY    colours[0x07]
#define DARKGREY     colours[0x08]
#define LIGHTBLUE    colours[0x09]
#define LIGHTGREEN   colours[0x0A]
#define LIGHTCYAN    colours[0x0B]
#define LIGHTRED     colours[0x0C]
#define LIGHTMAGENTA colours[0x0D]
#define YELLOW       colours[0x0E]
#define WHITE        colours[0x0F]

#define FRAMEBUF fb0

#define DEPTH   CYG_FB_DEPTH(FRAMEBUF)
#define WIDTH   CYG_FB_WIDTH(FRAMEBUF)
#define HEIGHT  CYG_FB_HEIGHT(FRAMEBUF)

#define GRID_X_SIZE             400
#define GRID_Y_SIZE             240
#define GRID_ABSOLUTE_X_POS     1
#define GRID_ABSOLUTE_Y_POS     19
#define GRID_STEP               25
#define MAX_X                   (GRID_X_SIZE + GRID_ABSOLUTE_X_POS)
#define MAX_Y                   (GRID_Y_SIZE + GRID_ABSOLUTE_Y_POS)

static void
reset_colours_to_true(void)
{
#if (CYG_FB_FLAGS0_TRUE_COLOUR & CYG_FB_FLAGS0(FRAMEBUF))
    int i;

    for (i = 0; i < 16; i++) {
        colours[i] = CYG_FB_MAKE_COLOUR(FRAMEBUF,
                                        cyg_fb_palette_vga[i + i + i], cyg_fb_palette_vga[i + i + i + 1],cyg_fb_palette_vga[i + i + i + 2]);
//      diag_printf("colours[%02d] = 0x%06X\n", i, colours[i]);
    }
#endif
}

void lcd_init(void * data)
{
    int i;

    if (CYG_FB_ON(FRAMEBUF)) {
        diag_printf("Open frambuf %s failed!\n", STRING(FRAMEBUF));
        return;
    }

    diag_printf("Frame buffer %s, ", STRING(FRAMEBUF));
    diag_printf("Depth %d, width %d\n", DEPTH, WIDTH);

    // 打开背光
    cyg_fb_ioctl_backlight backlight;
    backlight.fbbl_current = 1;
    i = sizeof(backlight);
    CYG_FB_IOCTL(FRAMEBUF, CYG_FB_IOCTL_BACKLIGHT_SET, &backlight, &i);

    if (CYG_FB_FLAGS0(FRAMEBUF) & CYG_FB_FLAGS0_TRUE_COLOUR) {
        reset_colours_to_true();
    }

    // 白色背景
    CYG_FB_FILL_BLOCK(FRAMEBUF, 0, 0, WIDTH, HEIGHT, WHITE);

    // 画一条横线
    CYG_FB_WRITE_HLINE(FRAMEBUF, 5, 20, 100, RED);

    // 填充一个区域
    CYG_FB_FILL_BLOCK(FRAMEBUF, 5, 30, 100, 20, YELLOW);

    // 一条竖线
    CYG_FB_WRITE_VLINE(FRAMEBUF, 1, 1, 100, BLUE);

    // 一条竖线
    CYG_FB_WRITE_VLINE(FRAMEBUF, 120, 1, 100, GREEN);
» 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
» 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
分享到:

 Leave a Reply

(必须)

(我会替您保密的)(必须)

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.

   
© 2012 velep.com | reille blog | 管理| 粤ICP备12094833号-2| 谷歌地图| 百度地图| Suffusion theme|Sayontan Sinha

无觅相关文章插件,快速提升流量