aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--02-usart/include/arch/arm/arch.h1
-rw-r--r--02-usart/include/arch/stm32l4xxx/peripherals/gpio.h302
-rw-r--r--02-usart/include/arch/stm32l4xxx/peripherals/rcc.h8
-rw-r--r--02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc100
-rw-r--r--02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc26
-rw-r--r--02-usart/include/arch/x86_64/arch.h1
-rw-r--r--02-usart/include/kern/gpio/gpio_manager.h187
-rw-r--r--02-usart/include/kern/gpio/sysled.h11
-rw-r--r--02-usart/include/kern/spin.h15
-rw-r--r--02-usart/src/arch/stm32l4xxx/peripherals/clock.c1
-rw-r--r--02-usart/src/arch/stm32l4xxx/peripherals/gpio.c52
-rw-r--r--02-usart/src/arch/stm32l4xxx/peripherals/irq.c26
-rw-r--r--02-usart/src/kern/dma/dma_manager.c1
-rw-r--r--02-usart/src/kern/gpio/gpio_manager.c402
-rw-r--r--02-usart/src/kern/gpio/sysled.c14
-rw-r--r--02-usart/src/kern/main.c39
-rw-r--r--02-usart/src/kern/spin.c49
-rw-r--r--02-usart/tests/test_gpio.c194
18 files changed, 1003 insertions, 426 deletions
diff --git a/02-usart/include/arch/arm/arch.h b/02-usart/include/arch/arm/arch.h
index 42b33bb..22d0987 100644
--- a/02-usart/include/arch/arm/arch.h
+++ b/02-usart/include/arch/arm/arch.h
@@ -20,6 +20,7 @@
#define GPIOA_BASE (0x48000000)
#define GPIOB_BASE (0x48000400)
#define GPIOC_BASE (0x48000800)
+#define GPIOH_BASE (0x48001C00)
#define SRAM1_BASE (0x20000000)
#define SRAM2_BASE (0x2000C000)
diff --git a/02-usart/include/arch/stm32l4xxx/peripherals/gpio.h b/02-usart/include/arch/stm32l4xxx/peripherals/gpio.h
index 20acf71..944d725 100644
--- a/02-usart/include/arch/stm32l4xxx/peripherals/gpio.h
+++ b/02-usart/include/arch/stm32l4xxx/peripherals/gpio.h
@@ -7,320 +7,60 @@
#include <stdint.h>
/*
- * Possible GPIO ports.
- */
-typedef enum {
- GPIO_PORT_A = 0,
- GPIO_PORT_B = 1,
- GPIO_PORT_C = 2,
- GPIO_PORT_D = 3
-} gpio_port_number_t;
-
-/*
* Structure defining the layout of the layout of the GPIO registers on the
* stm32l432 development board.
*/
typedef struct GPIO_PORT_STR {
/* Mode of each GPIO pin for this GPIO port. */
-#define gpio_mode0 (3 << 0)
-#define gpio_mode1 (3 << 2)
-#define gpio_mode2 (3 << 4)
-#define gpio_mode3 (3 << 6)
-#define gpio_mode4 (3 << 8)
-#define gpio_mode5 (3 << 10)
-#define gpio_mode6 (3 << 12)
-#define gpio_mode7 (3 << 14)
-#define gpio_mode8 (3 << 16)
-#define gpio_mode9 (3 << 18)
-#define gpio_mode10 (3 << 20)
-#define gpio_mode11 (3 << 22)
-#define gpio_mode12 (3 << 24)
-#define gpio_mode13 (3 << 26)
-#define gpio_mode14 (3 << 28)
-#define gpio_mode15 (3 << 30)
+#define gpio_mode_n(off) (3 << ((off) * 2))
__IO uint32_t mode_r; /* Mode register */
/* Output type for each gpio pin in this port. */
-#define gpio_otype0 (1 << 0)
-#define gpio_otype1 (1 << 1)
-#define gpio_otype2 (1 << 2)
-#define gpio_otype3 (1 << 3)
-#define gpio_otype4 (1 << 4)
-#define gpio_otype5 (1 << 5)
-#define gpio_otype6 (1 << 6)
-#define gpio_otype7 (1 << 7)
-#define gpio_otype8 (1 << 8)
-#define gpio_otype9 (1 << 9)
-#define gpio_otype10 (1 << 10)
-#define gpio_otype11 (1 << 11)
-#define gpio_otype12 (1 << 12)
-#define gpio_otype13 (1 << 13)
-#define gpio_otype14 (1 << 14)
-#define gpio_otype15 (1 << 15)
+#define gpio_otype_n(off) (1 << (off))
__IO uint32_t otype_r;
/* GPIO port output speed. */
-#define gpio_ospeed0 (3 << 0)
-#define gpio_ospeed1 (3 << 2)
-#define gpio_ospeed2 (3 << 4)
-#define gpio_ospeed3 (3 << 6)
-#define gpio_ospeed4 (3 << 8)
-#define gpio_ospeed5 (3 << 10)
-#define gpio_ospeed6 (3 << 12)
-#define gpio_ospeed7 (3 << 14)
-#define gpio_ospeed8 (3 << 16)
-#define gpio_ospeed9 (3 << 18)
-#define gpio_ospeed10 (3 << 20)
-#define gpio_ospeed11 (3 << 22)
-#define gpio_ospeed12 (3 << 24)
-#define gpio_ospeed13 (3 << 26)
-#define gpio_ospeed14 (3 << 28)
-#define gpio_ospeed15 (3 << 30)
+#define gpio_ospeed_n(off) (3 << ((off) * 2))
__IO uint32_t ospeed_r;
/* GPIO port pull-up/pull-down register */
-#define gpio_pupd0 (3 << 0)
-#define gpio_pupd1 (3 << 2)
-#define gpio_pupd2 (3 << 4)
-#define gpio_pupd3 (3 << 6)
-#define gpio_pupd4 (3 << 8)
-#define gpio_pupd5 (3 << 10)
-#define gpio_pupd6 (3 << 12)
-#define gpio_pupd7 (3 << 14)
-#define gpio_pupd8 (3 << 16)
-#define gpio_pupd9 (3 << 18)
-#define gpio_pupd10 (3 << 20)
-#define gpio_pupd11 (3 << 22)
-#define gpio_pupd12 (3 << 24)
-#define gpio_pupd13 (3 << 26)
-#define gpio_pupd14 (3 << 28)
-#define gpio_pupd15 (3 << 30)
+#define gpio_pupd_n(off) (3 << ((off) * 2))
__IO uint32_t pupd_r;
/* GPIO port input data register. */
-#define gpio_idr0 (1 << 0)
-#define gpio_idr1 (1 << 1)
-#define gpio_idr2 (1 << 2)
-#define gpio_idr3 (1 << 3)
-#define gpio_idr4 (1 << 4)
-#define gpio_idr5 (1 << 5)
-#define gpio_idr6 (1 << 6)
-#define gpio_idr7 (1 << 7)
-#define gpio_idr8 (1 << 8)
-#define gpio_idr9 (1 << 9)
-#define gpio_idr10 (1 << 10)
-#define gpio_idr11 (1 << 11)
-#define gpio_idr12 (1 << 12)
-#define gpio_idr13 (1 << 13)
-#define gpio_idr14 (1 << 14)
-#define gpio_idr15 (1 << 15)
+#define gpio_idr_n(off) (1 << (off))
__IO uint32_t id_r;
/* GPIO port output data register. */
-#define gpio_odr0 (1 << 0)
-#define gpio_odr1 (1 << 1)
-#define gpio_odr2 (1 << 2)
-#define gpio_odr3 (1 << 3)
-#define gpio_odr4 (1 << 4)
-#define gpio_odr5 (1 << 5)
-#define gpio_odr6 (1 << 6)
-#define gpio_odr7 (1 << 7)
-#define gpio_odr8 (1 << 8)
-#define gpio_odr9 (1 << 9)
-#define gpio_odr10 (1 << 10)
-#define gpio_odr11 (1 << 11)
-#define gpio_odr12 (1 << 12)
-#define gpio_odr13 (1 << 13)
-#define gpio_odr14 (1 << 14)
-#define gpio_odr15 (1 << 15)
- __IO uint32_t output_r;
+#define gpio_odr_n(off) (1 << (off))
+ __IO uint32_t od_r;
/* GPIO port bit set/reset register. */
-#define gpio_bs0 (1 << 0)
-#define gpio_bs1 (1 << 1)
-#define gpio_bs2 (1 << 2)
-#define gpio_bs3 (1 << 3)
-#define gpio_bs4 (1 << 4)
-#define gpio_bs5 (1 << 5)
-#define gpio_bs6 (1 << 6)
-#define gpio_bs7 (1 << 7)
-#define gpio_bs8 (1 << 8)
-#define gpio_bs9 (1 << 9)
-#define gpio_bs10 (1 << 10)
-#define gpio_bs11 (1 << 11)
-#define gpio_bs12 (1 << 12)
-#define gpio_bs13 (1 << 13)
-#define gpio_bs14 (1 << 14)
-#define gpio_bs15 (1 << 15)
-#define gpio_br0 (1 << 16)
-#define gpio_br1 (1 << 17)
-#define gpio_br2 (1 << 18)
-#define gpio_br3 (1 << 19)
-#define gpio_br4 (1 << 20)
-#define gpio_br5 (1 << 21)
-#define gpio_br6 (1 << 22)
-#define gpio_br7 (1 << 23)
-#define gpio_br8 (1 << 24)
-#define gpio_br9 (1 << 25)
-#define gpio_br10 (1 << 26)
-#define gpio_br11 (1 << 27)
-#define gpio_br12 (1 << 28)
-#define gpio_br13 (1 << 29)
-#define gpio_br14 (1 << 30)
-#define gpio_br15 (1 << 31)
+#define gpio_bs_n(off) (1 << (off))
+#define gpio_br_n(off) (1 << (off))
__IO uint32_t bsr_r;
/* GPIO port configuration lock register. */
-#define gpio_lck0 (1 << 0)
-#define gpio_lck1 (1 << 1)
-#define gpio_lck2 (1 << 2)
-#define gpio_lck3 (1 << 3)
-#define gpio_lck4 (1 << 4)
-#define gpio_lck5 (1 << 5)
-#define gpio_lck6 (1 << 6)
-#define gpio_lck7 (1 << 7)
-#define gpio_lck8 (1 << 8)
-#define gpio_lck9 (1 << 9)
-#define gpio_lck10 (1 << 10)
-#define gpio_lck11 (1 << 11)
-#define gpio_lck12 (1 << 12)
-#define gpio_lck13 (1 << 13)
-#define gpio_lck14 (1 << 14)
-#define gpio_lck15 (1 << 15)
+#define gpio_lck_n(off) (1 << (off))
#define gpio_lckk (1 << 16)
__IO uint32_t lck_r;
/* Alternate function low-register. */
-#define gpio_afsel0 (0xF << 0)
-#define gpio_afsel1 (0xF << 4)
-#define gpio_afsel2 (0xF << 8)
-#define gpio_afsel3 (0xF << 12)
-#define gpio_afsel4 (0xF << 16)
-#define gpio_afsel5 (0xF << 20)
-#define gpio_afsel6 (0xF << 24)
-#define gpio_afsel7 (0xF << 28)
+#define gpio_afsel_n(off) (0xf << ((off) * 4))
__IO uint32_t af_rl;
-
/* Alternate function high-register. */
-#define gpio_afsel8 (0xF << 0)
-#define gpio_afsel9 (0xF << 4)
-#define gpio_afsel10 (0xF << 8)
-#define gpio_afsel11 (0xF << 12)
-#define gpio_afsel12 (0xF << 16)
-#define gpio_afsel13 (0xF << 20)
-#define gpio_afsel14 (0xF << 24)
-#define gpio_afsel15 (0xF << 28)
__IO uint32_t af_rh;
-} PACKED gpio_port_t;
-/*
- * Enum defining the PINs in a GPIO port. Each port has 16 pins to use in
- * the stm32l432.
- */
-typedef enum GPIO_PIN_ENUM {
- PIN_0 = 0,
- PIN_1 = 1,
- PIN_2 = 2,
- PIN_3 = 3,
- PIN_4 = 4,
- PIN_5 = 5,
- PIN_6 = 6,
- PIN_7 = 7,
- PIN_8 = 8,
- PIN_9 = 9,
- PIN_10 = 10,
- PIN_11 = 11,
- PIN_12 = 12,
- PIN_13 = 13,
- PIN_14 = 14,
- PIN_15 = 15
-} gpio_pin_t;
+ /* GPIO port bit register. */
+#define gpio_br_n(off) (1 << (off))
+ __IO uint32_t br_r;
-/* Alternate function number. */
-typedef enum {
- AFN_0 = 0,
- AFN_1 = 1,
- AFN_2 = 2,
- AFN_3 = 3,
- AFN_4 = 4,
- AFN_5 = 5,
- AFN_6 = 6,
- AFN_7 = 7,
- AFN_8 = 8,
- AFN_9 = 9,
- AFN_10 = 10,
- AFN_11 = 11,
- AFN_12 = 12,
- AFN_13 = 13,
- AFN_14 = 14,
- AFN_15 = 15
-} alternate_function_t;
-
-/*
- * Enum defining the pin modes that are possible.
- */
-typedef enum {
- MODE_INPUT = 0,
- MODE_OUTPUT = 1,
- MODE_ALTERNATE = 2,
- MODE_ANALOG = 3
-} gpio_pin_mode_t;
-
-/*
- * Enum defining the pin speeds that are possible.
- */
-typedef enum {
- SPEED_2MHZ = 0,
- SPEED_10MHZ = 1,
- SPEED_50MHZ = 3,
-} speed_t;
-
-/*
- * Structure defining an OUTPUT pin. Structurally equivalent to the input pin,
- * but can be used in a slightly type-safe manner.
- */
-typedef struct {
- __IO gpio_port_t* gpio_port;
- gpio_pin_t pin;
-} gpio_output_pin_t;
-
-/*
- * Sets the mode on a GPIO pin.
- *
- * gpio_port: the gpio port to use.
- * pin: the pin number to set.
- * pin_mode: the mode to set the pin to.
- */
-void set_gpio_pin_mode(
- __IO gpio_port_t* gpio_port, gpio_pin_t pin, gpio_pin_mode_t pin_mode);
-
-/*
- * Sets the given GPIO pin to be an output pin. Returns an output_pin struct
- * corresponding to
- */
-gpio_output_pin_t set_gpio_pin_output(
- __IO gpio_port_t* gpio_port, gpio_pin_t pin);
-
-/*
- * Sets an output pin on or off.
- *
- * pin: the pin to toggle.
- * onoff: 0 for off, non-zero of on.
- */
-void set_gpio_output_pin(gpio_output_pin_t pin, bool onoff);
-
-#define pin_on(p) set_gpio_output_pin(p, 1)
-
-#define pin_off(p) set_gpio_output_pin(p, 0)
-
-/*
- * Enables a GPIO port and returns a reference to the register definition
- * of that GPIO port.
- */
-__IO gpio_port_t* enable_gpio(gpio_port_number_t number);
+ /* Analog switch control register. */
+#define gpio_asc_n(off) (1 << (off))
+ __IO uint32_t asc_r;
+} PACKED gpio_port_config_t;
-/* Sets the alternate function for a GPIO pin. */
-void set_gpio_alternate_function(
- __IO gpio_port_t* port, gpio_pin_t gpio_pin, alternate_function_t afn);
+static_assert(
+ offsetof(gpio_port_config_t, asc_r) == 0x2C, "Offset check failed");
-#endif /* CORE_GPIO_H__ */
+#endif
diff --git a/02-usart/include/arch/stm32l4xxx/peripherals/rcc.h b/02-usart/include/arch/stm32l4xxx/peripherals/rcc.h
index 861504e..de7b568 100644
--- a/02-usart/include/arch/stm32l4xxx/peripherals/rcc.h
+++ b/02-usart/include/arch/stm32l4xxx/peripherals/rcc.h
@@ -63,6 +63,14 @@ typedef struct {
#define rcc_tscen (1 << 16) /* Touch sensing controller clock enable. */
#define rcc_dmad2en (1 << 17) /* DMA2D clock enabled. */
__IO uint32_t ahb1en_r; /* AHB1 Peripheral enable register. 0x48 */
+
+#define rcc_gpioen(port) (1 << (port))
+#define rcc_otgfsen (1 << 12)
+#define rcc_adcen (1 << 13)
+#define rcc_dcmien (1 << 14)
+#define rcc_assen (1 << 16)
+#define rcc_hashen (1 << 17)
+#define rcc_rngen (1 << 18)
__IO uint32_t ahb2en_r; /* AHB2 Peripheral enable register. 0x4C */
__IO uint32_t ahb3en_r; /* AHB3 Peripheral enable register. 0x50 */
diff --git a/02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc b/02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc
new file mode 100644
index 0000000..66d347c
--- /dev/null
+++ b/02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc
@@ -0,0 +1,100 @@
+AFN(CAN1_RX, 9, PA11)
+AFN(CAN1_TX, 9, PA12)
+AFN(COMP1_OUT, 12, PA0, 12, PB0, 6, PA11, 6, PA6)
+AFN(COMP2_OUT, 12, PA2, 12, PA7, 12, PB5)
+AFN(I2C1_SCL, 4, PA9, 4, PB6)
+AFN(I2C1_SDA, 4, PA10, 4, PB7)
+AFN(I2C1_SMBA, 4, PA14, 4, PA1, 4, PB5)
+AFN(I2C3_SCL, 4, PA7)
+AFN(I2C3_SDA, 4, PB4)
+AFN(IR_OUT, 1, PA13)
+AFN(JTCK_SWCLK, 0, PA14)
+AFN(JTDI, 0, PA15)
+AFN(JTDO_TRACESWO, 0, PB3)
+AFN(JTMS_SWDIO, 0, PA13)
+AFN(LPTIM1_ETR, 1, PB6)
+AFN(LPTIM1_IN1, 1, PB5)
+AFN(LPTIM1_IN2, 1, PB7)
+AFN(LPTIM1_OUT, 1, PA14)
+AFN(LPTIM2_ETR, 14, PA5)
+AFN(LPTIM2_IN1, 14, PB1)
+AFN(LPTIM2_OUT, 14, PA4, 14, PA8)
+AFN(LPUART1_CTS, 8, PA6)
+AFN(LPUART1_RTS_DE, 8, PB1)
+AFN(LPUART1_RX, 8, PA3)
+AFN(LPUART1_TX, 8, PA2)
+AFN(MCO, 0, PA8)
+AFN(NJTRST, 0, PB4)
+AFN(QUADSPI_BK1_IO0, 10, PB1)
+AFN(QUADSPI_BK1_IO1, 10, PB0)
+AFN(QUADSPI_BK1_IO2, 10, PA7)
+AFN(QUADSPI_BK1_IO3, 10, PA6)
+AFN(QUADSPI_BK1_NCS, 10, PA2)
+AFN(QUADSPI_CLK, 10, PA3)
+AFN(SAI1_EXTCLK, 13, PA0, 13, PB0)
+AFN(SAI1_FS_A, 13, PA9)
+AFN(SAI1_FS_B, 13, PA14, 13, PA4, 13, PB6)
+AFN(SAI1_MCLK_A, 13, PA3)
+AFN(SAI1_MCLK_B, 13, PB4)
+AFN(SAI1_SCK_A, 13, PA8)
+AFN(SAI1_SCK_B, 13, PB3)
+AFN(SAI1_SD_A, 13, PA10)
+AFN(SAI1_SD_B, 13, PA13, 13, PB5)
+AFN(SPI1_MISO, 5, PA11, 5, PA6, 5, PB4)
+AFN(SPI1_MOSI, 5, PA12, 5, PA7, 5, PB5)
+AFN(SPI1_NSS, 5, PA15, 5, PA4, 5, PB0)
+AFN(SPI1_SCK, 5, PA1, 5, PA5, 5, PB3)
+AFN(SPI3_MISO, 6, PB4)
+AFN(SPI3_MOSI, 6, PB5)
+AFN(SPI3_NSS, 6, PA15, 6, PA4)
+AFN(SPI3_SCK, 6, PB3)
+AFN(SWPMI1_IO, 12, PA8)
+AFN(SWPMI1_RX, 12, PA14)
+AFN(SWPMI1_SUSPEND, 12, PA15)
+AFN(SWPMI1_TX, 12, PA13)
+AFN(TIM15_BKIN, 14, PA9)
+AFN(TIM15_CH1, 14, PA2)
+AFN(TIM15_CH1N, 14, PA1)
+AFN(TIM15_CH2, 14, PA3)
+AFN(TIM16_BKIN, 14, PB5)
+AFN(TIM16_CH1, 14, PA6)
+AFN(TIM16_CH1N, 14, PB6)
+AFN(TIM1_BKIN, 1, PA6)
+AFN(TIM1_BKIN2, 2, PA11)
+AFN(TIM1_BKIN2_COMP1, 12, PA11)
+AFN(TIM1_BKIN_COMP2, 12, PA6)
+AFN(TIM1_CH1, 1, PA8)
+AFN(TIM1_CH1N, 1, PA7)
+AFN(TIM1_CH2, 1, PA9)
+AFN(TIM1_CH2N, 1, PB0)
+AFN(TIM1_CH3, 1, PA10)
+AFN(TIM1_CH3N, 1, PB1)
+AFN(TIM1_CH4, 1, PA11)
+AFN(TIM1_ETR, 1, PA12)
+AFN(TIM2_CH1, 1, PA0, 1, PA15, 1, PA5)
+AFN(TIM2_CH2, 1, PA1, 1, PB3)
+AFN(TIM2_CH3, 1, PA2)
+AFN(TIM2_CH4, 1, PA3)
+AFN(TIM2_ETR, 14, PA0, 2, PA15, 2, PA5)
+AFN(TSC_G2_IO1, 9, PB4)
+AFN(TSC_G2_IO2, 9, PB5)
+AFN(TSC_G2_IO3, 9, PB6)
+AFN(TSC_G2_IO4, 9, PB7)
+AFN(TSC_G3_IO1, 9, PA15)
+AFN(USART1_CK, 7, PA8, 7, PB5)
+AFN(USART1_CTS, 7, PA11, 7, PB4)
+AFN(USART1_RTS_DE, 7, PA12, 7, PB3)
+AFN(USART1_RX, 7, PA10, 7, PB7)
+AFN(USART1_TX, 7, PA9, 7, PB6)
+AFN(USART2_CK, 7, PA4)
+AFN(USART2_CTS, 7, PA0)
+AFN(USART2_RTS_DE, 7, PA1)
+AFN(USART2_RX, 3, PA15, 7, PA3)
+AFN(USART2_TX, 7, PA2)
+AFN(USART3_CK, 7, PB0)
+AFN(USART3_CTS, 7, PA6)
+AFN(USART3_RTS_DE, 7, PA15, 7, PB1)
+AFN(USB_CRS_SYNC, 10, PA10)
+AFN(USB_DM, 10, PA11)
+AFN(USB_DP, 10, PA12)
+AFN(USB_NOE, 10, PA13)
diff --git a/02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc b/02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc
new file mode 100644
index 0000000..21c7234
--- /dev/null
+++ b/02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc
@@ -0,0 +1,26 @@
+PORT(A, 0)
+PORT(A, 1)
+PORT(A, 2)
+PORT(A, 3)
+PORT(A, 4)
+PORT(A, 5)
+PORT(A, 6)
+PORT(A, 7)
+PORT(A, 8)
+PORT(A, 9)
+PORT(A, 10)
+PORT(A, 11)
+PORT(A, 12)
+PORT(A, 13)
+PORT(A, 14)
+PORT(A, 15)
+PORT(B, 0)
+PORT(B, 1)
+PORT(B, 3)
+PORT(B, 4)
+PORT(B, 5)
+PORT(B, 6)
+PORT(B, 7)
+PORT(C, 14)
+PORT(C, 15)
+PORT(H, 3)
diff --git a/02-usart/include/arch/x86_64/arch.h b/02-usart/include/arch/x86_64/arch.h
index 5e1217c..c17721d 100644
--- a/02-usart/include/arch/x86_64/arch.h
+++ b/02-usart/include/arch/x86_64/arch.h
@@ -17,6 +17,7 @@
#define GPIOA_BASE (load_fake_ahb2__() + 0x0)
#define GPIOB_BASE (load_fake_ahb2__() + 0x400)
#define GPIOC_BASE (load_fake_ahb2__() + 0x800)
+#define GPIOH_BASE (load_fake_ahb2__() + 0x1C00)
#define SRAM1_BASE (load_fake_sram1__() + 0x0)
#define SRAM2_BASE (load_fake_sram2__() + 0x0)
diff --git a/02-usart/include/kern/gpio/gpio_manager.h b/02-usart/include/kern/gpio/gpio_manager.h
new file mode 100644
index 0000000..922a423
--- /dev/null
+++ b/02-usart/include/kern/gpio/gpio_manager.h
@@ -0,0 +1,187 @@
+#ifndef KERN_GPIO_GPIO_MANAGE_H_
+#define KERN_GPIO_GPIO_MANAGE_H_
+
+#include "kern/common.h"
+#include "arch/stm32l4xxx/peripherals/gpio.h"
+
+#define GPIO_ERROR_IN_USE 1
+#define GPIO_ERROR_INVALID_PIN_FOR_ALTERNATE_FUNCTION 2
+#define GPIO_ERROR_INVALID_PIN 3
+
+typedef enum {
+/* Creates vaules GPIO_PIN_<port><num> i.e. GPIO_PIN_A0 */
+#define PORT(p, pn) \
+ GPIO_PIN_P ## p ## pn,
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+#undef PORT
+
+ N_GPIO_PINS
+} gpio_pin_t;
+
+/* Alternate functions. */
+typedef enum {
+#define AFN(fn, ...) \
+ GPIO_ALTERNATE_FUNCTION_ ## fn,
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc"
+#undef AFN
+ GPIO_ALTERNATE_FUNCTION_EVENTOUT,
+} gpio_alternate_function_t;
+
+#define gpio_pin_for_alternate_function(af) ((af) / 16)
+#define gpio_pin_out_of_range(pin) \
+ ((pin) < 0 || (pin) >= N_GPIO_PINS)
+
+typedef enum {
+ GPIO_PORT_A,
+ GPIO_PORT_B,
+ GPIO_PORT_C,
+ GPIO_PORT_D,
+ GPIO_PORT_E,
+ GPIO_PORT_F,
+ GPIO_PORT_G,
+ GPIO_PORT_H,
+ GPIO_PORT_I,
+
+ N_GPIO_PORTS,
+} gpio_port_t;
+
+typedef enum {
+ GPIO_MODE_INPUT,
+ GPIO_MODE_OUTPUT,
+ GPIO_MODE_ALTERNATE,
+ GPIO_MODE_ANALOG
+} gpio_mode_t;
+
+/*
+ * Enum defining the pin speeds that are possible.
+ */
+typedef enum {
+ SPEED_2MHZ = 0,
+ SPEED_10MHZ = 1,
+ SPEED_50MHZ = 3,
+} gpio_speed_t;
+
+typedef enum {
+ GPIO_OUTPUT_TYPE_PUSH_PULL,
+ GPIO_OUTPUT_TYPE_OPEN_DRAIN
+} gpio_output_type_t;
+
+typedef enum {
+ GPIO_OUTPUT_SPEED_LOW,
+ GPIO_OUTPUT_SPEED_MEDIUM,
+ GPIO_OUTPUT_SPEED_HIGH,
+ GPIO_OUTPUT_SPEED_VERY_HIGH,
+} gpio_output_speed_t;
+
+typedef enum {
+ GPIO_PULL_DIR_NONE,
+ GPIO_PULL_DIR_UP,
+ GPIO_PULL_DIR_DOWN,
+} gpio_pull_dir_t;
+
+/* Returns the appropriate gpio_port for the provided pin. */
+inline static gpio_port_t get_port_for_pin(gpio_pin_t pin)
+{
+ switch (pin) {
+#define PORT(p, pn) \
+ case GPIO_PIN_P ## p ## pn: return GPIO_PORT_ ## p;
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+#undef PORT
+ case N_GPIO_PINS: return N_GPIO_PORTS;
+ }
+
+ /* Should be unreachable. */
+}
+
+#define DEFAULT_GPIO_OPTS_OUTPUT \
+ (gpio_pin_opts_t) { \
+ .mode = GPIO_MODE_OUTPUT, \
+ .pull_dir = GPIO_PULL_DIR_DOWN, \
+ .output_opts.speed = GPIO_OUTPUT_SPEED_MEDIUM, \
+ .output_opts.type = GPIO_OUTPUT_TYPE_PUSH_PULL, \
+ }
+
+#define DEFAULT_GPIO_OPTS_INPUT \
+ (gpio_pin_opts_t) { \
+ .mode = GPIO_MODE_OUTPUT, \
+ .pull_dir = GPIO_PULL_DIR_DOWN, \
+ }
+
+typedef struct {
+ gpio_mode_t mode;
+ gpio_pull_dir_t pull_dir;
+
+ union {
+ struct {
+ } input_opts;
+
+ struct {
+ gpio_output_speed_t speed;
+ gpio_output_type_t type;
+ } output_opts;
+
+ struct {
+ uint8_t function;
+ } alternate_opts;
+
+ struct {
+ } analog_opts;
+ };
+} gpio_pin_opts_t;
+
+/* Differentiates at compile-time from the a gpio_pin_t enum value and a pin
+ * that's been reserved. */
+typedef struct {
+ gpio_pin_t v_;
+} gpio_reserved_pin_t;
+
+/* Returns a pointer to the GPIO pin bus and offset. This is useful for when
+ * raw access to the values are needed. I.e. time critical applications. */
+void get_gpio_pin_port_off(
+ gpio_pin_t pin, gpio_port_config_t** out_cfg, int* out_off);
+
+/* Sets the given GPIO pin to high. */
+void set_gpio_pin_high(gpio_reserved_pin_t pin);
+
+/* Sets the given GPIO pin to low. */
+void set_gpio_pin_low(gpio_reserved_pin_t pin);
+
+/** returns true if a GPIO pin is in use. */
+bool gpio_pin_in_use(gpio_pin_t pin);
+
+/*
+ * Reserve the provided GPIO pin using the opts provided.
+ *
+ * sets error_out to GPIO_ERROR_IN_USE if the GPIO pin could not be reserved
+ * because it already has been reserved.
+ *
+ * The function will automatically enable the correct GPIO port bus.
+ */
+gpio_reserved_pin_t reserve_gpio_pin(
+ gpio_pin_t pin, gpio_pin_opts_t* opts, int* error_out);
+
+/* Enables and returns the pin reserved for the alternate function.
+ *
+ * If the `hint` parameter is defined (non -1) the manager will try
+ * to reserve that pin for the alternate function and fail if it can't.
+ *
+ * If `hint` is -1 then the first available pin for that alternate function
+ * will be reserved and returned.
+ *
+ *
+ */
+gpio_reserved_pin_t gpio_enable_alternate_function(
+ gpio_alternate_function_t fn,
+ gpio_pin_t hint,
+ int* error_out);
+
+/*
+ * Releases the GPIO pin so it can be reserved again in the future.
+ *
+ * The pin is reset during this process and if there are no more reserved pins
+ * on the corresponding port this function will disable the port. (last one out
+ * gets the lights.).
+ */
+void release_gpio_pin(gpio_reserved_pin_t gpio_pin);
+
+#endif /* KERN_GPIO_GPIO_MANAGE_H_ */
diff --git a/02-usart/include/kern/gpio/sysled.h b/02-usart/include/kern/gpio/sysled.h
new file mode 100644
index 0000000..b2c9056
--- /dev/null
+++ b/02-usart/include/kern/gpio/sysled.h
@@ -0,0 +1,11 @@
+/*
+ * Headers for interacting and managing the system LED.
+ */
+#ifndef SYSLED_H_
+#define SYSLED_H_
+
+#include "kern/gpio/gpio_manager.h"
+
+gpio_reserved_pin_t get_sysled();
+
+#endif
diff --git a/02-usart/include/kern/spin.h b/02-usart/include/kern/spin.h
deleted file mode 100644
index a23d25b..0000000
--- a/02-usart/include/kern/spin.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef H__SPIN_
-#define H__SPIN_
-
-#include <stdint.h>
-
-/*
- * Flash a code on the status LED.
- *
- * The flash codes a binary from MSB to LSB. A long flash is a 1, a short flash
- * is a 0. Each independent flashing is succeced by a break of 4 times that
- * of a long flash.
- */
-void spin(uint32_t base_delay, uint8_t code);
-
-#endif /* H__SPIN_ */
diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/clock.c b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c
index ba127a9..1029d39 100644
--- a/02-usart/src/arch/stm32l4xxx/peripherals/clock.c
+++ b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c
@@ -6,7 +6,6 @@
#include "arch/stm32l4xxx/peripherals/flash.h"
#include <stdint.h>
-#include "kern/spin.h"
#define TIMEOUT 10000
diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/gpio.c b/02-usart/src/arch/stm32l4xxx/peripherals/gpio.c
deleted file mode 100644
index a1e82c7..0000000
--- a/02-usart/src/arch/stm32l4xxx/peripherals/gpio.c
+++ /dev/null
@@ -1,52 +0,0 @@
-#include "arch/stm32l4xxx/peripherals/gpio.h"
-#include "arch/stm32l4xxx/peripherals/rcc.h"
-
-/*
- * Sets the mode of a pin on a gpio por.
- */
-void set_gpio_pin_mode(
- __IO gpio_port_t* gpio_port, gpio_pin_t pin, gpio_pin_mode_t mode)
-{
- /* Each pin has a 2-bit mode provided at bits pin#*2 and pin#*2+1 */
- gpio_port->mode_r &= ~(0x03 << pin * 2);
- gpio_port->mode_r |= mode << pin * 2;
-}
-
-gpio_output_pin_t set_gpio_pin_output(
- __IO gpio_port_t* gpio_port, gpio_pin_t pin)
-{
- set_gpio_pin_mode(gpio_port, pin, MODE_OUTPUT);
-
- return (gpio_output_pin_t){.gpio_port = gpio_port, .pin = pin};
-}
-
-void set_gpio_output_pin(gpio_output_pin_t pin, bool onoff)
-{
- if (onoff) {
- pin.gpio_port->output_r |= 1 << pin.pin;
- } else {
- pin.gpio_port->output_r &= ~(1 << pin.pin);
- }
-}
-
-void set_gpio_alternate_function(
- __IO gpio_port_t* port, gpio_pin_t gpio_pin, alternate_function_t afn)
-{
- __IO uint32_t* reg;
- if (gpio_pin < 8) {
- reg = &(port->af_rl);
- } else {
- reg = &(port->af_rh);
- gpio_pin -= 8;
- }
-
- uint32_t tmp = *reg & (~0x0f << gpio_pin * 4);
- *reg = tmp | (afn << gpio_pin * 4);
-}
-
-#define GPIO_PORTS_BASE_ADDR ((uint8_t*)0x48000000)
-__IO gpio_port_t* enable_gpio(gpio_port_number_t gpio_port_number)
-{
- RCC.ahb2en_r |= 1 << gpio_port_number; /* Enable the GPIO port. */
- return (__IO gpio_port_t*)(GPIO_PORTS_BASE_ADDR + (gpio_port_number * 0x400));
-}
diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/irq.c b/02-usart/src/arch/stm32l4xxx/peripherals/irq.c
index 8fb3e49..364b9a7 100644
--- a/02-usart/src/arch/stm32l4xxx/peripherals/irq.c
+++ b/02-usart/src/arch/stm32l4xxx/peripherals/irq.c
@@ -4,6 +4,7 @@
#include "arch.h"
#include "kern/delay.h"
+#include "kern/gpio/gpio_manager.h"
#define IRQ_RESERVED(n)
#define IRQ(name, uname_, n) \
@@ -16,10 +17,11 @@
void isr_simple_pin_on()
{
- __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B);
- gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3);
+ int ec;
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ gpio_reserved_pin_t pin3 = reserve_gpio_pin(GPIO_PIN_PB3, &opts, &ec);
- pin_on(pin3);
+ set_gpio_pin_high(pin3);
}
#define IRQ_RESERVED(n) 0,
@@ -47,13 +49,15 @@ const void* vectors[] __attribute__((section(".vectors"))) = {
*/
void unhandled_isr(uint8_t number)
{
- __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B);
- gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3);
+ int ec;
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ gpio_reserved_pin_t pin3 = reserve_gpio_pin(GPIO_PIN_PB3, &opts, &ec);
+
for (;;) {
for (int i = 0; i < 20; ++ i) {
- pin_on(pin3);
+ set_gpio_pin_high(pin3);
delay(1000000);
- pin_off(pin3);
+ set_gpio_pin_low(pin3);
delay(1000000);
}
delay(50000000);
@@ -62,15 +66,15 @@ void unhandled_isr(uint8_t number)
for (int i = 0; i < 8; ++ i) {
if (n & 1) {
// LSB is a 1
- pin_on(pin3);
+ set_gpio_pin_high(pin3);
delay(15000000);
- pin_off(pin3);
+ set_gpio_pin_low(pin3);
delay(15000000);
} else {
// LSB is a 0
- pin_on(pin3);
+ set_gpio_pin_high(pin3);
delay(1000000);
- pin_off(pin3);
+ set_gpio_pin_low(pin3);
delay(29000000);
}
diff --git a/02-usart/src/kern/dma/dma_manager.c b/02-usart/src/kern/dma/dma_manager.c
index 4336496..00e9f3d 100644
--- a/02-usart/src/kern/dma/dma_manager.c
+++ b/02-usart/src/kern/dma/dma_manager.c
@@ -75,7 +75,6 @@ static int try_reserve_dma_channel(
return !(in_use & (1 << chan.chan));
}
- // int in_use = __sync_fetch_and_or(&dma_inuse[dmasel], 1 << chan);
void release_dma_channel(dma_channel_t chan)
{
dma_channel_config_t* config = get_raw_channel_config(chan);
diff --git a/02-usart/src/kern/gpio/gpio_manager.c b/02-usart/src/kern/gpio/gpio_manager.c
new file mode 100644
index 0000000..82dd0ba
--- /dev/null
+++ b/02-usart/src/kern/gpio/gpio_manager.c
@@ -0,0 +1,402 @@
+#include "kern/gpio/gpio_manager.h"
+
+#include "arch/stm32l4xxx/peripherals/irq.h"
+#include "arch/stm32l4xxx/peripherals/rcc.h"
+
+/* A list of whether the pins are in use or not as a bitmask. */
+uint32_t pins_inuse[N_GPIO_PINS / 32 + (N_GPIO_PINS % 32 != 0)];
+
+struct gpio_afn_and_pin {
+ int8_t afn_number;
+ gpio_pin_t gpio_pin;
+};
+
+/*
+ * Returns which (pin, afn) pairs provide the given alternate function.
+ * The out array needs to have 5 positions.
+ *
+ * This function will use afn_number = -1 as the terminal.
+ *
+ * Note that EVENTOUT is a special case because all pins have an event out
+ * at afn=15 and should be assumed by other logic and thus is not handled
+ * by this function.
+ */
+static void get_ports_and_pins_for_alternate_function(
+ gpio_alternate_function_t afn, struct gpio_afn_and_pin* out)
+{
+ switch (afn) {
+#define AFN1(fn, ...) \
+ static_assert(false, "Unable to parse afn_table at " #fn);
+#define AFN3(fn, ...) \
+ static_assert(false, "Unable to parse afn_table at " #fn);
+#define AFN5(fn, ...) \
+ static_assert(false, "Unable to parse afn_table at " #fn);
+#define AFN7(fn, ...) \
+ static_assert(false, "Unable to parse afn_table at " #fn);
+
+#define AFN2(fn, afn, pin) \
+ out[0].afn_number = afn; \
+ out[0].gpio_pin = GPIO_PIN_ ## pin
+
+#define AFN4(fn, afn0, pin0, afn1, pin1) \
+ AFN2(fn, afn0, pin0); \
+ out[1].afn_number = afn1; \
+ out[1].gpio_pin = GPIO_PIN_ ## pin1
+
+#define AFN6(fn, afn0, pin0, afn1, pin1, afn2, pin2) \
+ AFN4(fn, afn0, pin0, afn1, pin1); \
+ out[2].afn_number = afn2; \
+ out[2].gpio_pin = GPIO_PIN_ ## pin2
+
+#define AFN8(fn, afn0, pin0, afn1, pin1, afn2, pin2, afn3, pin3) \
+ AFN6(fn, afn0, pin0, afn1, pin1, afn2, pin2); \
+ out[2].afn_number = afn3; \
+ out[2].gpio_pin = GPIO_PIN_ ## pin3
+
+#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
+#define GET_N(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
+#define AFN(fn, ...) \
+ case GPIO_ALTERNATE_FUNCTION_ ## fn: \
+ GET_MACRO(__VA_ARGS__, AFN8, AFN7, AFN6, AFN5, AFN4, AFN3, AFN2, AFN1)\
+ (fn, __VA_ARGS__); \
+ out[GET_N(__VA_ARGS__, 4, 4, 3, 3, 2, 2, 1, 1)] = \
+ (struct gpio_afn_and_pin){-1, -1}; \
+ break;
+
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc"
+ case GPIO_ALTERNATE_FUNCTION_EVENTOUT:
+ return;
+ }
+}
+
+static inline int offset_for_gpio_pin(gpio_pin_t pin)
+{
+ switch (pin) {
+#define PORT(p, pn) \
+ case GPIO_PIN_P ## p ## pn: return pn;
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+#undef PORT
+ case N_GPIO_PINS: return -1;
+ }
+
+ /* Should be unreachable. */
+ return -1;
+}
+
+inline bool gpio_pin_in_use(gpio_pin_t pin)
+{
+ return !!(pins_inuse[pin / 32] & (1 << (pin % 32)));
+}
+
+#define A(...)
+#define B(...)
+#define C(...)
+#define D(...)
+#define E(...)
+#define F(...)
+#define G(...)
+#define H(...)
+#define I(...)
+#define SELECT_MACRO(PORT) PORT
+#define PORT(port, pin) \
+ SELECT_MACRO(port)(GPIO_PIN_P ## port ## pin, pin)
+static int gc_port_a()
+{
+ return 0
+#undef A
+#define A(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef A
+#define A(...)
+}
+
+static int gc_port_b()
+{
+ return 0
+#undef B
+#define B(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef B
+#define B(...)
+}
+
+static int gc_port_c()
+{
+ return 0
+#undef C
+#define C(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef C
+#define C(...)
+}
+
+static int gc_port_d()
+{
+ return 0
+#undef D
+#define D(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef D
+#define D(...)
+}
+
+static int gc_port_e()
+{
+ return 0
+#undef E
+#define E(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef E
+#define E(...)
+}
+
+static int gc_port_f()
+{
+ return 0
+#undef F
+#define F(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef F
+#define F(...)
+}
+
+static int gc_port_g()
+{
+ return 0
+#undef G
+#define G(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef G
+#define G(...)
+}
+
+static int gc_port_h()
+{
+ return 0
+#undef H
+#define H(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef H
+#define H(...)
+}
+
+static int gc_port_i()
+{
+ return 0
+#undef I
+#define I(abspin, relpin) \
+ | (gpio_pin_in_use(abspin) << (relpin))
+#include "arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc"
+ ;
+#undef I
+#define I(...)
+}
+
+
+static inline bool gpio_pin_try_reserve(gpio_pin_t pin)
+{
+ int in_use = __sync_fetch_and_or(
+ &pins_inuse[pin / 32], 1 << (pin % 32));
+ return !(in_use & (1 << (pin % 32)));
+}
+
+inline static gpio_port_config_t* get_gpio_port_config(gpio_port_t port)
+{
+ switch(port) {
+ case GPIO_PORT_A: return (gpio_port_config_t*) GPIOA_BASE;
+ case GPIO_PORT_B: return (gpio_port_config_t*) GPIOB_BASE;
+ case GPIO_PORT_C: return (gpio_port_config_t*) GPIOC_BASE;
+ case GPIO_PORT_H: return (gpio_port_config_t*) GPIOH_BASE;
+ default: return NULL;
+ }
+}
+
+inline static gpio_port_config_t* get_gpio_port_config_for_pin(gpio_pin_t pin)
+{
+ gpio_port_t port = get_port_for_pin(pin);
+ return get_gpio_port_config(port);
+}
+
+gpio_reserved_pin_t reserve_gpio_pin(
+ gpio_pin_t pin, gpio_pin_opts_t* opts, int* error_out)
+{
+ *error_out = 0;
+ if (!gpio_pin_try_reserve(pin)) {
+ *error_out = GPIO_ERROR_IN_USE;
+ return (gpio_reserved_pin_t) { .v_ = -1 };
+ }
+
+ gpio_port_t port = get_port_for_pin(pin);
+ regset(RCC.ahb2en_r, rcc_gpioen(port), 1);
+
+ gpio_port_config_t* port_config = get_gpio_port_config(port);
+
+
+ int off = offset_for_gpio_pin(pin);
+
+ regset(port_config->mode_r, gpio_mode_n(off), opts->mode);
+ regset(port_config->pupd_r, gpio_pupd_n(off), opts->pull_dir);
+
+ switch(opts->mode) {
+ case GPIO_MODE_INPUT:
+ break;
+
+ case GPIO_MODE_OUTPUT:
+ regset(port_config->ospeed_r, gpio_ospeed_n(off), opts->output_opts.speed);
+ regset(port_config->otype_r, gpio_otype_n(off), opts->output_opts.type);
+ break;
+
+ case GPIO_MODE_ALTERNATE:
+ if (off < 8) {
+ regset(
+ port_config->af_rl,
+ gpio_afsel_n(off),
+ opts->alternate_opts.function);
+ } else {
+ regset(
+ port_config->af_rh,
+ gpio_afsel_n(off - 8),
+ opts->alternate_opts.function);
+ }
+ break;
+
+ case GPIO_MODE_ANALOG:
+ regset(port_config->asc_r, gpio_asc_n(off), 1);
+ break;
+ }
+
+ return (gpio_reserved_pin_t) { .v_ = pin };
+}
+
+gpio_reserved_pin_t gpio_enable_alternate_function(
+ gpio_alternate_function_t fn,
+ gpio_pin_t hint,
+ int* error_out)
+{
+ int i = 0;
+ gpio_pin_opts_t opts;
+ struct gpio_afn_and_pin afn_and_pin[5];
+
+ if (gpio_pin_out_of_range(hint) && hint != -1) {
+ *error_out = GPIO_ERROR_INVALID_PIN;
+ return (gpio_reserved_pin_t) { .v_ = -1 };
+ }
+
+ opts.mode = GPIO_MODE_ALTERNATE;
+
+ if (fn == GPIO_ALTERNATE_FUNCTION_EVENTOUT) {
+ afn_and_pin[i].afn_number = GPIO_ALTERNATE_FUNCTION_EVENTOUT;
+ if (hint == -1) {
+ hint = GPIO_PIN_PA0;
+ }
+ afn_and_pin[i].gpio_pin = hint;
+ } else {
+ get_ports_and_pins_for_alternate_function(fn, afn_and_pin);
+
+ if (hint == -1) {
+ hint = afn_and_pin[0].gpio_pin;
+ }
+
+ for(i = 0;
+ i < 5
+ && afn_and_pin[i].gpio_pin != hint
+ && afn_and_pin[i].gpio_pin != -1;
+ ++ i);
+
+ if (afn_and_pin[i].gpio_pin == -1 || i == 5) {
+ *error_out = GPIO_ERROR_INVALID_PIN_FOR_ALTERNATE_FUNCTION;
+ return (gpio_reserved_pin_t) { .v_ = -1 };
+ }
+ }
+
+ opts.alternate_opts.function = afn_and_pin[i].afn_number;
+ return reserve_gpio_pin(afn_and_pin[i].gpio_pin, &opts, error_out);
+}
+
+void release_gpio_pin(gpio_reserved_pin_t rpin)
+{
+ gpio_pin_t pin = rpin.v_;
+ // TODO this should be a critical section.
+ gpio_port_t port = get_port_for_pin(pin);
+ pins_inuse[pin / 32] &= ~(1 << (pin % 32));
+
+ int used;
+ switch(port) {
+ case GPIO_PORT_A:
+ used = gc_port_a();
+ break;
+ case GPIO_PORT_B:
+ used = gc_port_b();
+ break;
+ case GPIO_PORT_C:
+ used = gc_port_c();
+ break;
+ case GPIO_PORT_D:
+ used = gc_port_d();
+ break;
+ case GPIO_PORT_E:
+ used = gc_port_e();
+ break;
+ case GPIO_PORT_F:
+ used = gc_port_f();
+ break;
+ case GPIO_PORT_G:
+ used = gc_port_g();
+ break;
+ case GPIO_PORT_H:
+ used = gc_port_h();
+ break;
+ case GPIO_PORT_I:
+ used = gc_port_i();
+ break;
+
+ case N_GPIO_PORTS:
+ used = 1;
+ break;
+ }
+
+ if (!used) {
+ regset(RCC.ahb2en_r, rcc_gpioen(port), 0);
+ }
+}
+
+inline void get_gpio_pin_port_off(
+ gpio_pin_t pin, gpio_port_config_t** out_cfg, int* out_off)
+{
+ *out_cfg = get_gpio_port_config_for_pin(pin);
+ *out_off = offset_for_gpio_pin(pin);
+}
+
+void set_gpio_pin_high(gpio_reserved_pin_t pin)
+{
+ int off;
+ gpio_port_config_t* portcfg;
+ get_gpio_pin_port_off(pin.v_, &portcfg, &off);
+
+ regset(portcfg->od_r, (1 << off), 1);
+}
+
+void set_gpio_pin_low(gpio_reserved_pin_t pin)
+{
+ int off;
+ gpio_port_config_t* portcfg;
+ get_gpio_pin_port_off(pin.v_, &portcfg, &off);
+
+ regset(portcfg->od_r, (1 << off), 0);
+}
diff --git a/02-usart/src/kern/gpio/sysled.c b/02-usart/src/kern/gpio/sysled.c
new file mode 100644
index 0000000..a728da3
--- /dev/null
+++ b/02-usart/src/kern/gpio/sysled.c
@@ -0,0 +1,14 @@
+#include "kern/gpio/sysled.h"
+
+#define SYSLED GPIO_PIN_PB3
+
+gpio_reserved_pin_t get_sysled()
+{
+ if (gpio_pin_in_use(SYSLED)) {
+ return (gpio_reserved_pin_t) { .v_ = SYSLED };
+ }
+
+ int ec;
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ return reserve_gpio_pin(SYSLED, &opts, &ec);
+}
diff --git a/02-usart/src/kern/main.c b/02-usart/src/kern/main.c
index 0e0c89c..32166bc 100644
--- a/02-usart/src/kern/main.c
+++ b/02-usart/src/kern/main.c
@@ -10,24 +10,23 @@
#include "arch/stm32l4xxx/peripherals/irq.h"
#include "kern/dma/dma_manager.h"
+#include "kern/gpio/gpio_manager.h"
+#include "kern/gpio/sysled.h"
#include "kern/delay.h"
#include "kern/mem.h"
-#include "kern/spin.h"
#include "kern/string.h"
/** Overrides the default systick irq handler. */
void on_systick()
{
static int is_on = 0;
-
- __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B);
- gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3);
+ gpio_reserved_pin_t sysled = get_sysled();
if (is_on) {
- pin_off(pin3);
+ set_gpio_pin_low(sysled);
} else {
- pin_on(pin3);
+ set_gpio_pin_high(sysled);
}
is_on = ! is_on;
@@ -35,17 +34,26 @@ void on_systick()
void setup_usart2(uint32_t baud_rate)
{
- __IO gpio_port_t* port_a = enable_gpio(GPIO_PORT_A);
enable_hsi(&RCC, true);
+ int ec = 0;
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_TX, GPIO_PIN_PA2, &ec);
+
+ if (ec) {
+ unhandled_isr(ec & 0xff);
+ }
+
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_RX, GPIO_PIN_PA15, &ec);
+
+ if (ec) {
+ unhandled_isr(ec & 0xff);
+ }
+
set_usart2_clock_src(&RCC, USART_CLK_SRC_HSI16);
set_usart2_clock_enabled(&RCC, USART_CLK_SRC_HSI16);
- set_gpio_pin_mode(port_a, PIN_2, MODE_ALTERNATE);
- set_gpio_pin_mode(port_a, PIN_15, MODE_ALTERNATE);
- set_gpio_alternate_function(port_a, PIN_2, AFN_7);
- set_gpio_alternate_function(port_a, PIN_15, AFN_3);
-
/* De-assert reset of USART2 */
regset(RCC.apb1rst1_r, rcc_usart2rst, 0);
@@ -96,14 +104,13 @@ int main()
// regset(USART2.ic_r, usart_tccf, 1);
// dma_mem2p_initiate_transfer(dma_chan, thing, strlen(thing));
- __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B);
- gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3);
- pin_on(pin3);
+ gpio_reserved_pin_t sysled = get_sysled();
+ set_gpio_pin_high(sysled);
// usart_printf(&USART2, "Start Configuring Countdown!\n");
/* Set the countdown to start from 1,000,0000. */
- SCB.strv_r = 10000000;
+ SCB.strv_r = 1000000;
/* Enable interrupts. */
regset(SCB.stcs_r, scb_tickint, 1);
diff --git a/02-usart/src/kern/spin.c b/02-usart/src/kern/spin.c
deleted file mode 100644
index 7c4f6eb..0000000
--- a/02-usart/src/kern/spin.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "kern/spin.h"
-#include "kern/delay.h"
-#include "arch/stm32l4xxx/peripherals/gpio.h"
-
-#define SHORT_DELAY 200000
-#define LONG_DELAY (SHORT_DELAY * 2)
-
-static void flash_bit(
- uint32_t base, gpio_output_pin_t out_pin,
- uint8_t bit /* 0 => 0, non-zero => 1 */)
-{
- pin_on(out_pin);
- if (bit) {
- delay(base * 2);
- } else {
- delay(base);
- }
- pin_off(out_pin);
- delay(base);
-}
-
-void spin(uint32_t base, uint8_t c)
-{
- uint8_t code;
- __IO gpio_port_t* port_b = enable_gpio(GPIO_PORT_B);
- gpio_output_pin_t pin3 = set_gpio_pin_output(port_b, PIN_3);
-
- for (;;) {
- code = c;
- flash_bit(base, pin3, code & 0x80);
- code <<= 1;
- flash_bit(base, pin3, code & 0x80);
- code <<= 1;
- flash_bit(base, pin3, code & 0x80);
- code <<= 1;
- flash_bit(base, pin3, code & 0x80);
-
- code <<= 1;
- flash_bit(base, pin3, code & 0x80);
- code <<= 1;
- flash_bit(base, pin3, code & 0x80);
- code <<= 1;
- flash_bit(base, pin3, code & 0x80);
- code <<= 1;
- flash_bit(base, pin3, code & 0x80);
-
- delay(base * 4);
- }
-}
diff --git a/02-usart/tests/test_gpio.c b/02-usart/tests/test_gpio.c
new file mode 100644
index 0000000..bcb953c
--- /dev/null
+++ b/02-usart/tests/test_gpio.c
@@ -0,0 +1,194 @@
+#include "test_harness.h"
+
+#include "arch/stm32l4xxx/peripherals/rcc.h"
+#include "kern/gpio/gpio_manager.h"
+
+TEST(gpio_manager, smell)
+{
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ int ec = 5;
+ gpio_reserved_pin_t some_pin = reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_TRUE(gpio_pin_in_use(GPIO_PIN_PA15));
+
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+ release_gpio_pin(some_pin);
+
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ return 0;
+}
+
+TEST(gpio_manager, multiplereserve)
+{
+ int ec;
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_TRUE(ec == 0);
+
+ reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_EQ(ec, GPIO_ERROR_IN_USE);
+
+ return 0;
+}
+
+TEST(gpio_manager, alternate)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_TX, GPIO_PIN_PA2, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_RX, GPIO_PIN_PA15, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ gpio_port_config_t* gpioa = (gpio_port_config_t*) GPIOA_BASE;
+
+ ASSERT_EQ(regget(gpioa->mode_r, gpio_mode_n(15)), GPIO_MODE_ALTERNATE);
+ ASSERT_EQ(regget(gpioa->mode_r, gpio_mode_n(2)), GPIO_MODE_ALTERNATE);
+
+ ASSERT_EQ(regget(gpioa->af_rl, gpio_afsel_n(2)), 7);
+ ASSERT_EQ(regget(gpioa->af_rh, gpio_afsel_n(7)), 3);
+
+ return 0;
+}
+
+TEST(gpio_manager, bad_alternate)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_RX, GPIO_PIN_PA2, &ec);
+
+ ASSERT_EQ(ec, GPIO_ERROR_INVALID_PIN_FOR_ALTERNATE_FUNCTION);
+
+ return 0;
+}
+
+TEST(gpio_manager, bad_pin)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_RX, 99, &ec);
+
+ ASSERT_EQ(ec, GPIO_ERROR_INVALID_PIN);
+
+ return 0;
+}
+
+TEST(gpio_manager, alternate_then_reserve_fail)
+{
+ int ec;
+
+ /* Pretending to start the USART. */
+ gpio_enable_alternate_function(
+ GPIO_ALTERNATE_FUNCTION_USART2_TX, GPIO_PIN_PA2, &ec);
+
+ ASSERT_EQ(ec, 0);
+
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+ reserve_gpio_pin(GPIO_PIN_PA2, &opts, &ec);
+
+ ASSERT_EQ(ec, GPIO_ERROR_IN_USE);
+
+ return 0;
+}
+
+TEST(gpio_manager, get_gpio_pin_port_off)
+{
+
+ gpio_port_config_t* cfg;
+ int off;
+ get_gpio_pin_port_off(GPIO_PIN_PA5, &cfg, &off);
+
+ ASSERT_EQ(cfg, (void*)(GPIOA_BASE));
+ ASSERT_EQ(off, 5);
+
+ return 0;
+}
+
+TEST(gpio_manager, sets_gpio_settings)
+{
+ gpio_pin_opts_t opts;
+ int ec;
+
+ opts.mode = GPIO_MODE_OUTPUT;
+ opts.pull_dir = GPIO_PULL_DIR_NONE;
+ opts.output_opts.speed = GPIO_OUTPUT_SPEED_VERY_HIGH;
+ opts.output_opts.type = GPIO_OUTPUT_TYPE_PUSH_PULL;
+
+ reserve_gpio_pin(GPIO_PIN_PA2, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+
+ gpio_port_config_t* gpioa = (gpio_port_config_t*) GPIOA_BASE;
+
+ ASSERT_EQ(regget(gpioa->mode_r, gpio_mode_n(2)), GPIO_MODE_OUTPUT);
+ ASSERT_EQ(regget(gpioa->pupd_r, gpio_pupd_n(2)), GPIO_PULL_DIR_NONE);
+ ASSERT_EQ(regget(gpioa->ospeed_r, gpio_ospeed_n(2)), GPIO_OUTPUT_SPEED_VERY_HIGH);
+ ASSERT_EQ(regget(gpioa->otype_r, gpio_otype_n(2)), GPIO_OUTPUT_TYPE_PUSH_PULL);
+
+ return 0;
+}
+
+TEST(gpio_manager, gc)
+{
+ int ec;
+ gpio_pin_opts_t opts = DEFAULT_GPIO_OPTS_OUTPUT;
+
+ gpio_reserved_pin_t p1 = reserve_gpio_pin(GPIO_PIN_PA0, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+
+ gpio_reserved_pin_t p2 = reserve_gpio_pin(GPIO_PIN_PA1, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+
+ gpio_reserved_pin_t p3 = reserve_gpio_pin(GPIO_PIN_PA15, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+
+ gpio_reserved_pin_t p4 = reserve_gpio_pin(GPIO_PIN_PB3, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ gpio_reserved_pin_t p5 = reserve_gpio_pin(GPIO_PIN_PB1, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ gpio_reserved_pin_t p6 = reserve_gpio_pin(GPIO_PIN_PB0, &opts, &ec);
+ ASSERT_EQ(ec, 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p1);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p2);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 1);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p3);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p4);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p5);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 1);
+
+ release_gpio_pin(p6);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_A)), 0);
+ ASSERT_EQ(regget(RCC.ahb2en_r, rcc_gpioen(GPIO_PORT_B)), 0);
+
+ return 0;
+}