diff options
-rw-r--r-- | 02-usart/include/arch/arm/arch.h | 1 | ||||
-rw-r--r-- | 02-usart/include/arch/stm32l4xxx/peripherals/gpio.h | 302 | ||||
-rw-r--r-- | 02-usart/include/arch/stm32l4xxx/peripherals/rcc.h | 8 | ||||
-rw-r--r-- | 02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/afn_table.inc | 100 | ||||
-rw-r--r-- | 02-usart/include/arch/stm32l4xxx/peripherals/tables/stm32l432xx/gpio/port_table.inc | 26 | ||||
-rw-r--r-- | 02-usart/include/arch/x86_64/arch.h | 1 | ||||
-rw-r--r-- | 02-usart/include/kern/gpio/gpio_manager.h | 187 | ||||
-rw-r--r-- | 02-usart/include/kern/gpio/sysled.h | 11 | ||||
-rw-r--r-- | 02-usart/include/kern/spin.h | 15 | ||||
-rw-r--r-- | 02-usart/src/arch/stm32l4xxx/peripherals/clock.c | 1 | ||||
-rw-r--r-- | 02-usart/src/arch/stm32l4xxx/peripherals/gpio.c | 52 | ||||
-rw-r--r-- | 02-usart/src/arch/stm32l4xxx/peripherals/irq.c | 26 | ||||
-rw-r--r-- | 02-usart/src/kern/dma/dma_manager.c | 1 | ||||
-rw-r--r-- | 02-usart/src/kern/gpio/gpio_manager.c | 402 | ||||
-rw-r--r-- | 02-usart/src/kern/gpio/sysled.c | 14 | ||||
-rw-r--r-- | 02-usart/src/kern/main.c | 39 | ||||
-rw-r--r-- | 02-usart/src/kern/spin.c | 49 | ||||
-rw-r--r-- | 02-usart/tests/test_gpio.c | 194 |
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; +} |