2021-07-21 06:52 PM
I created a development board for an STM32L562CEU6P (P = SMPS part) which contains a 1.2V step down regulator for the externally-provided Vcore, and it also has a USB->serial converter (for various reasons I didn't want to use built-in USB) and an ST 10-pin SWD header.
And I've been dealing with a strange problem where the boards were apparently bricked after loading bad code. I eventually managed to unbrick them by playing with the power sequencing (I think possibly the USB->serial converter has been powering up the STM32 through I/O pins) and then I could investigate the bad code issue and make some discoveries.
So it seems like what is leading to the apparent bricking is my TPIU initialization code:
static void trace_setup(void) {
/* Enable trace subsystem (we'll use ITM and TPIU). */
SCS_DEMCR |= SCS_DEMCR_TRCENA;
/* Use Manchester code for asynchronous transmission. */
TPIU_SPPR = TPIU_SPPR_ASYNC_MANCHESTER;
TPIU_ACPR = 173; // ~460800 bps @ 80 MHz
/* Formatter and flush control. */
TPIU_FFCR &= ~TPIU_FFCR_ENFCONT;
/* Enable TRACESWO pin for async mode. */
DBGMCU_CR =
DBGMCU_CR_SLEEP |
DBGMCU_CR_STOP |
DBGMCU_CR_STANDBY |
DBGMCU_CR_TRACE_IOEN |
DBGMCU_CR_TRACE_MODE_ASYNC;
/* Unlock access to ITM registers. */
ITM_LAR = 0xC5ACCE55;
/* Enable ITM with ID = 1. */
ITM_TCR = (1 << 16) | ITM_TCR_ITMENA;
/* Enable stimulus port 1. */
ITM_TER[0] = 1;
}
I have not actually checked if this code is valid on a Cortex-M33 (it was ported from Cortex-M3) and perhaps it is not. At any rate, it seems to lock up the chip and put it into a state which cannot be recovered by NRST. This surprises me, as I would have thought that NRST would reset the entire chip. There are some exceptions to this rule mentioned in STM32F4 documentation (when using the regulator bypass the PA0 pin is used as an additional reset) but I don't think these would apply to STM32L5. Also, possibly the RTC domain does not get reset by NRST, but I don't think that is implicated here as I haven't done anything with it.
So after executing that code, I cannot connect to the chip using stm32flash (the method of giving a NRST pulse while BOOT0=1) and neither can I connect to the chip using SWD/JTAG. And then I have to undertake a careful power down/up sequence in which I am careful not to power up the chip through I/O pins from the USB->serial converter, then SWD works.
Now that I discovered this procedure I can work around the issue, but I wonder if I have discovered a new erratum? Or is this expected behaviour for a Cortex-M33 based chip? Or perhaps the issue is due to my using libopencm3 rather than stm32cube and being still in the process of converting STM32L4 definitions to STM32L5? (Maybe I accessed something other than TPIU if something else moved to that address and I used STM32L4 definitions).
Any ideas?
cheers, Nick
2021-07-21 09:18 PM
Discovered this in the reference manual RM0438 (dm00346336-stm32l552xx-and-stm32l562xx-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) just now...
52.11.1
DBGMCU registers
The DBGMCU registers are not reset by a system reset, only by a power-on reset.
That does explain things... I am currently implementing all register definitions for STM32L5 so I will probably discover soon how the TPIU differs between STM32L5 and STM32L4. Also I seem to recall that my code above is for the "Pelican TPIU" whatever that is -- it seems like the STM32F4 series TPIU was slightly modified from ARM?
2023-03-03 04:55 PM
I have a solution.
Documentation says:
DBGMCU registers
The DBGMCU registers are not reset by a system reset, only by a power-on reset. They are
accessible to the debugger via the AHB access port at base address 0xE004 4000.
DBGMCU configuration register (DBGMCU_CR)
Address offset: 0x04
Reset value: 0x0000 0000
Bits 7:6 TRACE_MODE[1:0]: trace pin assignment
0x0: trace pins assigned for asynchronous mode (TRACESWO)
0x1: trace pins assigned for synchronous mode with a port width of 1 (TRACECK,
TRACED0)
0x2: trace pins assigned for synchronous mode with a port width of 2 ((TRACECK,
TRACED0-1)
0x3: trace pins assigned for synchronous mode with a port width of 2 ((TRACECK,
TRACED0-3)
Bit 5 TRACE_EN: trace port and clock enable.
This bit enables the trace port clock, TRACECK.
0: disabled
1: enabled
Bit 4 TRACE_IOEN: trace pin enable
0: disabled - trace pins not assigned
1: enabled - trace pins assigned according to the value of TRACE_MODE field
*(volatile uint32_t *)(0xE0044004) = (1 << 4) | (1 << 5);
this will help