diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-12-08 14:22:05 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-12-08 14:22:05 -0700 |
commit | f89f75b5616de99865448f41b068a2783cd3648e (patch) | |
tree | 1e7599b8915d3fbb9a1a10892ba58fd44bea3f5d | |
parent | 546a5ccdba66dd8d8c19ce6d8486f46c84637cf2 (diff) | |
download | ch573-f89f75b5616de99865448f41b068a2783cd3648e.tar.gz ch573-f89f75b5616de99865448f41b068a2783cd3648e.tar.bz2 ch573-f89f75b5616de99865448f41b068a2783cd3648e.zip |
Cleaned up GPIO code quite a bit.
-rw-r--r-- | include/gpio.h | 88 | ||||
-rw-r--r-- | linker/ls.ld | 8 | ||||
-rw-r--r-- | src/btsel.c | 10 | ||||
-rw-r--r-- | src/gpio.c | 168 | ||||
-rw-r--r-- | src/main.c | 38 | ||||
-rw-r--r-- | src/systick.c | 4 |
6 files changed, 282 insertions, 34 deletions
diff --git a/include/gpio.h b/include/gpio.h new file mode 100644 index 0000000..ab793f1 --- /dev/null +++ b/include/gpio.h @@ -0,0 +1,88 @@ +#pragma once + +#include "ch573/gpio.h" + +#define GPIO_PORT_A ch573_gpio__gpio_port_a +#define GPIO_PORT_B ch573_gpio__gpio_port_b +#define GPIO_PORT CH573_GPIO__GPIO_PORT_T_INTF +#define GPIO_I CH573_GPIO__GPIO_T_INTF +#define GPIO ch573_gpio__gpio + +#define IS_PORT_B 0x80 + +typedef enum { + PIN_PA4 = 4, + PIN_PA5 = 5, + + PIN_PA8 = 8, + PIN_PA9 = 9, + PIN_PA10 = 10, + PIN_PA11 = 11, + PIN_PA12 = 12, + PIN_PA13 = 13, + PIN_PA14 = 14, + PIN_PA15 = 15, + + PIN_PB0 = IS_PORT_B | 0, + PIN_PB4 = IS_PORT_B | 4, + PIN_PB6 = IS_PORT_B | 6, + PIN_PB7 = IS_PORT_B | 7, + + PIN_PB10 = IS_PORT_B | 10, + PIN_PB11 = IS_PORT_B | 11, + PIN_PB12 = IS_PORT_B | 12, + PIN_PB13 = IS_PORT_B | 13, + PIN_PB14 = IS_PORT_B | 14, + PIN_PB15 = IS_PORT_B | 15, + + PIN_PB22 = IS_PORT_B | 8, + PIN_PB23 = IS_PORT_B | 9, +} gpio_pin_t; + +typedef enum { + PIN_CFG_INPUT_FLOATING, + PIN_CFG_INPUT_PULL_UP, + PIN_CFG_INPUT_PULL_DOWN, + PIN_CFG_OUTPUT_5mA, + PIN_CFG_OUTPUT_20mA, +} gpio_config_t; + +typedef enum { + AF_SPI = 8, + AF_UART1 = 5, + AF_UART0 = 4, + AF_TMR2 = 2, + AF_TMR1 = 1, + AF_TMR0 = 0, +} alternate_function_t; + +typedef enum { + INT_MODE_FALLING_EDGE, + INT_MODE_RISING_EDGE, + INT_MODE_LEVEL_HIGH, + INT_MODE_LEVEL_LOW +} interrupt_mode_t; + +typedef void (*gpio_callback_t)(gpio_pin_t pin); + +#define On_Gpio(arg) \ + static void __local_on_gpio__(gpio_pin_t pin); \ + __attribute__((__section__( \ + ".gpio_callbacks"))) static volatile gpio_callback_t __gpio__position = \ + __local_on_gpio__; \ + static void __local_on_gpio__(arg) + +/** Configure the given gpio pin for .*/ +void configure_gpio(gpio_pin_t pin, gpio_config_t); + +/** Read the input value of the gpio. */ +int read_gpio(gpio_pin_t pin); + +/** Sets the gpio pin. */ +void set_gpio(gpio_pin_t pin, int high); + +/** Set or unset the peripheral to the alternate set of pins. */ +void enable_alternate_funciton(alternate_function_t af, int enable); + +/** Enables the interrupt for a with the provided interrupt mode. */ +void enable_gpio_interrupt(gpio_pin_t pin, interrupt_mode_t int_mode); diff --git a/linker/ls.ld b/linker/ls.ld index 791647b..1a558a7 100644 --- a/linker/ls.ld +++ b/linker/ls.ld @@ -42,10 +42,10 @@ SECTIONS SYSTICK_LISTENERS_END = .; } > flash AT>flash - .bootsel_callbacks : ALIGN(0x04) { - BOOTSEL_LISTENERS_START = .; - KEEP(*(.bootsel_callbacks)); - BOOTSEL_LISTENERS_END = .; + .gpio_callbacks : ALIGN(0x04) { + GPIO_LISTENERS_START = .; + KEEP(*(.gpio_callbacks)); + GPIO_LISTENERS_END = .; } > flash AT>flash 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); +} @@ -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 <stdio.h> #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() |