From 087b4f5d9e3899d4476db2688e7699561db28452 Mon Sep 17 00:00:00 2001 From: Gabor Csapo Date: Wed, 21 Jun 2023 17:10:43 +0800 Subject: [PATCH] stm32h743xx_hic: Optimize HAL_GPIO_Init This function is called frequently during DAP transactions and the original implementation in the HAL loops through all the pins to arrive at the one it wants to change. Optimize the loop into a simple calculation to find the corrent bit position to change. --- source/hic_hal/stm32/stm32h743xx/DAP_config.h | 24 +++++--- source/hic_hal/stm32/stm32h743xx/gpio.c | 61 +++++++++++++++++++ 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/source/hic_hal/stm32/stm32h743xx/DAP_config.h b/source/hic_hal/stm32/stm32h743xx/DAP_config.h index 951316085c..88036be1e7 100644 --- a/source/hic_hal/stm32/stm32h743xx/DAP_config.h +++ b/source/hic_hal/stm32/stm32h743xx/DAP_config.h @@ -175,6 +175,14 @@ of the same I/O port. The following SWDIO I/O Pin functions are provided: // Configure DAP I/O pins ------------------------------ +/** Fast functions to init GPIOs. +The original HAL implementation cycles through all the pins because it allows +configuring multiple pins in the same call. We don't need this feature and +would rather just speed up the execution for faster DAP communication by removing +the internal loop. + */ +void HAL_GPIO_Init_Optimized(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init); + /** Setup JTAG I/O pins: TCK, TMS, TDI, TDO, nTRST, and nRESET. Configures the DAP Hardware I/O pins for JTAG mode: - TCK, TMS, TDI, nTRST, nRESET to output mode and set to high level. @@ -202,13 +210,13 @@ __STATIC_INLINE void PORT_SWD_SETUP(void) // Set SWCLK HIGH gpio_init.Pin = g_swd_dut_configs[g_cur_swd_dut].swclk.pin; - HAL_GPIO_Init(g_swd_dut_configs[g_cur_swd_dut].swclk.port, &gpio_init); + HAL_GPIO_Init_Optimized(g_swd_dut_configs[g_cur_swd_dut].swclk.port, &gpio_init); HAL_GPIO_WritePin(g_swd_dut_configs[g_cur_swd_dut].swclk.port, g_swd_dut_configs[g_cur_swd_dut].swclk.pin, GPIO_PIN_SET); // Set SWDIO HIGH gpio_init.Pin = g_swd_dut_configs[g_cur_swd_dut].swdio.pin; - HAL_GPIO_Init(g_swd_dut_configs[g_cur_swd_dut].swdio.port, &gpio_init); + HAL_GPIO_Init_Optimized(g_swd_dut_configs[g_cur_swd_dut].swdio.port, &gpio_init); HAL_GPIO_WritePin(g_swd_dut_configs[g_cur_swd_dut].swdio.port, g_swd_dut_configs[g_cur_swd_dut].swdio.pin, GPIO_PIN_SET); @@ -216,7 +224,7 @@ __STATIC_INLINE void PORT_SWD_SETUP(void) gpio_init.Pin = g_swd_dut_configs[g_cur_swd_dut].nreset.pin; gpio_init.Mode = GPIO_MODE_INPUT; gpio_init.Pull = GPIO_PULLDOWN; - HAL_GPIO_Init(g_swd_dut_configs[g_cur_swd_dut].nreset.port, &gpio_init); + HAL_GPIO_Init_Optimized(g_swd_dut_configs[g_cur_swd_dut].nreset.port, &gpio_init); if (g_cur_swd_dut == SWD_DUT0) { @@ -252,10 +260,10 @@ __STATIC_INLINE void PORT_OFF(void) }; gpio_init.Pin = g_swd_dut_configs[g_cur_swd_dut].swclk.pin; - HAL_GPIO_Init(g_swd_dut_configs[g_cur_swd_dut].swclk.port, &gpio_init); + HAL_GPIO_Init_Optimized(g_swd_dut_configs[g_cur_swd_dut].swclk.port, &gpio_init); gpio_init.Pin = g_swd_dut_configs[g_cur_swd_dut].swdio.pin; - HAL_GPIO_Init(g_swd_dut_configs[g_cur_swd_dut].swclk.port, &gpio_init); + HAL_GPIO_Init_Optimized(g_swd_dut_configs[g_cur_swd_dut].swclk.port, &gpio_init); HAL_GPIO_WritePin(g_swd_dut_configs[g_cur_swd_dut].swd_en_buf.port, g_swd_dut_configs[g_cur_swd_dut].swd_en_buf.pin, @@ -343,7 +351,7 @@ __STATIC_FORCEINLINE void PIN_SWDIO_OUT_ENABLE(void) .Mode = GPIO_MODE_OUTPUT_PP, .Speed = GPIO_SPEED_FREQ_VERY_HIGH, }; - HAL_GPIO_Init(g_swd_dut_configs[g_cur_swd_dut].swdio.port, &gpio_init); + HAL_GPIO_Init_Optimized(g_swd_dut_configs[g_cur_swd_dut].swdio.port, &gpio_init); g_swd_dut_configs[g_cur_swd_dut].swdio.port->BSRR = (g_swd_dut_configs[g_cur_swd_dut].swdio.pin << 16); } @@ -359,7 +367,7 @@ __STATIC_FORCEINLINE void PIN_SWDIO_OUT_DISABLE(void) .Mode = GPIO_MODE_INPUT, .Pull = GPIO_PULLUP, }; - HAL_GPIO_Init(g_swd_dut_configs[g_cur_swd_dut].swdio.port, &gpio_init); + HAL_GPIO_Init_Optimized(g_swd_dut_configs[g_cur_swd_dut].swdio.port, &gpio_init); g_swd_dut_configs[g_cur_swd_dut].swdio.port->BSRR = g_swd_dut_configs[g_cur_swd_dut].swdio.pin; } @@ -555,7 +563,7 @@ __STATIC_INLINE void DAP_SETUP(void) PORT_SWD_SETUP(); - HAL_GPIO_Init(CONNECTED_LED_PORT, &gpio_init); + HAL_GPIO_Init_Optimized(CONNECTED_LED_PORT, &gpio_init); HAL_GPIO_WritePin(CONNECTED_LED_PORT, CONNECTED_LED_PIN, GPIO_PIN_SET); } diff --git a/source/hic_hal/stm32/stm32h743xx/gpio.c b/source/hic_hal/stm32/stm32h743xx/gpio.c index 2b9462886a..1331a171be 100644 --- a/source/hic_hal/stm32/stm32h743xx/gpio.c +++ b/source/hic_hal/stm32/stm32h743xx/gpio.c @@ -27,6 +27,9 @@ #define GPIO_INIT_STABILIZATION_DELAY_MS (100) +#define GPIO_OUTPUT_TYPE (0x00000010U) +#define GPIO_MODE (0x00000003U) + static const dut_pin_group_t s_dut_pin_group[DUT_PIN_GROUP_ID_COUNT] = { [DUT_PIN_GROUP_ID_UDC0_RST_L] = @@ -423,3 +426,61 @@ bool gpio_dut_pin_group_is_active_high(dut_pin_group_id_t dut_pin_group_id) { return s_dut_pin_group[dut_pin_group_id].active_high; } + +// The fastest way to compute trailing zeros is using a lookup table +// For the source and more background pls see: +// https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightMultLookup +static uint8_t count_trailing_zeros_optimized(uint32_t input) +{ + static const uint32_t s_multiply_debruijn_bit_position[32] = + { + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + }; + return s_multiply_debruijn_bit_position[((uint32_t)((input & -input) * 0x077CB531U)) >> 27]; +} + +void HAL_GPIO_Init_Optimized(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_Init) +{ + uint32_t temp; + uint32_t position = count_trailing_zeros_optimized(GPIO_Init->Pin); + + /* Check the parameters */ + util_assert(IS_GPIO_ALL_INSTANCE(GPIOx)); + util_assert(IS_GPIO_PIN(GPIO_Init->Pin)); + util_assert(IS_GPIO_MODE(GPIO_Init->Mode)); + util_assert(IS_GPIO_PULL(GPIO_Init->Pull)); + util_assert((GPIO_Init->Mode != GPIO_MODE_AF_PP) || (GPIO_Init->Mode != GPIO_MODE_AF_OD)); + util_assert((GPIO_Init->Pin & ~(1 << position)) == 0); + + /*--------------------- GPIO Mode Configuration ------------------------*/ + /* Configure IO Direction mode (Input, Output, Alternate or Analog) */ + temp = GPIOx->MODER; + temp &= ~(GPIO_MODER_MODE0 << (position * 2U)); + temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2U)); + GPIOx->MODER = temp; + + /* In case of Output or Alternate function mode selection */ + if ((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD)) + { + /* Check the Speed parameter */ + util_assert(IS_GPIO_SPEED(GPIO_Init->Speed)); + /* Configure the IO Speed */ + temp = GPIOx->OSPEEDR; + temp &= ~(GPIO_OSPEEDR_OSPEED0 << (position * 2U)); + temp |= (GPIO_Init->Speed << (position * 2U)); + GPIOx->OSPEEDR = temp; + + /* Configure the IO Output Type */ + temp = GPIOx->OTYPER; + temp &= ~(GPIO_OTYPER_OT0 << position) ; + temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> 4U) << position); + GPIOx->OTYPER = temp; + } + + /* Activate the Pull-up or Pull down resistor for the current IO */ + temp = GPIOx->PUPDR; + temp &= ~(GPIO_PUPDR_PUPD0 << (position * 2U)); + temp |= ((GPIO_Init->Pull) << (position * 2U)); + GPIOx->PUPDR = temp; +}