嵌入式LINUX四按键驱动

嵌入式LINUX四按键驱动
嵌入式LINUX四按键驱动

对一个具有四个按键的按键驱动的分析

源代码:

/*Headers-------------------------------------------------*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#ifdef CONFIG_DEVFS_FS

#include

#endif

/*V ars----------------------------------------------------*/

#define DEVICE_NAME "buttons"

#define EXTINT_OFF (IRQ_EINT4 - 4)

unsigned int buttons_major=0;

unsigned int buttons_minor=0;

unsigned int type = IRQT_FALLING;

struct button_info {

unsigned int irq_no;

unsigned int gpio_port;

unsigned int IN;

int button_no;

};

struct button_info realarm_button_info[4] = {

{ IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_INP, 1 }, { IRQ_EINT8, S3C2410_GPG0, S3C2410_GPG0_INP, 2 },

{ IRQ_EINT11, S3C2410_GPG3, S3C2410_GPG3_INP, 3 }, { IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_INP, 4 }, };

struct realarm_button_dev

{

struct button_info buttoninfo_tab[4];

int extint_num[4];

struct semaphore sem;

wait_queue_head_t wq;

struct cdev buttons_dev;

};

struct realarm_button_dev *realarm_button_device;

void s3c_irq_ack(unsigned int irqno)

{

unsigned long bitval = 1UL << (irqno - IRQ_EINT0);

__raw_writel(bitval, S3C2410_SRCPND);

__raw_writel(bitval, S3C2410_INTPND);

return;

}

void s3c_irqext_ack(unsigned int irqno)

{

unsigned long req;

unsigned long bit;

bit = 1UL << (irqno - EXTINT_OFF);

__raw_writel(bit, S3C2410_EINTPEND);

req = __raw_readl(S3C2410_EINTPEND);

if (irqno <= IRQ_EINT7 )

{

if ((req & 0xf0) == 0)

s3c_irq_ack(IRQ_EINT4t7);

}

else

{

if ((req >> 8) == 0)

s3c_irq_ack(IRQ_EINT8t23);

return;

}

int realarm_interrupt_init(unsigned int irq, unsigned int type) {

unsigned long gpcon_reg;

unsigned long gpcon_offset;

unsigned long extint_reg;

unsigned long extint_offset;

unsigned long newvalue = 0;

unsigned long value;

if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))

{

gpcon_reg = S3C2410_GPFCON;

extint_reg = S3C2410_EXTINT0;

gpcon_offset = (irq - IRQ_EINT0) * 2;

extint_offset = (irq - IRQ_EINT0) * 4;

}

else if ((irq >= IRQ_EINT4) && (irq <= IRQ_EINT7))

{

gpcon_reg = S3C2410_GPFCON;

extint_reg = S3C2410_EXTINT0;

gpcon_offset = (irq - EXTINT_OFF) * 2;

extint_offset = (irq - EXTINT_OFF) * 4;

}

else if ((irq >= IRQ_EINT8) && (irq <= IRQ_EINT15)) {

gpcon_reg = S3C2410_GPGCON;

extint_reg = S3C2410_EXTINT1;

gpcon_offset = (irq - IRQ_EINT8) * 2;

extint_offset = (irq - IRQ_EINT8) * 4;

}

else if ((irq >= IRQ_EINT16) && (irq <= IRQ_EINT23)) {

gpcon_reg = S3C2410_GPGCON;

extint_reg = S3C2410_EXTINT2;

gpcon_offset = (irq - IRQ_EINT8) * 2;

extint_offset = (irq - IRQ_EINT16) * 4;

} else

{

return -1;

/* Set the GPIO to external interrupt mode */

value = __raw_readl(gpcon_reg);

value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset);

__raw_writel(value, gpcon_reg);

/* Set the external interrupt to pointed trigger type */

switch (type)

{

case IRQT_NOEDGE:

printk(KERN_WARNING "No edge setting!\n");

break;

case IRQT_RISING:

newvalue = S3C2410_EXTINT_RISEEDGE;

break;

case IRQT_FALLING:

newvalue = S3C2410_EXTINT_FALLEDGE;

break;

case IRQT_BOTHEDGE:

newvalue = S3C2410_EXTINT_BOTHEDGE;

break;

case IRQT_LOW:

newvalue = S3C2410_EXTINT_LOWLEV;

break;

case IRQT_HIGH:

newvalue = S3C2410_EXTINT_HILEV;

break;

default:

printk(KERN_ERR "No such irq type %d", type);

return -1;

}

value = __raw_readl(extint_reg);

value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); __raw_writel(value, extint_reg);

return 0;

static irqreturn_t buttons_irq(int irq, void *dev_id, struct pt_regs *req)

{

struct button_info *k;

int i;

int found = 0;

struct realarm_button_dev* dev = (struct realarm_button_dev *) dev_id;

int up;

for (i = 0; i < sizeof dev->buttoninfo_tab / sizeof dev->buttoninfo_tab[0]; i++) { k = dev->buttoninfo_tab + i;

if (k->irq_no == irq) {

found = 1;

if(irq <= IRQ_EINT3)

s3c_irq_ack(irq);

else

s3c_irqext_ack(irq);

disable_irq(irq);

mdelay(200);

s3c2410_gpio_cfgpin(k->gpio_port, k->IN);

up = s3c2410_gpio_getpin(k->gpio_port);

if (!up) {

dev->extint_num[i]++;

wake_up_interruptible(&dev->wq);

}

realarm_interrupt_init(irq, type);

enable_irq(irq);

break;

}

}

if (!found) {

printk("bad irq %d in button\n", irq);

return IRQ_NONE;

}

return IRQ_HANDLED;

}

int realarm_request_irq(struct realarm_button_dev* dev)

{

struct button_info *k;

int i;

int ret;

unsigned int irq;

for (i = 0; i < sizeof dev->buttoninfo_tab / sizeof dev->buttoninfo_tab[0]; i++) { k = dev->buttoninfo_tab + i;

irq = k->irq_no;

realarm_interrupt_init(irq, type);

ret = request_irq(irq, &buttons_irq, SA_INTERRUPT, DEVICE_NAME, dev);

if (ret) {

printk(KERN_WARNING "buttons:can't get irq no.\n");

return ret;

}

}

return 0;

}

int buttons_open(struct inode *inode, struct file *filp)

{

struct realarm_button_dev *dev;

dev = container_of(inode->i_cdev, struct realarm_button_dev, buttons_dev);

filp->private_data = dev;

realarm_request_irq(dev);

return 0;

}

int buttons_release(struct inode *inode, struct file *filp)

{

struct realarm_button_dev *dev = (struct realarm_button_dev *)filp->private_data;

struct button_info *k;

int i;

for (i = 0; i < sizeof dev->buttoninfo_tab / sizeof dev->buttoninfo_tab[1]; i++) { k = dev->buttoninfo_tab + i;

free_irq(k->irq_no, dev);

}

return 0;

}

ssize_t buttons_read(struct file *filp,char __user *buffer,size_t count,loff_t *ppos)

{

struct realarm_button_dev *dev = (struct realarm_button_dev *)filp->private_data;

if (down_interruptible(&dev->sem))

return -ERESTARTSYS;

interruptible_sleep_on(&dev->wq);

if(copy_to_user(buffer, (char *)dev->extint_num, sizeof(dev->extint_num)))

{

printk(KERN_ALERT "Copy to user error.\n");

return -EFAULT;

}

up(&dev->sem);

return sizeof(dev->extint_num);

}

struct file_operations buttons_fops = {

.owner = THIS_MODULE,

.open = buttons_open,

.release = buttons_release,

.read =buttons_read,

};

static int __init buttons_init(void)

{

int i;

int ret;

dev_t dev;

printk(KERN_INFO "Initial RealARM Buttons driver!\n");

if (buttons_major) {

dev = MKDEV(buttons_major, buttons_minor);

ret = register_chrdev_region(dev, 1, DEVICE_NAME);

} else {

ret = alloc_chrdev_region(&dev, buttons_minor, 1, DEVICE_NAME);

buttons_major = MAJOR(dev);

}

if (ret < 0) {

printk(KERN_WARNING "Buttons: can't get major %d\n", buttons_major);

return ret;

}

realarm_button_device = kmalloc(sizeof(struct realarm_button_dev), GFP_KERNEL);

if (!realarm_button_device) {

unregister_chrdev_region(dev, 1);

ret = -ENOMEM;

return ret;

}

memset(realarm_button_device, 0, sizeof(struct realarm_button_dev));

memcpy(realarm_button_device->buttoninfo_tab, realarm_button_info, sizeof(realarm_button_info));

for(i = 0; i < 4; i++)

{

realarm_button_device->extint_num[i] = 0;

}

init_MUTEX(&realarm_button_device->sem);

init_waitqueue_head(&realarm_button_device->wq);

cdev_init(&realarm_button_device->buttons_dev, &buttons_fops);

realarm_button_device->buttons_dev.owner = THIS_MODULE;

realarm_button_device->buttons_dev.ops = &buttons_fops;

ret = cdev_add(&realarm_button_device->buttons_dev, dev, 1);

if (ret) {

unregister_chrdev_region(dev, 1);

printk(KERN_NOTICE "Error %d adding buttons device\n",ret);

return ret;

}

#ifdef CONFIG_DEVFS_FS

devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, DEVICE_NAME);

printk(KERN_INFO"/dev/%s has been added to your system.\n",DEVICE_NAME);

#else

printk(DEVICE_NAME "Initialized\n");

printk(KERN_INFO "You must create the dev file manually.\n");

printk(KERN_INFO "Todo: mknod c /dev/%s %d 0\n",DEVICE_NAME,buttons_major);

#endif

return 0;

}

static void __exit buttons_cleanup(void)

{

dev_t dev = MKDEV(buttons_major, buttons_minor);

cdev_del(&realarm_button_device->buttons_dev);

kfree(realarm_button_device);

unregister_chrdev_region(dev, 1);

#ifdef CONFIG_DEVFS_FS

devfs_remove(DEVICE_NAME);

#endif

printk(KERN_INFO "unregistered the %s\n",DEVICE_NAME); }

module_init(buttons_init);

module_exit(buttons_cleanup);

MODULE_AUTHOR("LiuRui");

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION("Key driver for RealARM");

分析:

四个按键信息说明

struct button_info realarm_button_info[4] = {

{ IRQ_EINT19, S3C2410_GPG11, S3C2410_GPG11_INP, 1 }, { IRQ_EINT8, S3C2410_GPG0, S3C2410_GPG0_INP, 2 }, { IRQ_EINT11, S3C2410_GPG3, S3C2410_GPG3_INP, 3 }, { IRQ_EINT2, S3C2410_GPF2, S3C2410_GPF2_INP, 4 }, };

自定义按键结构把字符设备嵌入其中

struct realarm_button_dev

{

struct button_info buttoninfo_tab[4];//记录每个按键信息

int extint_num[4]; //用于记录按键的次数

struct semaphore sem;//消息变量

wait_queue_head_t wq;//等待队列

struct cdev buttons_dev;//嵌入字符设备

};

程序流程分析:

module_init(buttons_init);

module_exit(buttons_cleanup);

对file_operations 中各个函数的实现分析:

struct file_operations buttons_fops = {

.owner = THIS_MODULE,

.open = buttons_open,

.release = buttons_release,

.read = buttons_read,

};

buttons_open

先来说一下container_of函数

318#define container_of(ptr, type, member) ({ \

319const typeof( ((type *)0)->member ) *__mptr = (ptr); \

320(type *)( (char *)__mptr - offsetof(type,member) );})

指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址。

type

|---------- ----- |

| |

| |

|---------- ----- |

ptr-->| member |

|---------- ----- |

| |

| |

|---------- ----- |

buttons_release

buttons_read

来分析中断处理子程序流程

ret = request_irq(irq, &buttons_irq, SA_INTERRUPT, DEVICE_NAME, dev); 通过这句话把中断号和中断处理子程序绑定起来

对中断处理程序的分析

buttons_irq

字符设备驱动自此分析完毕,发现驱动并不向大家想象的那样难。通常各种常见驱动比如字符设备驱动,块设备驱动都有一定框架,各个模块的功能也很清晰,只要我们按照这个框架,一步一步就可以完成我们自己的驱动。

嵌入式Linux应用软件开发流程

从软件工程的角度来说,嵌入式应用软件也有一定的生命周期,如要进行需求分析、系统设计、代码编写、调试和维护等工作,软件工程的许多理论对它也是适用的。 但和其他通用软件相比,它的开发有许多独特之处: ·在需求分析时,必须考虑硬件性能的影响,具体功能必须考虑由何种硬件实现。 ·在系统设计阶段,重点考虑的是任务的划分及其接口,而不是模块的划分。模块划分则放在了任务的设计阶段。 ·在调试时采用交叉调试方式。 ·软件调试完毕固化到嵌入式系统中后,它的后期维护工作较少。 下面主要介绍分析和设计阶段的步骤与原则: 1、需求分析 对需求加以分析产生需求说明,需求说明过程给出系统功能需求,它包括:·系统所有实现的功能 ·系统的输入、输出 ·系统的外部接口需求(如用户界面) ·它的性能以及诸如文件/数据库安全等其他要求 在实时系统中,常用状态变迁图来描述系统。在设计状态图时,应对系统运行过程进行详细考虑,尽量在状态图中列出所有系统状态,包括许多用户无需知道的内部状态,对许多异常也应有相应处理。 此外,应清楚地说明人机接口,即操作员与系统间地相互作用。对于比较复杂地系统,形成一本操作手册是必要的,为用户提供使用该系统的操作步骤。为使系统说明更清楚,可以将状态变迁图与操作手册脚本结合起来。

在对需求进行分析,了解系统所要实现的功能的基础上,系统开发选用何种硬件、软件平台就可以确定了。 对于硬件平台,要考虑的是微处理器的处理速度、内存空间的大小、外部扩展设备是否满足功能要求等。如微处理器对外部事件的响应速度是否满足系统的实时性要求,它的稳定性如何,内存空间是否满足操作系统及应用软件的运行要求,对于要求网络功能的系统,是否扩展有以太网接口等。 对于软件平台而言,操作系统是否支持实时性及支持的程度、对多任务的管理能力是否支持前面选中的微处理器、网络功能是否满足系统要求以及开发环境是否完善等都是必须考虑的。 当然,不管选用何种软硬件平台,成本因素都是要考虑的,嵌入式Linux 正是在这方面具有突出的优势。 2、任务和模块划分 在进行需求分析和明确系统功能后,就可以对系统进行任务划分。任务是代码运行的一个映象,是无限循环的一段代码。从系统的角度来看,任务是嵌入式系统中竞争系统资源的最小运行单元,任务可以使用或等待CPU、I/O设备和内存空间等系统资源。 在设计一个较为复杂的多任务应用系统时,进行合理的任务划分对系统的运行效率、实时性和吞吐量影响都极大。任务分解过细会不断地在各任务之间切换,而任务之间的通信量也会很大,这样将会大大地增加系统的开销,影响系统的效率。而任务分解过粗、不够彻底又会造成原本可以并行的操作只能按顺序串行执行,从而影响系统的吞吐量。为了达到系统效率和吞吐量之间的平衡折中,在划分任务时应在数据流图的基础上,遵循下列步骤和原则:

嵌入式linux基本操作实验一的实验报告

实验一linux基本操作实验的实验报告 一实验目的 1、熟悉嵌入式开发平台部件,了解宿主机/目标机开发模式; 2、熟悉和掌握常用Linux的命令和工具。 二实验步骤 1、连接主机和目标板;(三根线,网线直接连接实验箱和PC机,实验箱UART2连接主机的UART口)。 2、Linux命令的熟悉与操作 PC端:在PC机的桌面上打开虚拟机,并启动Linux系统,打开命令终端,操作Linux基本命令,如:查看:ls,进入目录:cd,创建文件:mkdir,删除文件:rmdir,配置网络:ifconfig,挂载:mount,设置权限:chmod,编辑器:vi,拷贝:cp等命令,要求能熟练操作。 使用方法: 1.查看:ls Ls列出文件和目录 Ls–a 显示隐藏文件 Ls–l 显示长列格式ls–al 其中:蓝:目录;绿:可执行文件;红:压缩文件;浅蓝:链接文件;灰:其他文件;红底白字:错误的链接文件 2.进入目录:cd 改变当前目录:cd 目录名(进入用户home目录:cd ~;进入上一级目录:cd -) 3.创建文件:mkdir 建立文件/目录:touch 文件名/mkdir目录名 4.删除文件:rmdir 删除空目录:rmdir目录名 5.配置网络:ifconfig 网络- (以太网和WIFI无线) ifconfig eth0 显示一个以太网卡的配置 6.挂载:mount mount /dev/hda2 /mnt/hda2 挂载一个叫做hda2的盘- 确定目录'/ mnt/hda2' 已经存在 umount /dev/hda2 卸载一个叫做hda2的盘- 先从挂载点'/ mnt/hda2' 退出fuser -km /mnt/hda2 当设备繁忙时强制卸载 umount -n /mnt/hda2 运行卸载操作而不写入/etc/mtab文件- 当文件为只读或当磁盘写满时非常有用 mount /dev/fd0 /mnt/floppy 挂载一个软盘 mount /dev/cdrom /mnt/cdrom挂载一个cdrom或dvdrom mount /dev/hdc /mnt/cdrecorder挂载一个cdrw或dvdrom mount /dev/hdb /mnt/cdrecorder挂载一个cdrw或dvdrom mount -o loop file.iso /mnt/cdrom挂载一个文件或ISO镜像文件

嵌入式Linux系统中音频驱动的设计与实现

第31卷 第2期 2008年4月 电子器件 Ch in es e Jo u rnal Of Electro n Devi ces Vol.31 No.2Apr.2008 Design and Implementation of Audio Driver for Embedded Linux System YU Yue,YA O G uo -liang * (N ational A S I C S ystem Eng ine ering Center ,S outhe ast Unive rsity ,N anj ing 210096,China) Abstract:This paper intro duces the fundam ental principle and architecture of the audio system w hich con -sists of the CODEC UCB1400and the 805puls,and describes the design of audio dev ice dr iv er based on Audio Codec .97for Embedded Linux System.The paper focuses o n the implementatio n of the DM A trans -port and ioctl interface.T he audio dr iv e is running w ell in actual Embedded Linux system equipments.Key words:805plus;embedded Linux;Audio A C .97driver;DM A;ioctl interface EEACC :1130B 嵌入式Linux 系统中音频驱动的设计与实现 虞 跃,姚国良 * (东南大学国家专用集成电路系统工程中心,南京210096) 收稿日期:2007-07-09 作者简介:虞 跃(1982-),男,东南大学电子工程系国家专用集成电路工程技术研究中心硕士研究生,研究方向为嵌入式系统设计; 姚国良(1979-),男,东南大学电子工程系博士研究生,yuyueo@https://www.360docs.net/doc/742283441.html,. 摘 要:介绍了由805puls 处理器和U CB1400编解码芯片构成的音频系统体系结构及工作原理,接着阐述了嵌入式Linux 操作系统下基于A C .97协议标准的音频设备驱动程序的设计与实现。其中着重讲述了采用循环缓冲区进行音频数据的DM A 传输流程以及ioctl 接口的实现。此设计方案已在嵌入式L inux 系统中得到使用,运行效果良好。 关键词:805plus;嵌入式L inux ;AC .97音频驱动;DM A;ioctl 接口中图分类号:TP391 文献标识码:A 文章编号:1005-9490(2008)02-0709-03 嵌入式音频系统广泛应用于GPS 自动导航、PDA,3G 手机等移动信息终端,具备播放、录音功能的音频系统的应用使得移动信息终端上视听娱乐IP 电话、音频录制等成为可能,并推动了移动信息终端设备的发展。 在软件上,嵌入式操作系统的新兴力量Linux 的开源性,内核可定制等优点吸引了许多的开发者与开发商。它是个和U nix 相似、以核心为基础的、完全内存保护、多任务多进程的操作系统。支持广泛的计算机硬件,包括X86,A lpha,Sparc,M IPS,PPC,ARM ,NEC,MOT OROLA 等现有的大部分芯片[1]。 本文针对805puls 微处理器选用Philips 公司的编解码芯片(CODEC)U CB1400,构建了基于Au -dio Codec .97(AC .97)标准的音频系统。并介绍了该音频系统在Linux 操作系统2.4.19内核下驱动 程序的实现技术。 1 音频系统构架 1.1 微处理器805plus 805plus 是东南大学ASIC 系统工程技术研究中心和北京大学微处理器研究开发中心共同设计和开发的32bit 嵌入式微处理器,是采用H ar vard 结构的RISC 处理器。内部采用五级流水线结构,兼容16bit 和32bit 的指令系统805plus 嵌入式微处理器集成了存储接口EMI,时钟和功耗管理PM C,中断控制器INTC,通用定时器T IM ER,脉宽调制器PWM,实时时钟RT C,通用串口UA RT,LCD 控制器LCDC,AC .97控制器,同步外设接口SPI 。1.2 AC .97协议标准[2] AC'97协议标准是一套关于A C'97数字音频处理(AC'97Digital Controller)、AC '97数字串口(AC

CAN总线在嵌入式Linux下驱动程序的实现

CAN总线在嵌入式Linux下驱动程序的实现 时间:2009-11-05 09:41:22 来源:微计算机信息作者:黄捷峰蔡启仲郭毅锋田小刚 1 引言 基于嵌入式系统设计的工业控制装置,在工业控制现场受到各种干扰,如电磁、粉尘、天气等对系统的正常运行造成很大的影响。在工业控制现场各个设备之间要经常交换、传输数据,需要一种抗干扰性强、稳定、传输速率快的现场总线进行通信。文章采用CAN总线,基于嵌入式系统32位的S3C44B0X微处理器,通过其SPI接口,MCP2510 CAN控制器扩展CAN总线;将嵌入式操作系统嵌入到S3C44B0X微处理器中,能实现多任务、友好图形用户界面;针对S3C44B0X微处理器没有内存管理单元MMU,采用uClinux嵌入式操作系统。这样在嵌入式系统中扩展CAN设备关键技术就是CAN设备在嵌入式操作系统下驱动程序的实现。文章重点解决了CAN总线在嵌入式操作系统下驱动程序实现的问题。对于用户来说,CAN设备在嵌入式操作系统驱动的实现为用户屏蔽了硬件的细节,用户不用关心硬件就可以编出自己的用户程序。实验结果表明驱动程序的正确性,能提高整个系统的抗干扰能力,稳定性好,最大传输速率达到1Mb/s;硬件的错误检定特性也增强了CAN的抗电磁干扰能力。 2 系统硬件设计 系统采用S3C44B0X微处理器,需要扩展CAN控制器。常用的CAN控制器有SJA1000和MCP2510,这两种芯片都支持CAN2.0B标准。SJA1000采用的总线是地址线和数据线复用的方式,但是嵌入式处理器外部总线大多是地址线和数据线分开的结构,这样每次对SJA1000操作时需要先后写入地址和数据2次数据,而且SJA1000使用5V逻辑电平。所以应用MCP2510控制器进行扩展,收发器采用82C250。MCP2510控制器特点:1.支持标准格式和扩展格式的CAN数据帧结构(CAN2.0B);2.0~8字节的有效数据长度,支持远程帧;3.最大1Mb/s的可编程波特率;4.2个支持过滤器的接受缓冲区,3个发送缓冲区; 5.SPI高速串行总线,最大5MHz; 6.3~5.5V宽电压范围供电。MCP2510工作电压为3.3V,能够直接与S3C44B0X微处理器I/O口相连。为了进一步提高系统抗干扰性,可在CAN控制器和收发器之间加一个光隔6N137。其结构原理框图如图1: 图1.S3C44B0X扩展CAN结构框图图2.字符设备注册表 3 CAN设备驱动程序的设计 Linux把设备看成特殊的文件进行管理,添加一种设备,首先要注册该设备,增加它的驱动。设备驱动程序是操作系统内核与设备硬件之间的接口,并为应用程序屏蔽了硬件细节。在linux中用户进程不能直接对物理设备进行操作,必须通过系统调用向内核提出请求,

《嵌入式系统与开发》构建嵌入式Linux系统-实验报告

《嵌入式数据库sqlite移植及使用》 实验报告 学生姓名:陈彤 学号:13004405 专业班级:130044 指导教师:孙国梓 完成时间:2016.5.31 实验3 嵌入式数据库sqlite移植及使用 一.实验目的 理解嵌入式软件移植的基本方法,掌握sqlite数据库软件移植的步骤,掌握sqlite开发的两种方式—命令模式和C代码开发模式的使用方法,并编程实现简单通讯录查询实验。 二.实验内容 实验3.1 移植嵌入式数据库sqlite 实验3.2 简单通讯录查询实例设计和测试 三.预备知识 Linux使用、数据库相关知识等 四.实验设备及工具(包括软件调试工具) 硬件:ARM 嵌入式开发平台、PC 机Pentium100 以上、串口线。 软件:WinXP或UBUNTU开发环境。 五.实验步骤 5.1 移植嵌入式数据库sqlite 步骤【参看教材103页】: 第一步,解压缩sqlite源码,命令tar zxvf sqlite-autoconf-3080900.tar.gz,在解压后的文件夹下,可以看到源码文件有shell.c 和sqlite3.c文件,生成Makefile的配置脚本文件configure.ac ,并检查当前文件夹下__A__(A.存在 B.不存在)Makefile文件。 第二步利用configure脚本文件生成基于ARM实验台的Makefile,具体命令为./configure CC=arm-linux-gcc –prefix=/opt/sqlite –host=arm-linux(假设安装目录为/opt/sqlite),并检查当前文件夹下___A__(A.存在 B.不存在)Makefile文件。 第三步,编译sqlite,命令为_make_,编译过程中使用的编译器为_ arm-linux-gcc _。 第四步,安装sqlit,命令为_make install_。安装完成后到_/opt/sqlite_文件夹下去查看相关文件,可以看到该文件夹下有_bin_、_include_、__lib__和share文件夹,其中可执行文件sqlite3位于_./bin_文件夹,库位于_./lib_文件夹。 第五步,将sqlite3拷贝到开发板bin目录下,将库下的文件拷贝到开发板的lib目录下【注意链接文件的创建】 第六步,数据库的使用 方式1:命令操纵数据库 在超级终端环境下创建数据库stucomm.db,命令为_sqlite3 stucomm.db_; 创建数据表stutable,字段包括id 整型,name 字符型,phoneNum 字符型,具体命令为_sqlite> create table stutable (id int(20),name char(20),phoneNum char(20));_; 插入2条记录,记录信息如下 001,zhangsan,10086 002,lisi,10000

Linux驱动程序工作原理简介

Linux驱动程序工作原理简介 一、linux驱动程序的数据结构 (1) 二、设备节点如何产生? (2) 三、应用程序是如何访问设备驱动程序的? (2) 四、为什么要有设备文件系统? (3) 五、设备文件系统如何实现? (4) 六、如何使用设备文件系统? (4) 七、具体设备驱动程序分析 (5) 1、驱动程序初始化时,要注册设备节点,创建子设备文件 (5) 2、驱动程序卸载时要注销设备节点,删除设备文件 (7) 参考书目 (8) 一、linux驱动程序的数据结构 设备驱动程序实质上是提供一组供应用程序操作设备的接口函数。 各种设备由于功能不同,驱动程序提供的函数接口也不相同,但linux为了能够统一管理,规定了linux下设备驱动程序必须使用统一的接口函数file_operations 。 所以,一种设备的驱动程序主要内容就是提供这样的一组file_operations 接口函数。 那么,linux是如何管理种类繁多的设备驱动程序呢? linux下设备大体分为块设备和字符设备两类。 内核中用2个全局数组存放这2类驱动程序。 #define MAX_CHRDEV 255 #define MAX_BLKDEV 255 struct device_struct { const char * name; struct file_operations * fops; }; static struct device_struct chrdevs[MAX_CHRDEV]; static struct { const char *name; struct block_device_operations *bdops; } blkdevs[MAX_BLKDEV]; //此处说明一下,struct block_device_operations是块设备驱动程序内部的接口函数,上层文件系统还是通过struct file_operations访问的。

南邮嵌入式系统B实验报告2016年度-2017年度-2

_* 南京邮电大学通信学院 实验报告 实验名称:基于ADS开发环境的程序设计 嵌入式Linux交叉开发环境的建立 嵌入式Linux环境下的程序设计 多线程程序设计 课程名称嵌入式系统B 班级学号 姓名 开课学期2016/2017学年第2学期

实验一基于ADS开发环境的程序设计 一、实验目的 1、学习ADS开发环境的使用; 2、学习和掌握ADS环境下的汇编语言及C语言程序设计; 3、学习和掌握汇编语言及C语言的混合编程方法。 二、实验内容 1、编写和调试汇编语言程序; 2、编写和调试C语言程序; 3、编写和调试汇编语言及C语言的混合程序; 三、实验过程与结果 1、寄存器R0和R1中有两个正整数,求这两个数的最大公约数,结果保存在R3中。 代码1:使用C内嵌汇编 #include int find_gcd(int x,int y) { int gcdnum; __asm { MOV r0, x MOV r1, y LOOP: CMP r0, r1 SUBLT r1, r1, r0 SUBGT r0, r0, r1 BNE LOOP MOV r3, r0 MOV gcdnum,r3 //stop // B stop // END } return gcdnum; } int main() { int a; a = find_gcd(18,9);

printf("gcdnum:%d\n",a); return 0; } 代码2:使用纯汇编语言 AREA example1,CODE,readonly ENTRY MOV r0, #4 MOV r1, #9 start CMP r0, r1 SUBLT r1, r1, r0 SUBGT r0, r0, r1 BNE start MOV r3, r0 stop B stop END 2、寄存器R0 、R1和R2中有三个正整数,求出其中最大的数,并将其保存在R3中。 代码1:使用纯汇编语言 AREA examp,CODE,READONL Y ENTRY MOV R0,#10 MOV R1,#30 MOV R2,#20 Start CMP R0,R1 BLE lbl_a CMP R0,R2 MOVGT R3,R0 MOVLE R3,R2 B lbl_b lbl_a CMP R1,R2 MOVGT R3,R1 MOVLE R3,R2 lbl_b B . END 代码2:使用C内嵌汇编语言 #include int find_maxnum(int a,int b,int c)

基于linux的led驱动程序实现

基于linux的led驱动程序实现 一. 博创开发平台硬件LED的实现 博创开发平台设置了3个GPIO控制的LED和一个可直接产生外部硬件中断的按键,LED分别使用了S3C2410的GPC5,GPC6,GPC7三个GPIO,按键接到INT5中断。下面对S3C2410 GPIO的各个寄存器作出说明,用GPIO控制的LED就是通过操作GPIO的各个寄存器进行配置和操作的。S3C2410包含GPA 、GPB 、……、GPH 八个I/O端口。它们的寄存器是相似的:GPxCON 用于设置端口功能(00 表示输入、01表示输出、10 表示特殊功能、11 保留不用),GPxDAT 用于读/写数据,GPxUP 用于决定是否使用内部上拉电阻(某位为0 时,相应引脚无内部上拉;为1时,相应引脚使用内部上拉)。这里要稍微注意一点的地方是PORTA和其他几组端口的使用不太一样,这里不讨论A口,B到H组口的使用完全相同。以下是S3C2410手册上的数据[13]: 图1.1 S3C2410端口 GPC口有16个IO口,查datasheet《S3C2410》所用的地址为: 图1.2 C组GPIO的地址 即GPCCON 地址为0x56000020,GPCDAT地址为0x56000024,各位的设置具体见下图,则对应的GPCCON寄存器的位为:

图1.3 GPCCON寄存器相应的位 这里用到了5,6,7三个口,CON寄存器要完成对对应口的设置工作,将相应的口设置为输出状态,其他的口不用考虑,设置为输出的话就是0x15<<10,这样3个IO口就设置为了输出。下面就可以通过向DATA口写入低电平来点亮LED,GPCDAT的各位分布如下,每一个bit对应一个口。 图1.4 GPCDAT的位分布 GPCDAT有16位,我们这里要用到的就是5,6,7三位即将这3位设置为低电平点亮LED。具体使用情况见驱动的实现。 这三个LED的硬件原理图如下: 图1.5 GPIO控制的LED硬件原理图 二.通过GPIO控制的LED驱动程序 本驱动中没有用到内核提供的write_gpio宏,对硬件地址的操作完全自己实现,可分为以下几部分: ①模块的初始化和退出: int led_init(void)

Linux设备驱动程序举例

Linux设备驱动程序设计实例2007-03-03 23:09 Linux系统中,设备驱动程序是操作系统内核的重要组成部分,在与硬件设备之间 建立了标准的抽象接口。通过这个接口,用户可以像处理普通文件一样,对硬件设 备进行打开(open)、关闭(close)、读写(read/write)等操作。通过分析和设计设 备驱动程序,可以深入理解Linux系统和进行系统开发。本文通过一个简单的例子 来说明设备驱动程序的设计。 1、程序清单 //MyDev.c 2000年2月7日编写 #ifndef __KERNEL__ #define __KERNEL__//按内核模块编译 #endif #ifndef MODULE #define MODULE//设备驱动程序模块编译 #endif #define DEVICE_NAME "MyDev" #define OPENSPK 1 #define CLOSESPK 2 //必要的头文件 #include //同kernel.h,最基本的内核模块头文件 #include //同module.h,最基本的内核模块头文件 #include //这里包含了进行正确性检查的宏 #include //文件系统所必需的头文件 #include //这里包含了内核空间与用户空间进行数据交换时的函数宏 #include //I/O访问 int my_major=0; //主设备号 static int Device_Open=0; static char Message[]="This is from device driver"; char *Message_Ptr; int my_open(struct inode *inode, struct file *file) {//每当应用程序用open打开设备时,此函数被调用 printk ("\ndevice_open(%p,%p)\n", inode, file); if (Device_Open) return -EBUSY;//同时只能由一个应用程序打开 Device_Open++; MOD_INC_USE_COUNT;//设备打开期间禁止卸载 return 0; } static void my_release(struct inode *inode, struct file *file)

USB键盘驱动程序

/* * $Id: usbkbd.c,v 1.27 2001/12/27 10:37:41 vojtech Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * * USB HIDBP Keyboard support */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to <>, or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include #include #include #include #include #include #include /* * Version Information */ #define DRIVER_VERSION "" #define DRIVER_AUTHOR "Vojtech Pavlik <>" #define DRIVER_DESC "USB HID Boot Protocol keyboard driver" #define DRIVER_LICENSE "GPL"

linux 设备输入子系统---源代码示例。自动捕获键盘鼠标等外设消息

Linux input 子系统详解与代码示例 李邦柱于杭州2014/01/09 Email:helpylee@https://www.360docs.net/doc/742283441.html, 由于linux的驱动模型增加了input层,导致几乎所有的底层驱动都把数据封装在event里上报给input子系统。由此看来,这种改变让kernel 更具有模块化,各个模块的耦合度更低了。下面我们一起来研究input 层^_^ 1.从用户层的角度看input(event事件) 了解linux的人一定会对/dev,/ sys, /proc这几个目录有所印象,这是从内核导出到用户层的接口(从这里几乎可以观览内核)。kernel为我们导出了input在用户态的接口,就是/dev/input/下的接口,所以我们只关注这个目录下的event*(event0/event1/……)字符设备。 那么这些event*是干什么用的?简单来说就是我们对计算机的输入(包括敲击键盘,移动鼠标等等操作)经过内核(底层驱动,input)处理最后就上报到这些event*里面了。 而这里event0,event1,..就是用来区分各个外设的,可以通过命令来查看外设具体和哪个event相关联:这个命令是:cat /proc/bus/input/devices 所以我们用此命令在linux系统查看外设信息。 2.在linux/input.h中有这些数据的结构: structinput_event { structtimeval time; //事件发生的时间 __u16 type; //事件类类型:按键和移动鼠标就是不同类型 __u16 code; __s32 value; //事件值:按键a和按键b就对应不同值 }; code: 事件的代码.如果事件的类型代码是EV_KEY,该代码code为设备键盘代码.代码植0~127为键盘上的按键代码,0x110~0x116 为鼠标上按键代码,其中0x110(BTN_ LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标右键,0x112(BTN_ MIDDLE)为鼠标中键.其它代码含义请参

Linux设备驱动程序学习(18)-USB 驱动程序(三)

Linux设备驱动程序学习(18)-USB 驱动程序(三) (2009-07-14 11:45) 分类:Linux设备驱动程序 USB urb (USB request block) 内核使用2.6.29.4 USB 设备驱动代码通过urb和所有的 USB 设备通讯。urb用 struct urb 结构描述(include/linux/usb.h )。 urb以一种异步的方式同一个特定USB设备的特定端点发送或接受数据。一个USB 设备驱动可根据驱动的需要,分配多个 urb 给一个端点或重用单个 urb 给多个不同的端点。设备中的每个端点都处理一个 urb 队列, 所以多个 urb 可在队列清空之前被发送到相同的端点。 一个 urb 的典型生命循环如下: (1)被创建; (2)被分配给一个特定 USB 设备的特定端点; (3)被提交给 USB 核心; (4)被 USB 核心提交给特定设备的特定 USB 主机控制器驱动; (5)被 USB 主机控制器驱动处理, 并传送到设备; (6)以上操作完成后,USB主机控制器驱动通知 USB 设备驱动。 urb 也可被提交它的驱动在任何时间取消;如果设备被移除,urb 可以被USB 核心取消。urb 被动态创建并包含一个内部引用计数,使它们可以在最后一个用户释放它们时被自动释放。 struct urb

struct list_head urb_list;/* list head for use by the urb's * current owner */ struct list_head anchor_list;/* the URB may be anchored */ struct usb_anchor *anchor; struct usb_device *dev;/* 指向这个 urb 要发送的目标 struct usb_device 的指针,这个变量必须在这个 urb 被发送到 USB 核心之前被USB 驱动初始化.*/ struct usb_host_endpoint *ep;/* (internal) pointer to endpoint */ unsigned int pipe;/* 这个 urb 所要发送到的特定struct usb_device 的端点消息,这个变量必须在这个 urb 被发送到 USB 核心之前被 USB 驱动初始化.必须由下面的函数生成*/ int status;/*当 urb开始由 USB 核心处理或处理结束, 这个变量被设置为 urb 的当前状态. USB 驱动可安全访问这个变量的唯一时间是在 urb 结束处理例程函数中. 这个限制是为防止竞态. 对于等时 urb, 在这个变量中成功值(0)只表示这个 urb 是否已被去链. 为获得等时 urb 的详细状态, 应当检查 iso_frame_desc 变量. */ unsigned int transfer_flags;/* 传输设置*/ void*transfer_buffer;/* 指向用于发送数据到设备(OUT urb)或者从设备接收数据(IN urb)的缓冲区指针。为了主机控制器驱动正确访问这个缓冲, 它必须使用 kmalloc 调用来创建, 不是在堆栈或者静态内存中。对控制端点, 这个缓冲区用于数据中转*/ dma_addr_t transfer_dma;/* 用于以 DMA 方式传送数据到 USB 设备的缓冲区*/ int transfer_buffer_length;/* transfer_buffer 或者 transfer_dma 变量指向的缓冲区大小。如果这是 0, 传送缓冲没有被 USB 核心所使用。对于一个 OUT 端点, 如果这个端点大小比这个变量指定的值小, 对这个USB 设备的传输将被分成更小的块,以正确地传送数据。这种大的传送以连续的 USB 帧进行。在一个 urb 中提交一个大块数据, 并且使 USB 主机控制器去划分为更小的块, 比以连续地顺序发送小缓冲的速度快得多*/

嵌入式linux android驱动工程师 面试题总汇

嵌入式linux android驱动工程师面试题总汇 1.嵌入式系统中断服务子程序(ISR)收藏中断是嵌入式系统中重要的组成部分,这导致了很多编译开发商提供一种扩展—让标准C支持中断。具代表事实是,产生了一个新的关键字__interrupt。下面的代码就使用了__interrupt关键字去定义了一个中断服务子程序(ISR),请评论一下这段代码的。 2.C语言中对位的操作,比如对a的第三位清0,第四位置1.本来应该会的,一犯晕写反了,以后注意! #define BIT3 (1<<3) #define BIT4 (1<<4) a &= ~BIT3;a |= BIT4; 3.考到volatile含义并举例: 理解出错,举了很具体的例子,连程序都搬上去了,有些理解不深的没举出来…… volatile表示这个变量会被意想不到的改变,每次用他的时候都会小心的重新读取一遍,不适用寄存器保存的副本。 volatile表示直接存取原始地址 例: 并行设备的硬件寄存器(状态寄存器) 在多线程运行的时候共享变量也要时时更新 一个中断服务子程序中访问到的的非自动变量(不太清楚,正在查找资料ing……) 4.要求设置一绝对地址为0x67a9的整型变量的值为0xaa66

当时我的写法: #define AA *(volatile unsigned long *)0xaa66AA = 0x67a9; 答案: int *ptr =(int *)0xaa66; *ptr = 0x67a9; 我感觉自己写的应该不算错吧(自我感觉,还请达人指正),我写的适合裸机下用,当做寄存器用,而答案就是适合在操作系统下的写法。 1. linux内核里面,内存申请有哪几个函数,各自的区别? 2. IRQ和FIQ有什么区别,在CPU里面是是怎么做的? 3. int *a; char *b; a 和b本身是什么类型? a、b里面本身存放的只是一个地址,难道是这两个地址有不同么? 4.xx的上半部分和下半部分的问题: 讲下分成上半部分和下半部分的原因,为何要分?讲下如何实现? 5.内核函数mmap的实现原理,机制? 6.驱动里面为什么要有并发、互斥的控制?如何实现?讲个例子? 7. spinlock自旋锁是如何实现的? 8.任务调度的机制? 【二、本人碰到】

嵌入式linux实验指导书

目录 实验一 linux常用指令练习 (3) 1、在线帮助指令 (3) 2、linux开关机及注销指令。 (3) 重启指令: (3) 1)、reboot命令 (3) 2)、init 6命令 (3) 关机指令: (3) 1)、halt命令 (3) 2)、poweroff命令 (4) 3)、init 0命令 (4) 4)、shutdown命令 (4) 注销指令: (4) 3、用户管理命令 (4) 1)、用户切换su命令 (4) 2)、添加用户命令adduser/useradd (5) 3)、删除用户及更改用户属性 (5) 4)、设置用户密码 (6) 5)、查看用户信息 (6) 4、文件目录操作指令 (7) 1)、改变当前工作目录命令(cd) (7) 2)、显示当前路径pwd (7) 3)、查看当前目录下的文件命令ls (7) 4)、新建目录指令mkdir (8) 5)、删除目录命令rmdir (8) 6)、新建文件命令touch (8) 7)、删除文件指令rm (8) 8)、文件和目录的复制命令cp (8) 9)、文件和目录的移动命令mv (9) 10)、更改文件或目录的使用权限chmod (9) 11)、查看文件的命令cat (9) 12)、文件链接命令ln (9) 13)、文件压缩解压命令 (10) 5、网络相关命令 (11) 6、磁盘管理命令 (11) 7、挂载文件命令mount (12) 8、其他系统命令 (12) 练习1: (13) 练习2: (15) 练习3: (16) 练习4: (21) 实验二 VI文本编辑器的使用 (24) 1、练习使用VI指令 (24) 2、利用VI编写一个hello.c文件 (24)

LINUX系统必备程序安装步骤

1.红帽企业版5获得root权限方法: su root

2. 红帽企业版5 启动samba的方法: a.在安装LINUX的过程中将所有选项都选择上,这样可以确保samba等软件 都已经安装好。 b. 修改/etc/samba/smb.conf,添加: [root] comment = Root Directories browseable = yes writeable = yes path = / valid users = smb(用户名) c.添加用户: RHEL5: Useradd smb //添加smb系统用户 Smbpasswd -a smb //修改密码 d.重新启动samba: /etc/init.d/smb restart e.windows访问LINUX 访问LINUX的IP地址,输入用户名smb及密码就可以正常访问linux了

3.建立tftp服务器: a.在安装LINUX的过程中将所有选项都选择上,这样可以确保tftp等软件都 已经安装好。 b.建立TFTP主工作目录: mkdir /tftpboot c.修改配置文件 vi /etc/xinet d.d/tftp修改内容如下: d.重新启动tftp /etc/init.d/xinetd restart e.确认TFTP启动的是否成功:netstat –a | grep tftp

4.NFS a.配置vi /etc/exports b.重新启动NFS服务器:/etc/init.d/nfs restart

5.升级安装LINUX内核: a.解压缩内核代码tar –xvzf linux-2.6.32.27 b.拷贝config 文件将目录boot下的原先LINUX内核的CONFIG文件复制到 新内核的根目录下名字为.config c.make menuconfig d.make bzImage e.make modules f. make modules_install g.制作init ramdisk: h.内核安装: i.升级内核后重新启动机器所遇到的问题解决办法: 方法:编译时修改.config文件中的“CONFIG_SYSFS_DEPRECATED_V2”,默认该选项为not set,被注释掉的,将其改为y。即修改为 “CONFIG_SYSFS_DEPRECATED_V2=y”,修改后,再编译,重启即正常了。

linux驱动程序的编写

linux驱动程序的编写 一、实验目的 1.掌握linux驱动程序的编写方法 2.掌握驱动程序动态模块的调试方法 3.掌握驱动程序填加到内核的方法 二、实验内容 1. 学习linux驱动程序的编写流程 2. 学习驱动程序动态模块的调试方法 3. 学习驱动程序填加到内核的流程 三、实验设备 PentiumII以上的PC机,LINUX操作系统,EL-ARM860实验箱 四、linux的驱动程序的编写 嵌入式应用对成本和实时性比较敏感,而对linux的应用主要体现在对硬件的驱动程序的编写和上层应用程序的开发上。 嵌入式linux驱动程序的基本结构和标准Linux的结构基本一致,也支持模块化模式,所以,大部分驱动程序编成模块化形式,而且,要求可以在不同的体系结构上安装。linux是可以支持模块化模式的,但由于嵌入式应用是针对具体的应用,所以,一般不采用该模式,而是把驱动程序直接编译进内核之中。但是这种模式是调试驱动模块的极佳方法。 系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。同时,设备驱动程序是内核的一部分,它完成以下的功能:对设备初始化和释放;把数据从内核传送到硬件和从硬件读取数据;读取应用程序传送给设备文件的数据和回送应用程序请求的数据;检测和处理设备出现的错误。在linux操作系统下有字符设备和块设备,网络设备三类主要的设备文件类型。 字符设备和块设备的主要区别是:在对字符设备发出读写请求时,实际的硬件I/O一般就紧接着发生了;块设备利用一块系统内存作为缓冲区,当用户进程对设备请求满足用户要求时,就返回请求的数据。块设备是主要针对磁盘等慢速设备设计的,以免耗费过多的CPU时间来等待。 1 字符设备驱动结构 Linux字符设备驱动的关键数据结构是cdev和file_operations结构体。

相关文档
最新文档