S3c2410 LCD驱动学习心得[五篇]

时间:2019-05-12 07:55:03下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《S3c2410 LCD驱动学习心得》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《S3c2410 LCD驱动学习心得》。

第一篇:S3c2410 LCD驱动学习心得

S3c2410 LCD驱动学习心得

一 实验内容简要描述 1.实验目的

学会驱动程序的编写方法,配置S3C2410的LCD驱动,以及在LCD屏上显示包括bmp和jpeg两种格式的图片 2.实验内容

(1)分析S3c2410实验箱LCD以及LCD控制器的硬件原理,据此找出相应的硬件设置参数,参考xcale实验箱关于lcd的设置,完成s3c2410实验箱LCD的设置

(2)在LCD上显示一张BMP图片或JPEG图片 3.实验条件(软硬件环境)

PC机、S3C2410开发板、PXA255开发板 二 实验原理

1.S3C2410内置LCD控制器分析 1.1 S3C2410 LCD控制器

一块LCD屏显示图像,不但需要LCD驱动器,还需要有相应的LCD控制器。通常LCD驱动器会以COF/COG的形式与LCD 玻璃基板制作在一起,而LCD控制器则由外部电路来实现。而S3C2410内部已经集成了LCD控制器,因此可以很方便地去控制各种类型的LCD屏,例如:STN和TFT屏。S3C2410 LCD控制器的特性如下:(1)STN屏

支持3种扫描方式:4bit单扫、4位双扫和8位单扫 支持单色、4级灰度和16级灰度屏

支持256色和4096色彩色STN屏(CSTN)

支持分辩率为640*480、320*240、160*160以及其它规格的多种LCD(2)TFT屏

支持单色、4级灰度、256色的调色板显示模式 支持64K和16M色非调色板显示模式

支持分辩率为640*480,320*240及其它多种规格的LCD 对于控制TFT屏来说,除了要给它送视频资料(VD[23:0])以外,还有以下一些信号是必不可少的,分别是:

VSYNC(VFRAME):帧同步信号 HSYNC(VLINE):行同步信号 VCLK :像数时钟信号

VDEN(VM):数据有效标志信号

由于本项目所用的S3C2410上的LCD是TFT屏,并且TFT屏将是今后应用的主流,因此接下来,重点围绕TFT屏的控制来进行。

图1.1是S3C2410内部的LCD控制器的逻辑示意图:

图1.1 REGBANK 是LCD控制器的寄存器组,用来对LCD控制器的各项参数进行设置。而 LCDCDMA 则是LCD控制器专用的DMA信道,负责将视频资料从系统总线(System Bus)上取来,通过 VIDPRCS 从VD[23:0]发送给LCD屏。同时 TIMEGEN 和 LPC3600 负责产生 LCD屏所需要的控制时序,例如VSYNC、HSYNC、VCLK、VDEN,然后从 VIDEO MUX 送给LCD屏。

1.2 TFT屏时序分析

图1.2是TFT屏的典型时序。其中VSYNC是帧同步信号,VSYNC每发出1个脉冲,都意味着新的1屏视频资料开始发送。而HSYNC为行同步信号,每个HSYNC脉冲都表明新的1行视频资料开始发送。而VDEN则用来标明视频资料的有效,VCLK是用来锁存视频资料的像数时钟。

并且在帧同步以及行同步的头尾都必须留有回扫时间,例如对于VSYNC来说前回扫时间就是(VSPW+1)+(VBPD+1),后回扫时间就是(VFPD +1);HSYNC亦类同。这样的时序要求是当初CRT显示器由于电子枪偏转需要时间,但后来成了实际上的工业标准,乃至于后来出现的TFT屏为了在时序上于CRT兼容,也采用了这样的控制时序。

图1.2 S3C2410实验箱上的LCD是一款3.5寸TFT真彩LCD屏,分辩率为240*320,下图为该屏的时序要求。

图1.3 通过对比图1.2和图1.3,我们不难看出: VSPW+1=2-> VSPW=1 VBPD+1=2-> VBPD=1 LINVAL+1=320-> LINVAL=319 VFPD+1=3-> VFPD=2 HSPW+1=4-> HSPW=3 HBPD+1=7-> HBPW=6 HOZVAL+1=240-> HOZVAL=239 HFPD+1=31-> HFPD=30 以上各参数,除了LINVAL和HOZVAL直接和屏的分辩率有关,其它的参数在实际操作过程中应以上面的为参考,不应偏差太多。

1.3 LCD控制器主要寄存器功能详解

图1.4 LINECNT :当前行扫描计数器值,标明当前扫描到了多少行。

CLKVAL :决定VCLK的分频比。LCD控制器输出的VCLK是直接由系统总线(AHB)的工作频率HCLK直接分频得到的。做为240*320的TFT屏,应保证得出的VCLK在5~10MHz之间。MMODE :VM信号的触发模式(仅对STN屏有效,对TFT屏无意义)。

PNRMODE :选择当前的显示模式,对于TFT屏而言,应选择[11],即TFT LCD panel。BPPMODE :选择色彩模式,对于真彩显示而言,选择16bpp(64K色)即可满足要求。ENVID :使能LCD信号输出。

图1.5 VBPD,LINEVAL,VFPD,VSPW 的各项含义已经在前面的时序图中得到体现。

图1.6 HBPD,HOZVAL,HFPD 的各项含义已经在前面的时序图中得到体现。

图1.7 HSPW 的含义已经在前面的时序图中得到体现。MVAL 只对 STN屏有效,对TFT屏无意义。

HSPW 的含义已经在前面的时序图中得到体现,这里不再赘述。MVAL 只对 STN屏有效,对TFT屏无意义。

图1.8 VSTATUS :当前VSYNC信号扫描状态,指明当前VSYNC同步信号处于何种扫描阶段。HSTATUS :当前HSYNC信号扫描状态,指明当前HSYNC同步信号处于何种扫描阶段。

BPP24BL :设定24bpp显示模式时,视频资料在显示缓冲区中的排列顺序(即低位有效还是高位有效)。对于16bpp的64K色显示模式,该设置位无意义。

FRM565 :对于16bpp显示模式,有2中形式,一种是RGB=5:5:5:1,另一种是5:6:5。后一种模式最为常用,它的含义是表示64K种色彩的16bit RGB资料中,红色(R)占了5bit,绿色(G)占了6bit,兰色(B)占了5bit INVVCLK,INVLINE,INVFRAME,INVVD :通过前面的时序图,我们知道,CPU的LCD控制器输出的时序默认是正脉冲,而LCD需要VSYNC(VFRAME)、VLINE(HSYNC)均为负脉冲,因此 INVLINE 和 INVFRAME 必须设为“1 ”,即选择反相输出。INVVDEN,INVPWREN,INVLEND 的功能同前面的类似。

PWREN 为LCD电源使能控制。在CPU LCD控制器的输出信号中,有一个电源使能管脚LCD_PWREN,用来做为LCD屏电源的开关信号。

ENLEND 对普通的TFT屏无效,可以不考虑。

BSWP 和 HWSWP 为字节(Byte)或半字(Half-Word)交换使能。由于不同的GUI对FrameBuffer(显示缓冲区)的管理不同,必要时需要通过调整 BSWP 和 HWSWP 来适应GUI。2.Linux 驱动 2.1 FrameBuffer Linux是工作在保护模式下,所以用户态进程是无法像DOS那样使用显卡BIOS里提供的中断调用来实现直接写屏,Lin仿显卡的功能,将显ux抽象出FrameBuffer这个设备来供用户态进程实现直接写屏。Framebuffer机制模卡硬件结构抽象掉,可以通过Framebuffer的读写直接对显存进行操作。用户可以将Framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作可以立即反应在屏幕上。这种操作是抽象的,统一的。用户不必关心物理显存的位置、换页机制等等具体细节。这些都是由Framebuffer设备驱动来完成的。

在Linux系统下,FrameBuffer的主要的结构如图所示。Linux为了开发FrameBuffer程序的方便,使用了分层结构。fbmem.c处于Framebuffer设备驱动技术的中心位置。它为上层应用程序提供系统调用,也为下一层的特定硬件驱动提供接口;那些底层硬件驱动需要用到这儿的接口来向系统内核注册它们自己。

fbmem.c 为所有支持FrameBuffer的设备驱动提供了通用的接口,避免重复工作。下将介绍fbmem.c主要的一些数据结构。

2.2 数据结构

2.2.1 Linux FrameBuffer的数据结构

在FrameBuffer中,fb_info可以说是最重要的一个结构体,它是Linux为帧缓冲设备定义的驱动层接口。它不仅包含了底层函数,而且还有记录设备状态的数据。每个帧缓冲设备都与一个fb_info结构相对应。fb_info的主要成员如下 struct fb_info { int node;struct fb_var_screeninfo var;/* Current var */ struct fb_fix_screeninfo fix;/* Current fix */ struct fb_videomode *mode;/* current mode */

struct fb_ops *fbops;struct device *device;/* This is the parent */ struct device *dev;/* This is this fb device */

char __iomem *screen_base;/* Virtual address */ unsigned long screen_size;/* Amount of ioremapped VRAM or 0 */

………… };其中node成员域标示了特定的FrameBuffer,实际上也就是一个FrameBuffer设备的次设备号。fb_var_screeninfo结构体成员记录用户可修改的显示控制器参数,包括屏幕分辨率和每个像素点的比特数。fb_var_screeninfo中的xres定义屏幕一行有多少个点, yres定义屏幕一列有多少个点, bits_per_pixel定义每个点用多少个字节表示。其他域见以下代码注释。struct fb_var_screeninfo { __u32 xres;/* visible resolution */ __u32 yres;__u32 xoffset;/* offset from virtual to visible */ __u32 yoffset;/* resolution */ __u32 bits_per_pixel;/* bits/pixel */ __u32 pixclock;/* pixel clock in ps(pico seconds)*/ __u32 left_margin;/* time from sync to picture */ __u32 right_margin;/* time from picture to sync */ __u32 hsync_len;/* length of horizontal sync */ __u32 vsync_len;/* length of vertical sync */ ………… };在fb_info结构体中,fb_fix_screeninfo中记录用户不能修改的显示控制器的参数,如屏幕缓冲区的物理地址,长度。当对帧缓冲设备进行映射操作的时候,就是从fb_fix_screeninfo中取得缓冲区物理地址的。struct fb_fix_screeninfo { char id[16];/* identification string eg “TT Builtin” */ unsigned long smem_start;/* Start of frame buffer mem(physical address)*/ __u32 smem_len;/* Length of frame buffer mem */ unsigned long mmio_start;/* Start of Mem Mapped I/O(physical address)*/ __u32 mmio_len;/* Length of Memory Mapped I/O */ ………… };fb_info还有一个很重要的域就是fb_ops。它是提供给底层设备驱动的一个接口。通常我们编写字符驱动的时候,要填写一个file_operations结构体,并使用register_chrdev()注册之,以告诉Linux如何操控驱动。当我们编写一个FrameBuffer的时候,就要依照Linux FrameBuffer编程的套路,填写fb_ops结构体。这个fb_ops也就相当于通常的file_operations结构体。struct fb_ops { int(*fb_open)(struct fb_info *info, int user);int(*fb_release)(struct fb_info *info, int user);ssize_t(*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos);ssize_t(*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos);int(*fb_set_par)(struct fb_info *info);int(*fb_setcolreg)(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info);int(*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info)int(*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);…………… } 上面的结构体,根据函数的名字就可以看出它的作用,这里不在一一说明。下图给出了Linux FrameBuffer的总体结构,作为这一部分的总结。图2.2

2.2.2 S3C2410中LCD的数据结构

在S3C2410的LCD设备驱动中,定义了s3c2410fb_info来标识一个LCD设备,结构体如下: struct s3c2410fb_info { struct fb_info *fb;struct device *dev;struct s3c2410fb_mach_info *mach_info;struct s3c2410fb_hw regs;/* LCD Hardware Regs */ dma_addr_t map_dma;/* physical */ u_char * map_cpu;/* virtual */ u_int map_size;/* addresses of pieces placed in raw buffer */ u_char * screen_cpu;/* virtual address of buffer */ dma_addr_t screen_dma;/* physical address of buffer */ ………… };成员变量fb指向我们上面所说明的fb_info结构体,代表了一个FrameBuffer。dev则表示了这个LCD设备。map_dma,map_cpu,map_size这三个域向了开辟给LCD DMA使用的内存地址。screen_cpu,screen_dma指向了LCD控制器映射的内存地址。另外regs标识了LCD控制器的寄存器。struct s3c2410fb_hw { unsigned long lcdcon1;unsigned long lcdcon2;unsigned long lcdcon3;unsigned long lcdcon4;unsigned long lcdcon5;};这个寄存器和硬件的寄存器一一对应,主要作为实际寄存器的映像,以便程序使用。这个s3c2410fb_info中还有一个s3c2410fb_mach_info成员域。它存放了和体系结构相关的一些信息,如时钟、LCD设备的GPIO口等等。这个结构体定义为 struct s3c2410fb_mach_info { unsigned char fixed_syncs;/* do not update sync/border */ int type;/* LCD types */ int width;/* Screen size */ int height;struct s3c2410fb_val xres;/* Screen info */ struct s3c2410fb_val yres;struct s3c2410fb_val bpp;struct s3c2410fb_hw regs;/* lcd configuration registers */ /* GPIOs */ unsigned long gpcup;unsigned long gpcup_mask;unsigned long gpccon;unsigned long gpccon_mask;………… };

图2.3 上图表示了S3C2410驱动的整体结构,反映了结构体之间的相互关系 2.3 主要代码结构以及关键代码分析 2.3.1 FrameBuffer驱动的统一管理

fbmem.c实现了Linux FrameBuffer的中间层,任何一个FrameBuffer驱动,在系统初始化时,必须向fbmem.c注册,即需要调用register_framebuffer()函数,在这个过程中,设备驱动的信息将会存放入名称为registered_fb数组中,这个数组定义为 struct fb_info *registered_fb[FB_MAX];int num_registered_fb;它是类型为fb_info的数组,另外num_register_fb则存放了注册过的设备数量。

我们分析一下register_framebuffer的代码。int register_framebuffer(struct fb_info *fb_info){ int i;struct fb_event event;struct fb_videomode mode;if(num_registered_fb == FB_MAX)return-ENXIO;/* 超过最大数量 */ num_registered_fb++;for(i = 0;i < FB_MAX;i++)if(!registered_fb[i])break;/* 找到空余的数组空间 */ fb_info->node = i;

fb_info->dev = device_create(fb_class, fb_info->device, MKDEV(FB_MAJOR, i), “fb%d”, i);/* 为设备建立设备节点 */ if(IS_ERR(fb_info->dev)){ ………… } else{ fb_init_device(fb_info);/* 初始化改设备 */ } ………… return 0;} 从上面的代码可知,当FrameBuffer驱动进行注册的时候,它将驱动的fb_info结构体记录到全局数组registered_fb中,并动态建立设备节点,进行设备的初始化。注意,这里建立的设备节点的次设备号就是该驱动信息在registered_fb存放的位置,即数组下标i。在完成注册之后,fbmem.c就记录了驱动的fb_info。这样我们就有可能实现fbmem.c对全部FrameBuffer驱动的统一处理。

2.3.2 实现消息的分派

fbmem.c实现了对系统全部FrameBuffer设备的统一管理。当用户尝试使用一个特定的FrameBuffer时,fbmem.c怎么知道该调用那个特定的设备驱动呢?

我们知道,Linux是通过主设备号和次设备号,对设备进行唯一标识。不同的FrameBuffer设备向fbmem.c注册时,程序分配给它们的主设备号是一样的,而次设备号是不一样的。于是我们就可以通过用户指明的次设备号,来觉得具体该调用哪一个FrameBuffer驱动。下面通过分析fbmem.c的fb_open()函数来说明。(注:一般我们写FrameBuffer驱动不需要实现open函数,这里只是说明函数流程。)static int fb_open(struct inode *inode, struct file *file){ int fbidx = iminor(inode);struct fb_info *info;int res;/* 得到真正驱动的函数指针 */ if(!(info = registered_fb[fbidx]))return-ENODEV;if(info->fbops->fb_open){ res = info->fbops->fb_open(info,1);//调用驱动的open()if(res)module_put(info->fbops->owner);} return res;} 当用户打开一个FrameBuffer设备的时,将调用这里的fb_open()函数。传进来的inode就是欲打开设备的设备号,包括主设备和次设备号。fb_open函数首先通过iminor()函数取得次设备号,然后查全局数组registered_fb得到设备的fb_info信息,而这里面存放了设备的操作函数集fb_ops。这样,我们就可以调用具体驱动的fb_open()函数,实现open的操作。下面给出了一个LCD驱动的open()函数的调用流程图,用以说明上面的步骤。

图2.4

2.3.3 开发板S3C2410 LCD驱动的流程

(1)在mach-smdk2410.c中,定义了初始的LCD参数。注意这是个全局变量。static struct s3c2410fb_mach_info smdk2410_lcd_cfg = {.regs= {.lcdcon1 = S3C2410_LCDCON1_TFT16BPP | S3C2410_LCDCON1_TFT| S3C2410_LCDCON1_CLKVAL(7),......},.width = 240,.height = 320,.xres = {.min = 240,.max= 240,.defval = 240},.bpp = {.min = 16,.max= 16,.defval = 16},......};(2)内核初始化时候调用s3c2410fb_probe函数。下面分析这个函数的做的工作。首先先动态分配s3c2410fb_info空间。

fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info),&pdev->dev);把域mach_info指向mach-smdk2410.c中的smdk2410_lcd_cfg。info->mach_info = pdev->dev.platform_data;设置fb_info域的fix,var,fops字段。

fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;fbinfo->fix.type_aux = 0;fbinfo->fix.xpanstep = 0;

fbinfo->var.nonstd = 0;fbinfo->var.activate = FB_ACTIVATE_NOW;fbinfo->var.height = mach_info->height;fbinfo->var.width = mach_info->width;

fbinfo->fbops = &s3c2410fb_ops;……

该函数调用s3c2410fb_map_video_memory()申请DMA内存,即显存。

fbi->map_size = PAGE_ALIGN(fbi->fb->fix.smem_len + PAGE_SIZE);fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, &fbi->map_dma, GFP_KERNEL);

fbi->map_size = fbi->fb->fix.smem_len;…….设置控制寄存器,设置硬件寄存器。

memcpy(&info->regs, &mach_info->regs,sizeof(info->regs));info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;……….调用函数s3c2410fb_init_registers(),把初始值写入寄存器。

writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);

(3)当用户调用mmap()映射内存的时候,Fbmem.c把刚才设置好的显存区域映射给用户。start = info->fix.smem_start;len = PAGE_ALIGN((start & ~PAGE_MASK)+ info->fix.smem_len);io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end-vma->vm_start,vma->vm_page_prot);

……

这样就完成了驱动初始化到用户调用的整个过程。3.BMP和JPEG图形显示程序

3.1 在LCD上显示BMP或JPEG图片的主流程图

首先,在程序开始前。要在nfs/dev目录下创建LCD的设备结点,设备名fb0,设备类型为字符设备,主设备号为29,次设备号为0。命令如下: mknod fb0 c 29 0 在LCD上显示图象的主流程图如图3.1所示。程序一开始要调用open函数打开设备,然后调用ioctl获取设备相关信息,接下来就是读取图形文件数据,把图象的RGB值映射到显存中,这部分是图象显示的核心。对于JPEG格式的图片,要先经过JPEG解码才能得到RGB数据,本项目中直接才用现成的JPEG库进行解码。对于bmp格式的图片,则可以直接从文件里面提取其RGB数据。要从一个bmp文件里面把图片数据阵列提取出来,首先必须知道bmp文件的格式。下面来详细介绍bmp文件的格式。

图3.1

3.2 bmp位图格式分析

位图文件可看成由四个部分组成:位图文件头、位图信息头、彩色表和定义位图的字节阵列。如图3.2所示。

图3.2 文件头中各个段的地址及其内容如图3.3。

图3.3 位图文件头数据结构包含BMP图象文件的类型,显示内容等信息。它的数据结构如下定义: Typedef struct {

int bfType;//表明位图文件的类型,必须为BM long bfSize;//表明位图文件的大小,以字节为单位 int bfReserved1;//属于保留字,必须为本0 int bfReserved2;//也是保留字,必须为本0 long bfOffBits;//位图阵列的起始位置,以字节为单位 } BITMAPFILEHEADER; 图3.4 位图文件头的数据结构

(2)信息头中各个段的地址及其内容如图3.5所示。图3.5 位图信息头的数据结构包含了有关BMP图象的宽,高,压缩方法等信息,它的C语言数据结构如图3.6所示。Typedef struct { long biSize; //指出本数据结构所需要的字节数 long biWidth;//以象素为单位,给出BMP图象的宽度 long biHeight;//以象素为单位,给出BMP图象的高度 int biPlanes;//输出设备的位平面数,必须置为1 int biBitCount;//给出每个象素的位数 long biCompress;//给出位图的压缩类型 long biSizeImage;//给出图象字节数的多少 long biXPelsPerMeter;//图像的水平分辨率 long biYPelsPerMeter;//图象的垂直分辨率 long biClrUsed;//调色板中图象实际使用的颜色素数 long biClrImportant;//给出重要颜色的索引值 } BITMAPINFOHEADER;

图3.6 BITMAPINFOHEADER数据结构

(3)对于象素小于或等于16位的图片,都有一个颜色表用来给图象数据阵列提供颜色索引,其中的每块数据都以B、G、R的顺序排列,还有一个是reserved保留位。而在图形数据区域存放的是各个象素点的索引值。它的C语言结构如图3.7所示。

图3.7 颜色表数据结构

(4)对于24位和32位的图片,没有彩色表,他在图象数据区里直接存放图片的RGB数据,其中的每个象素点的数据都以B、G、R的顺序排列。每个象素点的数据结构如图3.8所示。

图3.8 图象数据阵列的数据结构

(5)由于图象数据阵列中的数据是从图片的最后一行开始往上存放的,因此在显示图象时,是从图象的左下角开始逐行扫描图象,即从左到右,从下到上。

(6)对S3C2410或PXA255开发板上的LCD来说,他们每个象素点所占的位数为16位,这16位按B:G:R=5:6:5的方式分,其中B在最高位,R在最低位。而从bmp图象得到的R、G、B数据则每个数据占8位,合起来一共24位,因此需要对该R、G、B数据进行移位组合成一个16位的数据。移位方法如下:

b >>= 3;g >>= 2;r >>= 3;RGBValue =(r<<11 | g << 5 | b);基于以上分析,提取各种类型的bmp图象的流程如图3.9所示

图 3.9

3.3 实现显示任意大小的图片

开发板上的LCD屏的大小是固定的,S3C2410上的LCD为:240*320,PXA255上的为:640*480。比屏幕小的图片在屏上显示当然没问题,但是如果图片比屏幕大呢?这就要求我们通过某种算法对图片进行缩放。

缩放的基本思想是将图片分成若干个方块,对每个方块中的R、G、B数据进行取平均,得到一个新的R、G、B值,这个值就作为该方块在LCD屏幕上的映射。缩放的算法描述如下:

(1)、计算图片大小与LCD屏大小的比例,以及方块的大小。为了适应各种屏幕大小,这里并不直接给lcd_width和lcd_height赋值为240和320。而是调用标准的接口来获取有关屏幕的参数。具体如下:

// Get variable screen information if(ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)){ printf(“Error reading variable information.”);exit(3);} unsigned int lcd_width=vinfo.xres;unsigned int lcd_height=vinfo.yres;

计算比例:

widthScale=bmpi->width/lcd_width;heightScale=bmpi->height/lcd_height;本程序中方块的大小以如下的方式确定: unsigned int paneWidth= unsigned int paneHeight=;符号 代表向上取整。

(2)、从图片的左上角开始,以(i* widthScale,j* heightScale)位起始点,以宽paneWidth 高paneHeight为一个小方块,对该方块的R、G、B数值分别取平均,得到映射点的R、G、B值,把该点作为要在LCD上显示的第(i , j)点存储起来。这部分的程序如下: //-------------取平均--------for(i=0;ir=div_round(color_sum_r,paneHeight*paneWidth);RGBvalue_256->g=div_round(color_sum_g,paneHeight*paneWidth);RGBvalue_256->b=div_round(color_sum_b,paneHeight*paneWidth);} } 3.4 图片数据提取及显示的总流程

通过以上的分析,整个图片数据提取及显示的总流程如图3.10 所示。图 3.10 三 实验过程与结果 1.Linux 源代码的修改

首先修改arch/arm/mach-smdk2410.c文件,加入以下代码。static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {.regs = {.lcdcon1 = S3C2410_LCDCON1_TFT16BPP | S3C2410_LCDCON1_TFT | S3C2410_LCDCON1_CLKVAL(7),.lcdcon2 = S3C2410_LCDCON2_VBPD(4)| S3C2410_LCDCON2_LINEVAL(319)| S3C2410_LCDCON2_VFPD(1)| S3C2410_LCDCON2_VSPW(1),.lcdcon3 = S3C2410_LCDCON3_HBPD(26)| S3C2410_LCDCON3_HOZVAL(239)| S3C2410_LCDCON3_HFPD(30),.lcdcon4 = S3C2410_LCDCON4_HSPW(13)| S3C2410_LCDCON4_MVAL(13),.lcdcon5 = S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_INVVLINE | S3C2410_LCDCON5_INVVFRAME | S3C2410_LCDCON5_PWREN | S3C2410_LCDCON5_HWSWP, },.lpcsel =((0xCE6)& ~7)| 1<<4,.width = 240,.height = 320,.xres = {.min = 240,.max = 240,.defval = 240, },.yres = {.min = 320,.max = 320,.defval = 320, },.bpp = {.min = 16,.max = 16,.defval = 16, }, };在函数smdk2410_machine_init()函数中加入LCD的初始化代码,见下 static void __init smdk2410_machine_init(void){ s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);smdk_machine_init();} 2.编译内核,产生zImage文件,放入tftp目录下。

3.在nfs的dev目录下建立FrameBuffer的设备节点,使用命令: mknod fb0 c 29 0 4.启动开发板,加载内核和文件系统。5.编写LCD的应用程序,程序见附录。

6.采用arm-linux-gcc 编译应用程序,产生可执行文件,放入nfs目录中。7.在开发板上运行编译好的可执行文件,便可。

8.下图是BMP位图显示程序,在S3C2410上的运行结果。

四 实验心得体会

1. LCD驱动的主要问题是没有LCD屏的文档,我们找不到它的那些参数值,后来只能参照Linux源码里面的其他LCD屏的参数进行实验。

2. 在驱动差错的过程中,我们采用跟踪打印的方法进行调试。刚开始的时候,内核打印出一行找不到LCD设备。我们定位到输出这行提示的代码处,进行反向跟踪。发现传给函数的设备指针为空,于是往上排查,终于发现源代码中没有定义LCD的设备信息。于是驱动问题也就顺利解决了。

3. 原来一直以为,只要LCD驱动工作正常了,内核起来的时候,液晶屏会显示出Logo。当时搞了很久一直没有,还以为是驱动的问题。后来随便写了一个LCD应用程序,竟然能用。

4. 在调试过程应用程序中发现,在读取文件头的时候,如果直接定义一个bitmapfileheader为它动态分配内存:

*bmph=(bitmapfileheader*)malloc(sizeof(bitmapfileheader));然后用fread((char*)bmph,sizeof(bitmapfileheader),1,f)把文件头一次性读出来,读出来的文件头是错误的,经过调试发现原因是bitmapfileheader这个结构体中的type属性原本应该占2字节,但是被编译器在分配内存的时候进行了内存对齐的优化,给他分配了4个字节的空间,造成读文件的错误。因此在编程中要特别注意内存对齐的影响。typedef struct { WORD type;(被优化)DWORD bfsize;DWORD reserved;DWORD offbits;} bitmapfileheader;5. 在嵌入式应用程序的移植过程中,我们原来认为ARM和PC机大小尾顺序是不同的,因此在应用程序中,也对这个差别进行了处理。当时,在调试过程中发现,PC机程序可以直接移植到ARM上,不需要任何改动。但是我们的程序,的确存在会产生大小尾问题代码(在使用fread()读入时)。这究竟是为什么?有人说,ARM是可以设置大小尾顺序的。后来这个问题也没有深究下去。五 参考文献

(1)嵌入式系统设计与应用开发:郑灵翔.北京:北京航天航空大学出版社 2006

第二篇:linux驱动及g-sensor学习心得

目录

1.MODULE_INIT和MODULE_EXIT..............................................................................................2 2.I2C_DRIVER......................................................................................................................................2 3.LINUX的INPUT子系统..................................................................................................................3 3.1 从驱动层到核心层.......................................................................................................................3 3.2 事件处理层的处理.......................................................................................................................3 3.3 设备结点的创建...........................................................................................................................4 3.4 设备的注销和释放.......................................................................................................................4 4.WORK QUEUE..................................................................................................................................4 5.HAL层开发........................................................................................................................................5 5.1 HAL_MODULE_INFO_SYM.....................................................................................................5 5.2 对设备文件的访问.......................................................................................................................7 6.BMA250功能描述..............................................................................................................................7 6.1 电源管理.......................................................................................................................................7 6.2 操作模式.......................................................................................................................................7 6.3 电源模式.......................................................................................................................................8 6.4 SENSOR数据..................................................................................................................................8 6.4.1 加速度....................................................................................................................................8 6.4.2 温度........................................................................................................................................8 6.5 偏移补偿.......................................................................................................................................9 6.5.1 慢补偿....................................................................................................................................9 6.5.2 快补偿....................................................................................................................................9 6.5.3 手动补偿..............................................................................................................................10 6.5.4 内嵌校准..............................................................................................................................10 6.6 非易失性存储器.........................................................................................................................10 6.7 中断控制器.................................................................................................................................10 6.7.1 new data中断.......................................................................................................................11 6.7.2 slope中断.............................................................................................................................11 6.7.3 tap中断.................................................................................................................................12 6.7.4 orientation中断....................................................................................................................12 6.7.5 flat中断................................................................................................................................14 6.7.6 low-g中断.............................................................................................................................15 6.7.7 high-g中断...........................................................................................................................15 7.SENSOR驱动开发步骤...................................................................................................................15 附录 BMA250寄存器表......................................................................................................................17 linux驱动及g-sensor学习心得

通过对g-sensor driver code的研究学习,我对linux设备驱动开发和g-sensor有了一定的了解,现将学习所得归纳如下。

1.module_init和module_exit

在pd318 project的g-sensor驱动程序bma250.c中,首先包含了两个头文件。其中init.h定义了驱动的初始化和退出相关的函数,module.h则定义了内核模块相关的函数、变量和宏。module_init和module_exit这两个宏就被定义在init.h中。

module_init的作用是声明一个驱动程序的入口函数,在init.h中可以看到对这个宏的定义如下:

#define module_init(x)__initcall(x);#define __initcall(fn)device_initcall(fn)#define device_initcall(fn)__define_initcall(“6”,fn,6)#define __define_initcall(level,fn,id)static initcall_t __initcall_##fn##id __used __attribute__((__section__(“.initcall” level “.init”)))= fn

如果驱动程序要以func函数作为驱动的入口,则可以这样声明:module_init(func)。经过上面的宏处理以后,变成__initcall_func6 __used加入到内核映射的“.initcall”区。内核加载的时候,会搜索“.initcall”区内的所有条目,并按优先级加载它们。通过module_init声明的驱动程序优先级为6,优先级越小越先加载。

对于驱动入口函数func,一般要加上__init属性,这个宏告诉编译器如果这个模块被编译到内核,则把这个函数放到(.init.text)段。而module_exit用于声明驱动程序的出口,对于驱动出口函数,一般要加上__exit属性,这个宏与__init类似,如果驱动被编译进内核,则__exit宏会忽略清理函数。

在内核初始化后期,所有带__init属性的函数会被放在同一个section里,在用完之后,一次性释放掉整个section。当函数初始化完成后,这个区域可以被清除掉以节约系统内存。

2.i2c_driver 在pd318 project中,g-sensor的PS pin连接VDDIO,操作模式采用带I²C接口的general mode,在bma250.c中可以了解到bma250的i2c_driver的结构定义如下:

struct i2c_driver bma250_driver = {.driver = {

.owner = THIS_MODULE,.name = SENSOR_NAME, },.id_table = bma250_id,.probe = bma250_probe,.remove };= bma250_remove, 在这个结构中,定义了驱动所属module、驱动名、驱动的id表、驱动初始化以及移除接口。可以通过i2c_add_driver将sensor driver添加进module中,通过i2c_del_driver将driver移除。

3.linux的input子系统

Linux系统提供了input子系统,可以用以实现系统中大多数输入设备的设备驱动,pd318中g-sensor的设备驱动就是通过它来实现的。

input子系统由核心层、驱动层和事件处理层三部分组成。当输入设备产生了一个输入事件时,由驱动层对事件加以识别,然后提交给核心层,核心层根据事件的类型将事件交给事件处理层处理,事件处理层将处理结果再反馈给用户。其中核心层由/drivers/input/input.c及相关头文件实现,对下提供了设备驱动的接口,对上提供了事件处理层的编程接口。这样,一个输入设备的输入过程可以分离为独立的两部分:驱动层到核心层,核心层到事件处理层,整个链路的这两部分的接口的创建是独立的。

3.1 从驱动层到核心层

驱动层负责和底层的硬件设备打交道,将底层硬件对用户输入的响应转换为标准的输入事件以后再向上发送给核心层。

驱动层先要调用input_allocate_device接口来分配一个设备,对设备进行一些属性赋值,如设备名、总线类型、响应事件类型及事件参数、驱动数据等等,然后通过input_register_device函数向input子系统中注册所要驱动的输入设备。对于g-sensor来说,驱动需要响应EV_ABS事件,该事件需要向核心层提供一个绝对坐标,事件参数ABS_X、ABS_Y、ABS_Z分别对应g-sensor在x、y、z轴上的偏移量。当g-sensor发生坐标变化时,驱动程序需要从相应寄存器中读出偏移量,然后通过input_report_abs接口上报给input子系统,由input子系统负责将事件及参数变化发送给事件处理层处理。

3.2 事件处理层的处理

驱动层只是把输入设备注册到input子系统中,在驱动中的code中并不创建设备结点。应用程序用来与设备打交道的设备结点的创建由事件处理层调用核心层的函数来实现。而对于常用输入设备(如mouse、keyboard、joystick等),在创建具体的设备结点之前,事件处理层需要先通过input_register_handler注册一类设备的输入事件处理函数及相关接口。以鼠标事件处理为例,mouse input_handler定义如下:

static struct input_handler mousedev_handler = {.event = mousedev_event, //向系统报告input事件,系统通过read方法读取

.connect = mousedev_connect, //和input_dev匹配后调用connect构建

.disconnect = mousedev_disconnect,.fops = &mousedev_fops, //event设备文件的操作方法.minor = MOUSEDEV_MINOR_BASE, //次设备号基准值

.name = “mousedev”,.id_table = mousedev_ids, //匹配规则 };

在linux中没有对g-sensor事件处理register的通用标准定义,对于这类事件,事件处理层会统一地当作evdev事件处理,为设备创建一个对应的设备文件,在HAL层可以通过open该设备文件来实现与底层的通信。

3.3 设备结点的创建

向input子系统注册一个硬件设备后,在input_register_handler中调用已经注册的所有类型的input handler的connect函数,每一个connect函数会根据注册设备所支持的事件类型判断是否与自己有关,如果有关就调用input_register_minor创建一个具体的设备结点。

此外,如果已经注册了一些硬件设备,此后再注册一类新的input handler,则同样会对所有已注册的设备调用新的input handler的connect函数以确定是否需要创建新的设备结点。

3.4 设备的注销和释放

在remove driver同时注销掉所注册的input设备,通过input_unregister_device函数注销设备,通过input_free_device接口释放设备资源。

4.work queue 在pd318 bma250.c的bma25_probe函数中可以看到,对于g-sensor状态的获取和report是通过linux的work queue机制来实现的。这里可以看到一个宏:INIT_DELAYED_WORK。这个宏被定义在/linux/workqueue.h中,具体定义如下:

#define INIT_WORK(_work, _func)

do {

__INIT_WORK((_work),(_func), 0);} while(0)

#define INIT_DELAYED_WORK(_work, _func)

do {

INIT_WORK(&(_work)->work,(_func));

init_timer(&(_work)->timer);

} while(0)

从这个定义中可以看到,INIT_DELAYED_WORK就是带有timer的INIT_WORK,而INIT_WORK所做的事情就是初始化一个工作,但是并不马上执行,需要将来某个时刻去触发执行。INIT_DELAYED_WORK(INIT_WORK)需要两个参数,一个是struct delayed_work(struct work_struct)结构体,一个是一个函数指针_func。这个初始化实际上就是为一个struct work_struct结构体绑定一个函数。在/linux/workqueue.h中可以看到struct work_struct的定义如下:

struct work_struct { atomic_long_t data;#define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ #define WORK_STRUCT_STATIC 1 /* static initializer(debugobjects)*/ #define WORK_STRUCT_FLAG_MASK(3UL)#define WORK_STRUCT_WQ_DATA_MASK(~WORK_STRUCT_FLAG_MASK)struct list_head entry;work_func_t func;#ifdef CONFIG_LOCKDEP struct lockdep_map lockdep_map;#endif };

在这个结构体中有一个成员函数func,初始化的目的就是使这个func指向INIT_WORK的第二个参数_func。以后调用schedule_delayed_work(schedule_work)时,只要传递struct delayed_work(struct work_struct)结构体参数即可,不需要再传递_func。这是因为,处理work的线程实际上跑的是一个死循环,有事情就处理,没事情就睡眠,而schedule_delayed_work(schedule_work)的作用就是唤醒这个线程。

INIT_DELAYED_WORK与schedule_delayed_work,INIT_WORK与schedule_work是对应着使用的,两者的区别就是schedule_work在唤醒线程的同时立刻执行_func,而schedule_delayed_work在唤醒线程后delay一段时间再执行。bma250.c通过使用INIT_DELAYED_WORK与schedule_delayed_work,实现g-sensor对不同取样频率的支持。

关于workqueue还有两个函数,它们是cancel_delayed_work和flush_scheduled_work。cancel_delayed_work的作用是对于一个延迟执行的工作而言,在工作还未执行的时候就把它给取消掉。而flush_scheduled_work的作用是为了防止有竞争条件的出现。一般在cancel_delayed_work之后都得调用flush_scheduled_work,函数会一直等待,直到队列中所有工作都被执行以后才返回。

5.HAL层开发

5.1 HAL_MODULE_INFO_SYM HAL层,即硬件抽象层,android层对于硬件的调用一般通过HAL的方式来完成。要想HAL的编写方法,首先需要了解HAL的运行机制。看android源码,可以发现android中实现调用HAL是通过hw_get_module来实现的。

int hw_get_module(const char *id, const struct hw_module_t **module);上面的是其函数原型,id会指定Hardware的id,这是一个字符串,比如sensor的id是#define SENSORS_HARDWARE_MODULE_ID “sensors”。如果找到了对应的hw_module_t结构体,会将其指针放入*module中。代码实现如下:

for(i=0;i

if(i < HAL_VARIANT_KEYS_COUNT){ /* 获取“ro.hardware”、“ro.product.board”、“ro.board.platform”、“ro.arch”等key的值*/

if(property_get(variant_keys[i], prop, NULL)== 0){

continue;

}

/* 获取并访问HAL动态链接库 */

snprintf(path, sizeof(path), “%s/%s.%s.so”,HAL_LIBRARY_PATH1, id, prop);

if(access(path, R_OK)== 0)break;

snprintf(path, sizeof(path), “%s/%s.%s.so”,HAL_LIBRARY_PATH2, id, prop);

if(access(path, R_OK)== 0)break;

} else {

snprintf(path, sizeof(path), “%s/%s.default.so”,HAL_LIBRARY_PATH1, id);

if(access(path, R_OK)== 0)break;

} }

status =-ENOENT;if(i < HAL_VARIANT_KEYS_COUNT+1){

/* 调用load函数打开动态链接库*/

status = load(id, path, module);}

这个函数的作用,就是获取动态链接库并调用load函数打开它。再看load函数,可以发现该函数中出现了一个宏HAL_MODULE_INFO_SYM_AS_STR。HAL_MODULE_INFO_SYM_AS_STR是硬件模块在动态链接库中的标志,定义在hardware.h中如下:

#define HAL_MODULE_INFO_SYM HMI #define HAL_MODULE_INFO_SYM_AS_STR “HMI”

再去对照一个sensors.app中的代码:

extern “C” const struct sensors_module_t HAL_MODULE_INFO_SYM = { common :{

tag : HARDWARE_MODULE_TAG,version_major : 1,version_minor : 0,id : SENSORS_HARDWARE_MODULE_ID,name : “Bosch sensor module”,author : “Bosch Sensortec”,methods : &sensors_module_methods,dso : NULL,reserved : {}, },get_sensors_list : sensors__get_sensors_list };这里的sensors_module_t结构体的定义为: struct sensors_module_t {

struct hw_module_t common;

int(*get_sensors_list)(struct sensors_module_t* module,struct sensor_t const** list);};它定义了一个hw_module_t类型的common成员,和获取sensors list的接口函数sensors__get_sensors_list。注意,这里的HAL_MODULE_INFO_SYM必须为这个名字,这样编译器才会将这个结构体的导出符号变为“HMI”。

从以上分析可以知道,HAL层开发就是要定义一个hw_module_t结构体,结构体名称命名为HAL_MODULE_INFO_SYM,然后实现结构体的相关内容即可。也就是说,HAL模块的入口地址就是HAL_MODULE_INFO_SYM变量,通过它,我们可以访问到HAL模块中所有想要外部访问到的方法。

5.2 对设备文件的访问

在HAL层可以通过访问3.2节中evdev.c生成的设备文件来实现对硬件设备的访问。对于g-sensor来说,要实现对于sensor的poll、setDelay、activate、close等函数接口。在poll接口中,程序通过一个循环去获取设备文件中显示出的sensor的坐标变化,在收到EV_SYN事件时,将sensor的坐标变化反馈给android系统,android对获取到的状态变化作出相应的处理。

6.bma250功能描述

6.1 电源管理

VDD :主电源,为所有内部模拟/数字功能块供电。VDDIO:专为数字I/O供电的单独电源引脚。

6.2 操作模式

General mode :sensor作为外部总线的一个从设备,可以配置、使用外部中断引脚INT1和INT2。

Dedicated mode :sensor作为一个独立设备,没有外部中断功能,使用内部中断机制,一次只能够被指派处理orientation recognition、tap sensing、slope detection三种中断中的一种。

PS引脚的连接状态决定了sensor采用哪种操作模式。PS = GND

general mode with SPI interface PS = VDDIO

general mode with I²C interface PS = float dedicated mode

6.3 电源模式

bma250具有三种电源模式:normal mode、low-power mode和suspend mode。normal mode :电路全开,整个g-sensor处于正常工作状态。

low-power mode :周期性地在睡眠和唤醒状态之间切换。睡眠状态下,除振荡器外所有器件不工作;唤醒状态下工作在正常状态。

suspend mode :包括振荡器在内的整个board处于power down状态,仅可以读取寄存器、写suspend位和softreset寄存器。

三种模式之间可能的状态切换如图1所示。

图1 电源模式切换图

6.4 sensor数据

6.4.1 加速度

每一个轴上的加速度数据都是10个bit,分为两个寄存器来存储(MSB :9~2 bit,LSB :1~0 bit)。x、y、z三个轴的加速度数据存储在寄存器0x02~0x07,依次存储x、y、z轴加速度的LSB、MSB数据。

加速度数据可以使用两种不同的数据流:unfiltered和filtered。使用哪种数据流由0x13寄存器的data_high_bw位决定。

unfiltered :采样频率为 2kHz,data_high_bw = 1。filtered : 采样频率为带宽的两倍,data_high_bw = 0。filtered加速度数据带宽由0x10寄存器的bw位决定。另外,bma250支持四种不同的加速度度量范围(range),分别为±2g、±4g、±8g和±16g,这由0x0F寄存器的低四位决定。

6.4.2 温度 由0x08寄存器决定,温度范围为-40°C ~ 87.5°C。

6.5 偏移补偿

偏移补偿就是根据ADC值对加速度数据作出一个补偿。不过用于补偿的公共寄存器(public register)0x38 ~ 0x3D对每个轴用于读写补偿的只有8 bit,而内部寄存器(internal register)对于每个加速度值都是用10 bit(MSB + LSB)来存储的。在这之间需要一个转换,补偿转换原则如图2所示。

图2 8-bit/10-bit补偿转换原则图

从上图可以看出,根据设定的range,公共寄存器的补偿值将要对输出的加速度数据作出补偿。例如,公共寄存器值为00000001b,从图2中得到加速度数据补偿为±7.8mg,对应内部寄存器为±2 LSB。

bma250支持四种偏移补偿方式:慢补偿、快补偿、手动补偿和内嵌校准。对于慢补偿和快补偿来说,0x37寄存器的offset_target_x、offset_target_y、offset_target_z决定了sensor在x、y、z轴上的目标值。而0x36的offset_reset位如果被置为1,则所有的偏移补偿寄存器都reset为0。

6.5.1 慢补偿

如果连续一定数量的采样加速度大于(小于)0x37寄存器所设置的目标值,偏移补偿值寄存器0x38 ~ 0x3D的值减少(增加)4 LSB。加速度数据的采样周期由0x37的cut_off位决定,如果cut_off位为0,采样周期为8,反之为16。

在x、y、z轴是否采用慢补偿分别由寄存器0x36中的hp_x_en、hp_y_en和hp_z_en决定。

6.5.2 快补偿

连续取16个加速度值,计算出平均值,将这个平均值与0x37寄存器所设置的目标值的差值写入0x37寄存器中。0x36寄存器的cal_trigger决定了对哪个轴实行快补偿。cal_trigger = 00b none cal_trigger = 01b x轴 cal_trigger = 10b y轴 cal_trigger = 11b z轴

当正在进行快补偿时,慢补偿被阻断。

6.5.3 手动补偿

通过数字接口去手动设置补偿值。在手动补偿时要注意不要影响正在进行的偏移补偿,所以一般在获得new data中断后立刻执行。在慢补偿有效或快补偿正在运行时,不允许对偏移补偿寄存器作出写操作。

6.5.4 内嵌校准

通过前面所提到的偏移补偿方法计算出合适的补偿值,然后将这些补偿值存放在EEPROM中。在每一次设备重置时,补偿值被load进image寄存器作为偏移补偿,直到它被用其他的补偿方式重写。

6.6 非易失性存储器

bma250具有三种存储器:hard-wired、valatile和non-valatile。non-valatile存储器通过EEPROM来实现,可以通过访问image寄存器来访问它。在bma250中共有八个image寄存器(0x38 ~ 0x3F),0x38 ~ 0x3D被用作存储偏移补偿值,0x3E和0x3F保留备用。

在两种情况下EEPROM内容会被load到image寄存器中去,一种情况是设备重置时,另一种情况是将0x33寄存器中的nvm_load值置为1。只要image寄存器还没有load完成,nv_ram位就为1,在完成后被置成0。image寄存器可以像其他寄存器一样执行读写操作。

写EEPROM要经过三步:

1)将新内容写入image寄存器;

2)将0x33寄存器中的nvm_prog_mode置成1,unlock EEPROM ;

3)将0x33寄存器中的nvm_prog_trig置为1,并保持nvm_prog_mode为1,激活写操作。

每次写EEPROM总是要更新整个EEPROM内容,可以通过读取0x33寄存器的nvm_rdy位来检测写状态。nvm_rdy等于1,表示写操作正在进行中;nvm_rdy等于0,表示写操作已完成。在写EEPROM时,电源模式必须处于normal mode,而且不能对image寄存器作出更新。

6.7 中断控制器

中断的清除取决于所选择的中断模式,bma250支持三种模式:non-latched、latched和temporary。中断模式可以通过0x21寄存器的低四位latch_int来设置,具体对应关系如表1所示。

只要满足中断激活条件,就会产生一个中断。在non-latched模式下,除了new data、orientation和flat中断会在一个固定时间后自动重置,其他中断只要激活条件不再有效,中断状态位和所选择的pin脚(INT1 and/or INT2)就会立刻被清除。

latched模式下,必须通过将0x21寄存器的reset_init位置为1来清除中断状态和pin脚。清除时如果中断条件仍然保持,中断状态会在加速度寄存器下次变化时再次被宣称。

表1 中断模式选择对应表

在temporary模式下,中断状态和pin脚在一段时间后被清除,这段时间由latch_int的具体值来决定。

bma250支持七种中断机制,分别为:new data、tap、slope、high-g、low-g、orientation和flat。其中,new data、tap、slope、high-g和low-g既可以使用filtered data也可以使用unfiltered data作为输入,这分别由0x1E寄存器的int_src_data、int_src_tap、int_src_slope、int_src_high和int_src_low位决定。而orientation和flat只能使用filtered data作为输入。

可以通过0x19 ~ 0x1B寄存器来建立中断类型到中断引脚的映射关系。例如,将0x19寄存器的int1_flag位置为1,就是建立了flat中断到INT1中断引脚的映射关系。

6.7.1 new data中断

new data中断提供了一个同步读取加速度数据的服务。它在将一个z轴的新值写入数据寄存器时产生,在下一次数据获取循环开始的时候自动清除。通过将0x17寄存器的data_en位置为1来使能new data中断,中断状态存储在0x0A的data_int位中。

6.7.2 slope中断

在sensor移动中产生连续的加速度信号,当一定数量的连续两个加速度信号的值差大于一个预设的临界值时,会产生一个slope中断。而在一定数量的连续两个加速度信号的值差小于这个预设值时,中断被清除。可以通过0x28寄存器的slope_th位来设置这个临界值,1 LSB slope_th对应1 LSB的加速度数据。

连续两个加速度信号的取值时间差取决于所选择的带宽,Δt=1/(2*bw)。而取值的数量由0x27寄存器的slope_dur来决定,N = slope_dur + 1。

通过设置0x16寄存器的slope_en_x、slope_en_y和slope_en_z为1来使能在x、y、z轴上的slope中断。在dedicated mode唤醒状态时,三个轴的slope中断都被使能,0x16寄存器上的这三个值无效。

中断状态存储在0x09的slope_int位。检测到的slope中断状态信息存放在0x0B寄存器中,slope_first_x、slope_first_y、slope_first_z分别标识了触发中断的轴状态,slope_sign位标识了正负(0为正,1为负)。

6.7.3 tap中断

tap中断类似于鼠标按键的click,当至少在一个轴上的加速度slope大于一个预定义的值时,该中断产生。

有两种tap事件:single tap和double tap。single tap是在一次tap事件后,紧跟着是一段安静时间,类似于鼠标的单击;而double tap是在一段定义好的时间内,连续发生两次tap事件,类似于鼠标的双击。

同一时间,只能有一种tap中断被使能。0x16寄存器的s_tap_en为1表示single tap使能,d_tap_en为1表示double tap使能。如果s_tap_en和d_tap_en同时被置为1,s_tap_en无效,只有double tap使能。

single tap的中断状态存储在0x09寄存器的s_tap_int位,double tap的中断状态存储在0x09寄存器的d_tap_int位。

通过设置0x2B寄存器的tap_th值来设置tap中断的slope预设临界值,在不同的range下,slope_th表示不同的数值。1 LSB的tap_th对应于2g-range下的62.5mg slope,4g-range下的125mg slope,8g-range下的250mg slope,16g-range下的500mg slope。

0x2A寄存器的tap_shock和tap_quiet对single tap和double tap都是有效的,tap_dur仅对double tap有效。在tap_shock的持续时间里,任何新的tap事件都会被忽略;在slope_quiet的持续时间里,不能有新的tap事件发生,否则第一次tap事件将会被取消。tap_shock为0(1)表示tap_shock的持续时间为50 ms(75 ms),tap_quiet为0(1)表示tap_quiet的持续时间为30 ms(20 ms)。tap_dur的持续时间如表2所示。

表2 tap_dur对应持续时间值表

tap中断产生后12.5 ms后会被自动清除。

0x0B 寄存器的tap_sign位标识了触发tap中断的第一次tap的slope正负(0为正,1为负)。触发中断的轴状态分别被存放在0x0B寄存器的tap_first_x、tap_first_y和tap_first_z中。

在低电模式(low-power mode)下,在唤醒状态时,对取样数量有一个限制,这由0x2B寄存器的tap_samp决定。tap_samp = 00b(01b、10b、11b),表示取样数量为2(4、8、16)。

6.7.4 orientation中断

orientation表示的是sensor相对于重力域矢量g的方向变化,假设z轴与g的夹角为θ,x轴与水平方向的夹角为φ,如下图3所示。

图3 sensor角度矢量图

假设x、y、z轴上的加速度分别为acc_x、acc_y和acc_z,则可以得到: acc_x = 1g * sinθ * cosφ acc_y =-1g * sinθ * sinφ acc_z = 1g * cosθ

有三种不同的orientation计算模式,在这三种模式下具有不同的转换临界值。这三种模式分别为:对称、高非对称和低非对称。这取决于0x2C寄存器的orient_mode值。orient_mode等于01b,工作在高非对称模式;orient_mode等于10b,工作在低非对称模式;否则,工作在对称模式。对于每一种orienttaion模式,0x0C寄存器的orient表示不同的意思。三种模式下,orient的意思分别如表

3、表

4、表5所示。

图3 对称模式下的0x0C寄存器orient意思示表

图4 高非对称模式下的0x0C寄存器orient意思示表

图5 低非对称模式下的0x0C寄存器orient意思示表

在以上三张表中,‘hyst’ 表示一个延迟,这个值通过0x0C寄存器的orient_hyst设置。1 LSB的orient_hyst对应于62.5 mg。

通过将0x16寄存器的orient_en位置为1来使能orientation中断。当0x0C寄存器的orient发生变化时,中断产生,一段之间后自动清除。中断状态存储在0x09寄存器的orient_int位。

0x0C寄存器的orient位发生变化后,中断的产生可能会被阻断,这可以通过0x2C寄存器的orient_blocking进行设置。

orient_blocking = 00b表示没有阻断; orient_blocking = 01b表示θ阻断;

orient_blocking = 10b表示θ阻断,或任一轴上的加速度slope > 0.2 g;

orient_blocking = 11b表示θ阻断,或任一轴上的加速度slope > 0.4 g,或orient值超过100 ms一直不稳定。

θ阻断通过下面的不等式定义:

参数blocking_theta由0x2D寄存器的orient_theta决定,由此可知阻断角度θ的取值范围为0° ~ 44.8°。

6.7.5 flat中断

flat中断,顾名思义,用于检测sensor是否位于水平状态,判断设备位于水平状态的条件时:

参数parameter_theta由0x2E寄存器的flat_theta决定,由此可知,flat角度可能取值范围也是0° ~ 44.8°。

通过将0x16寄存器的flat_en置为1使能flat中断。当0x0C寄存器的flat值发生变化,并且这个值保持稳定一段时间后,flat中断产生。保持稳定的时间的最小值由0x2F寄存器的flat_hold_time决定。flat_hold_time等于00b、01b、10b、11b分别表示0、512 ms、1024 ms、2048 ms。这个中断在一段之间后自动清除。flat中断状态存储在0x09寄存器的flat_int位。

6.7.6 low-g中断

这个中断是基于比较加速度数据和low-g临界值而产生的,比如对自由落体的侦测。通过设置0x17寄存器的low_en位使能该中断。low-g中断有两种模式:single mode和sum mode。single mode是只比较某一个轴的加速度,而sum mode是比较三个轴加速度的绝对值总和。这由0x24寄存器的low_mode位决定,0表示single mode,1表示sum mode。

low-g临界值通过0x23寄存器的low_th设置,1 LSB low_th对应于7.81 mg的加速度。可以通过设置0x24寄存器的low_hy来设置滞后值,1 LSB low_hy对应于125 mg的加速度值。

当某一轴上的加速度绝对值(single mode)或三轴加速度绝对值的总和(sum mode)小于临界值超过一段时间(这个时间由0x22寄存器的low_dur决定)后,中断产生;当某一轴上的加速度绝对值(single mode)或三轴加速度绝对值的总和(sum mode)大于临界值减去滞后值至少超过一个数据的获取时间后,中断被重置。

low-g中断产生前的延迟时间与low_dur的关系为:delay [ms] = [(0x22)low_dur + 1] * 2 ms。所以,延迟时间的可能范围为2 到512 ms。

6.7.7 high-g中断

这个中断是基于比较加速度数据和high-g临界值而产生的,主要用于对震动或其他的一些高加速度事件的侦测。

通过设置0x17寄存器的hign_en_x、high_en_y和high_en_z使能sensor在x、y和z轴上的high-g终端。

high-g临界值通过0x26寄存器的high_th设置,1 LSB high_th对应于2g-range下的7.81mg,4g-range下的15.63mg,8g-range下的31.25mg,16g-range下的62.5mg。可以通过设置0x24寄存器的high_hy来设置滞后值,1 LSB high_hy对应于2g-range下的125mg,4g-range下的250mg,8g-range下的500mg,16g-range下的1000mg。

当至少一个使能轴的加速度绝对值高于high-g临界值超过一段时间(这个时间由0x25寄存器的high_dur决定)后,中断产生。当所有使能轴的加速度绝对值都低于high-g临界值减去滞后值一段时间(由0x25寄存器的high_dur决定)后,中断被重置。

high-g中断产生前的延迟时间与high_dur的关系为:delay [ms] = [(0x22)high_dur + 1] * 2 ms。所以,延迟时间的可能范围为2 到512 ms。

7.sensor驱动开发步骤 综上所述,sensor驱动开发可以归纳为以下步骤来完成: 1.read && verify spec,确认chip功能以及register配置;

2.按照spec所述,在code中加入主要的配置数据,如电源模式、主要寄存器的配置、range支持、bandwidth支持、中断配置等; 3.设计主要的数据结构;

4.实现sensor数据的设置和获取接口;

5.通过module_init和module_exit接口加入driver层入口和出口函数函数;

6.定义i2c_driver,设置driver的probe和remove函数入口,通过i2c_add_driver和i2c_del_driver接口添加/移除driver; 7.实现driver的probe函数功能,函数中实现sensor的硬件配置,并通过linux的input子系统实现sensor数据的上报;

8.实现driver的remove函数功能,函数中实现设备的移除、资源的释放等。

9.HAL层中注册hw_module_t结构体,将结构体名称命名为HAL_MODULE_INFO_SYM;

10.判断sensor设备文件是否存在,通过open_input_device访问设备文件,并注册设备文件的poll、activate、close等函数; 11.实现sensor list的获取函数;

12.实现对设备文件的主要操作接口,完成上层与硬件设备的通信; 13.调试sensor功能。附录 bma250寄存器表

第三篇:创新驱动发展战略学习心得范文

精品学习资料范文

创新驱动发展战略学习心得

创新驱动发展战略学习心得

通过将近一个月的课程学习,我获益匪浅,对“创新”有了新的理解和认识。创新是一种探索未知事物、寻找科学真理的活动,意味着新的尝试,走新的道路。创新是引领发展的第一动力,必须摆在国家发展全局的核心位置,深入实施创新驱动发展战略。作为党员领导干部,更应该树立创新意识,自觉运用创新思维方式和方法谋划自身工作。

一、要树立创新的勇气

中国的改革航船已经驶入攻坚克难的深水区。只有创新思维,冲破思想观念的束缚,突破利益固化的藩篱,攻克体制机制上的顽症痼疾,才能进一步发展社会生产力和增强社会活力。创新,需要敢于冒险的勇气和魄力。中国改革创新,束缚怎么冲破? 藩篱如何突破? 顽症痼疾又怎样攻克? 倘若没有一往无前的勇气,没有壮士断腕的决心,没有背水一战的气概,没有迎难而上的担当,这艘改革航船将注定无法抵达胜利的彼岸。我们要拿出逢山开路的闯劲儿,拿出甩开膀子的干劲儿,拿出抓铁有痕的韧劲儿,拿出众人拾柴的心劲儿,拿出

精品学习资料范文

勇毅笃行的稳劲儿,用今天的改革为明天的远行铺路搭桥。

二、要讲究创新的方法

实现创新,需要具备追求卓越的意识、开拓创先的精神和独具卓识的方法。要学会掌握和运用逆向思维、发散思维和联想思维等方法,克服思维的单一性、孤立性,善于多角度、多层次、全方位地解决、学习实践中的各种问题,力争达到独创性、系统性。“创新是民族进步的灵魂,创新是国家兴旺发达不竭的动力”创新就在于创造,创造就在于人脑的训练。创新思维是发散思维和集中思维的结合,发散思维是构成创造性思维的主导成分。发散思维是在思维过程中通过重组所给的和记忆中的信息,得到众多可能的答案、设想或解决方案。它的特点为是以一个问题为中心,充分发挥人的联想力和想象力,突破原有的知识圈,从一点向四面八方想开去,从各个不同的角度或侧面进行思考,让思维多向流动,以便获得解决问题的全部可能。这种思考无一定方向、无一定范围、不墨守成规、不拘于传统方法,可以标新立异、异想天开,从已知的领域去探求未知的境界。所以,发散思维是一种创新思维方法,集中体现了创造性思维的本质牲特征。我们要有意识的训练运用这些思维方式和方法,创造性的开展自身的工作。

精品学习资料范文

三、要在实践中创新

创新思维来自于实践,服务于实践。要把创新思维和社会实践结合起来,在实践中统筹兼顾,用整体、全面的观点和方法处理和解决发展中的各种复杂性问题。日常学习和生活中,在一个有限的范围内,人们接触了一定的类似的概念后,会习惯性地形成一种思维定势,会“想当然”地认为事情就是大多数认为的那样,容易陷入“知其然而不知其所以然”的怪圈,不能看到事物的本来面目,在这样的状态下难以创新。因此,在各种实践探索过程中,要勇于拆掉习惯性思维的墙,打破所有束缚头脑的条条框框,要允许自己异想天开,主动丢弃从众心理和从众思维习惯,“不走寻常路”,不让自己被表象迷惑,增强洞察事物本质的能力,从根源上找到解决问题的新构思、新思想。实践,是创新思维的源头活水,实践中发现和产生的需求,是创新活动不竭的动力。因此,要积极投身和参与实践中,在实践中收获“观念更新、思维新颖、方法先进”的成果。

四、要加强知识的积累

要勤于学习各种知识,不断开阔视野。知识和经验是创新思维的基础。有丰富的阅历,广博的知识,就有足够的闪光点用来进行

精品学习资料范文

“想象”、“整合”和“类比”。阅历和知识越多样化,头脑中能够产生的关联就会越多。因此,要培养自己对各类事物的观察、学习兴趣,主动参与各种理论和实践活动,力争对各个行业、各种事物都有所了解。同时,要养成善于学习和思考的习惯,能将各个不同领域内看似毫无内在关联的问题、想法、事物成功地联系在一起,找出所有事物共同点、共通点,为“整合”、“创造”打好扎实的基础。最后,要锤炼坚持不懈的品格。创新的道路上,没有平坦的大道可走,挫折和失败在所难免。不仅需要超常的智力,更需要非凡的勇气和精神支撑。面对创新过程中可能遇到的各种困难,要努力克服畏难情绪和懒惰习气,把追求创新、努力创新作为学习、工作的要求和标准。注重锤炼自信、坚毅、独创、不迷信权威等品格,用锲而不舍、百折不挠的精神,不达目的不罢休的韧劲,义无反顾地去思、去闯。只有善于创新、勇于实践,把创新看成自己生命中的一部分,努力让世界变得更加美好,在创新的世界中收获属于自己的成功。

五、要注重人才队伍的创新要相信“时势造英雄”,要充分认识到国家的人口基数大,高效人才的流动。要鼓励科研人员创业创新。大力弘扬创新文化,厚植创新沃土,营造敢为人先、宽容失败的良好氛围,充分激发企业家精神,调动全社会创业创新积极性,汇聚成推动发展的磅礴力量。

精品学习资料范文

对于商贸工作而言,我认为“创新”所带来的影响将会更深远,其作用不可替代。

一、创新产业规模化和组织化建设,提升流通水平和层次。商贸流通企业规模小、流通水平低严重阻碍了商贸流通业的发展。一方面可以加大商贸流通企业的并购力度,鼓励企业以参股、控股、兼并、重组等方式实现更大范围的整合,形成更大的连锁型企业,优

第四篇:S3C2410 LCD驱动学习心得-4

3.BMP和JPEG图形显示程序

3.1 在LCD上显示BMP或JPEG图片的主流程图

首先,在程序开始前。要在nfs/dev目录下创建LCD的设备结点,设备名fb0,设备类型为字符设备,主设备号为29,次设备号为0。命令如下: mknod fb0 c 29 0 在LCD上显示图象的主流程图如图3.1所示。程序一开始要调用open函数打开设备,然后调用ioctl获取设备相关信息,接下来就是读取图形文件数据,把图象的RGB值映射到显存中,这部分是图象显示的核心。对于JPEG格式的图片,要先经过JPEG解码才能得到RGB数据,本项目中直接才用现成的JPEG库进行解码。对于bmp格式的图片,则可以直接从文件里面提取其RGB数据。要从一个bmp文件里面把图片数据阵列提取出来,首先必须知道bmp文件的格式。下面来详细介绍bmp文件的格式。

图3.1

3.2 bmp位图格式分析

位图文件可看成由四个部分组成:位图文件头、位图信息头、彩色表和定义位图的字节阵列。如图3.2所示。

图3.2 文件头中各个段的地址及其内容如图3.3。

图3.3 位图文件头数据结构包含BMP图象文件的类型,显示内容等信息。它的数据结构如下定义: Typedef struct {

int bfType;//表明位图文件的类型,必须为BM long bfSize;//表明位图文件的大小,以字节为单位 int bfReserved1;//属于保留字,必须为本0 int bfReserved2;//也是保留字,必须为本0 long bfOffBits;//位图阵列的起始位置,以字节为单位 } BITMAPFILEHEADER;

图3.4 位图文件头的数据结构

(2)信息头中各个段的地址及其内容如图3.5所示。

图3.5 位图信息头的数据结构包含了有关BMP图象的宽,高,压缩方法等信息,它的C语言数据结构如图3.6所示。Typedef struct { long biSize; //指出本数据结构所需要的字节数

long biWidth;//以象素为单位,给出BMP图象的宽度 long biHeight;//以象素为单位,给出BMP图象的高度 int

biPlanes;//输出设备的位平面数,必须置为1 int

biBitCount;//给出每个象素的位数 long biCompress;//给出位图的压缩类型 long biSizeImage;//给出图象字节数的多少 long biXPelsPerMeter;//图像的水平分辨率 long biYPelsPerMeter;//图象的垂直分辨率

long biClrUsed;//调色板中图象实际使用的颜色素数 long biClrImportant;//给出重要颜色的索引值 } BITMAPINFOHEADER;

图3.6 BITMAPINFOHEADER数据结构

(3)对于象素小于或等于16位的图片,都有一个颜色表用来给图象数据阵列提供颜色索引,其中的每块数据都以B、G、R的顺序排列,还有一个是reserved保留位。而在图形数据区域存放的是各个象素点的索引值。它的C语言结构如图3.7所示。

图3.7 颜色表数据结构(4)对于24位和32位的图片,没有彩色表,他在图象数据区里直接存放图片的RGB数据,其中的每个象素点的数据都以B、G、R的顺序排列。每个象素点的数据结构如图3.8所示。

图3.8 图象数据阵列的数据结构(5)由于图象数据阵列中的数据是从图片的最后一行开始往上存放的,因此在显示图象时,是从图象的左下角开始逐行扫描图象,即从左到右,从下到上。

(6)对S3C2410或PXA255开发板上的LCD来说,他们每个象素点所占的位数为16位,这16位按B:G:R=5:6:5的方式分,其中B在最高位,R在最低位。而从bmp图象得到的R、G、B数据则每个数据占8位,合起来一共24位,因此需要对该R、G、B数据进行移位组合成一个16位的数据。移位方法如下: b >>= 3;g >>= 2;r >>= 3;RGBValue =(r<<11 | g << 5 | b);基于以上分析,提取各种类型的bmp图象的流程如图3.9所示

图 3.9

本篇文章来源于 Linux公社网站(本篇文章来源于 Linux公社网站(

第五篇:S3C2410 LCD驱动学习心得-6

实验过程与结果 1.Linux 源代码的修改

首先修改arch/arm/mach-smdk2410.c文件,加入以下代码。static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {.regs = {

.lcdcon1 = S3C2410_LCDCON1_TFT16BPP |

S3C2410_LCDCON1_TFT |

S3C2410_LCDCON1_CLKVAL(7),.lcdcon2 = S3C2410_LCDCON2_VBPD(4)|

S3C2410_LCDCON2_LINEVAL(319)|

S3C2410_LCDCON2_VFPD(1)|

S3C2410_LCDCON2_VSPW(1),.lcdcon3 = S3C2410_LCDCON3_HBPD(26)|

S3C2410_LCDCON3_HOZVAL(239)|

S3C2410_LCDCON3_HFPD(30),.lcdcon4 = S3C2410_LCDCON4_HSPW(13)|

S3C2410_LCDCON4_MVAL(13),.lcdcon5 = S3C2410_LCDCON5_FRM565 |

S3C2410_LCDCON5_INVVLINE |

S3C2410_LCDCON5_INVVFRAME |

S3C2410_LCDCON5_PWREN |

S3C2410_LCDCON5_HWSWP, },.lpcsel =((0xCE6)& ~7)| 1<<4,.width = 240,.height = 320,.xres = {

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

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

.min = 16,.max = 16,.defval = 16,}, };在函数smdk2410_machine_init()函数中加入LCD的初始化代码,见下 static void __init smdk2410_machine_init(void){ s3c24xx_fb_set_platdata(&smdk2440_lcd_cfg);smdk_machine_init();} 2.编译内核,产生zImage文件,放入tftp目录下。

3.在nfs的dev目录下建立FrameBuffer的设备节点,使用命令:

mknod fb0 c 29 0 4.启动开发板,加载内核和文件系统。5.编写LCD的应用程序,程序见附录。

6.采用arm-linux-gcc 编译应用程序,产生可执行文件,放入nfs目录中。7.在开发板上运行编译好的可执行文件,便可。

8.下图是BMP位图显示程序,在S3C2410上的运行结果。

实验心得体会

1. LCD驱动的主要问题是没有LCD屏的文档,我们找不到它的那些参数值,后来只能参照Linux源码里面的其他LCD屏的参数进行实验。

2. 在驱动差错的过程中,我们采用跟踪打印的方法进行调试。刚开始的时候,内核打印出一行找不到LCD设备。我们定位到输出这行提示的代码处,进行反向跟踪。发现传给函数的设备指针为空,于是往上排查,终于发现源代码中没有定义LCD的设备信息。于是驱动问题也就顺利解决了。

3. 原来一直以为,只要LCD驱动工作正常了,内核起来的时候,液晶屏会显示出Logo。当时搞了很久一直没有,还以为是驱动的问题。后来随便写了一个LCD应用程序,竟然能用。4. 在调试过程应用程序中发现,在读取文件头的时候,如果直接定义一个bitmapfileheader为它动态分配内存:

*bmph=(bitmapfileheader*)malloc(sizeof(bitmapfileheader));然后用fread((char*)bmph,sizeof(bitmapfileheader),1,f)把文件头一次性读出来,读出来的文件头是错误的,经过调试发现原因是bitmapfileheader这个结构体中的type属性原本应该占2字节,但是被编译器在分配内存的时候进行了内存对齐的优化,给他分配了4个字节的空间,造成读文件的错误。因此在编程中要特别注意内存对齐的影响。typedef struct { WORD

type;(被优化)DWORD bfsize;DWORD reserved;DWORD offbits;} bitmapfileheader;5. 在嵌入式应用程序的移植过程中,我们原来认为ARM和PC机大小尾顺序是不同的,因此在应用程序中,也对这个差别进行了处理。当时,在调试过程中发现,PC机程序可以直接移植到ARM上,不需要任何改动。但是我们的程序,的确存在会产生大小尾问题代码(在使用fread()读入时)。这究竟是为什么?有人说,ARM是可以设置大小尾顺序的。后来这个问题也没有深究下去。

参考文献

(1)嵌入式系统设计与应用开发:郑灵翔.北京:北京航天航空大学出版社 2006

本篇文章来源于 Linux公社网站(

下载S3c2410 LCD驱动学习心得[五篇]word格式文档
下载S3c2410 LCD驱动学习心得[五篇].doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐

    “解放思想、改革开放、创新驱动、科学发展”学习心得

    “解放思想、改革开放、创新驱动、科学发展” 大讨论活动心得体会 上尤各庄小学---张晓君 接县教育局的“解放思想、改革开放、创新驱动、科学发展”大讨论活动的通知,我校全......

    《创新驱动与供给侧改革》学习心得[大全五篇]

    《创新驱动与供给侧改革》学习心得 3月30日下午,在县委中心组(扩大)理论学习会上,有幸聆听了中国人民大学世界经济研究中心主任黄卫平教授所作题为《创新驱动与供给侧改革》的专......

    解放思想改革开放创新驱动科学发展大讨论活动学习心得[精选]

    解放思想改革开放创新驱动科学发展大讨论活动学习心得 开展解放思想改革开放创新驱动科学发展大讨论活动,就是要提高工作的服务质量,为科学决策服务。要以开展解放思想改革开......

    创新驱动

    创新驱动为院校发展注入无限活力 ——理工大学 市东医院“理工医创新基地”建设一周年回顾 2010年早春,市东医院 上海理工大学、市东医院“理工医创新基地” 签约暨揭牌仪式......

    创新驱动发展

    创新驱动发展 党的十八大明确提出“科技创新是提高社会生产力和综合国力的战略支撑,必须摆在国家发展全局的核心位置。”强调要坚持走中国特色自主创新道路、实施创新驱动发......

    创新驱动发展

    创新驱动发展 十八大、“两会”相关论述 材料一:科技创新驱动发展战略党的十八报告强调,实施创新驱动发展战略。科技创新是提高 社会生产力和综合国力的战略支撑,必须摆在国家......

    创新驱动科学发展

    创新驱动科学发展 破除事业发展瓶颈开创广电工作新局面 ——县广电台2016年上半年工作总结及下半年工作谋划 上半年,县广播电视台在县委、县政府正确领导下,紧紧围绕县委、......

    任务驱动教学法

    一、“任务驱动”式教学的含义 “任务驱动”式教学是将整个知识体系分解为一个一个相对独立而相互关联的“任务”,让学生在一个个典型“任务”的驱动下有序展开学习活动,引导......