mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			152 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			C
		
	
	
/* mbed Microcontroller Library
 | 
						|
 * Copyright (c) 2006-2018 ARM Limited
 | 
						|
 * SPDX-License-Identifier: Apache-2.0
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#ifdef DEVICE_WATCHDOG
 | 
						|
 | 
						|
#include "watchdog_api.h"
 | 
						|
#include "reset_reason_api.h"
 | 
						|
#include "device.h"
 | 
						|
#include "mbed_error.h"
 | 
						|
#include <stdbool.h>
 | 
						|
 | 
						|
#define MAX_IWDG_PR 0x6 // Max value of Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR)
 | 
						|
#define MAX_IWDG_RL 0xFFFUL // Max value of Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR).
 | 
						|
 | 
						|
// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) to a prescaler_divider value.
 | 
						|
#define PR2PRESCALER_DIV(PR_BITS) \
 | 
						|
    (4UL << (PR_BITS))
 | 
						|
 | 
						|
// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR)
 | 
						|
// and Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR)
 | 
						|
// to a timeout value [ms].
 | 
						|
#define PR_RL2UINT64_TIMEOUT_MS(PR_BITS, RL_BITS) \
 | 
						|
    ((PR2PRESCALER_DIV(PR_BITS)) * (RL_BITS) * 1000ULL / (LSI_VALUE))
 | 
						|
 | 
						|
// Convert Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR) and a timeout value [ms]
 | 
						|
// to Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR)
 | 
						|
#define PR_TIMEOUT_MS2RL(PR_BITS, TIMEOUT_MS) \
 | 
						|
    (((TIMEOUT_MS) * (LSI_VALUE) / (PR2PRESCALER_DIV(PR_BITS)) + 999UL) / 1000UL)
 | 
						|
 | 
						|
#define MAX_TIMEOUT_MS_UINT64 PR_RL2UINT64_TIMEOUT_MS(MAX_IWDG_PR, MAX_IWDG_RL)
 | 
						|
#if (MAX_TIMEOUT_MS_UINT64 > UINT32_MAX)
 | 
						|
#define MAX_TIMEOUT_MS UINT32_MAX
 | 
						|
#else
 | 
						|
#define MAX_TIMEOUT_MS (MAX_TIMEOUT_MS_UINT64 & 0xFFFFFFFFUL)
 | 
						|
#endif
 | 
						|
 | 
						|
#define INVALID_IWDG_PR ((MAX_IWDG_PR) + 1) // Arbitrary value used to mark an invalid PR bits value.
 | 
						|
 | 
						|
// Pick a minimal Prescaler_divider bits (PR) value suitable for given timeout.
 | 
						|
static uint8_t pick_min_iwdg_pr(const uint32_t timeout_ms)
 | 
						|
{
 | 
						|
    for (uint8_t pr = 0; pr <= MAX_IWDG_PR; pr++) {
 | 
						|
        // Check that max timeout for given pr is greater than
 | 
						|
        // or equal to timeout_ms.
 | 
						|
        if (PR_RL2UINT64_TIMEOUT_MS(pr, MAX_IWDG_RL) >= timeout_ms) {
 | 
						|
            return pr;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return INVALID_IWDG_PR;
 | 
						|
}
 | 
						|
 | 
						|
IWDG_HandleTypeDef IwdgHandle;
 | 
						|
 | 
						|
watchdog_status_t hal_watchdog_init(const watchdog_config_t *config)
 | 
						|
{
 | 
						|
    const uint8_t pr = pick_min_iwdg_pr(config->timeout_ms);
 | 
						|
    if (pr == INVALID_IWDG_PR) {
 | 
						|
        return WATCHDOG_STATUS_INVALID_ARGUMENT;
 | 
						|
    }
 | 
						|
    const uint32_t rl = PR_TIMEOUT_MS2RL(pr, config->timeout_ms);
 | 
						|
 | 
						|
    IwdgHandle.Instance = IWDG;
 | 
						|
 | 
						|
    IwdgHandle.Init.Prescaler = pr;
 | 
						|
    IwdgHandle.Init.Reload    = rl;
 | 
						|
#if defined IWDG_WINR_WIN
 | 
						|
    IwdgHandle.Init.Window = IWDG_WINDOW_DISABLE;
 | 
						|
#endif
 | 
						|
 | 
						|
    if (HAL_IWDG_Init(&IwdgHandle) != HAL_OK) {
 | 
						|
        error("HAL_IWDG_Init error\n");
 | 
						|
    }
 | 
						|
 | 
						|
    return WATCHDOG_STATUS_OK;
 | 
						|
}
 | 
						|
 | 
						|
void hal_watchdog_kick(void)
 | 
						|
{
 | 
						|
    HAL_IWDG_Refresh(&IwdgHandle);
 | 
						|
}
 | 
						|
 | 
						|
watchdog_status_t hal_watchdog_stop(void)
 | 
						|
{
 | 
						|
    return WATCHDOG_STATUS_NOT_SUPPORTED;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t hal_watchdog_get_reload_value(void)
 | 
						|
{
 | 
						|
    // Wait for the Watchdog_prescaler_value_update bit (PVU) of
 | 
						|
    // Status_register (IWDG_SR) to be reset.
 | 
						|
    while (READ_BIT(IWDG->SR, IWDG_SR_PVU)) {
 | 
						|
    }
 | 
						|
    // Read Prescaler_divider bits (PR) of Prescaler_register (IWDG_PR).
 | 
						|
    const uint8_t pr = (IWDG->PR & IWDG_PR_PR_Msk) >> IWDG_PR_PR_Pos;
 | 
						|
 | 
						|
    // Wait for the Watchdog_counter_reload_value_update bit (RVU) of
 | 
						|
    // Status_register (IWDG_SR) to be reset.
 | 
						|
    while (READ_BIT(IWDG->SR, IWDG_SR_RVU)) {
 | 
						|
    }
 | 
						|
    // Read Watchdog_counter_reload_value bits (RL) of Reload_register (IWDG_RLR).
 | 
						|
    const uint32_t rl = (IWDG->RLR & IWDG_RLR_RL_Msk) >> IWDG_RLR_RL_Pos;
 | 
						|
 | 
						|
    return PR_RL2UINT64_TIMEOUT_MS(pr, rl);
 | 
						|
}
 | 
						|
 | 
						|
watchdog_features_t hal_watchdog_get_platform_features(void)
 | 
						|
{
 | 
						|
    watchdog_features_t features;
 | 
						|
    features.max_timeout = MAX_TIMEOUT_MS;
 | 
						|
    features.update_config = true;
 | 
						|
    features.disable_watchdog = false;
 | 
						|
 | 
						|
    /*  STM32 IWDG (Independent Watchdog) is clocked by its own dedicated low-speed clock (LSI) */
 | 
						|
    features.clock_typical_frequency = LSI_VALUE;
 | 
						|
 | 
						|
    /*  See LSI oscillator characteristics in Data Sheet */
 | 
						|
#if defined(STM32F1)
 | 
						|
    features.clock_max_frequency = 60000;
 | 
						|
#elif defined(STM32L0) || defined(STM32L1)
 | 
						|
    features.clock_max_frequency = 56000;
 | 
						|
#elif defined(STM32F2) || defined(STM32F4) || defined(STM32F7)
 | 
						|
    features.clock_max_frequency = 47000;
 | 
						|
#elif defined(STM32F0) || defined(STM32F3)
 | 
						|
    features.clock_max_frequency = 50000;
 | 
						|
#elif defined(STM32H7) || defined(STM32L4) || defined(STM32U5)
 | 
						|
    features.clock_max_frequency = 33600;
 | 
						|
#elif defined(STM32G0) || defined(STM32L5) || defined(STM32G4) || defined(STM32WB) || defined(STM32WL)
 | 
						|
    features.clock_max_frequency = 34000;
 | 
						|
#else
 | 
						|
#error "unsupported target"
 | 
						|
#endif
 | 
						|
 | 
						|
    return features;
 | 
						|
}
 | 
						|
 | 
						|
#endif // DEVICE_WATCHDOG
 |