[FL-1818] System setting and debug options. RTC HAL refactoring. (#902)
* FuriHal: RTC API refactoring. System Setting application. FuriCore: adjustable log levels. Minor code cleanup. * Storage: change logging levels for internal storage. * FuriCore: fix broken trace logging level
This commit is contained in:
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rtc.h
|
||||
* @brief This file contains all the function prototypes for
|
||||
* the rtc.c file
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||
#ifndef __RTC_H__
|
||||
#define __RTC_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
/* USER CODE END Includes */
|
||||
|
||||
extern RTC_HandleTypeDef hrtc;
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
void MX_RTC_Init(void);
|
||||
|
||||
/* USER CODE BEGIN Prototypes */
|
||||
|
||||
/* USER CODE END Prototypes */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __RTC_H__ */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -48,7 +48,7 @@
|
||||
#define HAL_PKA_MODULE_ENABLED
|
||||
/*#define HAL_QSPI_MODULE_ENABLED */
|
||||
#define HAL_RNG_MODULE_ENABLED
|
||||
#define HAL_RTC_MODULE_ENABLED
|
||||
/*#define HAL_RTC_MODULE_ENABLED */
|
||||
/*#define HAL_SAI_MODULE_ENABLED */
|
||||
/*#define HAL_SMBUS_MODULE_ENABLED */
|
||||
/*#define HAL_SMARTCARD_MODULE_ENABLED */
|
||||
|
@@ -1,123 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file rtc.c
|
||||
* @brief This file provides code for the configuration
|
||||
* of the RTC instances.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "rtc.h"
|
||||
|
||||
/* USER CODE BEGIN 0 */
|
||||
|
||||
/* USER CODE END 0 */
|
||||
|
||||
RTC_HandleTypeDef hrtc;
|
||||
|
||||
/* RTC init function */
|
||||
void MX_RTC_Init(void)
|
||||
{
|
||||
RTC_TimeTypeDef sTime = {0};
|
||||
RTC_DateTypeDef sDate = {0};
|
||||
|
||||
/** Initialize RTC Only
|
||||
*/
|
||||
hrtc.Instance = RTC;
|
||||
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
|
||||
hrtc.Init.AsynchPrediv = 127;
|
||||
hrtc.Init.SynchPrediv = 255;
|
||||
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
|
||||
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
|
||||
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
|
||||
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
|
||||
if (HAL_RTC_Init(&hrtc) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN Check_RTC_BKUP */
|
||||
return;
|
||||
/* USER CODE END Check_RTC_BKUP */
|
||||
|
||||
/** Initialize RTC and set the Time and Date
|
||||
*/
|
||||
sTime.Hours = 0x0;
|
||||
sTime.Minutes = 0x0;
|
||||
sTime.Seconds = 0x0;
|
||||
sTime.SubSeconds = 0x0;
|
||||
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
|
||||
sTime.StoreOperation = RTC_STOREOPERATION_RESET;
|
||||
if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sDate.WeekDay = RTC_WEEKDAY_MONDAY;
|
||||
sDate.Month = RTC_MONTH_JANUARY;
|
||||
sDate.Date = 0x1;
|
||||
sDate.Year = 0x0;
|
||||
|
||||
if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void HAL_RTC_MspInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 0 */
|
||||
/* RTC clock enable */
|
||||
__HAL_RCC_RTC_ENABLE();
|
||||
__HAL_RCC_RTCAPB_CLK_ENABLE();
|
||||
|
||||
/* RTC interrupt Init */
|
||||
HAL_NVIC_SetPriority(TAMP_STAMP_LSECSS_IRQn, 5, 0);
|
||||
HAL_NVIC_EnableIRQ(TAMP_STAMP_LSECSS_IRQn);
|
||||
/* USER CODE BEGIN RTC_MspInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_RTC_MspDeInit(RTC_HandleTypeDef* rtcHandle)
|
||||
{
|
||||
|
||||
if(rtcHandle->Instance==RTC)
|
||||
{
|
||||
/* USER CODE BEGIN RTC_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_RTC_DISABLE();
|
||||
__HAL_RCC_RTCAPB_CLK_DISABLE();
|
||||
|
||||
/* RTC interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(TAMP_STAMP_LSECSS_IRQn);
|
||||
/* USER CODE BEGIN RTC_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END RTC_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -6,7 +6,6 @@
|
||||
|
||||
extern usbd_device udev;
|
||||
extern COMP_HandleTypeDef hcomp1;
|
||||
extern RTC_HandleTypeDef hrtc;
|
||||
extern TIM_HandleTypeDef htim1;
|
||||
extern TIM_HandleTypeDef htim2;
|
||||
extern TIM_HandleTypeDef htim16;
|
||||
@@ -40,10 +39,6 @@ void HSEM_IRQHandler(void) {
|
||||
HAL_HSEM_IRQHandler();
|
||||
}
|
||||
|
||||
void RTC_WKUP_IRQHandler(void){
|
||||
HW_TS_RTC_Wakeup_Handler();
|
||||
}
|
||||
|
||||
void IPCC_C1_TX_IRQHandler(void){
|
||||
HW_IPCC_Tx_Handler();
|
||||
}
|
||||
|
@@ -82,165 +82,6 @@ extern "C" {
|
||||
void HW_UART_Interrupt_Handler(hw_uart_id_t hw_uart_id);
|
||||
void HW_UART_DMA_Interrupt_Handler(hw_uart_id_t hw_uart_id);
|
||||
|
||||
/******************************************************************************
|
||||
* HW TimerServer
|
||||
******************************************************************************/
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/**
|
||||
* This setting is used when standby mode is supported.
|
||||
* hw_ts_InitMode_Limited should be used when the device restarts from Standby Mode. In that case, the Timer Server does
|
||||
* not re-initialized its context. Only the Hardware register which content has been lost is reconfigured
|
||||
* Otherwise, hw_ts_InitMode_Full should be requested (Start from Power ON) and everything is re-initialized.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
hw_ts_InitMode_Full,
|
||||
hw_ts_InitMode_Limited,
|
||||
} HW_TS_InitMode_t;
|
||||
|
||||
/**
|
||||
* When a Timer is created as a SingleShot timer, it is not automatically restarted when the timeout occurs. However,
|
||||
* the timer is kept reserved in the list and could be restarted at anytime with HW_TS_Start()
|
||||
*
|
||||
* When a Timer is created as a Repeated timer, it is automatically restarted when the timeout occurs.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
hw_ts_SingleShot,
|
||||
hw_ts_Repeated
|
||||
} HW_TS_Mode_t;
|
||||
|
||||
/**
|
||||
* hw_ts_Successful is returned when a Timer has been successfully created with HW_TS_Create(). Otherwise, hw_ts_Failed
|
||||
* is returned. When hw_ts_Failed is returned, that means there are not enough free slots in the list to create a
|
||||
* Timer. In that case, CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER should be increased
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
hw_ts_Successful,
|
||||
hw_ts_Failed,
|
||||
}HW_TS_ReturnStatus_t;
|
||||
|
||||
typedef void (*HW_TS_pTimerCb_t)(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the timer server
|
||||
* This API shall be called by the application before any timer is requested to the timer server. It
|
||||
* configures the RTC module to be connected to the LSI input clock.
|
||||
*
|
||||
* @param TimerInitMode: When the device restarts from Standby, it should request hw_ts_InitMode_Limited so that the
|
||||
* Timer context is not re-initialized. Otherwise, hw_ts_InitMode_Full should be requested
|
||||
* @param hrtc: RTC Handle
|
||||
* @retval None
|
||||
*/
|
||||
void HW_TS_Init(HW_TS_InitMode_t TimerInitMode, RTC_HandleTypeDef *hrtc);
|
||||
|
||||
/**
|
||||
* @brief Interface to create a virtual timer
|
||||
* The user shall call this API to create a timer. Once created, the timer is reserved to the module until it
|
||||
* has been deleted. When creating a timer, the user shall specify the mode (single shot or repeated), the
|
||||
* callback to be notified when the timer expires and a module ID to identify in the timer interrupt handler
|
||||
* which module is concerned. In return, the user gets a timer ID to handle it.
|
||||
*
|
||||
* @param TimerProcessID: This is an identifier provided by the user and returned in the callback to allow
|
||||
* identification of the requester
|
||||
* @param pTimerId: Timer Id returned to the user to request operation (start, stop, delete)
|
||||
* @param TimerMode: Mode of the virtual timer (Single shot or repeated)
|
||||
* @param pTimerCallBack: Callback when the virtual timer expires
|
||||
* @retval HW_TS_ReturnStatus_t: Return whether the creation is sucessfull or not
|
||||
*/
|
||||
HW_TS_ReturnStatus_t HW_TS_Create(uint32_t TimerProcessID, uint8_t *pTimerId, HW_TS_Mode_t TimerMode, HW_TS_pTimerCb_t pTimerCallBack);
|
||||
|
||||
/**
|
||||
* @brief Stop a virtual timer
|
||||
* This API may be used to stop a running timer. A timer which is stopped is move to the pending state.
|
||||
* A pending timer may be restarted at any time with a different timeout value but the mode cannot be changed.
|
||||
* Nothing is done when it is called to stop a timer which has been already stopped
|
||||
*
|
||||
* @param TimerID: Id of the timer to stop
|
||||
* @retval None
|
||||
*/
|
||||
void HW_TS_Stop(uint8_t TimerID);
|
||||
|
||||
/**
|
||||
* @brief Start a virtual timer
|
||||
* This API shall be used to start a timer. The timeout value is specified and may be different each time.
|
||||
* When the timer is in the single shot mode, it will move to the pending state when it expires. The user may
|
||||
* restart it at any time with a different timeout value. When the timer is in the repeated mode, it always
|
||||
* stay in the running state. When the timer expires, it will be restarted with the same timeout value.
|
||||
* This API shall not be called on a running timer.
|
||||
*
|
||||
* @param TimerID: The ID Id of the timer to start
|
||||
* @param timeout_ticks: Number of ticks of the virtual timer (Maximum value is (0xFFFFFFFF-0xFFFF = 0xFFFF0000)
|
||||
* @retval None
|
||||
*/
|
||||
void HW_TS_Start(uint8_t TimerID, uint32_t timeout_ticks);
|
||||
|
||||
/**
|
||||
* @brief Delete a virtual timer from the list
|
||||
* This API should be used when a timer is not needed anymore by the user. A deleted timer is removed from
|
||||
* the timer list managed by the timer server. It cannot be restarted again. The user has to go with the
|
||||
* creation of a new timer if required and may get a different timer id
|
||||
*
|
||||
* @param TimerID: The ID of the timer to remove from the list
|
||||
* @retval None
|
||||
*/
|
||||
void HW_TS_Delete(uint8_t TimerID);
|
||||
|
||||
/**
|
||||
* @brief Schedule the timer list on the timer interrupt handler
|
||||
* This interrupt handler shall be called by the application in the RTC interrupt handler. This handler takes
|
||||
* care of clearing all status flag required in the RTC and EXTI peripherals
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HW_TS_RTC_Wakeup_Handler(void);
|
||||
|
||||
/**
|
||||
* @brief Return the number of ticks to count before the interrupt
|
||||
* This API returns the number of ticks left to be counted before an interrupt is generated by the
|
||||
* Timer Server. This API may be used by the application for power management optimization. When the system
|
||||
* enters low power mode, the mode selection is a tradeoff between the wakeup time where the CPU is running
|
||||
* and the time while the CPU will be kept in low power mode before next wakeup. The deeper is the
|
||||
* low power mode used, the longer is the wakeup time. The low power mode management considering wakeup time
|
||||
* versus time in low power mode is implementation specific
|
||||
* When the timer is disabled (No timer in the list), it returns 0xFFFF
|
||||
*
|
||||
* @param None
|
||||
* @retval The number of ticks left to count
|
||||
*/
|
||||
uint16_t HW_TS_RTC_ReadLeftTicksToCount(void);
|
||||
|
||||
/**
|
||||
* @brief Notify the application that a registered timer has expired
|
||||
* This API shall be implemented by the user application.
|
||||
* This API notifies the application that a timer expires. This API is running in the RTC Wakeup interrupt
|
||||
* context. The application may implement an Operating System to change the context priority where the timer
|
||||
* callback may be handled. This API provides the module ID to identify which module is concerned and to allow
|
||||
* sending the information to the correct task
|
||||
*
|
||||
* @param TimerProcessID: The TimerProcessId associated with the timer when it has been created
|
||||
* @param TimerID: The TimerID of the expired timer
|
||||
* @param pTimerCallBack: The Callback associated with the timer when it has been created
|
||||
* @retval None
|
||||
*/
|
||||
void HW_TS_RTC_Int_AppNot(uint32_t TimerProcessID, uint8_t TimerID, HW_TS_pTimerCb_t pTimerCallBack);
|
||||
|
||||
/**
|
||||
* @brief Notify the application that the wakeupcounter has been updated
|
||||
* This API should be implemented by the user application
|
||||
* This API notifies the application that the counter has been updated. This is expected to be used along
|
||||
* with the HW_TS_RTC_ReadLeftTicksToCount () API. It could be that the counter has been updated since the
|
||||
* last call of HW_TS_RTC_ReadLeftTicksToCount () and before entering low power mode. This notification
|
||||
* provides a way to the application to solve that race condition to reevaluate the counter value before
|
||||
* entering low power mode
|
||||
*
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void HW_TS_RTC_CountUpdated_AppNot(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -1,893 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* File Name : hw_timerserver.c
|
||||
* Description : Hardware timerserver source file for STM32WPAN Middleware.
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© Copyright (c) 2020 STMicroelectronics.
|
||||
* All rights reserved.</center></h2>
|
||||
*
|
||||
* This software component is licensed by ST under Ultimate Liberty license
|
||||
* SLA0044, the "License"; You may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at:
|
||||
* www.st.com/SLA0044
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "app_common.h"
|
||||
#include "hw_conf.h"
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
typedef enum
|
||||
{
|
||||
TimerID_Free,
|
||||
TimerID_Created,
|
||||
TimerID_Running
|
||||
}TimerIDStatus_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SSR_Read_Requested,
|
||||
SSR_Read_Not_Requested
|
||||
}RequestReadSSR_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
WakeupTimerValue_Overpassed,
|
||||
WakeupTimerValue_LargeEnough
|
||||
}WakeupTimerLimitation_Status_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HW_TS_pTimerCb_t pTimerCallBack;
|
||||
uint32_t CounterInit;
|
||||
uint32_t CountLeft;
|
||||
TimerIDStatus_t TimerIDStatus;
|
||||
HW_TS_Mode_t TimerMode;
|
||||
uint32_t TimerProcessID;
|
||||
uint8_t PreviousID;
|
||||
uint8_t NextID;
|
||||
}TimerContext_t;
|
||||
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
#define SSR_FORBIDDEN_VALUE 0xFFFFFFFF
|
||||
#define TIMER_LIST_EMPTY 0xFFFF
|
||||
|
||||
/* Private macros ------------------------------------------------------------*/
|
||||
/* Private variables ---------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* START of Section TIMERSERVER_CONTEXT
|
||||
*/
|
||||
|
||||
PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile TimerContext_t aTimerContext[CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER];
|
||||
PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t CurrentRunningTimerID;
|
||||
PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint8_t PreviousRunningTimerID;
|
||||
PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile uint32_t SSRValueOnLastSetup;
|
||||
PLACE_IN_SECTION("TIMERSERVER_CONTEXT") static volatile WakeupTimerLimitation_Status_t WakeupTimerLimitation;
|
||||
|
||||
/**
|
||||
* END of Section TIMERSERVER_CONTEXT
|
||||
*/
|
||||
|
||||
static RTC_HandleTypeDef *phrtc; /**< RTC handle */
|
||||
static uint8_t WakeupTimerDivider;
|
||||
static uint8_t AsynchPrescalerUserConfig;
|
||||
static uint16_t SynchPrescalerUserConfig;
|
||||
static volatile uint16_t MaxWakeupTimerSetup;
|
||||
|
||||
/* Global variables ----------------------------------------------------------*/
|
||||
/* Private function prototypes -----------------------------------------------*/
|
||||
static void RestartWakeupCounter(uint16_t Value);
|
||||
static uint16_t ReturnTimeElapsed(void);
|
||||
static void RescheduleTimerList(void);
|
||||
static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR);
|
||||
static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID);
|
||||
static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID);
|
||||
static uint16_t linkTimer(uint8_t TimerID);
|
||||
static uint32_t ReadRtcSsrValue(void);
|
||||
|
||||
__weak void HW_TS_RTC_CountUpdated_AppNot(void);
|
||||
|
||||
/* Functions Definition ------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Read the RTC_SSR value
|
||||
* As described in the reference manual, the RTC_SSR shall be read twice to ensure
|
||||
* reliability of the value
|
||||
* @param None
|
||||
* @retval SSR value read
|
||||
*/
|
||||
static uint32_t ReadRtcSsrValue(void)
|
||||
{
|
||||
uint32_t first_read;
|
||||
uint32_t second_read;
|
||||
|
||||
first_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));
|
||||
|
||||
second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));
|
||||
|
||||
while(first_read != second_read)
|
||||
{
|
||||
first_read = second_read;
|
||||
|
||||
second_read = (uint32_t)(READ_BIT(RTC->SSR, RTC_SSR_SS));
|
||||
}
|
||||
|
||||
return second_read;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a Timer in the list after the Timer ID specified
|
||||
* @param TimerID: The ID of the Timer
|
||||
* @param RefTimerID: The ID of the Timer to be linked after
|
||||
* @retval None
|
||||
*/
|
||||
static void LinkTimerAfter(uint8_t TimerID, uint8_t RefTimerID)
|
||||
{
|
||||
uint8_t next_id;
|
||||
|
||||
next_id = aTimerContext[RefTimerID].NextID;
|
||||
|
||||
if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
|
||||
{
|
||||
aTimerContext[next_id].PreviousID = TimerID;
|
||||
}
|
||||
aTimerContext[TimerID].NextID = next_id;
|
||||
aTimerContext[TimerID].PreviousID = RefTimerID ;
|
||||
aTimerContext[RefTimerID].NextID = TimerID;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a Timer in the list before the ID specified
|
||||
* @param TimerID: The ID of the Timer
|
||||
* @param RefTimerID: The ID of the Timer to be linked before
|
||||
* @retval None
|
||||
*/
|
||||
static void LinkTimerBefore(uint8_t TimerID, uint8_t RefTimerID)
|
||||
{
|
||||
uint8_t previous_id;
|
||||
|
||||
if(RefTimerID != CurrentRunningTimerID)
|
||||
{
|
||||
previous_id = aTimerContext[RefTimerID].PreviousID;
|
||||
|
||||
aTimerContext[previous_id].NextID = TimerID;
|
||||
aTimerContext[TimerID].NextID = RefTimerID;
|
||||
aTimerContext[TimerID].PreviousID = previous_id ;
|
||||
aTimerContext[RefTimerID].PreviousID = TimerID;
|
||||
}
|
||||
else
|
||||
{
|
||||
aTimerContext[TimerID].NextID = RefTimerID;
|
||||
aTimerContext[RefTimerID].PreviousID = TimerID;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a Timer in the list
|
||||
* @param TimerID: The ID of the Timer
|
||||
* @retval None
|
||||
*/
|
||||
static uint16_t linkTimer(uint8_t TimerID)
|
||||
{
|
||||
uint32_t time_left;
|
||||
uint16_t time_elapsed;
|
||||
uint8_t timer_id_lookup;
|
||||
uint8_t next_id;
|
||||
|
||||
if(CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
|
||||
{
|
||||
/**
|
||||
* No timer in the list
|
||||
*/
|
||||
PreviousRunningTimerID = CurrentRunningTimerID;
|
||||
CurrentRunningTimerID = TimerID;
|
||||
aTimerContext[TimerID].NextID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER;
|
||||
|
||||
SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE;
|
||||
time_elapsed = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
time_elapsed = ReturnTimeElapsed();
|
||||
|
||||
/**
|
||||
* update count of the timer to be linked
|
||||
*/
|
||||
aTimerContext[TimerID].CountLeft += time_elapsed;
|
||||
time_left = aTimerContext[TimerID].CountLeft;
|
||||
|
||||
/**
|
||||
* Search for index where the new timer shall be linked
|
||||
*/
|
||||
if(aTimerContext[CurrentRunningTimerID].CountLeft <= time_left)
|
||||
{
|
||||
/**
|
||||
* Search for the ID after the first one
|
||||
*/
|
||||
timer_id_lookup = CurrentRunningTimerID;
|
||||
next_id = aTimerContext[timer_id_lookup].NextID;
|
||||
while((next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[next_id].CountLeft <= time_left))
|
||||
{
|
||||
timer_id_lookup = aTimerContext[timer_id_lookup].NextID;
|
||||
next_id = aTimerContext[timer_id_lookup].NextID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Link after the ID
|
||||
*/
|
||||
LinkTimerAfter(TimerID, timer_id_lookup);
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* Link before the first ID
|
||||
*/
|
||||
LinkTimerBefore(TimerID, CurrentRunningTimerID);
|
||||
PreviousRunningTimerID = CurrentRunningTimerID;
|
||||
CurrentRunningTimerID = TimerID;
|
||||
}
|
||||
}
|
||||
|
||||
return time_elapsed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a Timer from the list
|
||||
* @param TimerID: The ID of the Timer
|
||||
* @param RequestReadSSR: Request to read the SSR register or not
|
||||
* @retval None
|
||||
*/
|
||||
static void UnlinkTimer(uint8_t TimerID, RequestReadSSR_t RequestReadSSR)
|
||||
{
|
||||
uint8_t previous_id;
|
||||
uint8_t next_id;
|
||||
|
||||
if(TimerID == CurrentRunningTimerID)
|
||||
{
|
||||
PreviousRunningTimerID = CurrentRunningTimerID;
|
||||
CurrentRunningTimerID = aTimerContext[TimerID].NextID;
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_id = aTimerContext[TimerID].PreviousID;
|
||||
next_id = aTimerContext[TimerID].NextID;
|
||||
|
||||
aTimerContext[previous_id].NextID = aTimerContext[TimerID].NextID;
|
||||
if(next_id != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
|
||||
{
|
||||
aTimerContext[next_id].PreviousID = aTimerContext[TimerID].PreviousID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer is out of the list
|
||||
*/
|
||||
aTimerContext[TimerID].TimerIDStatus = TimerID_Created;
|
||||
|
||||
if((CurrentRunningTimerID == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (RequestReadSSR == SSR_Read_Requested))
|
||||
{
|
||||
SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the number of ticks counted by the wakeuptimer since it has been started
|
||||
* @note The API is reading the SSR register to get how many ticks have been counted
|
||||
* since the time the timer has been started
|
||||
* @param None
|
||||
* @retval Time expired in Ticks
|
||||
*/
|
||||
static uint16_t ReturnTimeElapsed(void)
|
||||
{
|
||||
uint32_t return_value;
|
||||
uint32_t wrap_counter;
|
||||
|
||||
if(SSRValueOnLastSetup != SSR_FORBIDDEN_VALUE)
|
||||
{
|
||||
return_value = ReadRtcSsrValue(); /**< Read SSR register first */
|
||||
|
||||
if (SSRValueOnLastSetup >= return_value)
|
||||
{
|
||||
return_value = SSRValueOnLastSetup - return_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
wrap_counter = SynchPrescalerUserConfig - return_value;
|
||||
return_value = SSRValueOnLastSetup + wrap_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
* At this stage, ReturnValue holds the number of ticks counted by SSR
|
||||
* Need to translate in number of ticks counted by the Wakeuptimer
|
||||
*/
|
||||
return_value = return_value*AsynchPrescalerUserConfig;
|
||||
return_value = return_value >> WakeupTimerDivider;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_value = 0;
|
||||
}
|
||||
|
||||
return (uint16_t)return_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the wakeup counter
|
||||
* @note The API is writing the counter value so that the value is decreased by one to cope with the fact
|
||||
* the interrupt is generated with 1 extra clock cycle (See RefManuel)
|
||||
* It assumes all condition are met to be allowed to write the wakeup counter
|
||||
* @param Value: Value to be written in the counter
|
||||
* @retval None
|
||||
*/
|
||||
static void RestartWakeupCounter(uint16_t Value)
|
||||
{
|
||||
/**
|
||||
* The wakeuptimer has been disabled in the calling function to reduce the time to poll the WUTWF
|
||||
* FLAG when the new value will have to be written
|
||||
* __HAL_RTC_WAKEUPTIMER_DISABLE(phrtc);
|
||||
*/
|
||||
|
||||
if(Value == 0)
|
||||
{
|
||||
SSRValueOnLastSetup = ReadRtcSsrValue();
|
||||
|
||||
/**
|
||||
* Simulate that the Timer expired
|
||||
*/
|
||||
HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((Value > 1) ||(WakeupTimerDivider != 1))
|
||||
{
|
||||
Value -= 1;
|
||||
}
|
||||
|
||||
while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET);
|
||||
|
||||
/**
|
||||
* make sure to clear the flags after checking the WUTWF.
|
||||
* It takes 2 RTCCLK between the time the WUTE bit is disabled and the
|
||||
* time the timer is disabled. The WUTWF bit somehow guarantee the system is stable
|
||||
* Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between
|
||||
* due to the autoreload feature
|
||||
*/
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
|
||||
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
|
||||
HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */
|
||||
|
||||
MODIFY_REG(RTC->WUTR, RTC_WUTR_WUT, Value);
|
||||
|
||||
/**
|
||||
* Update the value here after the WUTWF polling that may take some time
|
||||
*/
|
||||
SSRValueOnLastSetup = ReadRtcSsrValue();
|
||||
|
||||
__HAL_RTC_WAKEUPTIMER_ENABLE(phrtc); /**< Enable the Wakeup Timer */
|
||||
|
||||
HW_TS_RTC_CountUpdated_AppNot();
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reschedule the list of timer
|
||||
* @note 1) Update the count left for each timer in the list
|
||||
* 2) Setup the wakeuptimer
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
static void RescheduleTimerList(void)
|
||||
{
|
||||
uint8_t localTimerID;
|
||||
uint32_t timecountleft;
|
||||
uint16_t wakeup_timer_value;
|
||||
uint16_t time_elapsed;
|
||||
|
||||
/**
|
||||
* The wakeuptimer is disabled now to reduce the time to poll the WUTWF
|
||||
* FLAG when the new value will have to be written
|
||||
*/
|
||||
if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET)
|
||||
{
|
||||
/**
|
||||
* Wait for the flag to be back to 0 when the wakeup timer is enabled
|
||||
*/
|
||||
while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET);
|
||||
}
|
||||
__HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */
|
||||
|
||||
localTimerID = CurrentRunningTimerID;
|
||||
|
||||
/**
|
||||
* Calculate what will be the value to write in the wakeuptimer
|
||||
*/
|
||||
timecountleft = aTimerContext[localTimerID].CountLeft;
|
||||
|
||||
/**
|
||||
* Read how much has been counted
|
||||
*/
|
||||
time_elapsed = ReturnTimeElapsed();
|
||||
|
||||
if(timecountleft < time_elapsed )
|
||||
{
|
||||
/**
|
||||
* There is no tick left to count
|
||||
*/
|
||||
wakeup_timer_value = 0;
|
||||
WakeupTimerLimitation = WakeupTimerValue_LargeEnough;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(timecountleft > (time_elapsed + MaxWakeupTimerSetup))
|
||||
{
|
||||
/**
|
||||
* The number of tick left is greater than the Wakeuptimer maximum value
|
||||
*/
|
||||
wakeup_timer_value = MaxWakeupTimerSetup;
|
||||
|
||||
WakeupTimerLimitation = WakeupTimerValue_Overpassed;
|
||||
}
|
||||
else
|
||||
{
|
||||
wakeup_timer_value = timecountleft - time_elapsed;
|
||||
WakeupTimerLimitation = WakeupTimerValue_LargeEnough;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* update ticks left to be counted for each timer
|
||||
*/
|
||||
while(localTimerID != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
|
||||
{
|
||||
if (aTimerContext[localTimerID].CountLeft < time_elapsed)
|
||||
{
|
||||
aTimerContext[localTimerID].CountLeft = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
aTimerContext[localTimerID].CountLeft -= time_elapsed;
|
||||
}
|
||||
localTimerID = aTimerContext[localTimerID].NextID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write next count
|
||||
*/
|
||||
RestartWakeupCounter(wakeup_timer_value);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
/* Public functions ----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* For all public interface except that may need write access to the RTC, the RTC
|
||||
* shall be unlock at the beginning and locked at the output
|
||||
* In order to ease maintainability, the unlock is done at the top and the lock at then end
|
||||
* in case some new implementation is coming in the future
|
||||
*/
|
||||
|
||||
void HW_TS_RTC_Wakeup_Handler(void)
|
||||
{
|
||||
HW_TS_pTimerCb_t ptimer_callback;
|
||||
uint32_t timer_process_id;
|
||||
uint8_t local_current_running_timer_id;
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
uint32_t primask_bit;
|
||||
#endif
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
|
||||
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
|
||||
#endif
|
||||
|
||||
/* Disable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
|
||||
|
||||
/**
|
||||
* Disable the Wakeup Timer
|
||||
* This may speed up a bit the processing to wait the timer to be disabled
|
||||
* The timer is still counting 2 RTCCLK
|
||||
*/
|
||||
__HAL_RTC_WAKEUPTIMER_DISABLE(phrtc);
|
||||
|
||||
local_current_running_timer_id = CurrentRunningTimerID;
|
||||
|
||||
if(aTimerContext[local_current_running_timer_id].TimerIDStatus == TimerID_Running)
|
||||
{
|
||||
ptimer_callback = aTimerContext[local_current_running_timer_id].pTimerCallBack;
|
||||
timer_process_id = aTimerContext[local_current_running_timer_id].TimerProcessID;
|
||||
|
||||
/**
|
||||
* It should be good to check whether the TimeElapsed is greater or not than the tick left to be counted
|
||||
* However, due to the inaccuracy of the reading of the time elapsed, it may return there is 1 tick
|
||||
* to be left whereas the count is over
|
||||
* A more secure implementation has been done with a flag to state whereas the full count has been written
|
||||
* in the wakeuptimer or not
|
||||
*/
|
||||
if(WakeupTimerLimitation != WakeupTimerValue_Overpassed)
|
||||
{
|
||||
if(aTimerContext[local_current_running_timer_id].TimerMode == hw_ts_Repeated)
|
||||
{
|
||||
UnlinkTimer(local_current_running_timer_id, SSR_Read_Not_Requested);
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
HW_TS_Start(local_current_running_timer_id, aTimerContext[local_current_running_timer_id].CounterInit);
|
||||
|
||||
/* Disable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
HW_TS_Stop(local_current_running_timer_id);
|
||||
|
||||
/* Disable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
|
||||
}
|
||||
|
||||
HW_TS_RTC_Int_AppNot(timer_process_id, local_current_running_timer_id, ptimer_callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
RescheduleTimerList();
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
* We should never end up in this case
|
||||
* However, if due to any bug in the timer server this is the case, the mistake may not impact the user.
|
||||
* We could just clean the interrupt flag and get out from this unexpected interrupt
|
||||
*/
|
||||
while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET);
|
||||
|
||||
/**
|
||||
* make sure to clear the flags after checking the WUTWF.
|
||||
* It takes 2 RTCCLK between the time the WUTE bit is disabled and the
|
||||
* time the timer is disabled. The WUTWF bit somehow guarantee the system is stable
|
||||
* Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between
|
||||
* due to the autoreload feature
|
||||
*/
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
|
||||
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Enable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void HW_TS_Init(HW_TS_InitMode_t TimerInitMode, RTC_HandleTypeDef *hrtc)
|
||||
{
|
||||
uint8_t loop;
|
||||
uint32_t localmaxwakeuptimersetup;
|
||||
|
||||
/**
|
||||
* Get RTC handler
|
||||
*/
|
||||
phrtc = hrtc;
|
||||
|
||||
/* Disable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
|
||||
|
||||
SET_BIT(RTC->CR, RTC_CR_BYPSHAD);
|
||||
|
||||
/**
|
||||
* Readout the user config
|
||||
*/
|
||||
WakeupTimerDivider = (4 - ((uint32_t)(READ_BIT(RTC->CR, RTC_CR_WUCKSEL))));
|
||||
|
||||
AsynchPrescalerUserConfig = (uint8_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_A) >> (uint32_t)POSITION_VAL(RTC_PRER_PREDIV_A)) + 1;
|
||||
|
||||
SynchPrescalerUserConfig = (uint16_t)(READ_BIT(RTC->PRER, RTC_PRER_PREDIV_S)) + 1;
|
||||
|
||||
/**
|
||||
* Margin is taken to avoid wrong calculation when the wrap around is there and some
|
||||
* application interrupts may have delayed the reading
|
||||
*/
|
||||
localmaxwakeuptimersetup = ((((SynchPrescalerUserConfig - 1)*AsynchPrescalerUserConfig) - CFG_HW_TS_RTC_HANDLER_MAX_DELAY) >> WakeupTimerDivider);
|
||||
|
||||
if(localmaxwakeuptimersetup >= 0xFFFF)
|
||||
{
|
||||
MaxWakeupTimerSetup = 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
MaxWakeupTimerSetup = (uint16_t)localmaxwakeuptimersetup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure EXTI module
|
||||
*/
|
||||
LL_EXTI_EnableRisingTrig_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT);
|
||||
LL_EXTI_EnableIT_0_31(RTC_EXTI_LINE_WAKEUPTIMER_EVENT);
|
||||
|
||||
if(TimerInitMode == hw_ts_InitMode_Full)
|
||||
{
|
||||
WakeupTimerLimitation = WakeupTimerValue_LargeEnough;
|
||||
SSRValueOnLastSetup = SSR_FORBIDDEN_VALUE;
|
||||
|
||||
/**
|
||||
* Initialize the timer server
|
||||
*/
|
||||
for(loop = 0; loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; loop++)
|
||||
{
|
||||
aTimerContext[loop].TimerIDStatus = TimerID_Free;
|
||||
}
|
||||
|
||||
CurrentRunningTimerID = CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER; /**< Set ID to non valid value */
|
||||
|
||||
__HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
|
||||
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
|
||||
HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */
|
||||
__HAL_RTC_WAKEUPTIMER_ENABLE_IT(phrtc, RTC_IT_WUT); /**< Enable interrupt in RTC module */
|
||||
}
|
||||
else
|
||||
{
|
||||
if(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTF) != RESET)
|
||||
{
|
||||
/**
|
||||
* Simulate that the Timer expired
|
||||
*/
|
||||
HAL_NVIC_SetPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
|
||||
|
||||
HAL_NVIC_SetPriority(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID, CFG_HW_TS_NVIC_RTC_WAKEUP_IT_PREEMPTPRIO, CFG_HW_TS_NVIC_RTC_WAKEUP_IT_SUBPRIO); /**< Set NVIC priority */
|
||||
HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
HW_TS_ReturnStatus_t HW_TS_Create(uint32_t TimerProcessID, uint8_t *pTimerId, HW_TS_Mode_t TimerMode, HW_TS_pTimerCb_t pftimeout_handler)
|
||||
{
|
||||
HW_TS_ReturnStatus_t localreturnstatus;
|
||||
uint8_t loop = 0;
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
uint32_t primask_bit;
|
||||
#endif
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
|
||||
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
|
||||
#endif
|
||||
|
||||
while((loop < CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER) && (aTimerContext[loop].TimerIDStatus != TimerID_Free))
|
||||
{
|
||||
loop++;
|
||||
}
|
||||
|
||||
if(loop != CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
|
||||
{
|
||||
aTimerContext[loop].TimerIDStatus = TimerID_Created;
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
|
||||
aTimerContext[loop].TimerProcessID = TimerProcessID;
|
||||
aTimerContext[loop].TimerMode = TimerMode;
|
||||
aTimerContext[loop].pTimerCallBack = pftimeout_handler;
|
||||
*pTimerId = loop;
|
||||
|
||||
localreturnstatus = hw_ts_Successful;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
|
||||
localreturnstatus = hw_ts_Failed;
|
||||
}
|
||||
|
||||
return(localreturnstatus);
|
||||
}
|
||||
|
||||
void HW_TS_Delete(uint8_t timer_id)
|
||||
{
|
||||
HW_TS_Stop(timer_id);
|
||||
|
||||
aTimerContext[timer_id].TimerIDStatus = TimerID_Free; /**< release ID */
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void HW_TS_Stop(uint8_t timer_id)
|
||||
{
|
||||
uint8_t localcurrentrunningtimerid;
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
uint32_t primask_bit;
|
||||
#endif
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
|
||||
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
|
||||
#endif
|
||||
|
||||
HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */
|
||||
|
||||
/* Disable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
|
||||
|
||||
if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running)
|
||||
{
|
||||
UnlinkTimer(timer_id, SSR_Read_Requested);
|
||||
localcurrentrunningtimerid = CurrentRunningTimerID;
|
||||
|
||||
if(localcurrentrunningtimerid == CFG_HW_TS_MAX_NBR_CONCURRENT_TIMER)
|
||||
{
|
||||
/**
|
||||
* List is empty
|
||||
*/
|
||||
|
||||
/**
|
||||
* Disable the timer
|
||||
*/
|
||||
if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET)
|
||||
{
|
||||
/**
|
||||
* Wait for the flag to be back to 0 when the wakeup timer is enabled
|
||||
*/
|
||||
while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == SET);
|
||||
}
|
||||
__HAL_RTC_WAKEUPTIMER_DISABLE(phrtc); /**< Disable the Wakeup Timer */
|
||||
|
||||
while(__HAL_RTC_WAKEUPTIMER_GET_FLAG(phrtc, RTC_FLAG_WUTWF) == RESET);
|
||||
|
||||
/**
|
||||
* make sure to clear the flags after checking the WUTWF.
|
||||
* It takes 2 RTCCLK between the time the WUTE bit is disabled and the
|
||||
* time the timer is disabled. The WUTWF bit somehow guarantee the system is stable
|
||||
* Otherwise, when the timer is periodic with 1 Tick, it may generate an extra interrupt in between
|
||||
* due to the autoreload feature
|
||||
*/
|
||||
__HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(phrtc, RTC_FLAG_WUTF); /**< Clear flag in RTC module */
|
||||
__HAL_RTC_WAKEUPTIMER_EXTI_CLEAR_FLAG(); /**< Clear flag in EXTI module */
|
||||
HAL_NVIC_ClearPendingIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Clear pending bit in NVIC */
|
||||
}
|
||||
else if(PreviousRunningTimerID != localcurrentrunningtimerid)
|
||||
{
|
||||
RescheduleTimerList();
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
|
||||
|
||||
HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void HW_TS_Start(uint8_t timer_id, uint32_t timeout_ticks)
|
||||
{
|
||||
uint16_t time_elapsed;
|
||||
uint8_t localcurrentrunningtimerid;
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
uint32_t primask_bit;
|
||||
#endif
|
||||
|
||||
if(aTimerContext[timer_id].TimerIDStatus == TimerID_Running)
|
||||
{
|
||||
HW_TS_Stop( timer_id );
|
||||
}
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
|
||||
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
|
||||
#endif
|
||||
|
||||
HAL_NVIC_DisableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Disable NVIC */
|
||||
|
||||
/* Disable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_DISABLE( phrtc );
|
||||
|
||||
aTimerContext[timer_id].TimerIDStatus = TimerID_Running;
|
||||
|
||||
aTimerContext[timer_id].CountLeft = timeout_ticks;
|
||||
aTimerContext[timer_id].CounterInit = timeout_ticks;
|
||||
|
||||
time_elapsed = linkTimer(timer_id);
|
||||
|
||||
localcurrentrunningtimerid = CurrentRunningTimerID;
|
||||
|
||||
if(PreviousRunningTimerID != localcurrentrunningtimerid)
|
||||
{
|
||||
RescheduleTimerList();
|
||||
}
|
||||
else
|
||||
{
|
||||
aTimerContext[timer_id].CountLeft -= time_elapsed;
|
||||
}
|
||||
|
||||
/* Enable the write protection for RTC registers */
|
||||
__HAL_RTC_WRITEPROTECTION_ENABLE( phrtc );
|
||||
|
||||
HAL_NVIC_EnableIRQ(CFG_HW_TS_RTC_WAKEUP_HANDLER_ID); /**< Enable NVIC */
|
||||
|
||||
#if (CFG_HW_TS_USE_PRIMASK_AS_CRITICAL_SECTION == 1)
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t HW_TS_RTC_ReadLeftTicksToCount(void)
|
||||
{
|
||||
uint32_t primask_bit;
|
||||
uint16_t return_value, auro_reload_value, elapsed_time_value;
|
||||
|
||||
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
|
||||
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
|
||||
|
||||
if((READ_BIT(RTC->CR, RTC_CR_WUTE) == (RTC_CR_WUTE)) == SET)
|
||||
{
|
||||
auro_reload_value = (uint32_t)(READ_BIT(RTC->WUTR, RTC_WUTR_WUT));
|
||||
|
||||
elapsed_time_value = ReturnTimeElapsed();
|
||||
|
||||
if(auro_reload_value > elapsed_time_value)
|
||||
{
|
||||
return_value = auro_reload_value - elapsed_time_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return_value = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return_value = TIMER_LIST_EMPTY;
|
||||
}
|
||||
|
||||
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
|
||||
|
||||
return (return_value);
|
||||
}
|
||||
|
||||
__weak void HW_TS_RTC_Int_AppNot(uint32_t TimerProcessID, uint8_t TimerID, HW_TS_pTimerCb_t pTimerCallBack)
|
||||
{
|
||||
pTimerCallBack();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
@@ -23,11 +23,3 @@ void furi_hal_bootloader_set_mode(FuriHalBootloaderMode mode) {
|
||||
LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR0, BOOT_REQUEST_DFU);
|
||||
}
|
||||
}
|
||||
|
||||
void furi_hal_bootloader_set_flags(FuriHalBootloaderFlag flags) {
|
||||
LL_RTC_BAK_SetRegister(RTC, LL_RTC_BKP_DR2, flags);
|
||||
}
|
||||
|
||||
FuriHalBootloaderFlag furi_hal_bootloader_get_flags() {
|
||||
return LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR2);
|
||||
}
|
@@ -77,14 +77,6 @@ void furi_hal_clock_init() {
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) {
|
||||
LL_RCC_ForceBackupDomainReset();
|
||||
LL_RCC_ReleaseBackupDomainReset();
|
||||
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
|
||||
}
|
||||
|
||||
LL_RCC_EnableRTC();
|
||||
|
||||
LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK2);
|
||||
LL_RCC_SetLPUARTClockSource(LL_RCC_LPUART1_CLKSOURCE_PCLK1);
|
||||
LL_RCC_SetADCClockSource(LL_RCC_ADC_CLKSOURCE_PLLSAI1);
|
||||
@@ -118,7 +110,6 @@ void furi_hal_clock_init() {
|
||||
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_AES2);
|
||||
|
||||
// APB1
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB);
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2);
|
||||
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_LPUART1);
|
||||
|
||||
|
@@ -158,7 +158,6 @@ void DMA2_Channel8_IRQHandler(void) {
|
||||
if (furi_hal_dma_channel_isr[1][7]) furi_hal_dma_channel_isr[1][7]();
|
||||
}
|
||||
|
||||
|
||||
void TAMP_STAMP_LSECSS_IRQHandler(void) {
|
||||
if (LL_RCC_IsActiveFlag_LSECSS()) {
|
||||
LL_RCC_ClearFlag_LSECSS();
|
||||
@@ -174,7 +173,6 @@ void TAMP_STAMP_LSECSS_IRQHandler(void) {
|
||||
void RCC_IRQHandler(void) {
|
||||
}
|
||||
|
||||
|
||||
void NMI_Handler(void) {
|
||||
if (LL_RCC_IsActiveFlag_HSECSS()) {
|
||||
LL_RCC_ClearFlag_HSECSS();
|
||||
@@ -206,5 +204,4 @@ void UsageFault_Handler(void) {
|
||||
}
|
||||
|
||||
void DebugMon_Handler(void) {
|
||||
|
||||
}
|
||||
|
122
firmware/targets/f7/furi-hal/furi-hal-rtc.c
Normal file
122
firmware/targets/f7/furi-hal/furi-hal-rtc.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <furi-hal-rtc.h>
|
||||
#include <stm32wbxx_ll_rcc.h>
|
||||
#include <stm32wbxx_ll_rtc.h>
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "FuriHalRtc"
|
||||
|
||||
#define FURI_HAL_RTC_BOOT_FLAGS_REG LL_RTC_BKP_DR0
|
||||
#define FURI_HAL_RTC_BOOT_VERSION_REG LL_RTC_BKP_DR1
|
||||
#define FURI_HAL_RTC_SYSTEM_REG LL_RTC_BKP_DR2
|
||||
|
||||
typedef struct {
|
||||
uint8_t log_level:4;
|
||||
uint8_t log_reserved:4;
|
||||
uint8_t flags;
|
||||
uint16_t reserved;
|
||||
} DeveloperReg;
|
||||
|
||||
void furi_hal_rtc_init() {
|
||||
if(LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSE) {
|
||||
LL_RCC_ForceBackupDomainReset();
|
||||
LL_RCC_ReleaseBackupDomainReset();
|
||||
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSE);
|
||||
}
|
||||
|
||||
LL_RCC_EnableRTC();
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_RTCAPB);
|
||||
|
||||
LL_RTC_InitTypeDef RTC_InitStruct = {0};
|
||||
RTC_InitStruct.HourFormat = LL_RTC_HOURFORMAT_24HOUR;
|
||||
RTC_InitStruct.AsynchPrescaler = 127;
|
||||
RTC_InitStruct.SynchPrescaler = 255;
|
||||
LL_RTC_Init(RTC, &RTC_InitStruct);
|
||||
|
||||
furi_log_set_level(furi_hal_rtc_get_log_level());
|
||||
|
||||
FURI_LOG_I(TAG, "Init OK");
|
||||
}
|
||||
|
||||
void furi_hal_rtc_set_log_level(uint8_t level) {
|
||||
uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG);
|
||||
((DeveloperReg*)&data)->log_level = level;
|
||||
LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data);
|
||||
furi_log_set_level(level);
|
||||
}
|
||||
|
||||
uint8_t furi_hal_rtc_get_log_level() {
|
||||
uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG);
|
||||
return ((DeveloperReg*)&data)->log_level;
|
||||
}
|
||||
|
||||
void furi_hal_rtc_set_flag(FuriHalRtcFlag flag) {
|
||||
uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG);
|
||||
((DeveloperReg*)&data)->flags |= flag;
|
||||
LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data);
|
||||
}
|
||||
|
||||
void furi_hal_rtc_reset_flag(FuriHalRtcFlag flag) {
|
||||
uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG);
|
||||
((DeveloperReg*)&data)->flags &= ~flag;
|
||||
LL_RTC_BAK_SetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG, data);
|
||||
}
|
||||
|
||||
bool furi_hal_rtc_is_flag_set(FuriHalRtcFlag flag) {
|
||||
uint32_t data = LL_RTC_BAK_GetRegister(RTC, FURI_HAL_RTC_SYSTEM_REG);
|
||||
return ((DeveloperReg*)&data)->flags & flag;
|
||||
}
|
||||
|
||||
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {
|
||||
furi_assert(datetime);
|
||||
|
||||
/* Disable write protection */
|
||||
LL_RTC_DisableWriteProtection(RTC);
|
||||
|
||||
/* Enter Initialization mode and wait for INIT flag to be set */
|
||||
LL_RTC_EnableInitMode(RTC);
|
||||
while(!LL_RTC_IsActiveFlag_INIT(RTC)) {}
|
||||
|
||||
/* Set time */
|
||||
LL_RTC_TIME_Config(RTC,
|
||||
LL_RTC_TIME_FORMAT_AM_OR_24,
|
||||
__LL_RTC_CONVERT_BIN2BCD(datetime->hour),
|
||||
__LL_RTC_CONVERT_BIN2BCD(datetime->minute),
|
||||
__LL_RTC_CONVERT_BIN2BCD(datetime->second)
|
||||
);
|
||||
|
||||
/* Set date */
|
||||
LL_RTC_DATE_Config(RTC,
|
||||
datetime->weekday,
|
||||
__LL_RTC_CONVERT_BIN2BCD(datetime->day),
|
||||
__LL_RTC_CONVERT_BIN2BCD(datetime->month),
|
||||
__LL_RTC_CONVERT_BIN2BCD(datetime->year - 2000)
|
||||
);
|
||||
|
||||
/* Exit Initialization mode */
|
||||
LL_RTC_DisableInitMode(RTC);
|
||||
|
||||
/* If RTC_CR_BYPSHAD bit = 0, wait for synchro else this check is not needed */
|
||||
if (!LL_RTC_IsShadowRegBypassEnabled(RTC)) {
|
||||
LL_RTC_ClearFlag_RS(RTC);
|
||||
while(!LL_RTC_IsActiveFlag_RS(RTC)) {};
|
||||
}
|
||||
|
||||
/* Enable write protection */
|
||||
LL_RTC_EnableWriteProtection(RTC);
|
||||
}
|
||||
|
||||
void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime) {
|
||||
furi_assert(datetime);
|
||||
|
||||
uint32_t time = LL_RTC_TIME_Get(RTC); // 0x00HHMMSS
|
||||
uint32_t date = LL_RTC_DATE_Get(RTC); // 0xWWDDMMYY
|
||||
|
||||
datetime->second = __LL_RTC_CONVERT_BCD2BIN((time>>0) & 0xFF);
|
||||
datetime->minute = __LL_RTC_CONVERT_BCD2BIN((time>>8) & 0xFF);
|
||||
datetime->hour = __LL_RTC_CONVERT_BCD2BIN((time>>16) & 0xFF);
|
||||
datetime->year = __LL_RTC_CONVERT_BCD2BIN((date >> 0) & 0xFF) + 2000;
|
||||
datetime->month = __LL_RTC_CONVERT_BCD2BIN((date >> 8) & 0xFF);
|
||||
datetime->day = __LL_RTC_CONVERT_BCD2BIN((date >> 16) & 0xFF);
|
||||
datetime->weekday = __LL_RTC_CONVERT_BCD2BIN((date >> 24) & 0xFF);
|
||||
}
|
@@ -1,7 +1,6 @@
|
||||
#include <furi-hal.h>
|
||||
|
||||
#include <comp.h>
|
||||
#include <rtc.h>
|
||||
#include <tim.h>
|
||||
#include <gpio.h>
|
||||
|
||||
@@ -13,18 +12,14 @@
|
||||
|
||||
void furi_hal_init() {
|
||||
furi_hal_clock_init();
|
||||
furi_hal_rtc_init();
|
||||
furi_hal_console_init();
|
||||
furi_hal_interrupt_init();
|
||||
furi_hal_delay_init();
|
||||
|
||||
// FreeRTOS glue
|
||||
furi_hal_os_init();
|
||||
|
||||
MX_GPIO_Init();
|
||||
FURI_LOG_I(TAG, "GPIO OK");
|
||||
|
||||
MX_RTC_Init();
|
||||
FURI_LOG_I(TAG, "RTC OK");
|
||||
furi_hal_bootloader_init();
|
||||
furi_hal_version_init();
|
||||
|
||||
@@ -59,6 +54,9 @@ void furi_hal_init() {
|
||||
furi_hal_bt_init();
|
||||
furi_hal_compress_icon_init();
|
||||
|
||||
// FreeRTOS glue
|
||||
furi_hal_os_init();
|
||||
|
||||
// FatFS driver initialization
|
||||
MX_FATFS_Init();
|
||||
FURI_LOG_I(TAG, "FATFS OK");
|
||||
|
@@ -57,7 +57,6 @@ C_SOURCES += \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_pwr_ex.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rcc.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_rtc_ex.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_hal_tim_ex.c \
|
||||
@@ -67,6 +66,7 @@ C_SOURCES += \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_i2c.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_lptim.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rcc.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_rtc.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_spi.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_tim.c \
|
||||
$(CUBE_DIR)/Drivers/STM32WBxx_HAL_Driver/Src/stm32wbxx_ll_usart.c \
|
||||
|
Reference in New Issue
Block a user