TA的每日心情 | 郁闷 2016-8-18 12:54 |
---|
签到天数: 4 天 连续签到: 1 天 [LV.2]偶尔看看I
|
拿到板子后,想自己做点东西时却发现官方并没有给提供GPIO库,不像树莓派那样有各种软件库的支持。看来只能自己动手了。以下是详细步骤:
1、下载i.MX6处理器的参考手册
51MB的体积加5789页的芯片手册,醉了。。。
2、看手册
首先通过板子的原理图可知这个板子有11个剩余的GPIO可供DIY,分别是:GPIO4_16、GPIO4_17、GPIO4_18、GPIO4_19、GPIO4_26、GPIO4_27、GPIO4_31、GPIO5_05、GPIO5_06、GPIO5_07、GPIO5_08。
在使用i.MX6的GPIO前首先要配置IOMUXC寄存器,将需要的管脚配置成GPIO之后才可以把它当GPIO用。
通过查询手册可知GPIO4_IO16这个脚的IOMUXC寄存器地址为0x20E009C。通过配置IOMUXC寄存器的前4位为0101(0x5)来将这个管脚配置为GPIO。
以此类推,得到了这些寄存器:
#define IOMUXC_GPIO4_16 0x20E009C#define IOMUXC_GPIO4_17 0x20E00A0#define IOMUXC_GPIO4_18 0x20E00A4#define IOMUXC_GPIO4_19 0x20E00A8#define IOMUXC_GPIO4_26 0x20E00FC#define IOMUXC_GPIO4_27 0x20E0100#define IOMUXC_GPIO4_31 0x20E00B8#define IOMUXC_GPIO5_05 0x20E00BC#define IOMUXC_GPIO5_06 0x20E00C0#define IOMUXC_GPIO5_07 0x20E00C4#define IOMUXC_GPIO5_08 0x20E00C8接着看手册:GPIO_GDIR functions as direction control when the IOMUXC is in GPIO mode. Each
bit specifies the direction of a one-bit signal. The mapping of each DIR bit to a
corresponding SoC signal is determined by the SoC's pin assignment and the IOMUX
table. For more details consult the IOMUXC chapter.
由此可知将IOMUXC寄存器配置成GPIO模式后,通过GPIO_GDIR寄存器就可以控制GPIO的输入输出方向了。
经过简单的搜索就找到了这个寄存器地址,还有GPIO4_DR数据寄存器。
#define GPIO4_DR 0x20A8000#define GPIO4_GDIR 0x20A8004#define GPIO5_DR 0x20AC000#define GPIO5_GDIR 0x20AC004这样,就集齐了简单控制GPIO输入输出的寄存器,可以来挑战BOSS了。
3、关于mmap系统调用
大家都知道用户态的程序都是在内存保护模式下使用内存,无法直接访问物理内存。同时用户程序使用的地址,也并不是物理地址,而是逻辑地址。至于这些逻辑地址对应的物理内存在哪里,用户进程本身并不知道。通过用户程序若想访问物理内存,有一种简单的方法,就是通过mmap系统调用将物理地址映射到用户空间,这样就可以像玩单片机一样操作GPIO了,不多说了,上代码:[gpio.c]
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/types.h>#include <fcntl.h>#include <sys/mman.h>#include "gpio.h"#define MAP_SIZE 4096UL#define MAP_MASK (MAP_SIZE - 1)unsigned long reg_read(off_t addr){ int memfd; void *map_base, *virt_addr; unsigned long val; if((memfd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) exit(1); map_base = mmap(0,MAP_SIZE,PROT_READ | PROT_WRITE,MAP_SHARED,memfd,addr & ~MAP_MASK); if(map_base == (void *) -1) exit(1); virt_addr = map_base + (addr & MAP_MASK); val=*((unsigned long *) virt_addr); if(munmap(map_base, MAP_SIZE) == -1) exit(1); close(memfd); return val;}void reg_write(unsigned long addr,unsigned long dat){ int memfd; void *map_base, *virt_addr; if((memfd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) exit(1); map_base = mmap(0,MAP_SIZE,PROT_READ | PROT_WRITE,MAP_SHARED,memfd,addr & ~MAP_MASK); if(map_base == (void *) -1) exit(1); virt_addr = map_base + (addr & MAP_MASK); *((unsigned long *) virt_addr) = dat; close(memfd);}void gpio_init(){ /* Configure IOMUX to select GPIO mode */ reg_write(IOMUXC_GPIO4_16,IOMUXC_GPIO); reg_write(IOMUXC_GPIO4_17,IOMUXC_GPIO); reg_write(IOMUXC_GPIO4_18,IOMUXC_GPIO); reg_write(IOMUXC_GPIO4_19,IOMUXC_GPIO); reg_write(IOMUXC_GPIO4_26,IOMUXC_GPIO); reg_write(IOMUXC_GPIO4_27,IOMUXC_GPIO); reg_write(IOMUXC_GPIO4_31,IOMUXC_GPIO); reg_write(IOMUXC_GPIO5_05,IOMUXC_GPIO); reg_write(IOMUXC_GPIO5_06,IOMUXC_GPIO); reg_write(IOMUXC_GPIO5_07,IOMUXC_GPIO); reg_write(IOMUXC_GPIO5_08,IOMUXC_GPIO);}void gpio_dir(int gpio,int dir){ unsigned long gdir; unsigned char port; gpio-=96; if(gpio>31){ gpio-=32; port=5; gdir=reg_read(GPIO5_GDIR); }else{ port=4; gdir=reg_read(GPIO4_GDIR); } if(dir){ if(port==4) reg_write(GPIO4_GDIR,gdir|(1<<gpio)); else reg_write(GPIO5_GDIR,gdir|(1<<gpio)); }else{ if(port==4) reg_write(GPIO4_GDIR,gdir&(~(1<<gpio))); else reg_write(GPIO5_GDIR,gdir&(~(1<<gpio))); }}void gpio_set(int gpio,int value){ unsigned long dr; unsigned char port; gpio-=96; if(gpio>31){ gpio-=32; port=5; dr=reg_read(GPIO5_DR); }else{ port=4; dr=reg_read(GPIO4_DR); } if(value){ if(port==4) reg_write(GPIO4_DR,dr|(1<<gpio)); else reg_write(GPIO5_DR,dr|(1<<gpio)); }else{ if(port==4) reg_write(GPIO4_DR,dr&(~(1<<gpio))); else reg_write(GPIO5_DR,dr&(~(1<<gpio))); }} int gpio_get(int gpio){ unsigned long dr; gpio-=96; if(gpio>31){ gpio-=32; dr=reg_read(GPIO5_DR); }else{ dr=reg_read(GPIO4_DR); } if(dr&(1<<gpio)) return 1; else return 0;}头文件:[gpio.h]#ifndef __GPIO_H__#define __GPIO_H__#define GPIO4_DR 0x20A8000#define GPIO4_GDIR 0x20A8004#define GPIO5_DR 0x20AC000#define GPIO5_GDIR 0x20AC004#define IOMUXC 0x20E0000#define IOMUXC_GPIO4_16 0x20E009C#define IOMUXC_GPIO4_17 0x20E00A0#define IOMUXC_GPIO4_18 0x20E00A4#define IOMUXC_GPIO4_19 0x20E00A8#define IOMUXC_GPIO4_26 0x20E00FC#define IOMUXC_GPIO4_27 0x20E0100#define IOMUXC_GPIO4_31 0x20E00B8#define IOMUXC_GPIO5_05 0x20E00BC#define IOMUXC_GPIO5_06 0x20E00C0#define IOMUXC_GPIO5_07 0x20E00C4#define IOMUXC_GPIO5_08 0x20E00C8#define IOMUXC_GPIO 0x5#define GPIO4_16 112#define GPIO4_17 113#define GPIO4_18 114#define GPIO4_19 115#define GPIO4_26 122#define GPIO4_27 123#define GPIO4_31 127#define GPIO5_05 133#define GPIO5_06 134#define GPIO5_07 135#define GPIO5_08 136void gpio_init();void gpio_dir(int gpio,int dir);void gpio_set(int gpio,int value);int gpio_get(int gpio);#endif4、测试例程
gpio_init(); //初始化GPIOgpio_dir(GPIO4_16,1); //配置GPIO为输出gpio_set(GPIO4_16,1); //配置GPIO输出高电平gpio_dir(GPIO4_17,0); //配置GPIO为输入gpio_get(GPIO4_17); //读取GPIO电平5、总结
貌似也没啥好总结的了,就这样吧,祝大家玩的开心。 |
|