Перейти к содержимому

Tamper rtc что это

  • автор:

Русские Блоги

После просмотра официального демо ST RTC_Tamper
На официальной плате STM32H743I-EVAL2 проверьте и поймите точки знаний, показанные в демонстрации.

Точки знаний, показанные в демонстрации RTC_Tamper, — это чтение и запись в регистр RTC STM32H743 и реакция обнаружения вторжения.
Эти 3 точки знаний очень полезны. Вы можете хранить некоторые конфиденциальные секреты в регистре RTC, и вы не хотите, чтобы за вами шпионили. Когда вы обнаружите, что дело открыто, вы можете взять некоторые Саморазрушающие меры.

Я перестроил проект с CubeMx с нуля, чтобы завершить чтение и запись регистров RTC и реализацию ответа на обнаружение вторжений.

тест

Для этого эксперимента необходимо установить 2 контакта с помощью CubeMx.

Контакт обнаружения вторжения PC13 RTC

Когда я впервые начал эксперимент, я все еще не понимал, почему кнопка PC13 будет вводить ответ обнаружения вторжения.
Позже я хотел понять, что это аппаратная реализация (поскольку PC13 является контактом обнаружения вторжения RTC), пока PC13 обозначен как RTC_TAMP1, нажатие PC13 приведет к прерыванию обнаружения вторжения RTC ответ.

Светодиодный индикатор

Когда программа работает на полной скорости и работает без STLINK, если вы хотите увидеть разницу до и после обнаружения вторжения, вам понадобится хотя бы одна инструкция.

Настройки STM32CubeMX

Настройки прерывания при обнаружении вторжений

Также необходимо выбрать соответствующее прерывание, иначе функция ответа на прерывание при обнаружении вторжения отсутствует.

Псевдоним настройки PIN-кода

PF10 — это светодиод.После установки псевдонима PORT и PIN псевдонима будут автоматически использоваться при инициализации этого вывода в CubeMx, который имеет лучшую ремонтопригодность. Нам не нужно самостоятельно определять макрос псевдонима вывода.

Предварительный просмотр проекта реконструирован с помощью CubeMx

/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "rtc.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* Backup registers table */ __IO FlagStatus TamperStatus = RESET; // BACKUP_COUNT define on main.h uint32_t aBKPDataReg[BACKUP_COUNT] = < RTC_BKP_DR0, RTC_BKP_DR1, RTC_BKP_DR2, RTC_BKP_DR3, RTC_BKP_DR4, RTC_BKP_DR5, RTC_BKP_DR6, RTC_BKP_DR7, RTC_BKP_DR8, RTC_BKP_DR9, RTC_BKP_DR10, RTC_BKP_DR11, RTC_BKP_DR12, RTC_BKP_DR13, RTC_BKP_DR14, RTC_BKP_DR15, RTC_BKP_DR16, RTC_BKP_DR17, RTC_BKP_DR18, RTC_BKP_DR19, RTC_BKP_DR20, RTC_BKP_DR21, RTC_BKP_DR22, RTC_BKP_DR23, RTC_BKP_DR24, RTC_BKP_DR25, RTC_BKP_DR26, RTC_BKP_DR27, RTC_BKP_DR28, RTC_BKP_DR29, RTC_BKP_DR30, RTC_BKP_DR31 >; /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) < /* USER CODE BEGIN 1 */ int index = 0; uint32_t ui_tmp = 0; /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_RTC_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) < /* USER CODE END WHILE */ HAL_Delay(100); HAL_GPIO_TogglePin(MY_LED1_GPIO_Port, MY_LED1_Pin); if (SET == TamperStatus) < TamperStatus = RESET; // Обнаружение вторжения происходит // Сначала посмотрим, соответствует ли регистр резервного копирования RTC установленному мной значению /*##-4- Check Data is stored on the Back Up registers ######################*/ for (index = 0; index < BACKUP_COUNT; index++) < ui_tmp = HAL_RTCEx_BKUPRead(&hrtc, aBKPDataReg[index]); if (ui_tmp != (0xDF59 + (index * 0x5A))) < // sTamper.NoErase = RTC_TAMPER_ERASE_BACKUP_ENABLE; // Резервное копирование RTC разрешено для стирания, и установлен флаг стирания. При обнаружении вторжения оборудование MCU напрямую очищает регистр резервного копирования RTC // Значит, ui_tmp уже 0 // Таким образом, вы можете поместить некоторые секреты в резервный регистр RTC и очистить эти секреты при открытии кейса // Вытяните контакт обнаружения вторжения PC.13RTC и подключите его к цифровому контакту заземления корпуса. Когда крышка открыта, на выводе обнаружения вторжения генерируется нарастающий фронт // Установите для параметра обнаружения вторжения RTC значение триггера нарастающего фронта sTamper.Trigger = RTC_TAMPERTRIGGER_RISINGEDGE ;, вы можете достичь цели открытия крышки и самоуничтожения данных // В сочетании с функцией перезаписи FLASH + IAP, можно также реализовать функцию самоуничтожения кода // Error_Handler(); ui_tmp = ui_tmp; >> // Очищаем резервный регистр RTC /*##-6- Deactivate the tamper ##############################*/ HAL_RTCEx_DeactivateTamper(&hrtc, RTC_TAMPER_1); // Проверяем, очищен ли резервный регистр RTC /*##-7- Check Data is cleared on the Back Up registers #####################*/ for (index = 0; index < BACKUP_COUNT; index++) < if (HAL_RTCEx_BKUPRead(&hrtc, aBKPDataReg[index]) != 0x00) < Error_Handler(); >> > /* USER CODE BEGIN 3 */ > /* USER CODE END 3 */ > /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) < RCC_OscInitTypeDef RCC_OscInitStruct = ; RCC_ClkInitTypeDef RCC_ClkInitStruct = ; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = ; /** Supply configuration update enable */ HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); /** Configure the main internal regulator output voltage */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3); while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) <> /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSI; RCC_OscInitStruct.HSIState = RCC_HSI_DIV1; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) < Error_Handler(); >/** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2 |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) < Error_Handler(); >PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC; PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSI; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) < Error_Handler(); >> /* USER CODE BEGIN 4 */ // CubeMx оставляет много USER CODE BEGIN x и USER CODE END x, поместите свой собственный рукописный код в эту границу // TAMP_STAMP_IRQHandler() => HAL_RTCEx_TamperTimeStampIRQHandler() => HAL_RTCEx_Tamper1EventCallback() // Реализуем слабую функцию HAL_RTCEx_Tamper1EventCallback () void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef * hrtc) < TamperStatus = SET; >/* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) < /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ do < HAL_Delay(10); >while (1); /* USER CODE END Error_Handler_Debug */ > #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) < /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ >#endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.h * @brief : Header for main.c file. * This file contains the common defines of the application. ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __MAIN_H #define __MAIN_H #ifdef __cplusplus extern "C" < #endif /* Includes ------------------------------------------------------------------*/ #include "stm32h7xx_hal.h" #include "stm32h7xx_hal.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Exported types ------------------------------------------------------------*/ /* USER CODE BEGIN ET */ /* USER CODE END ET */ /* Exported constants --------------------------------------------------------*/ /* USER CODE BEGIN EC */ #define BACKUP_COUNT RTC_BKP_NUMBER // aBKPDataReg define on main.c extern uint32_t aBKPDataReg[BACKUP_COUNT]; /* USER CODE END EC */ /* Exported macro ------------------------------------------------------------*/ /* USER CODE BEGIN EM */ /* USER CODE END EM */ /* Exported functions prototypes ---------------------------------------------*/ void Error_Handler(void); /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ /* Private defines -----------------------------------------------------------*/ #define MY_LED1_Pin GPIO_PIN_10 #define MY_LED1_GPIO_Port GPIOF /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ #ifdef __cplusplus >#endif #endif /* __MAIN_H */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/** ****************************************************************************** * File Name : gpio.c * Description : This file provides code for the configuration * of all used GPIO pins. ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "gpio.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /*----------------------------------------------------------------------------*/ /* Configure GPIO */ /*----------------------------------------------------------------------------*/ /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /** Configure pins */ void MX_GPIO_Init(void) < GPIO_InitTypeDef GPIO_InitStruct = ; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(MY_LED1_GPIO_Port, MY_LED1_Pin, GPIO_PIN_RESET); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = MY_LED1_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(MY_LED1_GPIO_Port, &GPIO_InitStruct); > /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/** ****************************************************************************** * File Name : gpio.h * Description : This file contains all the functions prototypes for * the gpio ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __gpio_H #define __gpio_H #ifdef __cplusplus extern "C" < #endif /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* USER CODE BEGIN Private defines */ /* USER CODE END Private defines */ void MX_GPIO_Init(void); /* USER CODE BEGIN Prototypes */ /* USER CODE END Prototypes */ #ifdef __cplusplus >#endif #endif /*__ pinoutConfig_H */ /** * @> */ /** * @> */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/** ****************************************************************************** * File Name : RTC.c * Description : This file provides code for the configuration * of the RTC instances. ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "rtc.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ RTC_HandleTypeDef hrtc; /* RTC init function */ void MX_RTC_Init(void) < int index = 0; uint32_t ui_tmp = 0; RTC_TamperTypeDef sTamper = ; /** 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; // CubeMx генерирует больше кода, чем официальная демонстрация if (HAL_RTC_Init(&hrtc) != HAL_OK) < Error_Handler(); >/** Enable the RTC Tamper 1 */ sTamper.Tamper = RTC_TAMPER_1; sTamper.Interrupt = RTC_TAMPER1_INTERRUPT; sTamper.Trigger = RTC_TAMPERTRIGGER_RISINGEDGE; // И нарастающий, и на спадающий фронт в порядке sTamper.NoErase = RTC_TAMPER_ERASE_BACKUP_ENABLE; // Резервное копирование RTC разрешено для стирания, и установлен флаг стирания. Когда происходит обнаружение вторжения, оборудование MCU непосредственно очищает регистр резервного копирования RTC sTamper.MaskFlag = RTC_TAMPERMASK_FLAG_DISABLE; sTamper.Filter = RTC_TAMPERFILTER_DISABLE; sTamper.SamplingFrequency = RTC_TAMPERSAMPLINGFREQ_RTCCLK_DIV32768; sTamper.PrechargeDuration = RTC_TAMPERPRECHARGEDURATION_1RTCCLK; sTamper.TamperPullUp = RTC_TAMPER_PULLUP_ENABLE; sTamper.TimeStampOnTamperDetection = RTC_TIMESTAMPONTAMPERDETECTION_ENABLE; // RTC_TIMESTAMPONTAMPERDETECTION_DISABLE также доступен if (HAL_RTCEx_SetTamper_IT(&hrtc, &sTamper) != HAL_OK) < Error_Handler(); >// Заполняем и проверяем резервный регистр RTC /* Clear the Tamper interrupt pending bit */ __HAL_RTC_TAMPER_CLEAR_FLAG(&hrtc,RTC_FLAG_TAMP1F); /*##-3- Write Data on the Back Up registers ################################*/ for (index = 0; index < BACKUP_COUNT; index++) < HAL_RTCEx_BKUPWrite(&hrtc, aBKPDataReg[index], 0xDF59 + (index * 0x5A)); >/*##-4- Check Data is stored on the Back Up registers ######################*/ for (index = 0; index < BACKUP_COUNT; index++) < ui_tmp = HAL_RTCEx_BKUPRead(&hrtc, aBKPDataReg[index]); if (ui_tmp != (0xDF59 + (index * 0x5A))) < 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(); /* RTC interrupt Init */ HAL_NVIC_SetPriority(TAMP_STAMP_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TAMP_STAMP_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(); /* RTC interrupt Deinit */ HAL_NVIC_DisableIRQ(TAMP_STAMP_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****/
/** ****************************************************************************** * File Name : RTC.h * Description : This file provides code for the configuration * of the RTC instances. ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* 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****/
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file stm32h7xx_it.c * @brief Interrupt Service Routines. ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32h7xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN TD */ /* USER CODE END TD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ extern RTC_HandleTypeDef hrtc; /* USER CODE BEGIN EV */ /* USER CODE END EV */ /******************************************************************************/ /* Cortex Processor Interruption and Exception Handlers */ /******************************************************************************/ /** * @brief This function handles Non maskable interrupt. */ void NMI_Handler(void) < /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ /* USER CODE END NonMaskableInt_IRQn 0 */ /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ /* USER CODE END NonMaskableInt_IRQn 1 */ >/** * @brief This function handles Hard fault interrupt. */ void HardFault_Handler(void) < /* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE END HardFault_IRQn 0 */ while (1) < /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ >> /** * @brief This function handles Memory management fault. */ void MemManage_Handler(void) < /* USER CODE BEGIN MemoryManagement_IRQn 0 */ /* USER CODE END MemoryManagement_IRQn 0 */ while (1) < /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ /* USER CODE END W1_MemoryManagement_IRQn 0 */ >> /** * @brief This function handles Pre-fetch fault, memory access fault. */ void BusFault_Handler(void) < /* USER CODE BEGIN BusFault_IRQn 0 */ /* USER CODE END BusFault_IRQn 0 */ while (1) < /* USER CODE BEGIN W1_BusFault_IRQn 0 */ /* USER CODE END W1_BusFault_IRQn 0 */ >> /** * @brief This function handles Undefined instruction or illegal state. */ void UsageFault_Handler(void) < /* USER CODE BEGIN UsageFault_IRQn 0 */ /* USER CODE END UsageFault_IRQn 0 */ while (1) < /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ /* USER CODE END W1_UsageFault_IRQn 0 */ >> /** * @brief This function handles System service call via SWI instruction. */ void SVC_Handler(void) < /* USER CODE BEGIN SVCall_IRQn 0 */ /* USER CODE END SVCall_IRQn 0 */ /* USER CODE BEGIN SVCall_IRQn 1 */ /* USER CODE END SVCall_IRQn 1 */ >/** * @brief This function handles Debug monitor. */ void DebugMon_Handler(void) < /* USER CODE BEGIN DebugMonitor_IRQn 0 */ /* USER CODE END DebugMonitor_IRQn 0 */ /* USER CODE BEGIN DebugMonitor_IRQn 1 */ /* USER CODE END DebugMonitor_IRQn 1 */ >/** * @brief This function handles Pendable request for system service. */ void PendSV_Handler(void) < /* USER CODE BEGIN PendSV_IRQn 0 */ /* USER CODE END PendSV_IRQn 0 */ /* USER CODE BEGIN PendSV_IRQn 1 */ /* USER CODE END PendSV_IRQn 1 */ >/** * @brief This function handles System tick timer. */ void SysTick_Handler(void) < /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ >/******************************************************************************/ /* STM32H7xx Peripheral Interrupt Handlers */ /* Add here the Interrupt Handlers for the used peripherals. */ /* For the available peripheral interrupt handler names, */ /* please refer to the startup file (startup_stm32h7xx.s). */ /******************************************************************************/ /** * @brief This function handles RTC tamper and timestamp interrupts through EXTI line 18. */ void TAMP_STAMP_IRQHandler(void) < /* USER CODE BEGIN TAMP_STAMP_IRQn 0 */ /* USER CODE END TAMP_STAMP_IRQn 0 */ HAL_RTCEx_TamperTimeStampIRQHandler(&hrtc); /* USER CODE BEGIN TAMP_STAMP_IRQn 1 */ /* USER CODE END TAMP_STAMP_IRQn 1 */ >/* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file stm32h7xx_it.h * @brief This file contains the headers of the interrupt handlers. ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __STM32H7xx_IT_H #define __STM32H7xx_IT_H #ifdef __cplusplus extern "C" < #endif /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Exported types ------------------------------------------------------------*/ /* USER CODE BEGIN ET */ /* USER CODE END ET */ /* Exported constants --------------------------------------------------------*/ /* USER CODE BEGIN EC */ /* USER CODE END EC */ /* Exported macro ------------------------------------------------------------*/ /* USER CODE BEGIN EM */ /* USER CODE END EM */ /* Exported functions prototypes ---------------------------------------------*/ void NMI_Handler(void); void HardFault_Handler(void); void MemManage_Handler(void); void BusFault_Handler(void); void UsageFault_Handler(void); void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); void TAMP_STAMP_IRQHandler(void); /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ #ifdef __cplusplus >#endif #endif /* __STM32H7xx_IT_H */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : stm32h7xx_hal_msp.c * Description : This file provides code for the MSP Initialization * and de-Initialization codes. ****************************************************************************** * @attention * * 

© Copyright (c) 2020 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN TD */ /* USER CODE END TD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN Define */ /* USER CODE END Define */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN Macro */ /* USER CODE END Macro */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* External functions --------------------------------------------------------*/ /* USER CODE BEGIN ExternalFunctions */ /* USER CODE END ExternalFunctions */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * Initializes the Global MSP. */ void HAL_MspInit(void) < /* USER CODE BEGIN MspInit 0 */ /* USER CODE END MspInit 0 */ __HAL_RCC_SYSCFG_CLK_ENABLE(); /* System interrupt init*/ /* USER CODE BEGIN MspInit 1 */ /* USER CODE END MspInit 1 */ >/* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

подводить итоги

Инженерная структура, созданная CubeMx, действительно чиста.

Из демонстрационного проекта мы действительно можем увидеть разницу между поставщиками восходящего и нижнего звена.
Производители апстрима продают микросхемы, и они подробно расскажут о функциях и характеристиках микросхем, привлекая пользователей к покупке микросхем для продуктов.
Последующие производители продают платы и решения для разработки, и они с меньшей вероятностью расскажут пользователям подробности. Все они посвящены основам и основным моментам. Предполагается, что энергия и стоимость недопустимы.

Даже на демонстрационных примерах исходных производителей, если вы внимательно следите за пошаговыми инструкциями, вы все равно можете увидеть код отходов.
например, если RTC инициализируется, устанавливаются следующие параметры

sTamper.NoErase = RTC_TAMPER_ERASE_BACKUP_ENABLE; // Резервное копирование RTC разрешено для стирания, и установлен флаг стирания. Когда происходит обнаружение вторжения, оборудование MCU непосредственно очищает регистр резервного копирования RTC 

Когда происходит обнаружение вторжения, содержимое регистра RTC было очищено оборудованием, и нет необходимости явно вызывать HAL_RTCEx_DeactivateTamper ()

Getting started with RTC

This article explains how to use the RTC. It provides code examples to use RTC Alarm with interrupt.

Contents

  • 1 What is a Real Time Clock (RTC)?
  • 2 Configure RTC and Alarm with interrupt
    • 2.1 Objectives
    • 2.2 Create the project in STM32CubeIDE
    • 2.3 Configure RTC
    • 2.4 Configure GPIO
    • 2.5 Generate project and edit main.c
    • 2.6 Compile and flash

    1 What is a Real Time Clock (RTC)?

    A RTC is an independent binary-coded decimal (BCD) timer/counter. The RTC provides a time-of-day clock/calendar with programmable alarm interrupt. In addition, the RTC can provide an automatic wakeup to manage all low-power modes. For STM32L476, main RTC features are the following:

    • Calendar with subseconds, seconds, minutes, hours, day, date of day in month, month and year.
    • Daylight saving compensation programmable by software.
    • Programmable alarm with interrupt function.
    • Automatic wakeup unit generating a periodic flag that triggers an automatic wakeup interrupt.
    • Reference clock detection: a more precise second source clock (50 or 60 Hz) can be used to enhance the calendar precision.
    • Accurate synchronization with an external clock using the subsecond shift feature.
    • Digital calibration circuit (periodic counter correction).
    • Time-stamp function for event saving.
    • Tamper detection event with configurable filter and internal pull-up.
    • 32 backup registers.
    • Maskable interrupts/events: Alarm A, Alarm B, Wakeup interrupt, Time-stamp and Tamper detection.

    2 Configure RTC and Alarm with interrupt

    2.1 Objectives

    Learn how to setup RTC with interrupt in STM32CubeIDE and how to create a simple RTC project with periodic alarm interrupt.
    Steps to follow:

    • Configure the LED pin and the RTC alarm interrupts in STM32CubeIDE and generate code.
    • Verify the correct functionality with periodic RTC alarm interrupts that toggle a LED.
    2.2 Create the project in STM32CubeIDE

    create STM32CubeIDE project.png

    In this example the NUCLEO-L476RG board is used.

    • Select NUCLEO-L476RG board using Board Selector as shown in the figure below.

    Select NUCLEO-L476RG board.png

    If the STM32L476 Cube library is not downloaded, it will download automatically. The operation may take some time.

    create project name.png

    • Initialize all peripherals with their default settings.

    Answer “Yes” to initialize all peripherals with their default mode? Popup as below:

    Popup.png

    2.3 Configure RTC
    • Set Internal Alarm to Alarm A.
    • Modify the seconds Alarm value to 1 in the parameter settings to set first Alarm to 1s.

    RTC configuration.png

    • Enable alarm interrupt.

    To enable the alarm interrupt, it is necessary to refer to the reference manual. The vectors table help you select the correct RTC alarm interrupt.
    STM32L476 has its RTC alarm interrupt connected to EXTI line as shown below.

    NVIC interruption.png

    2.4 Configure GPIO

    GPIO configuration1.png

    Green Led of NUCLEO-L476RG board is connected to PA5. Set it to output push-pull mode so that it can be toggled as alarm indication.

    LedPinGPIO.pngLED UM GPIO.png

    2.5 Generate project and edit main.c
    • Click «Ctrl+S« to generate the project.

    Generate project.png

    Information
    Insert your code between /* USER CODE BEGIN 4 */ and /* USER CODE END 4 */ tags.
    /* USER CODE BEGIN 4 */ void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)  RTC_AlarmTypeDef sAlarm; HAL_RTC_GetAlarm(hrtc,&sAlarm,RTC_ALARM_A,FORMAT_BIN); if(sAlarm.AlarmTime.Seconds>58)  sAlarm.AlarmTime.Seconds=0; >else sAlarm.AlarmTime.Seconds=sAlarm.AlarmTime.Seconds+1; > while(HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, FORMAT_BIN)!=HAL_OK)<> HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); > /* USER CODE END 4 */ 

    HAL_RTC_AlarmAEventCallback is called when the current time and date match the alarm time and date. In our example, it is set to 1 second in the future.

    Then, we need to increment the alarm time by 1 second to make sure that the callback can be triggered once again. After 1 minute, current time and alarm time no longer match, therefore the alarm is not triggered and the LED stops blinking.

    Information
    It is possible to make infinite periodic or more complex types of alarms with the use of alarm masks.

    For example, in order to make our LED toggling infinite, alarm masks can be used to ignore days, hours and minutes.

    In your main.c, search for the following line of code :

    sAlarm.AlarmMask = RTC_ALARMMASK_NONE; 

    And replace it with the following :

    sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES; 

    An alternative procedure is possible in CubeMX as shown in the figure below. Don’t forget to save the project and generate the code.

    alarmmask.png

    2.6 Compile and flash
    • Click on Build button
    • Click on Debug button (to run step by step)
    • Or on Run button (to execute)

    Getting started with RTC

    This article explains how to use the RTC. It provides code examples to use RTC Alarm with interrupt.

    Contents

    • 1 What is a Real Time Clock (RTC)?
    • 2 Configure RTC and Alarm with interrupt
      • 2.1 Objectives
      • 2.2 Create the project in STM32CubeIDE
      • 2.3 Configure RTC
      • 2.4 Configure GPIO
      • 2.5 Generate project and edit main.c
      • 2.6 Compile and flash

      1 What is a Real Time Clock (RTC)?

      A RTC is an independent binary-coded decimal (BCD) timer/counter. The RTC provides a time-of-day clock/calendar with programmable alarm interrupt. In addition, the RTC can provide an automatic wakeup to manage all low-power modes. For STM32L476, main RTC features are the following:

      • Calendar with subseconds, seconds, minutes, hours, day, date of day in month, month and year.
      • Daylight saving compensation programmable by software.
      • Programmable alarm with interrupt function.
      • Automatic wakeup unit generating a periodic flag that triggers an automatic wakeup interrupt.
      • Reference clock detection: a more precise second source clock (50 or 60 Hz) can be used to enhance the calendar precision.
      • Accurate synchronization with an external clock using the subsecond shift feature.
      • Digital calibration circuit (periodic counter correction).
      • Time-stamp function for event saving.
      • Tamper detection event with configurable filter and internal pull-up.
      • 32 backup registers.
      • Maskable interrupts/events: Alarm A, Alarm B, Wakeup interrupt, Time-stamp and Tamper detection.

      2 Configure RTC and Alarm with interrupt

      2.1 Objectives

      Learn how to setup RTC with interrupt in STM32CubeIDE and how to create a simple RTC project with periodic alarm interrupt.
      Steps to follow:

      • Configure the LED pin and the RTC alarm interrupts in STM32CubeIDE and generate code.
      • Verify the correct functionality with periodic RTC alarm interrupts that toggle a LED.
      2.2 Create the project in STM32CubeIDE

      create STM32CubeIDE project.png

      In this example the NUCLEO-L476RG board is used.

      • Select NUCLEO-L476RG board using Board Selector as shown in the figure below.

      Select NUCLEO-L476RG board.png

      If the STM32L476 Cube library is not downloaded, it will download automatically. The operation may take some time.

      create project name.png

      • Initialize all peripherals with their default settings.

      Answer “Yes” to initialize all peripherals with their default mode? Popup as below:

      Popup.png

      2.3 Configure RTC
      • Set Internal Alarm to Alarm A.
      • Modify the seconds Alarm value to 1 in the parameter settings to set first Alarm to 1s.

      RTC configuration.png

      • Enable alarm interrupt.

      To enable the alarm interrupt, it is necessary to refer to the reference manual. The vectors table help you select the correct RTC alarm interrupt.
      STM32L476 has its RTC alarm interrupt connected to EXTI line as shown below.

      NVIC interruption.png

      2.4 Configure GPIO

      GPIO configuration1.png

      Green Led of NUCLEO-L476RG board is connected to PA5. Set it to output push-pull mode so that it can be toggled as alarm indication.

      LedPinGPIO.pngLED UM GPIO.png

      2.5 Generate project and edit main.c
      • Click «Ctrl+S« to generate the project.

      Generate project.png

      Information
      Insert your code between /* USER CODE BEGIN 4 */ and /* USER CODE END 4 */ tags.
      /* USER CODE BEGIN 4 */ void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)  RTC_AlarmTypeDef sAlarm; HAL_RTC_GetAlarm(hrtc,&sAlarm,RTC_ALARM_A,FORMAT_BIN); if(sAlarm.AlarmTime.Seconds>58)  sAlarm.AlarmTime.Seconds=0; >else sAlarm.AlarmTime.Seconds=sAlarm.AlarmTime.Seconds+1; > while(HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, FORMAT_BIN)!=HAL_OK)<> HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); > /* USER CODE END 4 */ 

      HAL_RTC_AlarmAEventCallback is called when the current time and date match the alarm time and date. In our example, it is set to 1 second in the future.

      Then, we need to increment the alarm time by 1 second to make sure that the callback can be triggered once again. After 1 minute, current time and alarm time no longer match, therefore the alarm is not triggered and the LED stops blinking.

      Information
      It is possible to make infinite periodic or more complex types of alarms with the use of alarm masks.

      For example, in order to make our LED toggling infinite, alarm masks can be used to ignore days, hours and minutes.

      In your main.c, search for the following line of code :

      sAlarm.AlarmMask = RTC_ALARMMASK_NONE; 

      And replace it with the following :

      sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS|RTC_ALARMMASK_MINUTES; 

      An alternative procedure is possible in CubeMX as shown in the figure below. Don’t forget to save the project and generate the code.

      alarmmask.png

      2.6 Compile and flash
      • Click on Build button
      • Click on Debug button (to run step by step)
      • Or on Run button (to execute)

      RTC HAL stm32

      Речь пойдёт о программировании RTC (встроенных часов) в микроконтроллере stm32.

      Описание сделано для F103 и F303, но так как у них много общих функций, то читать нужно всё.

      Первым делом нужно указать источник тактирования для часов. Указываем внешний кварцевый резонатор, он есть на многих платах…

      В CubeMX выбираем RCC и указываем — Low Speed External (LSE) ⇨ Crystal/Ceramic Resonator

      В мультиплексоре RTC Clock Mux нужно указать источник LSE…

      Если внешнего кварца нет, тогда в мультиплексоре укажите LSI, а Low Speed External (LSE) ⇨ Disable.

      Переходим в раздел RTC и делаем так…

      Для F103

      Data Format ⇨ Binary data format .

      Со временем и календарём всё понятно. Формат 24-х часовой.

      Auto Predivider Calcalation ⇨ Enabled — активирован автоматический расчёт предделителя.

      Asynchronous Predivider value — предделитель часового кварца. С его помощью достигается тактирование в 1Гц (один тик в одну секунду). Если отключить автоматический режим, то нужно будет ввести число от 0 до 127.

      Для F303

      Здесь два предделителя для настройки частоты — Asynchronous Predivider value и Synchronous Predivider value . Для внешнего кварца укажите 127 и 255.

      Если у Вас LSI 40kHz, тогда во втором предделителе укажите 311. Если частота другая, тогда смотрите ниже.

      Настройка предделителей для разных источников тактирования…

      У нас тактируется от LSE = 32.768кГц, тогда исходя из формулы получается следующее: 128 * 256 = 32768 / 32.768кГц = 1Гц (один тик в секунду). Если уменьшить или увеличить какое-нибудь значение, то часы пойдут быстрее или медленнее.

      Hour Format — можно изменить формат времени 12/24.

      Day Light Saving: value of hour adjustment — зимнее/летнее время (добавляет/вычитает один час из текущего времени).

      Пишем код. В функции static void MX_RTC_Init(void) есть две структуры, их надо объявить как глобальные…

      /* USER CODE BEGIN PV */ RTC_TimeTypeDef sTime = ; RTC_DateTypeDef DateToUpdate = ; char trans_str[64] = ; /* USER CODE END PV */

      И заодно объявим массив для вывода данных в UART.

      У F303 структура даты называется sDate.

      В бесконечном цикле будем читать дату и время:

      /* USER CODE BEGIN WHILE */ while (1) < HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // RTC_FORMAT_BIN , RTC_FORMAT_BCD snprintf(trans_str, 63, "Time %d:%d:%d\n", sTime.Hours, sTime.Minutes, sTime.Seconds); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN); snprintf(trans_str, 63, "Date %d-%d-20%d\n", DateToUpdate.Date, DateToUpdate.Month, DateToUpdate.Year); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_Delay(1000); . 

      Если на пин Vbat подключить батерейку или просто подать 3 вольта, тогда после ресета данные будут сохраняться. Предварительно нужно в функции static void MX_RTC_Init(void) закомментировать установку времени и даты…

      /**Initialize RTC and set the Time and Date */ sTime.Hours = 10; sTime.Minutes = 34; sTime.Seconds = 0; sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation = RTC_STOREOPERATION_RESET; //if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK) // < // Error_Handler(); //>DateToUpdate.WeekDay = RTC_WEEKDAY_WEDNESDAY; DateToUpdate.Month = RTC_MONTH_FEBRUARY; DateToUpdate.Date = 20; DateToUpdate.Year = 19; //if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK) //< // Error_Handler(); //>

      Эти же функции можно использовать где-нибудь в программе для изменения времени/даты на лету.

      Теперь можно прошить ещё раз и понажимать ресет. Данные должны сохраняться.

      Помните о том, что при повторной генерации проекта в CubeMX комментарии удалятся!

      У микроконтроллера F103, дата не сохраняется. Это связано с тем, что F103 всего один 32-х битный регистр, см. спойлер…

      спойлер

      Вот так выглядит схема RTC в F103…

      От батарейки работает только регистр со временем и будильником, ну и ещё предделитель. То есть дату сохранить нельзя.

      Но, дату сохранить нельзя только если пользоваться HAL, если же написать свой костыль, тогда в RTC_CNT можно сохранять дату/время в UNIX-формате, то есть количество секунд прошедшее с 1970 года. А потом средствами СИ вытаскивать из этого числа дату и время.

      У более «жирных» камней сохраняется и дата и время.

      Если используется LSI, то данные сохранятся, но время идти не будет.

      Если у вас микроконтроллер F4xx или F7xx, и вы хотите считывать только время (без даты), то в любом случае нужно после функции HAL_RTC_GetTime(. ) вызывать HAL_RTC_GetDate(. ) , в противном случае время не будет обновляться.

      Будильник (Alarm) для F103

      Будильник сработает через пять секунд после старта.

      RTC OUT ⇨ RTC Output on the Tamper pin — во время срабатывания будильника на tamper-пин (РС13) будет подан кратковременный импульс. Можно подключить светодиод и посмотреть. На плате BluePill увидеть что-либо трудно так как импульс очень уж слабенький (я подключал через транзистор).

      Output ⇨ Alarm pulse signal on the TAMPER pin — во время срабатывания будильника подаётся импульс. При выборе этого режима появляется пункт с настройкой будильника — Alarm A .

      Можно сгенерировать проект, прошить и посмотреть как мигнёт светодиод.

      Output ⇨ RTC clock with a frequency divided by 64 on the TAMPER pin — на tamper-пин будет подана частота с часового кварца поделённая на 64. Можно осциллографом проверять точность кварца.

      Output ⇨ Second pulse signal on the TAMPER pin — на tamper-пин будет подаваться импульс раз в секунду.

      После того как попробуете эти режимы верните всё как на картинке.

      Включите прерывание от будильника…

      Будильник соединён с линией EXTI17 – RTC Alert event.

      Добавьте колбек будильника:

      /* USER CODE BEGIN 0 */ void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)

      Прошивайте и смотрите результат.

      Чтобы посмотреть настройки будильника из программы, нужно вызвать функцию HAL_RTC_GetAlarm() …

      пример

      Структуру будильника объявим как глобальную:

      /* USER CODE BEGIN PV */ RTC_TimeTypeDef sTime = ; RTC_DateTypeDef DateToUpdate = ; RTC_AlarmTypeDef sAlarm = ; // структура будильника char trans_str[64] = ; /* USER CODE END PV */
      /* USER CODE BEGIN WHILE */ while (1) < HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // RTC_FORMAT_BIN , RTC_FORMAT_BCD snprintf(trans_str, 63, "Time %d:%d:%d\n", sTime.Hours, sTime.Minutes, sTime.Seconds); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN); snprintf(trans_str, 63, "Date %d-%d-20%d\n", DateToUpdate.Date, DateToUpdate.Month, DateToUpdate.Year); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTC_GetAlarm(&hrtc, &sAlarm, RTC_ALARM_A, RTC_FORMAT_BIN); snprintf(trans_str, 63, "Alarm %d:%d:%d\n", sAlarm.AlarmTime.Hours, sAlarm.AlarmTime.Minutes, sAlarm.AlarmTime.Seconds); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_Delay(1000); . 

      Для программной установки будильника нужно воспользоваться функцией HAL_RTC_SetAlarm_IT() , она есть в функции инициализации — static void MX_RTC_Init(void) .

      Помимо прерывания от будильника, есть ещё прерывание, которое может вызываться раз в секунду.

      Включите глобальное прерывание…

      Добавьте ещё один колбек:

      /* USER CODE BEGIN 0 */ void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc)

      Перед бесконечным циклом добавьте функцию:

      /* USER CODE BEGIN 2 */ HAL_RTCEx_SetSecond_IT(&hrtc); /* USER CODE END 2 */

      Прошейте и смотрите.

      Как использовать этот функционал — например можно сделать так: в колбеке будильника запускаем это прерывание, после чего оно вызовется 10 раз и выключится. В прерывании можно делать что угодно, например подавать импульс на какой-нибудь пин с подключённой пищалкой.

      пример

      /* USER CODE BEGIN PV */ RTC_TimeTypeDef sTime = ; RTC_DateTypeDef DateToUpdate = ; RTC_AlarmTypeDef sAlarm = ; char trans_str[64] = ; volatile uint8_t count = 0; // добавить счётчик /* USER CODE END PV */
      /* USER CODE BEGIN 0 */ void HAL_RTCEx_RTCEventCallback(RTC_HandleTypeDef *hrtc) < // тут подаём импульс на какой-нибудь пин count++; if(count >9) HAL_RTCEx_DeactivateSecond(hrtc); // отключаем ежесекундное прерывание snprintf(trans_str, 63, "One sec\n"); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); > void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) < snprintf(trans_str, 63, "ALARM\n"); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTCEx_SetSecond_IT(hrtc); // запускаем ежесекундное прерывание >/* USER CODE END 0 */
      /* USER CODE BEGIN 2 */ //HAL_RTCEx_SetSecond_IT(&hrtc); /* USER CODE END 2 */

      Если установить RTC OUT ⇨ Disable …

      … то режимы Output ⇨ RTC clock with a frequency divided by 64 on the TAMPER pin и Output ⇨ Second pulse signal on the TAMPER pin будут работать, а если RTC OUT ⇨ No RTC Output , то на tamper-пин ничего нельзя подать.

      Tamper для F103 и F303

      В RTC OUT указывайте что хотите. Calendar можно включить, а можно и не включать.

      До этого мы использовали tamper-пин для вывода сигнала, а сейчас он будет выполнять обратную функцию.

      У F103 есть десять 16-ти битных регистров для хранения пользовательских данных (backup registers). Если подключена батарейка, то данные в этих регистрах не обнуляются ни при нажатии Reset, ни при выходе из спящего режима, ни при отключении основного питания.

      Если в эти регистры записать какие-то данные, то их можно будет стереть подав на tamper-пин кратковременный импульс.
      В Reference manual предлагается использовать этот функционал в качестве контроля несанкционированного доступа к устройству. Видимо поэтому это назвали Tamper (вмешательство).

      Какой именно сигнал послужит триггером, настраивается в пункте Tamper Trigger .

      Rising Edge — с LOW на HIGH.
      Falling Edge — с HIGH на LOW.

      Внутренняя подтяжка такая слабенькая, что срабатывает от прикосновения пальца, поэтому желательно подтянуть пин к «плюсу» резистором (10КОм).

      Запишем в первые два регистра данные:

      /* USER CODE BEGIN 2 */ HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 1234); // в первый регистр запишем число 1234 HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR2, 5678); // во второй регистр запишем число 5678 /* USER CODE END 2 */

      В бесконечном цикле читаем эти данные:

      /* USER CODE BEGIN WHILE */ while (1) < uint16_t reg_1 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1); uint16_t reg_2 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2); snprintf(trans_str, 63, "Reg_1 %d Reg_2 %d\n", reg_1, reg_2); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_Delay(1000); . 

      Прошейте эту программу и коротните пин на «землю» — данные обнулятся.

      Теперь если нажать Reset, то по идее данные должны будут записаться заново, но этого не случится. Дело в том, что после подачи сигнала запись в эти регистры будет запрещена. Чтобы восстановить возможность записи нужно полностью обесточить плату (батарейку тоже нужно отключить). Так происходит только в режиме Tamper, если его отключить, то эти регистры можно перезаписывать как угодно.

      Помимо обнуления регистров этот сигнал может вызывать прерывание…

      В программе нужно добавить только колбек:

      /* USER CODE BEGIN 0 */ void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef *hrtc)

      Если включено прерывание, то при нажатии Reset регистры с данными будут перезаписываться!

      Для работы без прерываний можно воспользоваться функцией ожидания сигнала.

      пример

      Структуру тампера объявляем глобально:

      /* USER CODE BEGIN PV */ RTC_TimeTypeDef sTime = ; RTC_DateTypeDef DateToUpdate = ; RTC_AlarmTypeDef sAlarm = ; RTC_TamperTypeDef sTamper = ; // структура тампера char trans_str[64] = ; /* USER CODE END PV */

      В бесконечном цикле делаем так:

      /* USER CODE BEGIN WHILE */ while (1) < static uint16_t count = 0; // просто счётчик для наглядности uint16_t reg_1 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1); uint16_t reg_2 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2); snprintf(trans_str, 63, "Before Reg_1 %d Reg_2 %d\n", reg_1, reg_2); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); snprintf(trans_str, 63, "Start %d Wait 10 sec. \n", count++); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTCEx_SetTamper(&hrtc, &sTamper); HAL_RTCEx_PollForTamper1Event(&hrtc, 10000); // ждём сигнала 10 сек. reg_1 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1); reg_2 = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR2); snprintf(trans_str, 63, "After Reg_1 %d Reg_2 %d\n\n", reg_1, reg_2); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_Delay(1000); . 

      Опять же, при нажатии Reset регистры с данными будут перезаписываться.

      У F303 15 пользовательских регистров и три tamper-пина.

      Прерывания включаются так…

      У каждого пина свой колбек:

      void HAL_RTCEx_Tamper1EventCallback(RTC_HandleTypeDef *hrtc) void HAL_RTCEx_Tamper2EventCallback(RTC_HandleTypeDef *hrtc) void HAL_RTCEx_Tamper3EventCallback(RTC_HandleTypeDef *hrtc)

      Всё остальное как у F103.

      Я когда ковырялся с этим функционалом, время от времени возникало ощущение что что-то «глючит» (регистры то записываются, то не записываются, то обнуляются, то не обнуляются), но потом стало понятно что это всего лишь следствие неправильных действий. Это к тому, что нужно проявить терпение и разобраться.

      Будильник (Alarm) для F303

      У этого микроконтроллера два будильника А и В…

      У них есть два варианта настроек:

      Internal Alarm — просто будильник, может вызывать прерывание.

      Routed to OUT — во время срабатывания будильника можно вызвать прерывание и/или подать кратковременный импульс на пин РС13 .

      Сейчас укажите Internal Alarm А .

      Настройте всё как на картинке…

      Время у нас установлено 10:34:00, а будильник сработает в 10:34:10.

      Sub Seconds — это миллисекунды.

      Следующие пункты, это различные комбинации настроек времени/даты срабатывания будильника. Например пункт Alarm Mask Date Week day ⇨ Enable говорит о том, что будильник должен срабатывать каждый день.

      Если активировать пункт Alarm Mask Minutes ⇨ Enable , то будильник будет срабатывать каждую минуту в течении часа. Срабатывания будут происходить не ровно в минуту, а минута + 10сек.

      Если активировать пункт Alarm Mask Seconds ⇨ Enable , то срабатывать будет каждую секунду в течении минуты.

      Этих комбинаций достаточно много, поэтому надеюсь что вы разберётесь самостоятельно.

      Alarm combinations

      Активируйте прерывание от будильника…

      В код добавьте колбек:

      /* USER CODE BEGIN 0 */ void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)

      Alarm B

      У Alarm B свой колбек:

      HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc)

      В бесконечном цикле будем выводить инфу:

      /* USER CODE BEGIN WHILE */ while (1) < HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); // RTC_FORMAT_BIN , RTC_FORMAT_BCD snprintf(trans_str, 63, "Time %d:%d:%d\n", sTime.Hours, sTime.Minutes, sTime.Seconds); //snprintf(trans_str, 63, "Time %d:%d:%d:%lu\n", sTime.Hours, sTime.Minutes, sTime.Seconds, sTime.SubSeconds); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN); snprintf(trans_str, 63, "Date %d-%d-20%d\n", DateToUpdate.Date, DateToUpdate.Month, DateToUpdate.Year); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTC_GetAlarm(&hrtc, &sAlarm, RTC_ALARM_A, RTC_FORMAT_BIN); snprintf(trans_str, 63, "Alarm %d:%d:%d\n", sAlarm.AlarmTime.Hours, sAlarm.AlarmTime.Minutes, sAlarm.AlarmTime.Seconds); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_Delay(1000); . 

      Чтобы будильник подавал импульс на пин РС13, надо указать Routed to OUT …

      В настройках появятся два дополнительных пункта…

      Output Polarity — на ножку будет подаваться «плюс».
      Output Type — почитайте здесь.

      Делайте как на картинке и не забудьте будильник настроить, он сбивается при изменении режима.

      Подключите светодиод к пину РС13 и смотрите как он мигнёт во время срабатывания будильника.

      WakeUp

      WakeUp может выводить МК из спящего режима, вызывать прерывание и подавать сигнал на пин РС13.

      WakeUp это простой 16-ти битный (от 0 до 65535) счётчик. Тактирование можно настроить с помощью предделителей часового генератора.

      Например если сделать так…

      Тогда счётчик будет увеличиваться со скоростью 2048 единиц в секунду и достигнет 10000 примерно через 5 секунд (32.768кГц / 16 = 2048, 10000 / 2048 = 4.88 сек). То есть WakeUp будет срабатывать каждые ~5 секунд.

      Можно не заморачиваться с предделителями, а просто указать 1Hz…

      Счётчик будет увеличиваться со скоростью 1 единица в секунду и срабатывать через каждые 5 сек.

      Таким образом можно настроить пробуждение МК на достаточно большой интервал. Например если указать 65000, то WakeUp будет срабатывать каждые 18 часов.

      Если включено прерывание, то на пин РС13 подаётся кратковременный импульс, а если отключено, то подаётся постоянный сигнал.

      И добавьте соответствующий колбек:

      /* USER CODE BEGIN 0 */ void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)

      Прошивайте и смотрите что получилось.

      Посмотреть значение счётчика можно так:

      uint32_t wu = HAL_RTCEx_GetWakeUpTimer(&hrtc); snprintf(trans_str, 63, "WakeUp %lu\n\n", wu); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000);
      HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);

      TimeStamp

      Прикольная функция. Если на пин РС13 подать внешний импульс, тогда в специальные регистры будут записаны текущие время и дата. Настройка только одна и она ничем не отличается от того, что написано в главе «Tamper для F103 и F303». То есть нужно указать фронт сигнала и подтянуть пин.

      В бесконечном цикле сделайте так:

      /* USER CODE BEGIN WHILE */ while (1) < HAL_RTCEx_GetTimeStamp(&hrtc, &sTime, &DateToUpdate, RTC_FORMAT_BIN); // читаем Time/Date Stamp snprintf(trans_str, 63, "TimeStamp %d:%d:%d\n", sTime.Hours, sTime.Minutes, sTime.Seconds); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); snprintf(trans_str, 63, "DateStamp %d-%d-%d\n", DateToUpdate.Date, DateToUpdate.Month, DateToUpdate.Year); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN); snprintf(trans_str, 63, "Time %d:%d:%d\n", sTime.Hours, sTime.Minutes, sTime.Seconds); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_RTC_GetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN); snprintf(trans_str, 63, "Date %d-%d-%d\n\n", DateToUpdate.Date, DateToUpdate.Month, DateToUpdate.Year); HAL_UART_Transmit(&huart1, (uint8_t*)trans_str, strlen(trans_str), 1000); HAL_Delay(1000); . 

      Прошейте МК и коротните РС13 на «землю».

      Данные из регистров записываются в структуры времени и даты (чтоб не создавать дополнительные структуры).

      Обратите внимание на то, что регистры обнуляются после чтения.

      Прерывание то же что и у Tamper…

      /* USER CODE BEGIN 0 */ void HAL_RTCEx_TimeStampEventCallback(RTC_HandleTypeDef *hrtc)

      Calibration

      В мануале про этот выход сказано так:

      «Выход RTC_CALIB используется для генерации сигнала переменной частоты. В зависимости от пожелания пользователя этот сигнал может играть роль опорной частоты для внешнего устройства или его можно подключить к зуммеру для генерации звука.»

      Есть два варианты частоты — 1Гц и 512Гц…

      Запускается и останавливается этот сигнал функциями…

      HAL_RTCEx_SetCalibrationOutPut(&hrtc, RTC_CALIBOUTPUT_1HZ); // или RTC_CALIBOUTPUT_512HZ HAL_RTCEx_DeactivateCalibrationOutPut(&hrtc);

      Можно помигать или попищать при срабатывании будильника.

      Для калибровки часов этот выход нужно подключить к осциллографу и добиваться необходимой частоты двумя способами:

      1. Манипулировать предделителями — грубая калибровка.
      2. С помощью пропусков (маскировки) или добавления тактов — мягкая калибровка.

      Осциллографа у меня нет поэтому я особо в этом не разбирался. За мягкую калибровку отвечает функция HAL_RTCEx_SetSmoothCalib() . Все подробности смотрите в AN3371, глава 1.4, стр. 17.

      Reference clock detection — на это пин можно подать опорную частоту (50 Гц) из розетки. Проводить эксперименты я не решился

      В мануале есть такая картика…

      В статье не описаны некоторые функции — посмотреть их можно в файлах stm32f3xx_hal_rtc.c и stm32f3xx_hal_rtc_ex.c.

      На этом всё.

      Всем спасибо

    • 26 февраля 2019, 02:16
    • stD
    • 66947

    -->

    Поддержать автора

    Задать вопрос по статье

    Известит Вас о новых публикациях

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *