s3c2440a启动过程详解
- 格式:docx
- 大小:16.74 KB
- 文档页数:3
文章记录了作者在S3C2440开发板上实现按键点亮LED驱动开发的详细过程,还记录了一些容易出现的错误,以及怎么解决这些错误。
一、驱动开发流程Linux驱动开发不同于应用程序的开发。
驱动开发是直接和硬件打交道的,通过对硬件的操作给应用程序提供一些接口函数,使得应用程序能够“间接”的控制硬件来工作。
对于按键点亮LED的驱动开发流程如下。
二、驱动开发具体步骤1、查看开发板TQ2440底板原理图,找到按键和LED模块,如下图:图-2 按键和LED电路图从上图我们可以清楚地看到K1~K4对应的管脚是ENT1~ENT4,LED1~LED4对应的管脚是nLED_1~nLED_4.2、查看TQ2440_核心板原理图,找到对应的CPU管脚,如下图:图-3 按键和LED对应CPU管脚电路图3、查看s3c2440芯片手册,查看CPU管脚的模式,如下图从上图我们可以看出按键对应的CPU管脚GPF0~GPF4都是占两位(如:GPF0[1:0])。
按键是一种中断,要想让按键工作在中断模式下,就要设置GPF0~GPF4(GPF3除外)管脚都设置在中断模式下,即为10。
对于LED对应的CPU管脚GPB5~GPB8也是占两位。
要想让LED工作,就要让LED工作在输出模式下,即对应管脚设置为01.4、编写按键点亮LED驱动程序/*调用内核头文件,和应用程序调用的头文件不一样*/#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/irq.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#include <linux/device.h>#include <linux/poll.h>#define DEVICE_NAME "tope-buttons" //自定义驱动称为“tope-buttons”。
第二章处理器工作模式2.1概述S3C2440采用了非常先进的ARM920T内核,它是由ARM(Advanced RISC Machines) 公司研制的。
2.2 处理工作状态从程序员的角度上看,ARM920T可以工作在下面两种工作状态下的一种:● ARM 状态:执行32位字对齐的ARM指令● THUMB 状态:执行16位半字对齐的THUMB指令。
在这种状态下,PC 寄存器的第一位来选择一个字中的哪个半字注意;这两种状态的转换不影响处理模式和寄存器的内容。
2.3 切换状态进入THUMB 状态进入THUMB 状态,可以通过执行BX指令,同时将操作数寄存器的状态位(0位)置1来实现。
当从异常(IRQ,FIQ,UNDEF,ABORT,SWI等)返回时,只要进入异常处理前处理器处于THUMB状态,也会自动进入THUMB状态。
进入ARM状态进入ARM状态,可以通过执行BX指令,并且操作数寄存器的状态位(0位)清零来实现。
当处理进入异常(IRQ,FIQ,RESET,UNDEF,ABORT,SWI等)。
这时,PC值保持在异常模式下的link寄存器中,并从异常向量地址处开始执行处理程序。
存储空间的格式ARM920T将存储器空间视为从0开始由字节组成的线性集合,字节0到3中保存了第一个字节,字节4到7中保存第二个字,以此类推,ARM920T对存储的字,可以按照小端或大端的方式对待。
大端格式:在这种格式中,字数据的高字节存储在低地址中,而字数据的低字节则存放2.4 指令长度指令可以是32位长度(在ARM状态下) 或16位长度(在THUMB状态) 。
数据类型ARM920T支持字节(8位),半字(16位) 和字(32位) 数据类型。
字必须按照4字节对齐,半字必须是2字节对齐。
2.5 操作模式ARM920T支持7种操作模式:● 用户模式(user模式),运行应用的普通模式● 快速中断模式(fiq模式),用于支持数据传输或通道处理● 中断模式(irq模式),用于普通中断处理● 超级用户模式(svc模式),操作系统的保护模式● 异常中断模式(abt模式),输入数据后登入或预取异常中断指令● 系统模式(sys模式),使操作系统使用的一个有特权的用户模式● 未定义模式(und模式),执行了未定义指令时进入该模式]外部中断,异常操作或软件控制都可以改变中断模式。
S3C2440 PLL设置详解CPU上电几毫秒后,晶振输出稳定,FCLK=Fin(晶振频率),CPU开始执行指令。
但实际上,FCLK可以高于Fin,为了提高系统时钟,需要用软件来启用PLL。
这就需要设置CLKDIVN,MPLLCON,UPLLCON这3个寄存器。
CLKDIVN寄存器用于设置FCLK,HCLK,PCLK三者的比例,MPLLCON用于设置主频FCLK,UPLLCON用于设置USB时钟UCLK。
S3C2440APLL源有两个,一个是MPLL,另一个是UPLL. MPLL用于CPU用外设,UPLL只用于USB.,包括CPU的FCLK,AHB总线外设的HCLK以及APB总线外设的PCLK。
S3C2440A包含两个锁相环(PLL):MPLL提供给FCLK、HCLK和PCLK,UPLL 专用于USB模块(48MHz)。
时钟控制逻辑可以不使用PLL来减慢时钟,并且可以由软件连接或断开各外设模块的时钟,以降低功耗。
S3C2440A的主时钟源由外部时钟(EXTCLK)或者外部晶振(XTIPll)提供,输入时钟源由模式控制引脚OM3和OM2控制选择,在复位信号的上升沿参考OM3和OM2的引脚将OM[3:2]的状态在内部锁定,如图1所示图1 引导启动时的时钟源选择选择不同输入时钟源时连接方式如图2所示:图2 时钟连接参考通过在片内集成的2个锁相环:MPLL和UPLL,可对输入的Fin=12MHz的晶振频率进行倍频。
S3C2440使用了三个倍频因子MDIV、PDIV和SDIV来设置倍频,通过寄存器MPLLCON和UPLLCON可分别设置各自的倍频因子。
其中MPLLCON寄存器用于设置处理器内核时钟主频FCLK,其输入输出频率间的关系为FCLK=MPLL=(2*m*Fin)/(p*2^s)其中m=(MDIV+8), p=(PDIV+2), s=SDIV。
其中UPLLCON寄存器用于产生48MHz或96MHz,提供USB时钟(UCLK),其输入输出频率间的关系为UCLK=UPLL=(m * Fin) / (p * 2^s)其中m=(MDIV+8), p=(PDIV+2), s=SDIV。
s3c2440触摸屏驱动(针对android版)s3c2440 触摸屏驱动(针对android版)和原来的触摸屏驱动区别不是很⼤,增加了report函数来将事件发送到应⽤层。
驱动结构:很简单的字符设备+平台设备驱动,总的结构来说,主要四个部分构成:proberemoveresumesuspend⼯作机制则是注册设备,然后发⽣ts按下事件后产⽣ts中断以及adc中断,获得按下坐标。
没有读写函数,重点就是在两个中断处理函数上。
1,平台设备架构部分分析:probe函数:流程:ts基址的重映射->获得并启动时钟->ADCCON、ADCDLY、ADCTSC的初始化->初始化input设备完善ts结构体->建⽴ts_filter_chain->申请中断->注册input设备(2.6.27后为event0不再是ts0)。
static int __init s3c2410ts_probe(struct platform_device *pdev){int rc;struct s3c2410_ts_mach_info *info;struct input_dev *input_dev;int ret = 0;dev_info(&pdev->dev,"Starting\n");info =(struct s3c2410_ts_mach_info*)pdev->dev.platform_data;//获得平台设备数据if(!info){dev_err(&pdev->dev,"Hm... too bad: no platform data forts\n");return-EINVAL;}#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUGprintk(DEBUG_LVL "Entering s3c2410ts_init\n");#endifadc_clock = clk_get(NULL,"adc");if(!adc_clock){dev_err(&pdev->dev,"failed to get adc clock source\n");return-ENOENT;}clk_enable(adc_clock);#ifdef CONFIG_TOUCHSCREEN_S3C2410_DEBUGprintk(DEBUG_LVL "got and enabled clock\n");#endifbase_addr = ioremap(S3C2410_PA_ADC,0x20);//将PA_ADC寄存器重映射到内存上if(base_addr ==NULL){dev_err(&pdev->dev,"Failed to remap register block\n"); ret =-ENOMEM;goto bail0;}/* If we acutally are a S3C2410: Configure GPIOs */if(!strcmp(pdev->name,"s3c2410-ts"))s3c2410_ts_connect();//初始化相关gpio⼝if((info->presc & 0xff)> 0)writel(S3C2410_ADCCON_PRSCEN |S3C2410_ADCCON_PRSCVL(info->presc&0xFF),base_addr + S3C2410_ADCCON);elsewritel(0, base_addr+S3C2410_ADCCON);/* Initialise registers */if((info->delay & 0xffff)> 0)writel(info->delay & 0xffff, base_addr + S3C2410_ADCDLY);writel(WAIT4INT(0), base_addr + S3C2410_ADCTSC);/* Initialise input stuff */memset(&ts, 0,sizeof(struct s3c2410ts));input_dev = input_allocate_device();if(!input_dev){dev_err(&pdev->dev,"Unable to allocate the input device\n");ret =-ENOMEM;}//初始化input设备ts.dev = input_dev;ts.dev->evbit[0]= BIT_MASK(EV_SYN)| BIT_MASK(EV_KEY)|BIT_MASK(EV_ABS);ts.dev->keybit[BIT_WORD(BTN_TOUCH)]= BIT_MASK(BTN_TOUCH);input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_Y, 0, 0x3FF, 0, 0);input_set_abs_params(ts.dev, ABS_PRESSURE, 0, 1, 0, 0);ts.dev->name = s3c2410ts_name;ts.dev->id.bustype = BUS_RS232;ts.dev->id.vendor = 0xDEAD;ts.dev->id.product = 0xBEEF;ts.dev->id.version = S3C2410TSVERSION;ts.state = TS_STATE_STANDBY;//设置ts状态为就绪ts.event_fifo = kfifo_alloc(TS_EVENT_FIFO_SIZE, GFP_KERNEL, NULL);//为event队列申请内存空间if(IS_ERR(ts.event_fifo)){ret =-EIO;goto bail2;}/* create the filter chain set up for the 2 coordinates we produce */ts.chain = ts_filter_chain_create(pdev, info->filter_config, 2);//针对android的,建⽴filter_chainif(IS_ERR(ts.chain))goto bail2;ts_filter_chain_clear(ts.chain);/* Get irqs */if(request_irq(IRQ_ADC, stylus_action, IRQF_SAMPLE_RANDOM,"s3c2410_action", ts.dev)){dev_err(&pdev->dev,"Could not allocate ts IRQ_ADC !\n"); iounmap(base_addr);goto bail3;}if(request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM, "s3c2410_action", ts.dev)){dev_err(&pdev->dev,"Could not allocate ts IRQ_TC !\n"); free_irq(IRQ_ADC, ts.dev);iounmap(base_addr);ret =-EIO;goto bail4;}dev_info(&pdev->dev,"Successfully loaded\n");/* All went ok, so register to the input system */rc = input_register_device(ts.dev);if(rc){ret =-EIO;goto bail5;}return 0;bail5:free_irq(IRQ_TC, ts.dev);free_irq(IRQ_ADC, ts.dev);clk_disable(adc_clock);iounmap(base_addr);disable_irq(IRQ_TC);bail4:disable_irq(IRQ_ADC);bail3:ts_filter_chain_destroy(ts.chain);kfifo_free(ts.event_fifo);bail2:input_unregister_device(ts.dev);bail1:iounmap(base_addr);bail0:return ret;}remove:就是probe的逆运算,static int s3c2410ts_remove(struct platform_device *pdev) {disable_irq(IRQ_ADC);disable_irq(IRQ_TC);free_irq(IRQ_TC,ts.dev);free_irq(IRQ_ADC,ts.dev);if(adc_clock){clk_disable(adc_clock);clk_put(adc_clock);adc_clock =NULL;}input_unregister_device(ts.dev);iounmap(base_addr);ts_filter_chain_destroy(ts.chain);kfifo_free(ts.event_fifo);return 0;}resume与suspend函数可有可⽆,完成触摸屏的激活和挂起,2,中断处理分析:三种模式转换过程:等待down中断模式->x,y连续坐标转换模式->等待up中断模式->等待down中断模式->..两个中断的发⽣:触摸屏按下,发⽣ts中断,开始ad转换,ad转换结束,发⽣adc中断。
U -Boot 从NAND Flash 启动的实现王磊(太原理工大学信息工程学院,山西太原030024)摘要:U -Boot 不能从NAND Flash 启动给应用带来些不便,因此修改U -Boot 使其支持从NAND Flash 启动。
分析了U -Boot 启动流程的两个阶段及实现从NAND Flash 启动的原理和思路,并根据NAND Flash 的物理结构和存储特点,增加U -Boot 对NAND Flash 的操作支持,从而完成把存储在NAND Flash 上的U -Boot 代码复制到SDRAM 中执行,实现从NAND Flash 的启动。
修改过后的U -Boot 可以直接从NAND Flash 启动,给应用带来便利。
关键词:U -Boot ;NAND Flash ;Bootloader ;S3C2440;移植中图分类号:TP316文献标识码:A文章编号:1674-6236(2010)05-0098-03Realization of U -Boot booting through NAND FlashWANG Lei(Department of Information Engineering ,Taiyuan University of Technology ,Taiyuan 030024,China )Abstract:It is not convenient that U -Boot can ’t boot through NAND Flash.In this paper ,the codes of U -Boot is modified to support that.This paper analyzes two steps of U -Boot and the method of supporting that the U -Boot boots from NAND Flash.Based on the memory characteristics and the physical structure of NAND Flash ,this paper adds the codes of NAND Flash in order to carry the codes to SDRAM that stored in the NAND Flash ,thus realizes U -Boot boots from NAND Flash.The modified U -Boot runs through NAND Flash straightly ,it is a great convenience to the application of U -Boot.Key words:U -Boot ;NAND Flash ;Bootloader ;S3C2440;porting电子设计工程Electronic Design Engineering第18卷Vol.18第5期No.52010年5月May.2010收稿日期:2009-10-11稿件编号:200910032作者简介:王磊(1985—),男,山西河津人,硕士研究生。
s3c2440a启动过程详解
1:s3c2440是32位的,所以可以寻址4GB空间,内存(SDRAM)和端口(特殊寄存器),还有ROM都映射到同一个4G空间里。
2:开发板上一般都用SDRAM做内存flash(nor、nand)来当做ROM。
其中nand flash没有地址线,一次至少要读一页(512B).其他两个有地址线(飞凌2440开发板使用大页nandflash,每页2Kb)。
飞凌的全线2440开发板采用的是2片SDRAM(单片为32M,最大可扩展到单片为64M)。
3:nandflash不能用来运行代码,只用来存储代码,NORflash,SDRAM 可以直接运行代码。
4:s3c2440总共有8个内存banks,6个内存bank可以当作ROM或者SRAM来使用,留下的2个bank除了当作ROM 或者SRAM,还可以用SDRAM(各种内存的读写方式不一样),7个bank的起始地址是固定的。
还有一个灵活的bank的内存地址,并且bank大小也可以改变。
5:s3c2440支持两种启动模式:NAND和非NAND(这里是nor flash)。
具体采用的方式取决于s3c2440的OM0、OM1两个引脚
OM[1:0]所决定的启动方式:
OM[1:0]=00时,处理器从NAND Flash启动;
OM[1:0]=01时,处理器从16位宽度的ROM启动;
OM[1:0]=10时,处理器从32位宽度的ROM启动;
OM[1:0]=11时,处理器从Test Mode启动。
当从NAND启动时,cpu会自动从NAND flash中读取前4KB的数据放置在片内SRAM里(s3c2440是soc),同时把这段片内SRAM映射到nGCS0片选的空间(即0x00000000)。
cpu是从0x00000000开始执行,也就是NAND flash里的前4KB内容。
因为NAND FLASH连地址线都没有,不能直接把NAND映射到0x00000000,只好使用片内SRAM做一个载体。
通过这个载体把nandflash中大代码复制到RAM(一般是SDRAM)中去执行。
当从非NAND flash启动时,nor flash被映射到0x00000000地址(就是nGCS0,这里就不需要片内SRAM来辅助了,所以片内SRAM 的起始地址还是0x40000000). 然后cpu从0x00000000开始执行(也就是在Norfalsh中执行)。
总结:
Arm的启动都是从0地址开始,所不同的是地址的映射不一样。
在arm上电的时候,要想让arm知道以某种方式(地址映射方式)运行,不可能通过你写的某段程序控制,因为这时候你的程序还没启动,这时候arm会通过引脚的电平来判断。
1.当引脚OM0跟OM1有一个是高电平时,这时地址0会映射到外部nGCS0片选的空间,也就是Norflash,程序就会从Norflash中启动,arm直接取Norflash中的指令运行。
2.当OM0跟OM1都为低电平,则0地址内部bootbuf(一段4k的SRAM)
开始。
系统上电,arm会自动把NANDflash中的前4K内容考到bootbuf (也就是0地址),然后从0地址运行。
这时NANDFlash中的前4K 就是启动代码(他的功能就是初始化硬件然后在把NANDFlash中的代码复制到RAM中,再把相应的指针指向该运行的地方)。
为什么会有这两种启动方式,关键还是两种flash的不同特点造成,NOR FLASH容量小,速度快,稳定性好,输入地址,然后给出读写信号即可从数据口得到数据,适合做程序存储器。
NAND FLASH 总容量大,但是读写都需要复杂的时序,更适合做数据存储器。
这种不同就造成了NORflash可以直接连接到arm的总线并且可以运行程序,而NANDflash必须搬移到内存(SDRAM)中运行。