8 years, 2 months ago.

STM32L476 LSE startup issues

Hi,

Has anyone verified that the STM32L476 Discovery or Nucleo is starting the LSE correctly? I have tested it on 3 boards, a Nucleo, a Discovery Board, and a custom board with a STM32L476RG and none of them will start the LSE into oscillation. Using the same code on a STM32L152 Nucleo will start it up correctly. See the attached scope captures.

The code looks like it tries to start the LSE, but will revert to the LSI if can not start. This is where my problem is, I want to use the RTC for wake up timing and the LSI is not very accurate.

Thanks

STM32L476 Nucleo /media/uploads/kholland/l4_nucleo_lse.jpeg /media/uploads/kholland/l4_nucleo_lse_2.jpeg STM32L476 Discovery Board /media/uploads/kholland/l4_discovery_lse.jpeg STM32L152 Nucleo /media/uploads/kholland/l152_nucleo_lse.jpeg

1 Answer

8 years, 2 months ago.

Extend the LSE timeout to 500mS. There is an update due very soon to correct the RTC reset issue on POR and nRST and includes this change.

If you want to use RTC for deep sleep / wake up see here:

https://developer.mbed.org/users/Sissors/code/WakeUp/

I am using this and works well. It also does not interfere with RTC time functions.

One BIG problem is the Interrupt function with the L476, in a nutshell it doesn't work resulting in all sorts of problems.

Accepted Answer

Thanks Paul for your quick reply. Is the stm32l4xx_hal_rcc.h file the only place to change the LSE timeout? I have changed it to 500mS and 5sec and neither one helps startup the LSE for me.

  1. define RCC_LSE_TIMEOUT_VALUE ((uint32_t)5000)
posted by Kevin Holland 17 Feb 2016

Yes, using the latest MBED-DEV library, I have mine set to 5000mS.

Below is the corrected RTC code, you could copy and replace this in yours, not sure if it will effect the LSE start up. I have this running on both Nucleo and Disco boards + prototype board. I have fitted the 8MHz crystal and use this, but sure it works without. I also tend to use mine HSE clocked at 80MHz (without USB), it does run quite quick. But as I mentioned Interrupts are all over the place, causes Ticker issues as well and RTOS won't run. I have messaged ST and they are looking at this, just have to wait :(

rtc_api.c

/* mbed Microcontroller Library
 *******************************************************************************
 * Copyright (c) 2015, STMicroelectronics
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 3. Neither the name of STMicroelectronics nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************
 */
#include "rtc_api.h"

#if DEVICE_RTC

#include "mbed_error.h"

#if DEVICE_RTC_LSI 
 static int rtc_inited = 0; 
#endif 

static RTC_HandleTypeDef RtcHandle;

void rtc_init(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
    uint32_t rtc_freq = 0;
    
#if DEVICE_RTC_LSI  
    rtc_inited = 1;  
#endif  

    RtcHandle.Instance = RTC;

    // Enable Power clock
    __HAL_RCC_PWR_CLK_ENABLE();

    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();

    // Reset Backup domain
    __HAL_RCC_BACKUPRESET_FORCE();
    __HAL_RCC_BACKUPRESET_RELEASE();


    // Enable LSE Oscillator
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
    RCC_OscInitStruct.LSEState       = RCC_LSE_ON; // External 32.768 kHz clock on OSC_IN/OSC_OUT
    RCC_OscInitStruct.LSIState       = RCC_LSI_OFF;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) == HAL_OK) { // Check if LSE has started correctly
        // Connect LSE to RTC
        PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
        PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
        HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
        rtc_freq = LSE_VALUE;
    }
    else {
      error("RTC error: LSE clock initialization failed.");
    }
#else
        // Enable LSI clock
        RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
        RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
        RCC_OscInitStruct.LSEState       = RCC_LSE_OFF;
        RCC_OscInitStruct.LSIState       = RCC_LSI_ON;
        if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
            error("Cannot initialize RTC with LSI\n");
        }
        // Connect LSI to RTC
        PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
        PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
        if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) {
            error("Cannot initialize RTC with LSI\n");
        }
        // This value is LSI typical value. To be measured precisely using a timer input capture for example.
        rtc_freq = 40000;
    }
#endif

    // Enable RTC
    __HAL_RCC_RTC_ENABLE();

    RtcHandle.Init.HourFormat     = RTC_HOURFORMAT_24;
    RtcHandle.Init.AsynchPrediv   = 127;
    RtcHandle.Init.SynchPrediv    = (rtc_freq / 128) - 1;
    RtcHandle.Init.OutPut         = RTC_OUTPUT_DISABLE;
    RtcHandle.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
    RtcHandle.Init.OutPutType     = RTC_OUTPUT_TYPE_OPENDRAIN;

    if (HAL_RTC_Init(&RtcHandle) != HAL_OK) {
        error("Cannot initialize RTC\n");
    }
}

void rtc_free(void)
{
    // Enable Power clock
    __HAL_RCC_PWR_CLK_ENABLE();

    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();

    // Reset Backup domain
    __HAL_RCC_BACKUPRESET_FORCE();
    __HAL_RCC_BACKUPRESET_RELEASE();

    // Disable access to Backup domain
    HAL_PWR_DisableBkUpAccess();

    // Disable LSI and LSE clocks
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI | RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.PLL.PLLState   = RCC_PLL_NONE;
    RCC_OscInitStruct.LSIState       = RCC_LSI_OFF;
    RCC_OscInitStruct.LSEState       = RCC_LSE_OFF;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);
#if DEVICE_RTC_LSI
    rtc_inited = 0;
#endif

}

int rtc_isenabled(void)
{
#if DEVICE_RTC_LSI
    return rtc_inited;
#else
  if ((RTC->ISR & RTC_ISR_INITS) ==  RTC_ISR_INITS) return 1;
  else return 0;
#endif

}

/*
 RTC Registers
   RTC_WeekDay 1=monday, 2=tuesday, ..., 7=sunday
   RTC_Month   1=january, 2=february, ..., 12=december
   RTC_Date    day of the month 1-31
   RTC_Year    year 0-99
 struct tm
   tm_sec      seconds after the minute 0-61
   tm_min      minutes after the hour 0-59
   tm_hour     hours since midnight 0-23
   tm_mday     day of the month 1-31
   tm_mon      months since January 0-11
   tm_year     years since 1900
   tm_wday     days since Sunday 0-6
   tm_yday     days since January 1 0-365
   tm_isdst    Daylight Saving Time flag
*/
time_t rtc_read(void)
{
    RTC_DateTypeDef dateStruct;
    RTC_TimeTypeDef timeStruct;
    struct tm timeinfo;

    RtcHandle.Instance = RTC;

    // Read actual date and time
    // Warning: the time must be read first!
    HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
    HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);

    // Setup a tm structure based on the RTC
    timeinfo.tm_wday = dateStruct.WeekDay;
    timeinfo.tm_mon  = dateStruct.Month - 1;
    timeinfo.tm_mday = dateStruct.Date;
    timeinfo.tm_year = dateStruct.Year + 100;
    timeinfo.tm_hour = timeStruct.Hours;
    timeinfo.tm_min  = timeStruct.Minutes;
    timeinfo.tm_sec  = timeStruct.Seconds;

    // Convert to timestamp
    time_t t = mktime(&timeinfo);

    return t;
}

void rtc_write(time_t t)
{
    RTC_DateTypeDef dateStruct;
    RTC_TimeTypeDef timeStruct;

    RtcHandle.Instance = RTC;
    
     // Enable Power clock
    __HAL_RCC_PWR_CLK_ENABLE();

    // Enable access to Backup domain
    HAL_PWR_EnableBkUpAccess();

    // Convert the time into a tm
    struct tm *timeinfo = localtime(&t);

    // Fill RTC structures
    dateStruct.WeekDay        = timeinfo->tm_wday;
    dateStruct.Month          = timeinfo->tm_mon + 1;
    dateStruct.Date           = timeinfo->tm_mday;
    dateStruct.Year           = timeinfo->tm_year - 100;
    timeStruct.Hours          = timeinfo->tm_hour;
    timeStruct.Minutes        = timeinfo->tm_min;
    timeStruct.Seconds        = timeinfo->tm_sec;
    timeStruct.TimeFormat     = RTC_HOURFORMAT12_PM;
    timeStruct.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
    timeStruct.StoreOperation = RTC_STOREOPERATION_RESET;

    // Change the RTC current date/time
    HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);
    HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
}

You need to add this line in device.h file, under line 50 :

device.h file

#define DEVICE_RTC_LSI          0 
posted by Paul Staron 17 Feb 2016

Thanks Paul, the timeout value did work. The LSE on this processor is a lot more sensitive to my scope probe then the L152. After double checking it does look like it is starting.

As for the interupt problems for the L476, I switched to a offline complier (GCC) and they have gone away so far. It might be related to the errata that ST posted. Problem 1.1 - http://www.st.com/st-web-ui/static/active/en/resource/technical/document/errata_sheet/DM00111498.pdf

posted by Kevin Holland 17 Feb 2016

Kevin, there is now a fix for the interrupt issue, NVIC_RAM_VECTOR_ADDRESS is set to 0x20000000 instead of 0x10000000 in the cmsis_nvic.c file.

I have corrected my MBED-DEV library and the interrupts now work as expected.

Using the corrected RTC and NVIC code, deep sleep and RTC wake up are working well @ 6uA deep sleep with rapid and accurate wake up.

Paul

posted by Paul Staron 18 Feb 2016