Board logo

标题: 单片机和嵌入式系统linux的区别(二) [打印本页]

作者: fxfreefly    时间: 2010-11-15 14:44     标题: 单片机和嵌入式系统linux的区别(二)

2. 带操作系统与不带操作系统的软件开发的区别
用通俗的话来说,一个处理芯片不运行操作系统,我们就把它称为单片机,而单片机编程就是写裸板程序,这个程序直接在板子上运行;相对的,另一种程序就是基于操作系统的程序,说得简单点就是,这种程序可以通过统一的接口调用“别人写好的代码”,在“别人的基础上”更快更方便地实现自己的功能。
2.1. 驱动开发的区别
驱动开发的区别我总结有两点:能否借用、是否通用。
2.1.1 能否借用
基于操作系统的软件资源非常丰富,你要写一个Linux设备驱动时,首先在网上找找,如果有直接拿来用;其次是找到类似的,在它的基础上进行修改;如果实在没有,就要研究设备手册,从零写起。而不带操作系统的驱动开发,一开始就要深入了解设备手册,从零开始为它构造运行环境,实现各种函数以供应用程序使用。
举个例子,要驱动一块LCD,在单片机上的做法是:
① 首先要了解LCD的规格,弄清楚怎么设置各个寄存器,比如设置LCD的时钟、分辨率、象素
② 划出一块内存给LCD使用
③ 编写一个函数,实现在指定坐标描点。比如根据x、y坐标在这块内存里找到这个象素对应的小区域,填入数据。

基于操作系统时,我们首先是找到类似的驱动,弄清楚驱动结构,找到要修改的地方进行修改。
下面是单片机操作LCD的代码:
① 初始化:
void Tft_Lcd_Init(int type)
        {
               /*
                * 设置LCD控制器的控制寄存器LCDCON1~5
                * 1. LCDCON1:
                * 设置VCLK的频率:VCLK(Hz) = HCLK/[(CLKVAL+1)x2]
                * 选择LCD类型: TFT LCD
                * 设置显示模式: 16BPP
                * 先禁止LCD信号输出
                * 2. LCDCON2/3/4:
                * 设置控制信号的时间参数
                * 设置分辨率,即行数及列数
                * 现在,可以根据公式计算出显示器的频率:
                * 当HCLK=100MHz时,
                * Rate = 1/[{(VSPW+1)+(VBPD+1)+(LIINEVAL+1)+(VFPD+1)}x
                *        {(HSPW+1)+(HBPD+1)+(HFPD+1)+(HOZVAL+1)}x
                *        {2x(CLKVAL+1)/(HCLK)}]
                *        = 60Hz
                * 3. LCDCON5:
                *        设置显示模式为16BPP时的数据格式: 5:6:5
                *        设置HSYNC、VSYNC脉冲的极性(这需要参考具体LCD的接口信号): 反转
                *        半字(2字节)交换使能
                */
                LCDCON1 = (CLKVAL_TFT_320240<<8) | (LCDTYPE_TFT<<5) | \
                                        (BPPMODE_16BPP<<1) | (ENVID_DISABLE<<0);
                LCDCON2 = (VBPD_320240<<24) | (LINEVAL_TFT_320240<<14) | \
                                        (VFPD_320240<<6) | (VSPW_320240);
                LCDCON3 = (HBPD_320240<<19) | (HOZVAL_TFT_320240<<8) | (HFPD_320240);
                LCDCON4 = HSPW_320240;
        //        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | \
        //                                (HWSWP<<1);
                        LCDCON5 = (FORMAT8BPP_565<<11) | (HSYNC_INV<<9) | (VSYNC_INV<<8) | (VDEN_INV << 6) | \
                                                (HWSWP<<0);

        /*
                * 设置LCD控制器的地址寄存器LCDSADDR1~3
                * 帧内存与视口(view point)完全吻合,
                * 图像数据格式如下:
                *        |----PAGEWIDTH----|
                *        y/x    0    1    2    239
                *        0    rgb rgb rgb ... rgb
                *        1    rgb rgb rgb ... rgb
                * 1. LCDSADDR1:
                *    设置LCDBANK、LCDBASEU
                * 2. LCDSADDR2:
                *    设置LCDBASEL: 帧缓冲区的结束地址A[21:1]
                * 3. LCDSADDR3:
                *    OFFSIZE等于0,PAGEWIDTH等于(240*2/2)
                */
                LCDSADDR1 = ((LCDBUFFER>>22)<<21) | LOWER21BITS(LCDBUFFER>>1);
                LCDSADDR2 = LOWER21BITS((LCDBUFFER+ \
                                            (LINEVAL_TFT_320240+1)*(HOZVAL_TFT_320240+1)*2)>>1);
                LCDSADDR3 = (0<<11) | (LCD_XSIZE_TFT_320240*2/2);

        /* 禁止临时调色板寄存器 */
                TPAL = 0;

        fb_base_addr = LCDBUFFER;
                bpp = 16;
                xsize = 320;
                ysize = 240;
        }

② 描点:
/*
        * 画点
        * 输入参数:
        *        x、y : 象素坐标
        *        color: 颜色值
        *                对于16BPP: color的格式为0xAARRGGBB (AA = 透明度),
        *        需要转换为5:6:5格式
        *                对于8BPP: color为调色板中的索引值,
        *        其颜色取决于调色板中的数值
        */
        void PutPixel(UINT32 x, UINT32 y, UINT32 color)
        {
                UINT8 red,green,blue;

        switch (bpp){
                        case 16:
                        {
                                UINT16 *addr = (UINT16 *)fb_base_addr + (y * xsize + x);
                                red = (color >> 19) & 0x1f;
                                green = (color >> 10) & 0x3f;
                                blue = (color >> 3) & 0x1f;
                                color = (red << 11) | (green << 5) | blue; // 格式5:6:5
                                *addr = (UINT16) color;
                                break;
                        }

                        case 8:
                        {
                                UINT8 *addr = (UINT8 *)fb_base_addr + (y * xsize + x);
                                *addr = (UINT8) color;
                                break;
                        }

                default:
                                break;
                }
        }

下面是在Linux的LCD驱动里修改的地方(arch\arm\mach-s3c2440\mach-smdk2440.c):
        /* 320x240 */
        static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {
                .regs = {
                        .lcdcon1 = S3C2410_LCDCON1_TFT16BPP | \
                                S3C2410_LCDCON1_TFT | \
                                S3C2410_LCDCON1_CLKVAL(0x04),

                .lcdcon2 = S3C2410_LCDCON2_VBPD(1) | \
                                S3C2410_LCDCON2_LINEVAL(239) | \
                                S3C2410_LCDCON2_VFPD(5) | \
                                S3C2410_LCDCON2_VSPW(1),

                .lcdcon3 = S3C2410_LCDCON3_HBPD(36) | \
                                S3C2410_LCDCON3_HOZVAL(319) | \
                                S3C2410_LCDCON3_HFPD(19),

                .lcdcon4 = S3C2410_LCDCON4_MVAL(13) | \
                                S3C2410_LCDCON4_HSPW(5),

                .lcdcon5 = S3C2410_LCDCON5_FRM565 |
                                S3C2410_LCDCON5_INVVLINE |
                                S3C2410_LCDCON5_INVV |
                                S3C2410_LCDCON5_INVVDEN |
                                S3C2410_LCDCON5_PWREN |
                                S3C2410_LCDCON5_HWSWP,
                },

        .gpccon = 0xaaaa56aa,
                .gpccon_mask = 0xffffffff,
                .gpcup = 0xffffffff,
                .gpcup_mask = 0xffffffff,

        .gpdcon = 0xaaaaaaaa,
                .gpdcon_mask = 0xffffffff,
                .gpdup = 0xffffffff,
                .gpdup_mask = 0xffffffff,

        .fixed_syncs = 1,
                .type = S3C2410_LCDCON1_TFT,
                .width = 320,
                .height = 240,

        .xres = {
                        .min = 320,
                        .max = 320,
                        .defval = 320,
                },

        .yres = {
                        .max = 240,
                        .min = 240,
                        .defval = 240,
                },

        .bpp = {
                        .min = 16,
                        .max = 16,
                        .defval = 16,
                },
        };

这并不表示代码Linux的驱动程序就比单片机的驱动程序好写,怎么在几万个文件中找到要修改的代码,这也是需要艰苦的学习的。基于操作系统的驱动开发,既要懂得芯片的具体操作,也要理解操作系统的软件结构。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0