//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include /* printk() */
#include /* kmalloc() */
#include /* everything... */ #include /* error codes */ #include /* size_t */
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include
#include
#include
#include
#include "s3c2410-adc.h"
#include
#define DEVICE_NAME "adc"
#define ADCRA W_MINOR 0
#define ADC_INPUT(x) ((x)<<3)
#define PRSCVL(x) ((x)<<6)
static int adc_major = 249;
typedef struct {
struct semaphore lock; //声明一个信号量
wait_queue_head_t wait; //声明一个等待队列头
int channel;//选择哪一路AD转换器
int prescale;//预分频值
}ADC_DEV;
static ADC_DEV adcdev;
/*
*中断处理函数
*/
static irqreturn_t adcdone_int_handler(int irq,void *dev_id,struct pt_regs *regs)
{
wake_up(&adcdev.wait);//唤醒等待队列
return IRQ_HANDLED ;
}
/*
*对设备进行写操作,buffer一定是用户空间的
*/
static ssize_t s3c2410_adc_write(struct file *file, const char *buffer, size_t count, loff_t * ppos) {
int data;
if(count!=sizeof(data)){
printk(KERN_INFO"the size of input data must be %d\n", sizeof(data));
return 0;
}
copy_from_user(&data, buffer, count);//从用户空间拷贝数据到内核空间
adcdev.channel=ADC_WRITE_GETCH(data);//得到哪一路AD转换器
adcdev.prescale=ADC_WRITE_GETPRE(data);//得到预分频值
//printk(KERN_INFO"set adc channel=%d, prescale=0x%x\n", adcdev.channel, adcdev.prescale);
return count;
}
/*
*对设备进行读操作,buffer一定是用户空间的
*/
static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
int ret = 0;
if (down_interruptible(&adcdev.lock))//获得信号量
return -ERESTARTSYS;
writel(readl(S3C2410_ADCCON) &(~1),S3C2410_ADCCON);//对AD控制寄存器进行操作,具体参看s3c2410 datasheet
writel( (1<<14) | (255<<6) |(1<<0)|(1<<0)| ADC_INPUT(adcdev.channel),S3C2410_ADCCON);
sleep_on( &adcdev.wait );
ret = readl(S3C2410_ADCDA T0);
ret &= 0x3ff;
//printk(KERN_INFO"AIN[%d] = 0x%04x, %d\n", adcdev.channel, ret, readl(S3C2410_ADCCON) & 0x80 ? 1:0);
copy_to_user(buffer, (char *)&ret, sizeof(ret));//拷贝内核数据到用户空间
up(&adcdev.lock);
return sizeof(ret);
}
/*
*打开设备
*/
static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
int ret;
printk("in adc open");
ret = request_irq(IRQ_ADC, adcdone_int_handler, 0, DEVICE_NAME, NULL);//注册中断例程
if (ret) {
return ret;
}
init_MUTEX(&adcdev.lock);//初始化一个互斥的信号量,并设置为1
init_waitqueue_head(&(adcdev.wait));//初始化等待队列
adcdev.channel=0;
adcdev.prescale=0xff;
printk(KERN_INFO"adc opened\n");
return 0;
}
/*
*关闭设备
*/
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
free_irq(IRQ_ADC, NULL);//释放中断资源
printk(KERN_INFO"adc closed\n");
return 0;
}
/*
*初始化并添加结构提struct cdev到系统之中
*/
static void adc_setup_cdev(struct cdev *dev, int minor,
struct file_operations *fops)
{
int err, devno = MKDEV(adc_major, minor);
cdev_init(dev, fops);//初始化结构体struct cdev
dev->owner = THIS_MODULE;
dev->ops = fops;//给结构体里的ops成员赋初值,这里是对设备操作的具体的实现函数err = cdev_add (dev, devno, 1);//将结构提struct cdev添加到系统之中
/* Fail gracefully if need be */
if (err)
printk (KERN_NOTICE "Error %d adding adc %d", err, minor);
}
static struct cdev AdcDevs;
/*
*定义一个file_operations结构体,来实现对设备的具体操作的功能
*/
static struct file_operations adc_remap_ops = {
owner: THIS_MODULE,
open: s3c2410_adc_open,
read:s3c2410_adc_read,
write: s3c2410_adc_write,
release: s3c2410_adc_release,
};
/*
*初始化设备驱动模块,主要完成对字符设备结构体的初始化和添加到系统中,并得到一个
设备的设备号
*/
static int adc_init(void)
{
writel(0,S3C2410_ADCTSC); //XP_PST(NOP_MODE);
int result;
dev_t dev = MKDEV(adc_major, 0);//将主设备号和次设备号定义到一个dev_t数据类型的结构体之中
/* Figure out our device number. */
if (adc_major)
result = register_chrdev_region(dev, 1, "adc");//静态注册一个设备,设备号先前指定好,并得到一个设备名,cat /proc/device来查看信息
else {
result = alloc_chrdev_region(&dev, 0, 1, "adc");//如果主设备号被占用,则由系统提供一个主设备号给设备驱动程序
adc_major = MAJOR(dev);//得到主设备号
}
if (result < 0) {
return result;
}
if (adc_major == 0)
adc_major = result;//如果静态分配失败。把动态非配的设备号给设备驱动程序adc_setup_cdev(&AdcDevs, 0, &adc_remap_ops);//初始化和添加结构体struct cdev到系统之中
printk(KERN_INFO"adc device installed, with major %d\n", adc_major);
return 0;
}
/*
*卸载驱动模块
*/
static void adc_cleanup(void)
{
cdev_del(&AdcDevs);//删除结构体struct cdev
unregister_chrdev_region(MKDEV(adc_major, 0), 1);//卸载设备驱动所占有的资源
printk(KERN_INFO"adc device uninstalled\n");
}
module_init(adc_init);//初始化设备驱动程序的入口
module_exit(adc_cleanup);//卸载设备驱动程序的入口
MODULE_LICENSE("Dual BSD/GPL"); //模块应该指定代码所使用的许可证
嵌入式Linux应用软件开发流程
从软件工程的角度来说,嵌入式应用软件也有一定的生命周期,如要进行需求分析、系统设计、代码编写、调试和维护等工作,软件工程的许多理论对它也是适用的。 但和其他通用软件相比,它的开发有许多独特之处: ·在需求分析时,必须考虑硬件性能的影响,具体功能必须考虑由何种硬件实现。 ·在系统设计阶段,重点考虑的是任务的划分及其接口,而不是模块的划分。模块划分则放在了任务的设计阶段。 ·在调试时采用交叉调试方式。 ·软件调试完毕固化到嵌入式系统中后,它的后期维护工作较少。 下面主要介绍分析和设计阶段的步骤与原则: 1、需求分析 对需求加以分析产生需求说明,需求说明过程给出系统功能需求,它包括:·系统所有实现的功能 ·系统的输入、输出 ·系统的外部接口需求(如用户界面) ·它的性能以及诸如文件/数据库安全等其他要求 在实时系统中,常用状态变迁图来描述系统。在设计状态图时,应对系统运行过程进行详细考虑,尽量在状态图中列出所有系统状态,包括许多用户无需知道的内部状态,对许多异常也应有相应处理。 此外,应清楚地说明人机接口,即操作员与系统间地相互作用。对于比较复杂地系统,形成一本操作手册是必要的,为用户提供使用该系统的操作步骤。为使系统说明更清楚,可以将状态变迁图与操作手册脚本结合起来。
在对需求进行分析,了解系统所要实现的功能的基础上,系统开发选用何种硬件、软件平台就可以确定了。 对于硬件平台,要考虑的是微处理器的处理速度、内存空间的大小、外部扩展设备是否满足功能要求等。如微处理器对外部事件的响应速度是否满足系统的实时性要求,它的稳定性如何,内存空间是否满足操作系统及应用软件的运行要求,对于要求网络功能的系统,是否扩展有以太网接口等。 对于软件平台而言,操作系统是否支持实时性及支持的程度、对多任务的管理能力是否支持前面选中的微处理器、网络功能是否满足系统要求以及开发环境是否完善等都是必须考虑的。 当然,不管选用何种软硬件平台,成本因素都是要考虑的,嵌入式Linux 正是在这方面具有突出的优势。 2、任务和模块划分 在进行需求分析和明确系统功能后,就可以对系统进行任务划分。任务是代码运行的一个映象,是无限循环的一段代码。从系统的角度来看,任务是嵌入式系统中竞争系统资源的最小运行单元,任务可以使用或等待CPU、I/O设备和内存空间等系统资源。 在设计一个较为复杂的多任务应用系统时,进行合理的任务划分对系统的运行效率、实时性和吞吐量影响都极大。任务分解过细会不断地在各任务之间切换,而任务之间的通信量也会很大,这样将会大大地增加系统的开销,影响系统的效率。而任务分解过粗、不够彻底又会造成原本可以并行的操作只能按顺序串行执行,从而影响系统的吞吐量。为了达到系统效率和吞吐量之间的平衡折中,在划分任务时应在数据流图的基础上,遵循下列步骤和原则:
Linux网络设备驱动开发实验
实验三:Linux网络设备驱动开发实验 一、实验目的 读懂linux网络设备驱动程序例子,并且实际加载驱动程序,加载进操作系统以后,会随着上层应用程序的触发而执行相应动作,具体执行的动作可以通过代码进行改变。 ●读懂源码及makefile ●编译驱动程序 ●加载 ●多种形式触发动作 二、预备知识 熟悉linux驱动基本原理,能读懂简单的makefile。 三、实验预计时间 80-120分钟左右 四、驱动程序部分具体步骤 要求读懂一个最简单的驱动程序,在驱动程序的诸如“xxx_open”、“xxx_read”等标准接口里面加入打印语句。可参考多模式教学网上的驱动样例。 五、用于触发驱动动作的应用程序及命令 驱动程序就是以静态的标准接口库函数形式存在,网络设备驱动会受到两大类情况的触发,一种是linux里面的控制台里面的命令,另一种是套接口应用程序,首先要搞清都有哪些具体的命令和应用程序流程,应用程序参考多模式教学网的例子。 六、运行测试 提示:需要将驱动程序以dll加载进系统中,并且触发应用程序调用各种文件操作的接口函数,使得驱动有所动作,打印出相关信息。 1.编译驱动: cd /某某目录/vnetdev/ make clean make 2.加载驱动与打开网卡: insmod netdrv.ko
ifconfig vnet0 up 3.运行应用程序 ../raw 4.通过命令“修改网卡MTU”触发驱动执行动作: ifconfig vnet0 mtu 1222 5.显示内核打印: cat /var/log/messages 6.卸载: ifconfig vnet0 down rmmod netdrv.ko 7.修改代码中的某些函数中的打印信息,重新试验上述流程。 至此大家都应该真正理解和掌握了驱动程序-操作系统-应用程序的三者联动机制。 七、实验结果 由图可知能正常加载网卡驱动,并且能够打印调试信息。
嵌入式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镜像文件
嵌入式点亮一个LED灯的程序
飞凌OK6410开发板(裸板)第一个点亮LED灯程序,主要的C程序,完整程序请下载附件。 #define rGPMCON (*(volatile unsigned *)(0x7F008820)) #define rGPMDAT (*(volatile unsigned *)(0x7F008824)) #define rGPMPUD (*(volatile unsigned *)(0x7F008828)) void msDelay(int time) { volatile unsigned int i,j; for(i = 0; i < 2000000; i++) for(j=0; j