nuclear@0: #include nuclear@1: #include nuclear@0: #include nuclear@1: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "bcm_host.h" nuclear@0: nuclear@1: #define REG_GPIO_BASE 0x200000 nuclear@1: #define REG_GPFSEL_BASE 0x200000 nuclear@1: #define REG_GPSET_BASE 0x20001c nuclear@1: #define REG_GPCLR_BASE 0x200028 nuclear@1: #define REG_GPLEV_BASE 0x200034 nuclear@1: #define REG_GPPUD 0x200094 nuclear@1: #define REG_GPPUDCLK_BASE 0x200098 nuclear@0: nuclear@0: #define FSEL_BITS 3 nuclear@0: #define FSEL_INPUT 0 nuclear@0: #define FSEL_OUTPUT 1 nuclear@0: nuclear@0: #define FSEL_SHIFT(i) (((i) % 10) * 3) nuclear@0: #define FSEL_MASK(i) (3 << FSEL_SHIFT(i)) nuclear@0: nuclear@0: #define REG(r) (volatile uint32_t*)((unsigned char*)iomem + (r)) nuclear@0: nuclear@0: void *iomem; nuclear@0: int quit; nuclear@0: nuclear@0: static inline void set_pin_func(int pin, int func); nuclear@0: static inline void set_pin_state(int pin, int s); nuclear@0: static inline int get_pin_state(int pin); nuclear@1: static inline void set_pullup(int pin, int en); nuclear@1: static inline void set_pulldown(int pin, int en); nuclear@0: static void sighandler(int s); nuclear@0: nuclear@0: int main(void) nuclear@0: { nuclear@0: int fd; nuclear@0: int i; nuclear@1: uint32_t io_addr, io_size, mmap_size; nuclear@1: void *mmap_ptr; nuclear@0: nuclear@0: signal(SIGINT, sighandler); nuclear@0: signal(SIGQUIT, sighandler); nuclear@0: signal(SIGSEGV, sighandler); nuclear@0: signal(SIGILL, sighandler); nuclear@0: signal(SIGFPE, sighandler); nuclear@0: nuclear@0: io_addr = bcm_host_get_peripheral_address(); nuclear@0: io_size = bcm_host_get_peripheral_size(); nuclear@0: printf("I/O registers\n"); nuclear@0: printf(" addr: %x\n", io_addr); nuclear@0: printf(" size: %d\n", io_size); nuclear@0: nuclear@1: if((fd = open("/dev/gpiomem", O_RDWR | O_SYNC)) >= 0) { nuclear@1: mmap_size = 0xb4; /* last gpio reg addr + 4 */ nuclear@1: if((mmap_ptr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == (void*)-1) { nuclear@1: perror("failed to map I/O registers"); nuclear@1: return 1; nuclear@1: } nuclear@1: iomem = ((unsigned char*)mmap_ptr) - REG_GPIO_BASE; nuclear@1: } else if((fd = open("/dev/mem", O_RDWR | O_SYNC)) >= 0) { nuclear@1: mmap_size = io_size; nuclear@1: if((mmap_ptr = mmap(0, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, io_addr)) == (void*)-1) { nuclear@1: perror("failed to map I/O registers"); nuclear@1: return 1; nuclear@1: } nuclear@1: iomem = mmap_ptr; nuclear@1: } else { nuclear@0: perror("failed to open /dev/mem"); nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: /* configure GPIO pins 4 and 17 as outputs */ nuclear@0: set_pin_func(4, FSEL_OUTPUT); nuclear@0: set_pin_func(17, FSEL_OUTPUT); nuclear@1: /* configure GPIO pin 22 as input, and enable it's pulldown resistor */ nuclear@1: set_pin_func(22, FSEL_INPUT); nuclear@1: set_pulldown(22, 1); nuclear@0: nuclear@0: i = 0; nuclear@0: while(!quit) { nuclear@1: if(get_pin_state(22)) { nuclear@1: set_pin_state(4, 1); nuclear@1: set_pin_state(17, 1); nuclear@1: } else { nuclear@1: set_pin_state(4, i & 1); nuclear@1: set_pin_state(17, (~i) & 1); nuclear@1: ++i; nuclear@1: } nuclear@1: usleep(250000); nuclear@0: } nuclear@0: nuclear@0: set_pin_state(4, 0); nuclear@0: set_pin_state(17, 0); nuclear@0: set_pin_func(4, FSEL_INPUT); nuclear@0: set_pin_func(17, FSEL_INPUT); nuclear@1: set_pulldown(22, 0); nuclear@0: nuclear@1: munmap(mmap_ptr, mmap_size); nuclear@0: close(fd); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static inline void set_pin_func(int pin, int func) nuclear@0: { nuclear@0: int reg_addr, val; nuclear@0: reg_addr = REG_GPFSEL_BASE + (pin / 10) * 4; nuclear@0: val = *REG(reg_addr); nuclear@0: *REG(reg_addr) = (val & FSEL_MASK(pin)) | (func << FSEL_SHIFT(pin)); nuclear@0: } nuclear@0: nuclear@0: static inline void set_pin_state(int pin, int s) nuclear@0: { nuclear@0: int reg_addr; nuclear@0: int regidx = pin / 32; nuclear@0: int bit = pin % 32; nuclear@0: nuclear@0: if(s) { nuclear@0: reg_addr = REG_GPSET_BASE + regidx * 4; nuclear@0: *REG(reg_addr) |= 1 << bit; nuclear@0: } else { nuclear@0: reg_addr = REG_GPCLR_BASE + regidx * 4; nuclear@0: *REG(reg_addr) |= 1 << bit; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static inline int get_pin_state(int pin) nuclear@0: { nuclear@0: int reg_addr; nuclear@0: int regidx = pin / 32; nuclear@0: int bit = pin % 32; nuclear@0: nuclear@0: reg_addr = REG_GPLEV_BASE + regidx * 4; nuclear@0: return (*REG(reg_addr) >> bit) & 1; nuclear@0: } nuclear@0: nuclear@1: #define delay_cycles(x) \ nuclear@1: __asm__ __volatile__ ( \ nuclear@1: "mov %0, #150\n" \ nuclear@1: "1:\n\t" \ nuclear@1: "nop\n\t" \ nuclear@1: "subs %0, %0, #1\n\t" \ nuclear@1: "bne 1b\n\t" \ nuclear@1: :: "r"(x)) nuclear@1: nuclear@1: static inline void set_pull_updown(int pin, int updown) nuclear@1: { nuclear@1: int regidx = pin / 32; nuclear@1: int bit = pin % 32; nuclear@1: int clk_addr = REG_GPPUDCLK_BASE + regidx * 4; nuclear@1: nuclear@1: *REG(REG_GPPUD) = updown; nuclear@1: delay_cycles(150); nuclear@1: *REG(clk_addr) = bit; nuclear@1: delay_cycles(150); nuclear@1: *REG(REG_GPPUD) = 0; nuclear@1: *REG(clk_addr) = 0; nuclear@1: } nuclear@1: nuclear@1: static inline void set_pullup(int pin, int en) nuclear@1: { nuclear@1: set_pull_updown(pin, en ? 2 : 0); nuclear@1: } nuclear@1: nuclear@1: static inline void set_pulldown(int pin, int en) nuclear@1: { nuclear@1: set_pull_updown(pin, en ? 1 : 0); nuclear@1: } nuclear@1: nuclear@0: static void sighandler(int s) nuclear@0: { nuclear@0: quit = 1; nuclear@0: }