Skip to main content
Visitor II
July 13, 2023
Question

STM32L47 Stuck During Reset

  • July 13, 2023
  • 15 replies
  • 5998 views

Hi all,

I am currently experiencing some weird reset behavior for my STM32L47 chip. Due to a non-optimal combination of HW the chip resets from time to time, and I am assuming an ESD issue being the reason for this. As long as the resets are recoverable, it does not really matter.

This is where the trouble arises: Some of the resets are not recoverable, and the chip get stuck in a weird state and will not power on correctly. We see that the watchdog triggers, but it does not enter its mainloop. If you spam the pin-reset it can in some cases reset correctly, but pressing it once does not get it out of this freezed state. So the easiest way to get out of this state is to cut the power and turn it on again. Checking the control status registers during resets we have found the following:

  • Some resets report pin- and IWWG-resets. This is fine and then the chip resets correctly.
  • When the reset reports pin-, IWWG- and Brownout-resets, it get stuck in the "freezed" state.

So the common denominator for resets that causes the chip to freeze is brownout. If this indicates an actual brownout, or simply a "bug" due to some strange ESD behavior I can't really tell. We have tried measuring during resets as well, but we have not found any obvious bugs in the HW. We have also simulated a brownout, but did not manage to get it into the freezed state.

We tried to increase the brownout level from 1.7 V (default) to 2.5 V, but this had no effect and we still experienced the "freezed" behavior.

Does anyone have any tips on what this freezed behavior can be caused by? Is there some obvious configuration to look into when experience these types of bugs? FYI: the chip are currently running RUST code.

This topic has been closed for replies.

15 replies

waclawek.jan
Super User
July 13, 2023

Spurious bootloader (system-memory) entry? BOOT0 pin is wired how exactly?

JW

Visitor II
July 14, 2023

Hi @waclawek.jan 

I am a collegue of @hlanden 

The BOOT0 pin is pulled low with a 10kΩ,

There are indication that the system is stuck at clock init and we are also calling a couple of statics (buffers) before WD is initialized but not sure if this has any implications.

 

 

waclawek.jan
Super User
July 14, 2023

> There are indication that the system is stuck at clock init

What indication? The usual thing to do when something like this is suspected is to toggle a pin around the suspected routine and observe on oscilloscope (or just watch if it's a LED).

What is the clock? How is it used? Is there any LSE clock/VBAT? You may perhaps want to post relevant portion of schematics.

JW

Visitor II
July 14, 2023

Hi again ;)
Attaching clock configuration, can provide more info if needed. I also added the init of the periphs...
Added the schematics for the clock HSE and LSE, and power inputs.

We tested changing the IWDG timeout to random number eg. 6-10 sec. Then we observed the NRST changing accoringly but the system was still in a "Lockout" mode. Only a full power cycle would start it normally again.
Connecting a debugger unstucks the MCU. 

 

 

 

 // clock configuration (clocks run at nearly the maximum frequency)
 let clocks = rcc
 .cfgr
 .lse(CrystalBypass::Disable, ClockSecuritySystem::Disable)
 .msi(MsiFreq::RANGE4M)
 .sysclk(FREQ_HZ.hz())
 .pclk1(FREQ_HZ.hz())
 .pclk2(FREQ_HZ.hz())
 .freeze(&mut flash_parts.acr, &mut pwr);

 // clock configuration using HSE external high speed crystal
 /*
 let clocks = rcc
 .cfgr
 .hse(
 20_000_000.hz(),
 CrystalBypass::Disable,
 ClockSecuritySystem::Disable,
 )
 .pll_source(PllSource::HSE)
 .sysclk_with_pll(FREQ_HZ.hz(), PllConfig::new(2, 16, PllDivider::Div2))
 .pclk1(FREQ_HZ.hz())
 .pclk2(FREQ_HZ.hz())
 .freeze(&mut flash_parts.acr, &mut pwr);
 */
 delay_ms!(clocks, 400);
 green_led.set_low().unwrap();
pub fn init_peripherals(
 mut dev: hal::stm32::Peripherals,
 uart5_dma_rx_buffer: &'static mut imu_config::Uart5DmaRxBuffer,
 uart4_dma_rx_buffer: &'static mut lidar_config::Uart4DmaRxBuffer,
) -> (
 imu_config::Uart5DmaRxContext,
 hal::serial::Rx<hal::pac::UART5>,
 can_lib::Can,
 IndependentWatchdog,
 GreenLedPin,
 RedLedPin,
 BlueLedPin,
 YellowLedPin,
 BuzzerPwm,
 LidarTx,
 LidarRx,
 lidar_config::Uart4DmaRxContext,
 power_gates::PowerGatesControl,
 BmsSet,
 Ws2812,
 ImuRstPin,
 NfcBindings,
 WcanSenders,
 Tms320Serial,
 SmcuInterface,
 hal::flash::Parts,
 AdcChannels,
) {
 // Enable watchdog ASAP
 let mut watchdog = IndependentWatchdog::new(dev.IWDG);
 watchdog.stop_on_debug(&dev.DBGMCU, true);
 watchdog.start(MilliSeconds(10000));

 // Not sure who took them, so we try to steal them instad
 let mut cp = unsafe { cortex_m::peripheral::Peripherals::steal() };

 // Re-allocate interrupt vector table to 0x0800_0000
 // This has to be done so code can run from both Bank1 and Bank2
 unsafe {
 cp.SCB.vtor.write(0x0800_0000);
 }

 let mut flash_parts = dev.FLASH.constrain();
 let rcc_reg = dev.RCC;
 rcc_reg.apb1enr1.modify(|_, w| w.can1en().set_bit());

 let mut rcc = rcc_reg.constrain();

 // Dubious enabling of the DMA clocking
 unsafe {
 let rcc_ptr = &*hal::pac::RCC::ptr(); // RCC pointer
 // enable DMA1 clock: peripheral clock enable register
 rcc_ptr.ahb1enr.modify(|_, w| w.dma1en().set_bit());
 }
 let dma1 = dev.DMA1;
 dma1.cselr.write(|w| w.c5s().bits(1));
 let dma1_channels = dma1.split(&mut rcc.ahb1);
 let _dma2_channels = dev.DMA2.split(&mut rcc.ahb1);

 

 

 

ARed_2-1689344058585.png

 

 

waclawek.jan
Super User
July 15, 2023

> Then we observed the NRST changing accoringly but the system was still in a "Lockout" mode

What do you mean by "Lockout" mode? Is it repeated watchdog reset (i.e. NRST resetting periodically)?

Have you tried to spot the exact point where the problem occurs, e.g. by the "toggle a pin/LED around suspicious pieces of code" method? I don't Rust but the piece of code you've posted appears to be pretty high level, so if you are using some sort of library you should dig there too.

What you see may be also consequence of the VBAT brownout erratum. A simple way to check is to add an explicit backup-domain reset *before* any attempt to set up clocks - and as you don't have a backup battery, this should also remain there, too.

JW

Explorer
July 17, 2023

Hi there,

I'm a collegue of these two guys. So by "lockout mode" @ARed  means that STM enters an unknown state at which it doesn't do anything and it can not be reset either internally (watchdog) or externally by NRST pin pulling low. 

However, at this state the internal watchdog triggers as if it tries to reset the STM, but the chip doesn't come back. Once in this state, STM will stay "stuck" until the battery is running-on, drains. The only way to reset it is to reset power (e.g. unplug battery). 

What you mentioned about VBAT brownout erratum might be relevant here.  While monitoring some pins to try and capture something with an oscilloscope, we saw that when this occurred there was a dip in the STM power line, which is the same for VBAT. I add a picture here to show that better. 

The scale here is 1V/div.

waclawek.jan
Super User
July 17, 2023

> it doesn't do anything

How do you know that? Can't it be running in its internal bootloader? Or stuck in some unhandled error, or in a loop during attempt to start up? Maybe using a debugger could reveal that.

Nonetheless, if the waveform you've shown is VBAT, regardless of whether it is connected to VDD/VDDA or both, if it goes below ground i.e. to negative as much as you've shown, that may be a concern too, and may have resulted in latchup; so you may want to eliminate that possibility first, by reviewing the power supply arrangement.

JW

waclawek.jan
Super User
July 17, 2023

I don't use and don't understand Rust, and that's probably the case with most users here.

So why don't you just describe the whole sequence you do in terms of registers/bits writes and reads.

> Trying to set the RCC_BDCR.BDRST bit before clock init makes the LSE hang on LSERDY bit.

You should first enable PWR by setting RCC_APB1ENR1.PWREN, in order to be enable backup domain access by setting PWR_CR1.DBP, and then you need to write one to RCC_BDCR.BDRST and then zero to RCC_BDCR.BDRST, before you try to start LSE.

JW

Explorer
July 19, 2023

We actually don't enable  backup domain access before starting the LSE, is this something could potentially cause problems? Is it necessary to do that?

waclawek.jan
Super User
July 19, 2023

 

Without enabling backup domain access you wouldn't be able to enable LSE at all. If you have enabled LSE, maybe some of the drivers you are using enabled DBP for you.

JW

Explorer
July 20, 2023

Not exactly sure how we do that, but i will check and come back to you. But is this the same sequence if we would like to use HSE?

waclawek.jan
Super User
July 20, 2023

Use HSE for what? It has a different primary purpose (alhtough HSE/32 is one of the possible inputs to RTC, if that's what you intend it for).

No, HSE is not in the backup domain, so there is no need to enable access to it.

I'm not sure what is your hardware and what do you want to accomplish, but in some cases it's a good idea to perform initial proof-of-concept experiments on some "known-good" hardware such as Nucleo or Disco boards.

JW

Explorer
July 21, 2023
void SystemClock_Config(void)
{
 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 /** Configure the main internal regulator output voltage
 */
 if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)
 {
 Error_Handler();
 }

 /** Initializes the RCC Oscillators according to the specified parameters
 * in the RCC_OscInitTypeDef structure.
 */
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
 RCC_OscInitStruct.LSIState = RCC_LSI_ON;
 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
 RCC_OscInitStruct.PLL.PLLM = 2;
 RCC_OscInitStruct.PLL.PLLN = 16;
 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7;
 RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
 RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
 {
 Error_Handler();
 }

 /** Initializes the CPU, AHB and APB buses clocks
 */
 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
 {
 Error_Handler();
 }
}


This is how the clock setup is done by the CubeMX generated code. First it sets up power, then the clocks. Is this the sequence you described earlier?
waclawek.jan
Super User
July 21, 2023

> This is how the clock setup is done by the CubeMX generated code.
> First it sets up power, then the clocks. Is this the sequence you described earlier?

I'm not sure what to answer to this.

I believe I've recommended to:

  • make sure power supply is correct during powerdown - negative VDD may cause the mcu to behave unpredictably;
  • by bisection and toggling a pin/observing find the point where the mcu stucks upon startup
  • add backup domain reset before anything else in startup, to prevent the backup-domain-brownout problem

JW