aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2024-12-08 14:22:05 -0700
committerJosh Rahm <joshuarahm@gmail.com>2024-12-08 14:22:05 -0700
commitf89f75b5616de99865448f41b068a2783cd3648e (patch)
tree1e7599b8915d3fbb9a1a10892ba58fd44bea3f5d
parent546a5ccdba66dd8d8c19ce6d8486f46c84637cf2 (diff)
downloadch573-f89f75b5616de99865448f41b068a2783cd3648e.tar.gz
ch573-f89f75b5616de99865448f41b068a2783cd3648e.tar.bz2
ch573-f89f75b5616de99865448f41b068a2783cd3648e.zip
Cleaned up GPIO code quite a bit.
-rw-r--r--include/gpio.h88
-rw-r--r--linker/ls.ld8
-rw-r--r--src/btsel.c10
-rw-r--r--src/gpio.c168
-rw-r--r--src/main.c38
-rw-r--r--src/systick.c4
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);
+}
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 <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()