Tiny6410 LED字符设备驱动

发布者:吾道明亮最新更新时间:2017-01-12 来源: eefocus关键字:Tiny6410  LED字符  设备驱动 手机看文章 扫描二维码
随时随地手机看文章

1.查看用户手册

led1、led2、led3、led4 连接的分别是 GPK4、GPK5、GPK6、GPK7

2、查询6410芯片手册

 

 

下面还需要3个步骤:

1、设置GPIO为OUTPUT。

   将GPK4、GPK5、GPK6、GPK7设置为输出output=0001

   即GPKCON0的19:28都配置为0001

 

2、设置GPIO的数据。

   将GPKDATA的4:7位赋值为0

 

3、设置GPKUP为上拉。

   将GPKUP的4:7位设置为10

 

3、代码

led_driver.c

 

  1. #include   /*它定义了模块的 API、类型和宏(MODULE_LICENSE、MODULE_AUTHOR等等),所有的内核模块都必须包含这个头文件。*/   

  2.     

  3. #include   /*使用内核信息优先级时要包含这个文件,一般在使用printk函数时使用到优先级信息*/  

  4.   

  5. #include     

  6. #include  /* copy_to_user,copy_from_user */     

  7. #include      /*readl writel*/  

  8. #include      

  9. #include       

  10. #include       

  11.   

  12.     

  13. #define LED_MAJOR   243  

  14.   

  15. #define LED_ON      1  

  16. #define LED_OFF     0  

  17. #define LED_1_ON    2  

  18. #define LED_1_OFF   3  

  19. #define LED_2_ON    4  

  20. #define LED_2_OFF   5  

  21. #define LED_3_ON    6  

  22. #define LED_3_OFF   7  

  23. #define LED_4_ON    8  

  24. #define LED_4_OFF   9  

  25.   

  26.    

  27. static int led_open (struct inode *inode,struct file *filp)    

  28.     

  29. {    

  30.     unsigned tmp;       

  31.   

  32.     tmp = readl(S3C64XX_GPKCON);      

  33.     tmp = (tmp&0x0000ffff)| 0x1111ffff;  

  34.     writel(tmp, S3C64XX_GPKCON);     

  35.   

  36.     printk("#########open######\n");    

  37.     return 0;    

  38. }    

  39.     

  40. static int led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)    

  41. {      

  42.     return count;    

  43. }    

  44.     

  45.     

  46. static int led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)  

  47.   

  48. {    

  49.     char wbuf[10];    

  50.     unsigned tmp;       

  51.       

  52.     if(copy_from_user(wbuf,buf,count))  

  53.         return -EFAULT;    

  54.   

  55.         switch(wbuf[0])    

  56.         {    

  57.           

  58.         case LED_ON:   

  59.                 tmp = readl(S3C64XX_GPKDAT);       

  60.             tmp &= (0x0f);       

  61.             writel(tmp, S3C64XX_GPKDAT);  

  62.             printk("turn on!\n");      

  63.                 break;  

  64.   

  65.         case LED_OFF:    

  66.             tmp  = readl(S3C64XX_GPKDAT);       

  67.             tmp |= (0xf0);       

  68.             writel(tmp, S3C64XX_GPKDAT);   

  69.             printk("turn off!\n");     

  70.             break;             

  71.   

  72.         case LED_1_ON:    

  73.             tmp = readl(S3C64XX_GPKDAT);       

  74.             tmp &= (0xef);       

  75.             writel(tmp, S3C64XX_GPKDAT);   

  76.             printk("turn off!\n");     

  77.             break;    

  78.   

  79.         case LED_1_OFF:   

  80.                 tmp = readl(S3C64XX_GPKDAT);       

  81.             tmp |= (0xf0);       

  82.             writel(tmp, S3C64XX_GPKDAT);  

  83.             printk("turn on!\n");      

  84.                 break;    

  85.   

  86.         case LED_2_ON:    

  87.             tmp = readl(S3C64XX_GPKDAT);       

  88.             tmp &= (0xdf);       

  89.             writel(tmp, S3C64XX_GPKDAT);   

  90.             printk("turn off!\n");     

  91.             break;    

  92.   

  93.         case LED_2_OFF:   

  94.                 tmp = readl(S3C64XX_GPKDAT);       

  95.             tmp |= (0xf0);       

  96.             writel(tmp, S3C64XX_GPKDAT);  

  97.             printk("turn on!\n");      

  98.                 break;    

  99.   

  100.         case LED_3_ON:    

  101.             tmp = readl(S3C64XX_GPKDAT);       

  102.             tmp &= (0xbf);       

  103.             writel(tmp, S3C64XX_GPKDAT);   

  104.             printk("turn off!\n");     

  105.             break;    

  106.   

  107.         case LED_3_OFF:   

  108.                 tmp = readl(S3C64XX_GPKDAT);       

  109.             tmp |= (0xf0);       

  110.             writel(tmp, S3C64XX_GPKDAT);  

  111.             printk("turn on!\n");      

  112.                 break;    

  113.   

  114.         case LED_4_ON:    

  115.             tmp = readl(S3C64XX_GPKDAT);       

  116.             tmp &= (0x7f);       

  117.             writel(tmp, S3C64XX_GPKDAT);   

  118.             printk("turn off!\n");     

  119.             break;    

  120.   

  121.         case LED_4_OFF:   

  122.                 tmp  = readl(S3C64XX_GPKDAT);       

  123.             tmp |= (0xf0);       

  124.             writel(tmp, S3C64XX_GPKDAT);  

  125.             printk("turn on!\n");      

  126.                 break;    

  127.           

  128.   

  129.         default :    

  130.                 break;    

  131.         }    

  132.      return 0;    

  133. }    

  134.     

  135. int led_release (struct inode *inode, struct file *filp)    

  136. {    

  137.     printk("#########release######\n");    

  138.     return 0;    

  139. }    

  140.     

  141. struct file_operations led_fops =  

  142. {    

  143.     .owner = THIS_MODULE,    

  144.     .open = led_open,    

  145.     .read = led_read,    

  146.     .write = led_write,    

  147.     .release = led_release,    

  148. };    

  149.     

  150. int __init led_init (void)    

  151. {     

  152.     int rc;    

  153.     printk ("Test led dev\n");    

  154.     rc = register_chrdev(LED_MAJOR,"led",&led_fops);   

  155.    

  156.     if (rc <0)    

  157.     {    

  158.         printk ("register %s char dev error\n","led");    

  159.         return -1;    

  160.     }    

  161.     printk ("ok!\n");    

  162.     return 0;    

  163. }    

  164.     

  165. void __exit led_exit (void)    

  166. {    

  167.     unregister_chrdev(LED_MAJOR,"led");    

  168.     printk ("module exit\n");    

  169.     return ;    

  170. }    

  171.     

  172. module_init(led_init);    

  173. module_exit(led_exit);    


Makefile

 

 

 

  1. obj-m := led_driver.o    

  2. KDIR :=/home/workdir/kernel/linux-2.6.38  

  3. all:    

  4.     make -C $(KDIR) M=$(shell pwd) modules    

  5. install:    

  6.     cp driver_led.ko /tftpboot/    

  7. clean:    

  8.     make -C $(KDIR) M=$(shell pwd) clean   



 

 

测试文件

 

test_led.c

 

  1. #include     

  2. #include     

  3. #include     

  4. #include     

  5.   

  6.   

  7. #define LED_OFF     0  

  8. #define LED_ON      1  

  9. #define LED_1_ON    2  

  10. #define LED_1_OFF   3  

  11. #define LED_2_ON    4  

  12. #define LED_2_OFF   5  

  13. #define LED_3_ON    6  

  14. #define LED_3_OFF   7  

  15. #define LED_4_ON    8  

  16. #define LED_4_OFF   9  

  17.   

  18. int main (void)    

  19. {    

  20.     int  i=0;  

  21.     int  fd;    

  22.     char buf[10]={  

  23.             LED_ON ,   LED_OFF ,  

  24.             LED_1_ON,  LED_1_OFF,  

  25.             LED_2_ON,  LED_2_OFF,  

  26.             LED_3_ON,  LED_3_OFF,  

  27.             LED_4_ON,  LED_4_OFF,             

  28.          };    

  29.   

  30.     fd = open("/dev/led",O_RDWR);    

  31.     if (fd < 0)    

  32.     {    

  33.         printf ("Open /dev/led file error\n");    

  34.         return -1;    

  35.     }       

  36.   

  37.     while(i<10)    

  38.     {    

  39.         write(fd,&buf[i],4);    

  40.         sleep(1);    

  41.         i++;  

  42.     }    

  43.     close (fd);    

  44.     return 0;    

  45.     

  46. }    



 

上述编译没有问题,就可以下到板子测试了。

 

加载驱动          insmod  led_driver.ko

创建设备文件    mknod /dev/led c 243 0  其中243要跟驱动文件中的设备号一致

运行测试文件    ./test_led

完成。

 

------------------------------------------------------------------------------------------

参考资料:

 

#include /*它定义了模块的 API、类型和宏(MODULE_LICENSE、MODULE_AUTHOR等等),所有的内核模块都必须包含这个头文件。/
#include /*使用内核信息优先级时要包含这个文件,一般在使用printk函数时使用到优先级信息*/
#include //头文件:module_init、module_exit等宏定义。
#include ////struct file_operations
#include
#include // S3C2410 GPIO寄存器定义
#include // s3c2410_gpio_setpin, s3c2410_gpio_cfgpin等
#include //class_create device_create(注意,有些2.6.27以前是的可能是class_device_create,如果出现implicate 错误时,看一下这个头问题里边是哪一个),udev,自动在/dev下创建设备节点
#include //字符设备节点注册,函数有cdev_init,cdev_add,cdev_del等早期的办法是register_chrdev,unregister_chrdev这种方法应避免使用。
#define DEVICE_NAME "leds" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define LED_MAJOR 231 /* 主设备号 */
/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
#define IOCTL_LED_ON 1
#define IOCTL_LED_OFF 0
/* 用来指定LED所用的GPIO引脚 */
static unsigned long led_table [] =
{
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8,
};
/* 用来指定GPIO引脚的功能:输出 */
static unsigned int led_cfg_table [] =
{
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP,
};
struct leds_type
{
struct cdev cdev;
};
struct leds_type *my_leds_dev;
/* 应用程序对设备文件/dev/EmbedSky-leds执行open(...)时,
* 就会调用EmbedSky_leds_open函数
*/
static int EmbedSky_leds_open(struct inode *inode, struct file *file)
{
int i;
for (i = 0; i < 4; i++)
{
// 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
}
return 0;
}
/* 应用程序对设备文件/dev/EmbedSky-leds执行ioclt(...)时,
* 就会调用EmbedSky_leds_ioctl函数
*/
static int EmbedSky_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
if (arg > 4)
{
return -EINVAL;
}
switch(cmd)
{
case IOCTL_LED_ON:
// 设置指定引脚的输出电平为0
s3c2410_gpio_setpin(led_table[arg], 0);
return 0;
case IOCTL_LED_OFF:
// 设置指定引脚的输出电平为1
s3c2410_gpio_setpin(led_table[arg], 1);
return 0;
default:
return -EINVAL;
}
}
/* 这个结构是字符设备驱动程序的核心
* 当应用程序操作设备文件时所调用的open、read、write等函数,
* 最终会调用这个结构中指定的对应函数
*/
static struct file_operations EmbedSky_leds_fops =
{
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = EmbedSky_leds_open, 
.ioctl = EmbedSky_leds_ioctl,
};
static char __initdata banner[] = "TQ2440/SKY2440 LEDS, (c) 2008,2009 www.embedsky.net/n";
static struct class *led_class;
/*
* 执行“insmod EmbedSky_leds.ko”命令时就会调用这个函数
*/
static int __init EmbedSky_leds_init(void)
{
int ret;
dev_t devno=MKDEV(LED_MAJOR,0);
printk("init led/n");
printk(banner);
/* 注册字符设备驱动程序
* 参数为主设备号、设备名字、file_operations结构;
* 这样,主设备号就和具体的file_operations结构联系起来了,
* 操作主设备为LED_MAJOR的设备文件时,就会调用EmbedSky_leds_fops中的相关成员函数
ret = register_chrdev_region(devno, 1,DEVICE_NAME);//获得设备编号
my_leds_dev=kmalloc(sizeof(struct leds_type),GFP_KERNEL);
/*这个必须有不然会在加载模块时出现Unable to handle kernel NULL pointer dereference at virtual addres 00000000 错误,这是由于在这里my_leds_dev仅仅是个指针,没有相应大小的分配内存,所以使用时会出错,,,寻找这个错误是比较麻烦的*/
if(!my_leds_dev)
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(my_leds_dev,0,sizeof(struct leds_type));
cdev_init(&(my_leds_dev->cdev),&EmbedSky_leds_fops);
ret=cdev_add(&(my_leds_dev->cdev),devno,1);
/*注意:与早期的设备注册方法不同,早期的直接register_chrdev()就可以,*/
if(ret)printk(KERN_NOTICE"ERROR %d",ret); 
//注册一个类,使mdev可以在"/dev/"目录下面建立设备节点
led_class = class_create(THIS_MODULE, DEVICE_NAME);
if(IS_ERR(led_class))
{
printk("Err: failed in EmbedSky-leds class. /n");
return -1;
}
//创建一个设备节点,节点名为DEVICE_NAME
device_create(led_class, NULL, MKDEV(LED_MAJOR, 0), NULL, DEVICE_NAME);
printk(DEVICE_NAME " initialized/n");
return 0;
fail_malloc: unregister_chrdev_region(devno,1);
return ret;
}
/*
* 执行”rmmod EmbedSky_leds.ko”命令时就会调用这个函数
*/
static void __exit EmbedSky_leds_exit(void)
{
/* 卸载驱动程序 */
unregister_chrdev(LED_MAJOR, DEVICE_NAME);
device_destroy(led_class, MKDEV(LED_MAJOR, 0)); //删掉设备节点
class_destroy(led_class); //注销类
}
/* 这两行指定驱动程序的初始化函数和卸载函数 */
module_init(EmbedSky_leds_init);
module_exit(EmbedSky_leds_exit);
/* 描述驱动程序的一些信息,不是必须的 */
MODULE_AUTHOR("http://www.embedsky.net"); // 驱动程序的作者
MODULE_DESCRIPTION("TQ2440/SKY2440 LED Driver"); // 一些描述信息
MODULE_LICENSE("GPL"); // 遵循的协议
上面代码中,led_table数组相当于对应了GPB的四个IO口的索引,通过这四个值,对这四个IO口进行相关操作。例如:
S3C2410_GPB5 = S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)
= S3C2410_GPIO_BANKB + 5
= 32*1 + 5
在s3c2410_gpio_setpin(S3C2410_GPB5,0)中,该函数首先通过S3C2410_GPB5获得GPB的虚拟地址和偏移地址,再对GPB5的GPBDAT寄存器进行操作,具体
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
void __iomem *base = S3C2410_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat;
local_irq_save(flags);
dat = __raw_readl(base + 0x04);//读取GPIO的DAT数据到dat
dat &= ~(1 << offs); //先将要设置的IO口拉低
dat |= to << offs; //再将形参的to值赋给dat
__raw_writel(dat, base + 0x04);//最后将DAT值写进GPIO的DAT
local_irq_restore(flags);
}

上面的 函数调用了两个子函数,具体定义如下

#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)
其中S3C24XX_VA_GPIO定义如下:

#define S3C24XX_VA_GPIO S3C2410_ADDR(0x00E00000)
#define S3C2410_ADDR(x) (0xF0000000 + (x))
这里S3C2410_ADDR的基地址为0xF0000000(??),也即2440所有寄存器的虚拟地址的基地址。0x00E00000表示2440的GPIO的偏移地址,也就是说其GPIO的虚拟地址首地址为0xF0E00000。

再看看S3C2410_GPIO_BASE(pin)的定义,我们不仿把S3C2410_GPB5的值放进去计算,可以得到(S3C2410_GPB5&~31)=32。其目的就是去掉GPB的偏移值,然后再右移一位,和GPIO的虚拟地址首地址相加。因此,S3C2410_GPIO_BASE(pin)只代表了对应GPIO组的虚拟地址,如GPB的虚拟地址为10000(B)+0xF0E00000=0xF0E00010。依此类推,可以得到所有GPIO的偏移地址,具体如下表:


BANK
(pin&~31)
(pin&~31)>>1
S3C2410_GPIO_BASE(pin)

GPA
32*0
0000,0000
0x00
0xF0E00000

GPB
32*1
0010,0000
0x10
0xF0E00010

GPC
32*2
0100,0000
0x20
0xF0E00020

GPD
32*3
0110,0000
0x30
0xF0E00030

GPE
32*4
1000,0000
0x40
0xF0E00040

GPF
32*5
1010,0000
0x50
0xF0E00050

GPG
32*6
1100,0000
0x60
0xF0E00060

GPH
32*7
1110,0000
0x70
0xF0E00070


S3C2410_GPIO_OFFSET用于获得具体GPIO的偏移地址。如GPB5,则S3C2410_GPIO_OFFSET(pin) = (pin)&31 = (32*1 + 5) & 31 = 5。有了*base和off,就可以操作具体的寄存器了。
函数s3c2410_gpio_cfgpin()用于配置GPCON寄存器。具体代码
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
void __iomem *base = S3C2410_GPIO_BASE(pin);
unsigned long mask;
unsigned long con;
unsigned long flags;
if (pin < S3C2410_GPIO_BANKB)
{
mask = 1 << S3C2410_GPIO_OFFSET(pin);//GPA的寄存器只占一位
}
else 
{
mask = 3 << S3C2410_GPIO_OFFSET(pin)*2;//非GPA的寄存器占两位
}
local_irq_save(flags);
con = __raw_readl(base + 0x00);//先保留GPCON的值
con &= ~mask; //再将要设置的管脚的CON值清零
con |= function; //然后将形参传进来的配置赋给CON
__raw_writel(con, base + 0x00); //最后将CON值写进GPCON寄存器
local_irq_restore(flags);
}
上面的LED驱动程序中,led_cfg_table数组给出了GPB相应管脚的属性设置,调用上面的函数后即设置为Output。

到此为止,整个S3C2440的IO口操作,应该就一目了然了

#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v)) 
# define __chk_io_ptr(x) (void)0

__chk_io_ptr()是编译器为了更细致地检查参数的属性,用于调试,正常编译时没有作用。 
volatile为了防止Compiler优化。

内核中,对所有的地址都是通过虚拟地址进行访问的.因此,不能直接访问0x56000010的物理地址,如果要对0x56000010的物理地址进行访问(一般是外设寄存器),那么需要把0x56000010的物理地址映射为虚拟地址,然后对该虚拟地址进行访问就是对实际的物理地址进行访问了。 
需要注意的是:在进行映射时,该虚拟地址需要disable cache和Write Buffer, 否则就是加了volatile也是没有用的

这个IOREMAP的实现过程中 
/* 
* figure out the physical address offset in a page size 
* PAGE_MASK = (1 << 10) 
*/ 
offset = phys_addr &~ PAGE_MASK; 
/* 
* figure out physical address with page align 
*/ 
phys_addrs &= PAGE_MASK; 
/* 
* get the real size with page align 
*/ 
size = PAGE_ALIGN(last_addr) - phys_addrs; 
下面是通过vmlist中查找以size大小的空闲块,所以从这里可以看出,已经做过了页的对齐,只以映射的大小

杂项设备(misc device)

杂项设备也是在嵌入式系统中用得比较多的一种设备驱动。在 Linux 内核的include/linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。 

也就是说,misc设备其实也就是特殊的字符设备。 

字符设备(char device) 

使用register_chrdev(LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时,如果有多个设备使用该函数注册驱动程序,LED_MAJOR不能相同,否则几个设备都无法注册(我已验证)。如果模块使用该方式注册并且 LED_MAJOR为0(自动分配主设备号 ),使用insmod命令加载模块时会在终端显示分配的主设备号和次设备号,在/dev目录下建立该节点,比如设备leds,如果加载该模块时分配的主设备号和次设备号为253和0,则建立节点:mknod leds c 253 0。使用register_chrdev (LED_MAJOR,DEVICE_NAME,&dev_fops)注册字符设备驱动程序时都要手动建立节点 ,否则在应用程序无法打开该设备。

__raw_readl和__raw_writel

Linux对I/O的操作都定义在asm/io.h中,相应的在arm平台下,就在asm-arm/io.h中。

#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile unsigned char __force *)(a) = (v))

#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile unsigned short __force *)(a) = (v))

#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile unsigned int __force *)(a) = (v))在include/linux/compiler.h中:

#ifdef __CHECKER__……
extern void __chk_io_ptr(void __iomem *);
#else……
# define __chk_io_ptr(x) (void)0……
#endif

__raw_readl(a)展开是:((void)0, *(volatile unsigned int _force *)(a))。在定义了__CHECKER__的时候先调用__chk_io_ptr检查该地址,否则__chk_io_ptr什么也不做,*(volatile unsigned int _force *)(a)就是返回地址为a处的值。(void)xx的做法有时候是有用的,例如编译器打开了检查未使用的参数的时候需要将没有用到的参数这么弄一下才能编译通过。

CPU对I/O的物理地址的编程方式有两种:一种是I/O映射,一种是内存映射。__raw_readl和__raw_writel等是原始的操作I/O的方法,由此派生出来的操作方法有:inb、outb、_memcpy_fromio、readb、writeb、ioread8、iowrite8等。


关键字:Tiny6410  LED字符  设备驱动 引用地址:Tiny6410 LED字符设备驱动

上一篇:Cortex-M3/4的Hard Fault调试方法
下一篇:Tiny6410 设备驱动之helloworld

推荐阅读最新更新时间:2024-03-16 15:30

利用WinDriver开发PCI设备驱动程序
    摘要: WinDriver是一套PCI驱动程序开发包。它改变了传统驱动程序开发的方法与思路,极在地简化了驱动程序的编制;同时,又没有牺牲驱动程序的性能,是一套高效、快捷的PCI驱动程序开发软件包。特别适合专业硬件人员的使用。     关键词: 设备驱动程序 WinDriver PCI WinDriver是Jungo公司出版的一个设备驱动程序开发组件,它可以大大加速PCI设备驱动程序的开发。作者在实际的项目中采用了WinDriver来开发设备驱动程序,取得了相当好的运行效果。从目前国内的资料上来看,大多数设计人员还是在用DDK、Wtools开发设备驱动程序,因而作者觉得有必要向大家介绍与推荐这个软件。
[嵌入式]
基于IEEE1394b的双向传输设备驱动程序设计
现有的大部分数据传输接口总线造价比较高,且难以满足实际运用中对传输速率的要求,成了阻碍整个系统性能提高的一大屏障。IEEE-1394是现今最高速的串行总线接口之一,IEEE1394lb更是在原有IEEE1394的基础上速度更快,支持距离更长,在实时批量数据传输方面有广泛的应用前景。 基于1394传输系统设备驱动文献,大部分都是基于IEEE1394a的,而IEEE1394b以其更高的速度展现出了更大的魅力,对实时大批量的数据传输具有重大意义,但是Microsoft并没有提供对1394b的支持,在Windows自带的1394不能支持其S800的速度,因此1394b在应用上受到局限,Unibrian提供了FireAPI SDK
[模拟电子]
嵌入式Linux字符设备驱动的设计与应用
  1引言   随着嵌入式系统的发展,嵌入式 Linux以其稳定性和开放源代码的优点在嵌入式系统的开发中得到广泛应用。越来越多的软硬件厂商使用嵌入式 Linux来开发自己的产品,对基于嵌入式 Linux平台开发设备的驱动程序和应用程序的需求在成倍增长。本文通过实现对 PXA255开发板外围字符设备(电机、数码管、串口和 mini键盘)的操作和控制,详细讨论了嵌入式 linux字符设备驱动的设计与应用。   2系统的设计框架   系统的设计分为字符设备驱动程序和人机交互界面两部分。驱动程序为应用程序提供了操作设备的接口;人机交互界面的设计实现设备应用程序并完成人机交互的功能。整个系统软硬件的关系如图 1:字符设备被映射到 Li
[单片机]
嵌入式Linux<font color='red'>字符</font><font color='red'>设备驱动</font>的设计与应用
07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-查询+中断+引入poll机制的按键驱动程序
一、查询方式的按键驱动程序 查询方式的按键驱动程序,与LED驱动程序类似,我们来复习一下上节的写好的字符设备驱动程序框架,改写出查询方式的按键驱动程序。 (1)按键驱动程序如下: Open中配置引脚 Read中返回引脚状态 入口函数:地址映射 虚拟地址 #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include asm/uaccess.h #include asm/irq.h #include asm/io.h #
[单片机]
07-S3C2440驱动学习(一)嵌入式linux<font color='red'>字符</font><font color='red'>设备驱动</font>-查询+中断+引入poll机制的按键驱动程序
嵌入式Linux下的USB设备驱动技术
  Linux以其稳定、高效、易定制、硬件支持广泛、源代码开放等特点,已在嵌入式领域迅速崛起,被国际上许多大型的跨国企业用作嵌入式产品的系统平台。   USB是Universal Serial Bus (通用串行总线)的缩写,是1995年由Microsoft、Compaq、IBM等公司联合制定的一种新的PC串行通信协议。它是一种快速、灵活的总线接口。与其它通信接口相比较,USB接口的最大特点是易于使用,这也是USB的主要设计目标。USB的成功得益于在USB标准中除定义了通信的物理层和电器层标准外。还定义了一套相对完整的软件协议堆栈。这使得多数USB设备都很容易在各种平台上工作。作为一种高速总线接口,USB适用于多种设备(如数码相机
[嵌入式]
基于ARM的无线网卡设备驱动方案
  随着嵌入式系统中无线局域网的接入,既可以实现对嵌人式系统的无线控制和数据传输,又可以满足一些特殊应用的场合。这里通过对USB无线网卡的Linux设备驱动的深入理解和分析,成功地移植在Atmel 9261 ARM处理器上。实现了嵌入式系统的无线局域网接入。利用该平台,可以进一步设计完善医用伽马相机和小型SPECT设备的手持数据采集系统,使得控制人员能够远离数据采集现场,而通过远程终端来控制现场数据和各种控制信号,较好地解决了安全性问题。   1 硬件系统构成   1.1 USB无线网卡介绍   无线网卡是无线局域网(WLAN)的重要组成部分,WLAN的物理层及MAC层是用无线网卡的硬件及其软件完成的,而LLC层以上各层均由计
[单片机]
基于ARM的无线网卡<font color='red'>设备驱动</font>方案
从Linux内核LED驱动来理解字符设备驱动开发流程
开发环境 环境说明 详细信息 备注信息 操作系统 Ubunut 18.04.3 LTS 开发板 S3C2440(JZ2440-V3) kernel版本 linux-3.4.2 官网地址 busybox版本 busybox-1.22.1 官网地址 编译器 arm-linux-gcc-4.4.3 下载地址 编译器路径 /opt/FriendlyARM/toolschain/4.4.3/bin 绝对路径 1. Linux字符设备驱动的组成 引自宋宝华《Linux设备驱动开发详解--基于最新的Linux 4.0内核》P138内容: 在Linux中,字符设备驱动由如下几个部分组成。 1. 字符设备
[单片机]
从Linux内核<font color='red'>LED</font>驱动来理解<font color='red'>字符</font><font color='red'>设备驱动</font>开发流程
PCI总线电机控制卡的WDM设备驱动程序设计
1引言 微型计算机界以INTEL公司为主推出了PCI总线规范。采用PCI总线设备所具有的配置空间以及PCI总线通过桥接电路与CPU相连的技术使PCI总线具有广泛的适应性,并且PCI总线采用宽字节和高达33Mb的时钟频率的猝发和主控方式传输能满足高速设备的要求。 在WINDOWS操作系统下,开发PCI设备的驱动程序最好的方案是WDM驱动程序。在一个系统中开发出WDM驱动程序,稍加修改即可在其他系统中编译运行。 2WINDOWS驱动程序模型WDM WDM(WINDOWSDriverProgramModel)是一个模块化的、分层次类型的微型驱动程序结构,它是编写设备驱动程序的主要模型。设备驱动程序是提供连接到计算机的硬件
[嵌入式]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved