使用mmap函式映射Memory的方式來操作GPIO,達到高速存取的目的,比起傳統的sysfs更為有效率,使得後面其他功能更為Real time,首先創建gpio.h,宣告函式的原型
gpio.h #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <sched.h> #include <sys/mman.h> #define MMIO_SUCCESS 0 #define MMIO_ERROR_DEVMEM -1 #define MMIO_ERROR_MMAP -2 #define BASE 0xB01B0000 #define GPIO_INC 3 #define GPIO_OUTEN 0 #define GPIO_INEN 1 #define GPIO_DAT 2 #define GPIO_LENGTH (0x254+1) (GPIO_END_ADDR - GPIO_START_ADDR) #define GPIO_LENGTH 528 (?) (GPIO_END_ADDR - GPIO_START_ADDR) /* ref1: kernel/arch/arm/mach-owl/include/mach/gpio.h //GPIOA/B/C/D/E, GPIOE0~4 #define NR_OWL_GPIO ref2: kernel/arch/arm/mach-owl/gpio.owi.h owl_gpio_chip.ngpio */ int s500_mmio_init(void); void s500_mmio_set_input(int gpio_number); void s500_mmio_set_output(int gpio_number); void s500_mmio_set_high(int gpio_number); void s500_mmio_set_low(int gpio_number); uint32_t s500_mmio_read_input(int gpio_number); void set_max_priority(void); void set_default_priority(void);----------------------------------------
其中大部分都是GPIO常用的功能,和程式的Priority,其中BASE,GPIO_INC,GPIO_OUTEN,GPIO_INEN,GPIO_DAT和GPIO_LENGTH由Action S500的Datasheet來決定。因為每3個Word(32 Bit)為一個GPIO Bank,因此設置累加為3,即GPIO_INC,而每個Bank中OUT的offset為0,IN為1,DAT為2,即可完成對於任何GPIO number找到對應的Register Address來進行操作
gpio.c #include "gpio.h" volatile uint32_t* s500_mmio_gpio = NULL; int s500_mmio_init(void) { if (s500_mmio_gpio == NULL) { int fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd == -1) { // Error opening /dev/mem. Probably not running as root. return MMIO_ERROR_DEVMEM; } // Map GPIO memory to location in process space. s500_mmio_gpio = (uint32_t*)mmap(NULL, GPIO_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE); close(fd); if (s500_mmio_gpio == MAP_FAILED) { // Don't save the result if the memory mapping failed. s500_mmio_gpio = NULL; return MMIO_ERROR_MMAP; } } return MMIO_SUCCESS; } void s500_mmio_set_input(int gpio_number) { *(s500_mmio_gpio + ((gpio_number)/32)*GPIO_INC + GPIO_INEN) |= (1<<((gpio_number)%32)); *(s500_mmio_gpio + ((gpio_number)/32)*GPIO_INC + GPIO_OUTEN) &= ~(1<<((gpio_number)%32)); } void s500_mmio_set_output(int gpio_number) { *(s500_mmio_gpio + ((gpio_number)/32)*GPIO_INC + GPIO_INEN) &= ~(1<<((gpio_number)%32)); *(s500_mmio_gpio + ((gpio_number)/32)*GPIO_INC + GPIO_OUTEN) |= (1<<((gpio_number)%32)); } void s500_mmio_set_high(int gpio_number) { *(s500_mmio_gpio + ((gpio_number)/32)*GPIO_INC + GPIO_DAT) |= (1<<((gpio_number)%32)); } void s500_mmio_set_low(int gpio_number) { *(s500_mmio_gpio + ((gpio_number)/32)*GPIO_INC + GPIO_DAT) &= ~(1<<((gpio_number)%32)); } uint32_t s500_mmio_read_input(int gpio_number) { return (*(s500_mmio_gpio + ((gpio_number)/32)*GPIO_INC + GPIO_DAT) & (1<<((gpio_number)%32)) ? 1 : 0); } void set_max_priority(void) { struct sched_param sched; memset(&sched, 0, sizeof(sched)); // Use FIFO scheduler with highest priority for the lowest chance of the kernel context switching. sched.sched_priority = sched_get_priority_max(SCHED_FIFO); sched_setscheduler(0, SCHED_FIFO, &sched); } void set_default_priority(void) { struct sched_param sched; memset(&sched, 0, sizeof(sched)); // Go back to default scheduler with default 0 priority. sched.sched_priority = 0; sched_setscheduler(0, SCHED_OTHER, &sched); }---------------------------------------
main.c #include <stdio.h> #include <stdlib.h> #include "gpio.h" void main (void) { if (s500_mmio_init() < 0) printf("error open mem!n"); set_max_priority(); s500_mmio_set_output(IN1); set_default_priority(); }ref: 【LeMaker Guitar試用體驗】居家水族箱
沒有留言:
張貼留言