From f89f75b5616de99865448f41b068a2783cd3648e Mon Sep 17 00:00:00 2001 From: Josh Rahm Date: Sun, 8 Dec 2024 14:22:05 -0700 Subject: Cleaned up GPIO code quite a bit. --- src/btsel.c | 10 ---- src/gpio.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 38 +++++++------ src/systick.c | 4 ++ 4 files changed, 190 insertions(+), 30 deletions(-) create mode 100644 src/gpio.c (limited to 'src') diff --git a/src/btsel.c b/src/btsel.c index 873b20a..c9c7e06 100644 --- a/src/btsel.c +++ b/src/btsel.c @@ -26,13 +26,3 @@ void enable_bootsel_button(void) GPIO_I.pb_interrupt_flag.set(GPIO, 1 << BOOTSEL_PIN); GPIO_I.pb_interrupt_enable.set(GPIO, 1 << BOOTSEL_PIN); } - -IRQ(gpio_b) -{ - bootsel_cb_t* cur = &BOOTSEL_LISTENERS_START; - while (cur != &BOOTSEL_LISTENERS_END) { - (*cur)(); - ++cur; - } - GPIO_I.pb_interrupt_flag.set(GPIO, 1 << BOOTSEL_PIN); -} diff --git a/src/gpio.c b/src/gpio.c new file mode 100644 index 0000000..e016179 --- /dev/null +++ b/src/gpio.c @@ -0,0 +1,168 @@ +#include "gpio.h" + +#include "ch573/pfic.h" +#include "isr_vector.h" + +void configure_gpio(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 read_gpio(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 set_gpio(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 enable_alternate_function(alternate_function_t afn) +{ + GPIO_I.pin_alternate.set(GPIO, 1 << afn); +} + +#define PFIC ch573_pfic__pfic +static void enable_gpio_pfic(int irq) +{ + PFIC->interrupt_priority_threshold = 0x10; + PFIC->interrupt_enable |= irq; +} + +void enable_gpio_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); +} diff --git a/src/main.c b/src/main.c index 8deb257..525db53 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,7 @@ #include "system.h" #include "systick.h" #include "ws2812b.h" +#include "gpio.h" #ifndef LED_BYTE_ORDER #define LED_BYTE_ORDER GRB @@ -61,7 +62,6 @@ uint8_t amp(uint8_t in, uint8_t n) return min(out, 255); } - static void set_system_clock_60Mhz(void) { clock_cfg_t clk_cfg = {0}; @@ -74,7 +74,7 @@ static void set_system_clock_60Mhz(void) } #define N_LEDS 255 -#define N_DMA_XFER 3 +#define N_DMA_XFER 4 extern int uart1_FILE_get(FILE* f); @@ -89,24 +89,26 @@ static size_t debounce = 0; On_SysTick() { if (debounce > 0) { - debounce --; + debounce--; } time++; spin_lock = 0; } -On_BootSelPress() +On_Gpio(gpio_pin_t pin) { - if (debounce > 0) return; - debounce = 10; - - size_t tmp = current_pattern_idx; - tmp ++; - if (tmp >= n_patterns) { - tmp = 0; + if (pin == PIN_PB7) { + if (debounce > 0) return; + debounce = 10; + + size_t tmp = current_pattern_idx; + tmp++; + if (tmp >= n_patterns) { + tmp = 0; + } + current_pattern_idx = tmp; + printf("Switch to '%s'\n", patterns[current_pattern_idx].name); } - current_pattern_idx = tmp; - printf("Switch to '%s'\n", patterns[current_pattern_idx].name); } /* @@ -117,12 +119,6 @@ int main(void) char buf[N_LEDS * TOTAL_BYTES_PER_LED]; PFIC_I.vector_table_control.set(PFIC, 1); - PFIC->interrupt_priority_threshold = 0x10; - PFIC->interrupt_enable |= IRQ_SysTick; - PFIC->interrupt_priority_threshold = 0x10; - PFIC->interrupt_enable |= IRQ_GpioA; - PFIC->interrupt_priority_threshold = 0x10; - PFIC->interrupt_enable |= IRQ_GpioB; set_system_clock_60Mhz(); set_systick(250000); @@ -148,7 +144,9 @@ int main(void) printf("\nRunning Pattern '%s'\n", patterns[current_pattern_idx].name); - enable_bootsel_button(); + configure_gpio(PIN_PB7, PIN_CFG_INPUT_PULL_UP); + enable_gpio_interrupt(PIN_PB7, INT_MODE_FALLING_EDGE); + // enable_bootsel_button(); size_t n = sizeof(buf); struct ws2812b_buf ws_buf; diff --git a/src/systick.c b/src/systick.c index 3cd7bfa..4b57702 100644 --- a/src/systick.c +++ b/src/systick.c @@ -3,10 +3,12 @@ #include #include "ch573/systick.h" +#include "ch573/pfic.h" #include "isr_vector.h" #define SYSTICK_I CH573_SYSTICK__SYSTICK_T_INTF #define SYSTICK ch573_systick__systick +#define PFIC ch573_pfic__pfic void set_systick(uint64_t systick) { @@ -15,6 +17,8 @@ void set_systick(uint64_t systick) SYSTICK_I.cfg.interrupt_enable.set(SYSTICK, 1); SYSTICK_I.cfg.enabled.set(SYSTICK, ENABLED); + PFIC->interrupt_priority_threshold = 0x10; + PFIC->interrupt_enable |= IRQ_SysTick; } uint64_t get_systick() -- cgit