完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
3.动手写驱动
3.1 确定LED引脚 首先查看开发板原理图,确定LED所在引脚。这里,我选用了LED1,所在引脚为GPIO3_26。 查看开发板原理图以及i.mx283A的数据手册,确定GPIO3_26即为数据手册中的E8(Bank3,Pin26)。 3.2浏览数据手册 因为这款芯片对我来说是全新的,所以,我需要从数据手册入手,大致了解一下这款芯片。 首先便是芯片的概述,从这里,可以了解其内部资源,特性等,随便看看就好。 然后,我打开了数据手册的目录。我本来是想看看它的时钟树的,却发现并没有这一节。(在STM32中,时钟树是一个很重要的概念,所以这里首先就想到来看时钟树。) 然后,我打开了第八章,从这里,有用的部分主要是:引脚定义,引脚复用功能。 之后是第九章: 从目录中可以看到,这里有GPIO的控制,复用,接口,相关寄存器等,从这一章,应该就可以完成GPIO的所有操作了。 从9.1节可以了解到:
往下翻,发现了这一页: 这里完整地写出了想要控制一个引脚应该做什么,真是太棒了。 3.3 确定寄存器 下面就是查找上图中的寄存器,了解寄存器功能,然后挨个配置了。 3.3.1. 复用功能选择寄存器HW_PINCTRL_MUXSEL7 找到GPIO3_26对应的寄存器。这个寄存器是控制引脚复用功能的,例如,我们可以向其21-20位写入11b来设置GPIO3_26引脚功能为GPIO。 同时,应该注意到,由于我们等会要直接操作寄存器,所以,还得记下寄存器的地址。 3.3.2. Driver strength 及电压控制寄存器HW_PINCTRL_DRIVE15 3.3.3. 上拉电阻使能寄存器HW_PINCTRL_PULL3 3.3.4. 输出值控制寄存器HW_PINCTRL_DOUT3 这个寄存器是用来控制GPIO输出高/低电平的。 3.3.5. 输出使能寄存器HW_PINCTRL_DOE3: 使能对应的位,GPIO才能有输出。 3.4 编写程序 由于这篇文章的目的主要是记录面对一款新的芯片如何处理,所以编程过程就不再赘述。 #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* After setting the field in the HW_PINCTRL_MUXSELx to program for GPIO control, the HW_PINCTRL_DRIVEx register bit is set for the desired drive strength and pin voltage. Set bits in HW_PINCTRL_PULLx as required to enable pullups. • The HW_PINCTRL_DOUTx register bit is then loaded with the level that will initially be driven on the pin. • Finally, the HW_PINCTRL_DOEx register bit is set. • Once set, the logic value the HW_PINCTRL_DOUTx bit will be driven on the pin and the value can be toggled with repeated writes. */ static volatile unsigned int *HW_PINCTRL_MUXSEL7;// 8001_8170 复用选择寄存器 static volatile unsigned int *HW_PINCTRL_DRIVE15;// 8001_83F0 static volatile unsigned int *HW_PINCTRL_PULL3; // 8001_8630h static volatile unsigned int *HW_PINCTRL_DOUT3; // 8001_8730h 输出控制寄存器 3.26在第26位 static volatile unsigned int *HW_PINCTRL_DOE3; // 8001_8B30h 输出使能寄存器 3.26在第26位 static volatile unsigned int *HW_PINCTRL_DIN3; // 8001_8930h 输入数据寄存器 3.26在第26位 static int led_major; static struct class *my_led_class; static int my_led_open(struct inode *node, struct file *file) { printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__); *HW_PINCTRL_MUXSEL7 |= 0x03 << 20; /*复用为GPIO*/ *HW_PINCTRL_DRIVE15 |= 0x03 << 8; /*drive stren = 12mA*/ *HW_PINCTRL_DRIVE15 &= ~(0x01 << 7); *HW_PINCTRL_PULL3 |= 0x01 << 26; /*Set this bit to one to disable the internal keeper on pin 8, SAIF1_SDATA0*/ *HW_PINCTRL_DOUT3 |= 0x01 << 26; /*默认输出高,熄灭*/ *HW_PINCTRL_DOE3 |= 0x01 << 26; /*输出使能*/ return 0; } ssize_t my_led_read(struct file *file, char __user *buff, size_t size, loff_t *offset) { char status = 0; sleep(1); status = (char)((*HW_PINCTRL_DOUT3 >> 26) & 0X01); copy_to_user(buff, &status, 1); return 1; } ssize_t my_led_write(struct file *file, const char __user *buff, size_t size, loff_t *offset) { // printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__); char val; copy_from_user(&val, buff, 1); /* to set gpio register: out 1/0 */ if (val) { /* set gpa10 to let led off */ *HW_PINCTRL_DOUT3 |= (1<<26); } else { /* set gpa10 to let led on */ *HW_PINCTRL_DOUT3 &= ~(1<<26); } return 1; } int my_led_close(struct inode *node, struct file *file) { printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__); return 0; } struct file_operations my_led_ops = { .owner = THIS_MODULE, .open = my_led_open, .read = my_led_read, .write = my_led_write, .release = my_led_close, }; static int __init my_led_init(void) { printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__); HW_PINCTRL_MUXSEL7 = ioremap(0x80018170, 4); HW_PINCTRL_DRIVE15 = ioremap(0x800183F0, 4); HW_PINCTRL_PULL3 = ioremap(0x80018630, 4); HW_PINCTRL_DOUT3 = ioremap(0x80018730, 4); HW_PINCTRL_DOE3 = ioremap(0x80018B30, 4); HW_PINCTRL_DIN3 = ioremap(0x80018930, 4); led_major = register_chrdev(0,"my_led",&my_led_ops); my_led_class = class_create(THIS_MODULE, "my_led_cls"); device_create(my_led_class, NULL, MKDEV(led_major, 0), NULL, "my_led"); return 0; } static void __exit my_led_exit(void) { printk("%s %s %dn", __FILE__, __FUNCTION__, __LINE__); iounmap(HW_PINCTRL_MUXSEL7); iounmap(HW_PINCTRL_DRIVE15); iounmap(HW_PINCTRL_PULL3); iounmap(HW_PINCTRL_DOUT3); iounmap(HW_PINCTRL_DOE3); iounmap(HW_PINCTRL_DIN3); device_destroy(my_led_class, MKDEV(led_major, 0)); class_destroy(my_led_class); unregister_chrdev(led_major, "my_led"); } module_init(my_led_init); module_exit(my_led_exit); MODULE_LICENSE("GPL"); 3.5测试 测试发现,可以正常控制LED的亮灭;但是当读取LED状态时,LED会自动熄灭,暂没找出原因。 4.回顾 ①在写完驱动程序时,我并不能确定能用,因为那个时钟树我还没有看到,心里很不踏实。后来我又回去查找时钟树,发现了一张图,里面描述了时钟分配等 ,但是再回去找,不知道在哪一页了,所以就不能贴出来了。但是程序确实能用,可能是不需要再配置时钟了吧。 ②还是不应该畏惧英文文档,其实大致都能看懂的,偶尔有个词不认识,百度一下也就知道了。 |
|
|
|
只有小组成员才能发言,加入小组>>
3280 浏览 9 评论
2958 浏览 16 评论
3460 浏览 1 评论
9004 浏览 16 评论
4052 浏览 18 评论
1115浏览 3评论
573浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
571浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2303浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1859浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 12:21 , Processed in 1.074072 second(s), Total 80, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号