S3C2410 NANDFLASH的配置实验

2024-06-15

S3C2410 NANDFLASH的配置实验(精选5篇)

S3C2410 NANDFLASH的配置实验 篇1

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

S3C2410 NANDFLASH的配置实验 篇2

1 系统设计

在此,把嵌入式技术与无线电台通信技术相结合,设计一种无线数据采集系统。该系统分为数据采集模块、数据传输/接收模块、数据处理模块,如图1所示。数据采集模块通过将传感器得到的模拟信号转换成数字信号,再用无线芯片发送出去。A/D转换芯片采用MAX132;数据传输芯片采用无线传输/接收芯片IA4421。用单片机配置MAX132和IA4421实现信号采集和发送。数据处理模块采用S3C2410芯片,并且配置无线芯片IA4421为无线接收模式。这样就实现了数据采集、传输与处理。

2 数据采集

数据采集模块使用A/D转换芯片,通过把接收到的模拟信号转换成数字信号,再通过数据传输模块将数字信号传输到数据处理模块。

MAX132是18位外加1个符号位,具有高精度分辨率,以串行方式工作的A/D转换芯片[2]。它可在-512~+512 mV全范围内提供2 μV的分辨率,精度可达±0.006%满量程。芯片较一般的积分型ADC具有更高的转换速度,可达每秒100次,简单的4线串行接口使其容易与其他所有的微处理器连接。MAX132在普通工作方式下,典型供电电流为60 mA,在休眠模式下仅为1 μA。MAX132还具有用于外部多路开关或可编程增益放大器的4个可编程的数字输出;芯片内部还有可选50 Hz工频的干扰抑制电路;芯片输入电流很小,仅为10 pA。MAX132具有分辨率高,功耗低,价格低,体积小等特点,可广泛应用于远程数据采集、电池供电仪器仪表和传感器信号测量及工业过程控制等[3]。电路设计如图2所示。

图2为MAX132的典型应用电路图。其中,元件值是针对每秒转换16次,60 Hz工频干扰抑制选择的。通过2.5 V的高精度基准源,MAX872分压后产生545 mV的基准电压。待测电压信号从INH1和INL0端口差分输入;片选信号undefined,串行数据输入/输出端DIN,DOUT,时钟信号Sclk与单片机连接实现。

如图3所示,当IA4421芯片的undefined脚作为启动转换时,undefined为高电平;若将undefined置低电平,则10 ms之内又变为高电平,就执行一次转换,然后回到空闲模式。如果undefined一直处于低电平,就连续进行转换,直到undefined再次变为高电平。

3 数据传输模块

3.1 数据传输模块硬件设计

数据传输模块采用IA4421芯片。IA4421支持天线直接驱动,设计相当简单方便,并且通信距离长[4]。IA4421是全集成的单晶片低功耗、多频道的FSK收发器,在无需申请注册的433 MHz,868 MHz,915 MHz频段,设计完全符合FCC的ETSI认证相关规定,内部集成有高频功率放大器、低噪声放大器、I/Q转换混频器,基带滤波器、放大器、I/Q解调器等,所需的RF都已集成,只需要一个晶振和几颗去耦电容[5]。

3.2 数据传输模块软件设计

3.2.1 发射器的功能

(1) 发送采集数据指令,打开采集系统,为发送数据做好准备。

(2) 与发射器实现自动对码。发射器控制软件程序流程图如图4所示[6],单片机上电初始化后,完成对IA4421的配制。此时,芯片被配置为发射模式,然后打开中断,等待数据输入,接收到采集的信号,最后将信息发送出去。

3.2.2 接收器的功能

接收器主程序流程与发送器程序流程很相似,在此不再画流程图,仅将接收器的功能介绍为:配置IA4421芯片为接受模式,发送准备好的信号;接收数据,然后再传输给处理单元,处理单元为S3C2410主芯片。

4 数据处理模块

数据处理模块采用S3C2410芯片。S3C2410处理器是Samsung公司基于ARM公司的ARM920T处理器核。它采用0.18 μm制造工艺的32位微控制[7]。该处理器拥有独立的16 KB指令Cache和16 KB数据Cache,MMU,支持TFT的LCD控制器,NAND闪存控制器,3路UART,4路DMA,4路带PWM的Timer,I/O口,RTC,8路10位ADC,Touch Screen接口,I2C-BUS 接口,IIS-BUS 接口,2个USB主机,1个USB设备,SD主机和MMC接口,2路SPI。S3C2410处理器最高可运行在203 MHz[7]。

采用嵌入式Linux操作系统,Linux内核稳定且代码尺寸小巧,易于裁减[8]。 应用程序窗口系统采用Qt/Embedded系统技术,Qt/Embedded是基于Qt的嵌入式GUI和应用程序开发的工具包,可运行在多种嵌入式设备上,主要运行在嵌入式Linux系统上,为嵌入式应用程序提供Qt的标准API[9]。Qt/E作为嵌入式GUI的实现工具,支持帧缓冲驱动,可以在没有X2Server或X2LIB支持的条件下直接写帧缓冲,节省了内存使用,提高了程序的运行效率[10]。

(1) 配置无线接收芯片为接收模式,发送接收数据命令,通知IA4421准备好接收收据,且发送准备好的信号,通知发送模块发送数据。

(2) 将接收到的数据进行运算分析,然后将结果反映到LCD上;应用程序具有分析功能,对信号的性能进行分析,且在信号出错情况下做出报警处理。

5 结 语

该系统采用了MAX132芯片,实现了模拟信号到数据信号的转变,又用IA4421实现了数据的无线传输。考虑了系统的实用性与灵活性,可以灵活的布线,不受物理环境影响,且采用S3C2410作为数据处理模块的主芯片。

参考文献

[1]缪爱国,刁扣锁.基于嵌入式Linux和GPRS的无线数据通信的设计与实现[J].电子器件,2004,27(4):715-718.

[2]贺中武,肖明清,赖根.串行模/数转换器MAX132与标准并行口接口及编程[J].电子测量技术,2003(2):12-13.

[3]陈万春.串行接口的±18位模/数转换器MAX132及其应用[J].集成电路应用,1997(1):6-9.

[4]张科帆,张淑华,涂强,等.基于IA4421的数字化无线温度传感器的设计与实现[J].现代电子技术,2008,31(20):189-191.

[5]亚讯科技(香港)有限公司.IA4421中文资料[Z].2004.

[6]庄晓龙.基于MSP430和IA4421的高尔夫球车遥控系统[J].机电工程,2008(11):108-110.

[7]孔德勇,杨斌.基于S3C2410嵌入式无线监控系统的设计[J].微计算机信息,2009,25(5):114-116.

[8]赖于树.ARM微处理器于应用开发[M].北京:电子工业出版社,2007.

[9]王灵芝,陈磊松.基于嵌入式Linux与QT的MP3播放器的设计[J].漳州师范学院学报:自然科学版,2009,22(1):39-43.

S3C2410 NANDFLASH的配置实验 篇3

关键词:嵌入式S3C2410vivi引导程序

1 概述

引导程序是计算机引导系统软件的一个重要工具,大家对80X86微型机上的引导系统不会陌生,嵌入式系统的引导程序的作用与其相似,通过引导程序可以对系统中的一些主要部件做初始化,对嵌入式系统来说,就是诸如CPU、存储器件、串行口、网络口等部件要做初始配置,相对于微型机来说,嵌入式系统的存储管理出于效率的考虑,对使用有更为精确、严格的要求,引导程序可以分配内存空间的映射,将系统的软件和硬件环境处于最佳的工作状态,为下一步操作系统的引导做好准备工作。

2 vivi引导程序

2.1 vivi简介

Vivi是由韩国Mizi公司面向ARM9处理器开发的引导系统,支持S3C2410处理器。它工作于两种可选模式下,一种是启动加载模式,另一种是下载模式,后面会给出这两种模式的具体分析。启动加载模式下,会完成操作系统的自动引导,下载模式下,会通过一个命令行接口提供的命令完成相应功能。

2.2 vivi程序架构分析

Vivi系统是由一段很小的引导程序构成,它的代码包括如下几个目录:arch,init,drivers,lib和include。

①arch子目录: vivi可以支持很多类型的目标板,不同类型的目标板会对应不同的子目录,文中给出的Vivi引导系统Boot Loader中只包括了S3C2410目录;②Init: vivi的执行就是由这个目录的用C语言写成的main.c文件开始执行,该目录下还有一个名称为version.c的文件;③drivers:内核工作时的设备驱动程序都包括于这个目录,它又将设备驱动分为三种类型,分别置于MTD,串口,网络三个目录下,其中MTD实现的是核心设备的驱动管理,它又分为map,nand,nor三个目录;④lib:针对一些平台实现的公共的代码,用于接口功能的实现;⑤include:实现头文件管理,文中S3C2410的头文件就置于该目录下,它是头文件的公共目录。

3 vivi运行流程分析

3.1 vivi初始化阶段一(在/arch/s3C2410/head.s文件内)

3.1.1 硬件初始化

当上电或复位后,vivi启动,位于NANDFlash中的前4KB程序便从NANDFlash中由S3C2410自动拷贝到一个叫SteppingStone的4KB的内部RAM中,该RAM之后被映射到地址0x00处。此时,也就是vivi前4KB代码开始运行,进行第一阶段的硬件初始化,主要工作为:关Watchdog Timer,关中断,初始化PLL和时钟主频设定,初始化存储器控制器。

3.1.2 配置串口

该步初始化串口寄存器。

3.1.3 复制自身到SDRAM中

当初始化串口结束,vivi开始把自身从NANDFlash中复制到SDRAM中,之后在SDRAM中运行。

3.2 vivi初始化阶段二(在/init/main.c文件内)

3.2.1 继续初始化实验系统硬件

通过board_init()函数完成,该函数在/arch/s3c2410/smdk.c中,主要完成两个功能,时钟初始化(init_time()),以及IO口的配置(set_gpios())。

3.2.2 内存映射初始化,内存管理单元初始化

通过mem_map_init()、mmu_init()函数来完成,这两个函数在/arch/s3c2410/mmu.c中。该启动代码,使用NAND设备作为启动设备。内存映射完后,要使能MMU。

3.2.3 初始化堆

通过heap_init()函数完成,该函数在/lib/head.c中,初始化堆。

3.2.4 初始化mtd设备

通过mtd_init()函数完成,该函数在/drivers/mtd/maps/s3c2410_flash.c中,初始化mtd设备。

3.2.5 初始化私有数据

通过init_priv_data()函数完成,该函数在/lib/priv_data/rw.c中,初始化私有数据。

3.2.6 初始化内置命令

通过init_builtin_cmds()函数完成,该函数在/lib/command.c中,初始化内置命令。

3.2.7 启动vivi

通过boot_or_vivi()函数完成,此时引导过程在超级终端上建立人机界面,并等待用户输入命令。若接收到用户输入非回车键,进入vivi模式,否则,等待一会儿,系统自启动。

4 vivi的二个重要命令的分析

当vivi处于下载模式时,它为用户提供一个命令行接口,通过该接口能使用vivi提供的一些命令集,下面就给出在这种模式下的三个重要命令的分析,通过这二个命令,能完成与系统相关的重要功能。

4.1 load命令

load 命令完成加载二进制文件到flash或ram中。

格式为:load [ | ]

其中,参数是指加载到哪?具体为flash和ram;数确定要加载的二进制文件的位置。如果需要使用预定义的mtd分区定义,则应加上分区定义名,否则指定位置和文件的大小。参数确定文件的传输协议。vivi现在只能使用xmodem协议,所以,”x”是有效的。

例如,裝载zImage 到flash中。要用命令:vivi> load flash kernel x,或者指定地址和文件大小:vivi> load flash 0x800000xc0000 x

4.2 boot命令

boot命令是启动保存在flash或ram中的linux内核命令。

命令格式为:boot [ | ]

其中,参数是linux内核存放在什么介质上。有效值为ram,nor,smc;参数确定要加载的linux内核文件的位置。如果需要使用预定义的mtd分区定义,则应加上分区定义名,否则指定位置和文件的大小。

例如,vivi> boot ram,该过程能使vivi从ram中启动linux内核。

5 结束语

本文给出了嵌入式系统引导程序的一个特定产品vivi的详细的分析,通过分析,要掌握它的结构、工作过程,除此之外,运行于嵌入式系统下的引导程序有很多,如U-boot,Redboot等,虽然由不同的厂家开发,但它们的工作原理是相似的,因此,文中对vivi的分析,能起到以点带面的作用。

参考文献:

[1]《基于ARM9嵌入式系统的BootLoader设计》,叶林等.《科技信息》2009(11).

[2]《基于s3c2410开发板的Boot Loader的启动分析》,刘军芳等.《微计算机信息》2006(17).

[3]《基于ARM的嵌入式系统Boot Loader启动流程分析》,万永波.《微计算机信息》2005(2).

S3C2410 NANDFLASH的配置实验 篇4

U-Boot(UniversalBootLoader),即通用Bootloader,是遵循GPL条款的开源项目,由德国DENX小组开发。支持多种CPU架构,如:X86、Power PC、ARM等;U-Boot可以引导多种操作系统,如:Linux、Net BSD、Vx Works等;U-Boot有较高的可靠性和稳定性,高度灵活的功能设置,丰富的设备驱动程序和开发调试文档以及强大的网络技术支持。

U-Boot移植所用平台是武汉创维特信息技术有限公司研发的JXARM9-2410-1教学实验系统。该实验箱核心CPU采用三星公司的ARM9处理器S3C2410X。核心板标配置32MB NOR flash、16MB NAND flash及64MB SDRAM。扩展版上集成了众多的接口。可稳定运行Linux、Win CE、Vx Works、Nucleus、μC/OS-Ⅱ等嵌入式操作系统。

1 U-Boot源码结构

U-Boot目录下有比较多的子目录,这些子目录可分为4类,分别是:CPU架构相关或开发板相关子目录;通用函数子目录;通用设备驱动程序子目录;工具、例程、文档子目录。

具体子目录如下:

board:存放和开发板有关的文件,U-Boot所支持的每个开发板,都会以子目录的形式存放在该目录下,主要用于设置SDRAM、flash存储器的驱动。

common:存放U-Boot支持的所有命令的源码,每个命令存在于该目录下的一个文件中。

cpu:存放和CPU架构有关的目录,如arm920t。

disk:存放和磁盘驱动有关的文件。

doc:存放U-Boot的说明文档。

driver:存放各类具体设备的驱动程序,基本上可以通用,通过宏从外面引入平台相关的函数。

dtt:存放和数字温度器和调温器有关的驱动。

examples:存放可以在U-Boot下运行的一些测试程序,如hello_world.c,timer.c。

include:存放头文件和开发板配置文件,开发板的配置文件都放在include/configs目录下。

lib_xxx:存放和处理器体系架构相关的库文件,如lib_i386,lib_arm目录下分别包含与i386、ARM体系结构相关的文件。

net:存放与网络协议相关的文件,如bootp,nfst,ftp。

post:存放上电自检文件。

rtc:存放实时时钟驱动程序文件。

tools:存放用于生成S-Record或U-Boot镜像文件的工具。

2 U-Boot启动过程分析

2.1 U-Boot运行的第一阶段

U-Boot运行过程分为两个阶段,针对S3C2410处理器和smdk2410开发板,第一阶段的源码文件在cpu/arm920t/start.S和board/smdk2410/lowlevel_init.S中,第一阶段源码用汇编语言实现,所做的工作主要包括:

上电后设置CPU为管理模式(SVC)。

关闭看门狗。

关中断。

设置时钟相关寄存器。

关闭缓冲器和禁止MMU。

跳转到board/smdk2410/lowlevel_init.S中设置SDRAM内存。

代码搬运,把自己从NOR flash复制到内存中。

设置栈空间。

清零BSS段。

2.2 U-Boot运行的第二阶段

U-B o o t第二阶段从l i b_a r m/b o a r d.c中的start_armboot函数开始,所做的工作有:

初始化IRQ/FIQ模式的栈。

设置系统时钟。

初始化定时器。

检查flash上的参数是否有效。

初始化串口控制台。

检测系统内存映射。

初始化NOR flash

将环境参数读入内存指定位置。

初始化网络设备。

调用main_loop。

循环读取串口数据,执行相应命令。

3 移植过程

3.1 下载U-Boot源码

官方下载地址:ftp://ftp.denx.de/pub/U-Boot/

3.2 解压源文件

3.3 准备相关文件

JXARM9-2410-1实验箱的硬件配置和三星公司开发板smdk2410相近,为简化移植过程,可以以smdk2410开发板为基础,进行源码的增删。

3.3.1 复制文件并改名

本着不破坏原有代码的原则,可复制smdk2410开发板的相关文件并改名。

把smdk2410.c文件的名字改为jxarm2410.c

3.3.2 修改jxarm2410目录下的Makefile

把其中的smdk2410.o改为jxarm2410.o,即:COBJS:=jxarm2410.o flash.o

3.3.3 添加支持NOR flash的文件

JXARM9-2410-1实验箱所用NOR flash的型号和smdk2410开发板所用NOR flash的型号不同,为此删除从smdk2410复制过来的flash.c文件。

JXARM9-2410-1实验箱所用NOR flash型号为28f128JA,单片16MB,共用2片,总容量32MB;而U-Boot所支持开发板xm250所用flash亦为28f128JA,为此复制其flash.c文件到jxarm2410开发板目录下。

修改board/jxarm2410/flash.c文件。

在函数unsigned long flash_init(void)中屏蔽掉"case 1"语句,即:

修改为:

3.3.4 修改rtl8019.c文件

JXARM9-2410-1所用以太网控制芯片为rtl8019。

在get_reg函数中添加关键字volatile,修改为:

3.4 修改顶层Makefile

3.4.1 指定交叉编译器的位置

3.4.2 添加针对jxam2410的配置命令

3.5 修改配置头文件jxarm2410.h文件

3.5.1 修改针对以太网控制芯片的配置

smdk2410开发板所用以太网芯片为cs8900,为此在jxarm2410.h中屏蔽掉cs8900的相关配置,添加JXARM9-2410-1所用网络芯片rtl8019的相关配置:

#define CONFIG_DRIVER_RTL8019 1/*使用rtl8019网络芯片*/

#define RTL8019_BASE 0x18000300/*设置基地址*/

3.5.2 添加网络相关配置

3.5.3 修改U-Boot命令行提示符

3.5.4 修改和添加NOR flash存储器相关配置

3.6 配置、编译、链接和生成可执行文件uboot.bin

3.7 把u-boot.bin下载到实验箱并执行

超级终端连接JXARM9-2410-1的UART0口,上图为在超级终端中显示的信息,可见U-Boot已经可正常运行,并且可以查看NOR flash的信息。

4 结束语

U-Boot功能强大,支持多种CPU架构,包含众多开发板的移植源码,是非常理想的Bootloader。本文详述了U-Boot在S3C2410上的移植过程,当移植其它的U-Boot版本,或在其它的硬件平台上移植时,可以此作为参考。也可以此移植为基础,扩展U-Boot的功能。

参考文献

[1]韦东山.嵌入式Linux应用开发完全手册[M].北京:人民邮电出版社.

[2]孙秋野.ARM嵌入式系统开发典型模块[M].北京:人民邮电出版社.

[3]杜春雷.ARM体系机构与编程[M].北京:清华大学出版社.

[4]张伟.U-Boot的启动流程及移植[J].仪表技术,2009(4):17-19.

[5]杨峰.U-Boot下NorFLASH驱动实现[J].电子技术,2008(3):35-37.

S3C2410 NANDFLASH的配置实验 篇5

S3C2410是Samsung公司推出的一款基于ARM920T内核的16/32位RISC嵌入式微处理器, 最高工作频率可达203MHz, 主要面向手持设备以及高性价比、低功耗的应用。芯片实现了MMU、AMBA (Advanced Microcontroller Bus Architecture) 、BUS和哈佛 (Harvard) 高速缓存体系结构。其中, MMU主要用于管理虚拟内存, AMBA总线是ARM公司设计的一种用于高性能嵌入式系统的总线标准, 高速缓存由独立的16KB指令Cache和16KB数据Cache组成。S3C2410还提供了大量的内部设备和丰富的外部接口。

CS8900A 是由美国CIRRUS LOGIC 公司生产的以太网控制器, 由于其优良的性能、低功耗及低廉的价格, 使其在市场上10Mbps 嵌入式网络应用中占有相当的比例。本文研究基于S3C2410的以太网控制芯片的CS8900A驱动程序设计。

1 CS8900A特性分析

CS8900A 芯片主要性能为:①符合Ethernet II 与IEEE802.3 (10Base5、10Base2、10BaseT) 标准;②全双工, 收发可同时达到10Mbps 的速率;③内置SRAM, 用于收发缓冲, 降低对主处理器的速度要求;④支持16 位数据总线, 4个中断申请线以及三个DMA请求线;CS8900A有两种工作模式, 一种是I/O访问方式, 一种是内存访问方式。网卡芯片复位后默认工作方式为I/O连接, I/O端口基址为300H。下面对它的几个主要工作寄存器进行介绍 (寄存器后括号内的数字为寄存器地址相对基址300H的偏移量) , 这些寄存器直接与编程控制有关;⑤LINECTL (0112H) LINECTL决定CS8900的基本配置和物理接口。在本系统中, 设置初始值为00d3H, 选择物理接口为10BASE-T, 并使能设备的发送和接收控制位;⑥RXCTL (0104H) RXCTL 控制CS8900 接收特定数据报。设置RXTCL的初始值为0d05H, 接收网络上的广播或者目标地址同本地物理地址相同的正确数据报;⑦RXCFG (0102H) RXCFG控制CS8900 接收到特定数据报后会引发接收中断。RXCFG可设置为0103H, 这样当收到一个正确数据报后, CS8900 会产生一个接收中断;⑧BUSCT (0116H) BUSCT 可控制芯片的I/O 接口的一些操作。设置初始值为8017H, 打开CS8900 的中断总控制位;⑨ISQ (0120H) ISQ 是网卡芯片的中断状态寄存器, 内部映射接收中断状态寄存器和发送中断状态寄存器的内容;⑩PORT0 (0000H) 发送和接收数据时, CPU 通过PORT0 传递数据; (11) TXCMD (0004H) 发送控制寄存器, 如果写入数据00C0H, 那么网卡芯片在全部数据写入后开始发送数据; (12) TXLENG (0006H) 发送数据长度寄存器, 发送数据时, 首先写入发送数据长度, 然后将数据通过PORT0 写入芯片。

2 驱动程序流程

以下为几个最主要的工作寄存器 (为16 位) , CS8900A 支持8 位模式, 当读或写16 位数据时, 低位字节对应偶地址, 高位字节对应奇地址。例如, 向TXCMD 中写入00C0H, 则可将00h 写入305H, 将C0H 写入304H。系统工作时, 应首先对网卡芯片进行初始化, 即写寄存器LINECTL、RXCTL、RCCFG、BUSCT。

发数据时, 写控制寄存器TXCMD, 并将发送数据长度写入TXLENG, 然后将数据依次写入PORT0口, 如将第一个字节写入300H, 第二个字节写入301H, 第三个字节写入300H, 依此类推。网卡芯片将数据组织为链路层类型并添加填充位和CRC 校验送到网络。同样, 处理器查询状态寄存器的数据, 当有数据来到后, 读取接收到的数据帧。

以太网驱动程序就是对以太网络接口芯片CS8900A 编程, 正确初始化芯片并提供数据输入输出和控制接口给高层网络协议使用。驱动程序的第一步是对其进行初始化:初始化内容包括检测CS8900A 芯片是否存在, 然后软件复位CS8900A。如果使用Memory Map 方式访问CS8900A 芯片内部寄存, 就设置CS8900A 内部寄存基地址 (默认为IO 方式访问) , 设置CS8900A 的MAC 地址, 关闭事件中断 (本程序使用查询方式, 如果使用中断方式, 则添加中断服务程序再打开CS8900A 中断允许位) 。配置CS8900A 10BT, 然后允许CS8900A 接收和发送, 接收发送64-1518 字节的网络帧及网络广播帧。详细说明见CS8900A用户手册。

初始化流程如图1所示, CS8900A接收流程如图2所示, CS8900A发送流程如图3所示。

3 驱动程序主要代码

驱动模块中最核心的功能是要提供接收、发送以太帧函数, 供上层协议调用, 下面对这两个函数进行说明。接收以太网帧子程序, 其中参数tms 表示最长等待时间, database指如果接收帧正确则将该帧写到以database为基址的内存中, 如果接收成功返回长度, 否则返回0。

发送以太网帧, 发送的数据指针在data中, length指长度 (以字节为单位) , 发送成功则返回1, 否则返回0 。

4 驱动程序的实验检测

测试过程:通过JTAG将驱动程序下载到开发板的RAM中运行, 然后在PC机上运行send.exe, 根据提示选择网卡、输入通过网线传输的文件名、输入命令 (下载到RAM/烧到Nor Flash/烧到Nand Flash) 、输入地址之后即可看到传输开始, 一直到传输结束, 结束之后显示传输速度、文件大小、传输时间等相关信息。需要说明的是并不需要输入接收方 (开发板) 的IP地址和MAC地址, PC端发送程序通过广播可自动获取开发板IP和MAC地址。

经过测试发现, 传输速度较快, 尤其对比较大的文件, 文件越大传输速度越快, 当传输文件达到10MB以上时传输速度可达360KB/s-380KB/s。经过计算已经非常接近开发板接收速度的极限。这样16MB的WinCE镜像在40多秒钟即可传输完毕, 并可看到WinCE正常运行。比起用仿真器Embest PowerICE下载速度快了许多倍。

参考文献

[1]周毓林, 宁杨, 陆贵强, 等.Windows CE.net内核定制及应用开发[M].北京:电子工业出版社, 2004.

[2]汪兵, 李存斌, 陈鹏.EVC高级编程及应用开发[M].北京:中国水利水电出版社, 2005.

[3]周立功.ARM嵌入式系统基础教程[M].北京:北京航空航天大学出版社, 2005.

[4]李广弟, 朱月秀, 王秀山.单片机基础[M].北京.北京航空航天大学出版社.2001.

[5]张崙.32位嵌入式系统硬件设计与调试[M].北京:机械工业出版社, 2005.

【S3C2410 NANDFLASH的配置实验】推荐阅读:

上一篇:教师工作总结个人1000字下一篇:文明和环保创造环境的作文1100字

本站热搜

    相关推荐