#include "gpio.h" #include "ch573/pfic.h" #include "isr_vector.h" /* Sets all the GPIO pins to INPUT_PULL_UP configuration. This is to reduce * electrical noise in the system. */ void gpio_init() { // Set GPIO's to input. GPIO_PORT.dir_reg.set(GPIO_PORT_A, 0x0); GPIO_PORT.dir_reg.set(GPIO_PORT_B, 0x0); // Turn off all the pull-down resistors. GPIO_PORT.pd_drv_reg.set(GPIO_PORT_A, 0x0); GPIO_PORT.pd_drv_reg.set(GPIO_PORT_B, 0x0); // Turn on the pull up resistors. GPIO_PORT.pu_reg.set(GPIO_PORT_A, 0xffffffff); GPIO_PORT.pu_reg.set(GPIO_PORT_B, 0xffffffff); } void gpio_configure_pin(gpio_pin_t pin, gpio_config_t cfg) { int ipin = pin; struct ch573_gpio__gpio_port_t* port; if (pin & IS_PORT_B) { port = GPIO_PORT_B; ipin &= ~IS_PORT_B; } else { port = GPIO_PORT_A; } switch (cfg) { case PIN_CFG_INPUT_FLOATING: GPIO_PORT.dir.set(port, DIR_IN, ipin); GPIO_PORT.pu.set(port, DISABLED, ipin); GPIO_PORT.pd_drv.set(port, 0, ipin); break; case PIN_CFG_INPUT_PULL_UP: GPIO_PORT.dir.set(port, DIR_IN, ipin); GPIO_PORT.pu.set(port, ENABLED, ipin); GPIO_PORT.pd_drv.set(port, 0, ipin); break; case PIN_CFG_INPUT_PULL_DOWN: GPIO_PORT.dir.set(port, DIR_IN, ipin); GPIO_PORT.pu.set(port, DISABLED, ipin); GPIO_PORT.pd_drv.set(port, 1, ipin); break; case PIN_CFG_OUTPUT_5mA: GPIO_PORT.dir.set(port, DIR_OUT, ipin); GPIO_PORT.pu.set(port, DISABLED, ipin); GPIO_PORT.pd_drv.set(port, 0, ipin); break; case PIN_CFG_OUTPUT_20mA: GPIO_PORT.dir.set(port, DIR_OUT, ipin); GPIO_PORT.pu.set(port, DISABLED, ipin); GPIO_PORT.pd_drv.set(port, 1, ipin); break; } } int gpio_read(gpio_pin_t pin) { int ipin = pin; struct ch573_gpio__gpio_port_t* port; if (pin & IS_PORT_B) { port = GPIO_PORT_B; ipin &= ~IS_PORT_B; } else { port = GPIO_PORT_A; } return !!GPIO_PORT.pin.in.get(port, ipin); } void gpio_set(gpio_pin_t pin, int high) { int ipin = pin; struct ch573_gpio__gpio_port_t* port; if (pin & IS_PORT_B) { port = GPIO_PORT_B; ipin &= ~IS_PORT_B; } else { port = GPIO_PORT_A; } GPIO_PORT.out.set(port, !!high, ipin); } void gpio_enable_alternate_function(alternate_function_t afn, int enable) { if (enable) { GPIO_I.pin_alternate.set(GPIO, 1 << afn); } else { GPIO->pin_alternate &= ~(1 << afn); }; } #define PFIC ch573_pfic__pfic static void enable_gpio_pfic(int irq) { PFIC->interrupt_priority_threshold = 0x10; PFIC->interrupt_enable |= irq; } void gpio_enable_interrupt(gpio_pin_t pin, interrupt_mode_t int_mode) { int ipin = pin; struct ch573_gpio__gpio_port_t* port; volatile uint16_t* port_int_mode; volatile uint16_t* port_int_enable; volatile uint16_t* port_int_flag; if (pin & IS_PORT_B) { port = GPIO_PORT_B; ipin &= ~IS_PORT_B; port_int_mode = &GPIO->pb_interrupt_mode; port_int_flag = &GPIO->pb_interrupt_flag; port_int_enable = &GPIO->pb_interrupt_enable; enable_gpio_pfic(IRQ_GpioB); } else { port = GPIO_PORT_A; port_int_mode = &GPIO->pa_interrupt_mode; port_int_flag = &GPIO->pa_interrupt_flag; port_int_enable = &GPIO->pa_interrupt_enable; enable_gpio_pfic(IRQ_GpioA); } switch (int_mode) { case INT_MODE_FALLING_EDGE: *port_int_mode |= 1 << ipin; GPIO_PORT.clr.set(port, 1 << ipin); break; case INT_MODE_RISING_EDGE: *port_int_mode |= 1 << ipin; GPIO_PORT.out.set(port, 1, ipin); break; case INT_MODE_LEVEL_HIGH: *port_int_mode &= ~(1 << ipin); GPIO_PORT.out.set(port, 1, ipin); break; case INT_MODE_LEVEL_LOW: *port_int_mode &= ~(1 << ipin); GPIO_PORT.clr.set(port, 1 << ipin); break; } *port_int_flag = 1 << ipin; *port_int_enable |= 1 << ipin; } extern gpio_callback_t GPIO_LISTENERS_START; extern gpio_callback_t GPIO_LISTENERS_END; void fire_irq(volatile uint16_t* int_flag_ptr, int is_port_b) { gpio_callback_t* cur = &GPIO_LISTENERS_START; uint16_t pin = 0; uint16_t intflag = *int_flag_ptr; for (pin = 0; pin < 16; ++pin) { if (intflag & (1 << pin)) { // If this pin triggered an interrupt, fire the GPIO listeners. for (cur = &GPIO_LISTENERS_START; cur < &GPIO_LISTENERS_END; ++cur) { (*cur)(pin | is_port_b); } *int_flag_ptr |= 1 << pin; // Clear the interrupt for this pin. } } *int_flag_ptr = 0xffff; } IRQ(gpio_b) { fire_irq(&GPIO->pb_interrupt_flag, IS_PORT_B); } IRQ(gpio_a) { fire_irq(&GPIO->pa_interrupt_flag, 0); }