1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #19792 from kyleb29/bugfix-19787

cpu/stm32/periph_i2c: prevent corrupting AFIO->MAPR
This commit is contained in:
Marian Buschsieweke 2023-11-20 20:33:16 +00:00 committed by GitHub
commit f9e4affd19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 20 deletions

View File

@ -56,14 +56,6 @@ extern "C" {
#define XTIMER_BACKOFF (19)
/** @} */
/* The boards debug header only exports SWD, so JTAG-only pins PA15, PB3(*),
* and PB4 can be remapped as regular GPIOs instead. (Note: PB3 is also used as
* SWO. The user needs to take care to not enable SWO with the debugger while
* at the same time PB3 is used as GPIO. But RIOT does not use SWO in any case,
* so if a user adds this feature in her/his own code, she/he should be well
* aware of this.)
*/
#define STM32F1_DISABLE_JTAG /**< Disable JTAG to allow pins being used as GPIOs */
#ifdef __cplusplus
}
#endif

View File

@ -1,9 +1,2 @@
# load the common Makefile.include for Nucleo boards
include $(RIOTBOARD)/common/nucleo64/Makefile.include
# On-board debugger uses SWD, so JTAG-only pins PA15, PB3(*), and PB4 can be
# remapped as regular GPIOs instead. (Note: PB3 is also used as SWO. The user
# needs to take care to not enable SWO with the debugger while at the same time
# PB3 is used as GPIO. But RIOT does not use SWO in any case, so if a user adds
# this feature in her/his own code, she/he should be well aware of this.)
CFLAGS += -DSTM32F1_DISABLE_JTAG

View File

@ -333,6 +333,26 @@ void _wlx5xx_init_subghz_debug_pins(void)
#endif
}
static void swj_init(void)
{
#if defined(CPU_FAM_STM32F1)
/* Only if the selected SWJ config differs from the reset value, we
* actually need to do something. Since both sides are compile time
* constants, this hole code gets optimized out by default */
if (CONFIG_AFIO_MAPR_SWJ_CFG != SWJ_CFG_FULL_SWJ) {
/* The remapping periph clock must first be enabled */
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
/* Handling of the MAPR register is a bit involved due to the
* write-only nature of the SWJ_CFG field, which returns undefined
* garbage on read. `afio_mapr_read()` will read the current MAPR
* value, but clear the SWF_CFG vield. `afio_mapr_wriote()` will then
* write the value read back, but apply the `SWF_CFG` configuration
* from `CONFIG_AFIO_MAPR_SWJ_CFG` first.*/
afio_mapr_write(afio_mapr_read());
}
#endif
}
void cpu_init(void)
{
/* initialize the Cortex-M core */
@ -362,10 +382,7 @@ void cpu_init(void)
/* initialize stdio prior to periph_init() to allow use of DEBUG() there */
early_init();
#ifdef STM32F1_DISABLE_JTAG
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
#endif
swj_init();
/* trigger static peripheral initialization */
periph_init();

View File

@ -107,6 +107,67 @@ enum {
};
/** @} */
/**
* @brief Possible values of the `SWJ_CFG` field in the AFIO->MAPR register
*
* @details This wraps the vendor header file preprocessor macros into a
* C language `enum`.
*/
typedef enum {
/**
* @brief Both JTAG-DP and SW-DP enabled, reset state
*/
SWJ_CFG_FULL_SWJ = 0,
/**
* @brief Both JTAG-DP and SW-DP enabled, but NJTRST disabled and pin
* usable as GPIO
*/
SWJ_CFG_NO_NJTRST = AFIO_MAPR_SWJ_CFG_NOJNTRST,
/**
* @brief Only SW-DP enabled, JTAG pins usable as GPIOS
*/
SWJ_CFG_NO_JTAG_DP = AFIO_MAPR_SWJ_CFG_JTAGDISABLE,
/**
* @brief Neither JTAG-DP nor SW-DP enabled, JTAG and SWD pins usable as
* GPIOS
*/
SWJ_CFG_DISABLED = AFIO_MAPR_SWJ_CFG_DISABLE,
} afio_mapr_swj_cfg_t;
#ifndef CONFIG_AFIO_MAPR_SWJ_CFG
/**
* @brief By default, disable JTAG and keep only SWD
*
* This frees the JTAG pins for use as regular GPIOs. We do not support flashing
* or debugging via JTAG anyway, so there is nothing lost except for a few bytes
* of ROM to initialize the `SWJ_CFG` register.
*/
#define CONFIG_AFIO_MAPR_SWJ_CFG SWJ_CFG_NO_JTAG_DP
#endif
/**
* @brief Read the current value of the AFIO->MAPR register reproducibly
*
* This will explicitly clear the write-only `SWJ_CFG` field [26:24], as the
* values read back are undefined.
*/
static inline uint32_t afio_mapr_read(void)
{
return AFIO->MAPR & (~(AFIO_MAPR_SWJ_CFG_Msk));
}
/**
* @brief Write to the AFIO->MAPR register apply the SWJ configuration
* specified via @ref CONFIG_AFIO_MAPR_SWJ_CFG
*
* @pre @p new_value has all bits in the range [26:24] cleared (the
* `SWJ_CFG` field).
*/
static inline void afio_mapr_write(uint32_t new_value)
{
AFIO->MAPR = CONFIG_AFIO_MAPR_SWJ_CFG | new_value;
}
#ifdef __cplusplus
}
#endif

View File

@ -120,7 +120,7 @@ static void _init_pins(i2c_t dev)
/* The remapping periph clock must first be enabled */
RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
/* Then the remap can occur */
AFIO->MAPR |= AFIO_MAPR_I2C1_REMAP;
afio_mapr_write(afio_mapr_read() | AFIO_MAPR_I2C1_REMAP);
}
gpio_init_af(i2c_config[dev].scl_pin, GPIO_AF_OUT_OD);
gpio_init_af(i2c_config[dev].sda_pin, GPIO_AF_OUT_OD);