init commit

сделаны базовые хедеры:
- mylibs_config
- mylibs_defs
- mylibs_include
- trace
- trackers
- bit_access

также сделан модуль general_gpio.c/.h

Но надо проверить переструктуризированные модули

Остальные модули  __general_XXX в целом готовы и как-то работают (на МЗКТЭ) но не структуризированы
This commit is contained in:
2025-10-18 18:27:37 +03:00
commit f61aa1ff0f
304 changed files with 57234 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
/*********************************UART**************************************
Данный файл содержит объявления базовых функции и дефайны для инициализации
UART.
***************************************************************************/
#ifndef __FLASH_GENERAL_H_
#define __FLASH_GENERAL_H_
//////////////////////////////////////////////////////////////////////
/////////////////////////---USER SETTINGS---/////////////////////////
/////////////////////////---USER SETTINGS---/////////////////////////
#include "mylibs_defs.h"
/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
HAL_StatusTypeDef FLASH_Enable_DualBankMode(void);
HAL_StatusTypeDef FLASH_WriteProtection(uint32_t BankN, uint32_t WriteProtection);
/* functions for reading bytes/halswords/words */
uint8_t FLASH_Read_Byte(uint32_t add);
uint16_t FLASH_Read_HalfWord(uint32_t add);
uint32_t FLASH_Read_Word(uint32_t add);
/* functions for writing bytes/halswords/words */
HAL_StatusTypeDef FLASH_Write_Byte(uint32_t Address, uint8_t Data);
HAL_StatusTypeDef FLASH_Write_HalfWord(uint32_t Address, uint16_t Data);
HAL_StatusTypeDef FLASH_Write_Word(uint32_t Address, uint32_t Data);
///////////////////////////---FUNCTIONS---///////////////////////////
#ifndef LED_PWM_TICKS
#define LED_PWM_TICKS 15
#endif
#ifndef LED_ON
#define LED_ON 1
#endif
#ifndef LED_OFF
#define LED_OFF 0
#endif
#ifndef SW_ON
#define SW_ON 1
#endif
#ifndef SW_OFF
#define SW_OFF 0
#endif
#endif // __FLASH_GENERAL_H_

View File

@@ -0,0 +1,100 @@
/**
**************************************************************************
* @file general_spi.h
* @brief Заголовочны файл модуля инициализации SPI.
*************************************************************************/
#ifndef __SPI_GENERAL_H_
#define __SPI_GENERAL_H_
//////////////////////////////////////////////////////////////////////
/////////////////////////---USER SETTINGS---/////////////////////////
#define HAL_SPI_MODULE_ENABLED // need to uncomment these defines in stm32f4xx_hal_conf.h
// also need to add hal_spi.c (source code)
#define USE_SPI1
#define USE_SPI2
#define USE_SPI3
/////////////////////////---USER SETTINGS---/////////////////////////
#include "mylibs_defs.h"
/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
typedef struct // struct with settings for custom function
{
SPI_HandleTypeDef hspi;
GPIO_TypeDef *CLK_GPIOx;
uint32_t CLK_PIN;
uint32_t CLK_GPIO_AlternageFunc;
GPIO_TypeDef *MISO_GPIOx;
uint32_t MISO_PIN;
uint32_t MISO_GPIO_AlternageFunc;
GPIO_TypeDef *MOSI_GPIOx;
uint32_t MOSI_PIN;
uint32_t MOSI_GPIO_AlternageFunc;
}SPI_SettingsTypeDef;
///////////////////////---STRUCTURES & ENUMS---//////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
/**
* @brief Initialize SPI with SPI_SettingsTypeDef structure.
* @param sspi - указатель на структуру с настройками SPI.
* @return HAL status.
* @note Данная структура содержит хендл ЮАРТ и настройки перефирии (GPIO)
*/
HAL_StatusTypeDef SPI_Base_Init(SPI_SettingsTypeDef *sspi);
/**
* @brief Initialize GPIO for SPI.
* @param GPIOx - порт для настройки.
* @param GPIO_PIN_RX - пин для настройки на прием.
* @param GPIO_PIN_TX - пин для настройки на передачу.
*/
void SPI_GPIO_Init(SPI_SettingsTypeDef *sspi);
/**
* @brief Initialize DMA for SPI.
* @param hspi - указатель на хендл SPI для настройки DMA.
* @param hdma_rx - указатель на хендл DMA для линии приема SPI.
* @param DMAChannel - указатель на канал DMA/поток DMA в STM32F407.
* @param DMA_CHANNEL_X - канал DMA.
*/
void SPI_DMA_Init(SPI_HandleTypeDef *hspi, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X);
/**
* @brief Initialize SPI & DMA clock and interrupt.
* @param hspi - указатель на хендл SPI для инициализации.
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых SPI,
дефайнами определяются используемые SPI.
*/
void SPI_MspInit(SPI_HandleTypeDef *hspi);
/**
* @brief Deinitialize SPI & DMA clock and interrupt.
* @param hspi - указатель на хендл SPI для деинициализации.
* @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых SPI,
дефайнами в rs_message.h определяются используемые SPI.
*/
void SPI_MspDeInit(SPI_HandleTypeDef *hspi);
/**
* @brief Check that spi init structure have correct values.
* @param sspi - указатель на структуру с настройками SPI.
* @return HAL status.
*/
HAL_StatusTypeDef Check_SPI_Init_Struct(SPI_SettingsTypeDef *sspi);
///////////////////////////---FUNCTIONS---///////////////////////////
#endif // __SPI_GENERAL_H_

View File

@@ -0,0 +1,130 @@
/**
**************************************************************************
* @file general_tim.h
* @brief Заголовочный файл для базовой работы с таймерами.
*************************************************************************/
#ifndef __TIM_GENERAL_H_
#define __TIM_GENERAL_H_
/////////////////////////////////////////////////////////////////////
/////////////////////////---USER SETTINGS---/////////////////////////
#define HAL_TIM_MODULE_ENABLED // need to uncomment this define in stm32f4xx_hal_conf.h
#define USE_TIM1
#define USE_TIM2
#define USE_TIM3
#define USE_TIM4
#define USE_TIM5
#define USE_TIM6
#define USE_TIM7
#define USE_TIM8
#define USE_TIM9
#define USE_TIM10
#define USE_TIM11
#define USE_TIM12
#define USE_TIM13
#define USE_TIM14
/* note: used uart defines in modbus.h */
/////////////////////////---USER SETTINGS---/////////////////////////
#include "mylibs_defs.h"
/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
#define TIM_IT_CONF_Pos 0
//#define TIM_PWM_CONF_Pos 1
//#define TIM_CLCK_SRC_CONF_Pos 2
//#define TIM_SLAVE_CONF_Pos 3
//#define TIM_MASTER_CONF_Pos 4
//#define TIM_BDTR_CONF_Pos 5
#define TIM_IT_CONF (1<<(TIM_IT_CONF_Pos))
//#define TIM_PWM_CONF (1<<(TIM_PWM_Pos))
#define TIM_Alternate_Mapping(INSTANCE) ((((INSTANCE) == TIM1) || ((INSTANCE) == TIM2))? GPIO_AF1_TIM1: \
(((INSTANCE) == TIM3) || ((INSTANCE) == TIM4) || ((INSTANCE) == TIM5))? GPIO_AF2_TIM3: \
(((INSTANCE) == TIM8) || ((INSTANCE) == TIM9) || ((INSTANCE) == TIM10) || ((INSTANCE) == TIM11))? GPIO_AF3_TIM8: \
(((INSTANCE) == TIM12) || ((INSTANCE) == TIM13) || ((INSTANCE) == TIM14))? GPIO_AF9_TIM12: \
(0))
////////////////////////////---DEFINES---////////////////////////////]
/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
typedef enum
{
TIM_DEFAULT = 0,
TIM_IT_MODE = TIM_IT_CONF,
// TIM_PWM_MODE = TIM_PWM_ENABLE,
// TIM_PWM_IT_MODE = TIM_PWM_ENABLE | TIM_IT_CONF,
}TIM_ITModeTypeDef;
typedef enum
{
TIM_Base_Disable = 0,
TIM_TickBase_1US = 1,
TIM_TickBase_10US = 10,
TIM_TickBase_100US = 100,
TIM_TickBase_1MS = 1000,
TIM_TickBase_10MS = 10000,
TIM_TickBase_100MS = 100000,
}TIM_MHzTickBaseTypeDef;
typedef struct // struct with settings for custom function
{
TIM_HandleTypeDef htim;
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_SlaveConfigTypeDef sSlaveConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
TIM_ITModeTypeDef sTimMode;
TIM_MHzTickBaseTypeDef sTickBaseUS;
uint8_t sTickBasePrescaler;
float sTimAHBFreqMHz;
float sTimFreqHz;
}TIM_SettingsTypeDef;
typedef struct // struct with variables for encoder
{
int16_t Encoder_Diff;
TIM_HandleTypeDef *htim;
TIM_Encoder_InitTypeDef sConfig;
GPIO_TypeDef *GPIOx;
uint32_t GPIO_PIN_TI1;
uint32_t GPIO_PIN_TI2;
uint32_t GPIO_PIN_SW;
}TIM_EncoderTypeDef;
///////////////////////---STRUCTURES & ENUMS---//////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
/* Initialize TIM with TIM_SettingsTypeDef structure */
HAL_StatusTypeDef TIM_Base_Init(TIM_SettingsTypeDef* stim);
/* Initialize PWM Channel and GPIO for output */
HAL_StatusTypeDef TIM_Output_PWM_Init(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfigOC, uint32_t TIM_CHANNEL, GPIO_TypeDef *GPIOx, uint32_t PWM_PIN);
/* Initialize TIM Encoder functional */
HAL_StatusTypeDef TIM_Encoder_Init(TIM_EncoderTypeDef *henc1, TIM_HandleTypeDef *htim);
/* Initialize OC Comparator */
HAL_StatusTypeDef TIM_OC_Comparator_Init(TIM_HandleTypeDef *htim, uint32_t TIM_CHANNEL);
/* Start delay via TIM */
HAL_StatusTypeDef TIM_Delay_Start(TIM_HandleTypeDef *htim);
/* Delay via TIM */
HAL_StatusTypeDef TIM_Delay(TIM_HandleTypeDef *htim, uint16_t delay);
/* Wait Delay via TIM without blocking app */
HAL_StatusTypeDef TIM_Delay_NonBlocking(TIM_HandleTypeDef *htim, uint16_t delay);
/* Initialize TIMs clock and interrupt */
void TIM_Base_MspInit(TIM_HandleTypeDef* htim, TIM_ITModeTypeDef it_mode);
/* DeInitialize TIMs clock and interrupt */
void TIM_Base_MspDeInit(TIM_HandleTypeDef* htim);
///////////////////////////---FUNCTIONS---///////////////////////////
#endif // __TIM_GENERAL_H_

View File

@@ -0,0 +1,108 @@
/**
**************************************************************************
* @file general_uart.h
* @brief Заголовочный файл для модуля инициализации UART.
*************************************************************************/
#ifndef __UART_GENERAL_H_
#define __UART_GENERAL_H_
//////////////////////////////////////////////////////////////////////
/////////////////////////---USER SETTINGS---/////////////////////////
#define HAL_UART_MODULE_ENABLED // need to uncomment these defines in stm32f4xx_hal_conf.h
//#define HAL_USART_MODULE_ENABLED // maybe also need to add hal_uart.h/.c (source code)
//#define USE_USART1
//#define USE_USART2
//#define USE_USART3
//#define USE_UART4
//#define USE_UART5
//#define USE_USART6
/* note: used uart defines in modbus.h */
/////////////////////////---USER SETTINGS---/////////////////////////
#include "interface_config.h" /* used uart defines in modbus.h */
/////////////////////////////////////////////////////////////////////
////////////////////////////---DEFINES---////////////////////////////
#include "mylibs_defs.h"
/**
* @brief Analog for HAL define. Remade with pointer to structure.
* @note @ref __HAL_LINKDMA.
*/
#define __USER_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \
do{ \
(__HANDLE__)->__PPP_DMA_FIELD__ = (__DMA_HANDLE__); \
(__DMA_HANDLE__)->Parent = (__HANDLE__);} while(0U)
////////////////////////////---DEFINES---////////////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////---STRUCTURES & ENUMS---//////////////////////
typedef struct // struct with settings for custom function
{
UART_HandleTypeDef huart;
GPIO_TypeDef *GPIOx;
uint16_t GPIO_PIN_RX;
uint16_t GPIO_PIN_TX;
DMA_Stream_TypeDef *DMAChannel; // DMAChannel = 0 if doesnt need
uint32_t DMA_CHANNEL_X; // DMAChannel = 0 if doesnt need
}UART_SettingsTypeDef;
///////////////////////---STRUCTURES & ENUMS---//////////////////////
/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
/**
* @brief Initialize UART with UART_SettingsTypeDef structure.
* @param suart - указатель на структуру с настройками UART.
* @return HAL status.
* @note Данная структура содержит хендл ЮАРТ и настройки перефирии (GPIO)
*/
HAL_StatusTypeDef UART_Base_Init(UART_SettingsTypeDef *suart);
/**
* @brief Initialize GPIO for UART.
* @param GPIOx - порт для настройки.
* @param GPIO_PIN_RX - пин для настройки на прием.
* @param GPIO_PIN_TX - пин для настройки на передачу.
*/
void UART_GPIO_Init(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN_RX, uint16_t GPIO_PIN_TX);
/**
* @brief Initialize DMA for UART.
* @param huart - указатель на хендл UART для настройки DMA.
* @param hdma_rx - указатель на хендл DMA для линии приема UART.
* @param DMAChannel - указатель на канал DMA/поток DMA в STM32F407.
* @param DMA_CHANNEL_X - канал DMA.
*/
void UART_DMA_Init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X);
/**
* @brief Initialize UART & DMA clock and interrupt.
* @param huart - указатель на хендл UART для инициализации.
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых UART,
дефайнами определяются используемые UART.
*/
void UART_MspInit(UART_HandleTypeDef *huart);
/**
* @brief Deinitialize UART & DMA clock and interrupt.
* @param huart - указатель на хендл UART для деинициализации.
* @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых UART,
дефайнами в rs_message.h определяются используемые UART.
*/
void UART_MspDeInit(UART_HandleTypeDef *huart);
/**
* @brief Check that uart init structure have correct values.
* @param suart - указатель на структуру с настройками UART.
* @return HAL status.
*/
HAL_StatusTypeDef Check_UART_Init_Struct(UART_SettingsTypeDef *suart);
///////////////////////////---FUNCTIONS---///////////////////////////
#endif // __UART_GENERAL_H_

View File

@@ -0,0 +1,159 @@
/**
**************************************************************************
* @file mylibs_defs.h
* @brief Заголочный файл для дефайнов библиотеки MyLibsGeneral.
**************************************************************************
* @defgroup BIT_ACCESS_DEFINES Bit access defines
* @ingroup MYLIBS_DEFINES
* @brief Макросы и typedef'ы для работы с битами в unsigned типах.
* @details
* В этом файле определены макросы для получения значения конкретного бита^
* - @ref uint8_bit
* - @ref uint16_bit
* - @ref uint32_bit
* - @ref uint64_bit
*
* Особенности использования:
* - Индекс бита должен быть **константой на этапе компиляции**.
* Пример верного использования:
* @code
* uint8_t val = 0x05;
* uint8_t b2 = uint8_bit(val, 2); // Получить бит 2
* uint8_bit(val, 6) = 1; // Записать бит 6
* @endcode
* - Нельзя использовать переменные в качестве индекса:
* @code
* uint8_t i = 2;
* uint8_bit(val, i); // Не сработает!
* @endcode
* - Макросы возвращают 0 или 1.
* - Доступ реализован через приведение к `union` с битовыми полями, поэтому это
* безопасный способ работы с отдельными битами без ручного сдвига и маскирования.
* @{
*************************************************************************/
#ifndef __BIT_ACCESS_H_
#define __BIT_ACCESS_H_
#include "mylibs_defs.h"
typedef union
{
uint8_t all;
struct
{
unsigned bit0:1;
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned bit4:1;
unsigned bit5:1;
unsigned bit6:1;
unsigned bit7:1;
}bit;
}uint8_BitTypeDef;
typedef union
{
uint16_t all;
struct
{
unsigned bit0:1;
unsigned bit1:1;
unsigned bit2:1;
unsigned bit3:1;
unsigned bit4:1;
unsigned bit5:1;
unsigned bit6:1;
unsigned bit7:1;
unsigned bit8:1;
unsigned bit9:1;
unsigned bit10:1;
unsigned bit11:1;
unsigned bit12:1;
unsigned bit13:1;
unsigned bit14:1;
unsigned bit15:1;
}bit;
}uint16_BitTypeDef;
typedef union
{
uint32_t all;
struct
{
unsigned bit0:1; unsigned bit1:1; unsigned bit2:1; unsigned bit3:1;
unsigned bit4:1; unsigned bit5:1; unsigned bit6:1; unsigned bit7:1;
unsigned bit8:1; unsigned bit9:1; unsigned bit10:1; unsigned bit11:1;
unsigned bit12:1; unsigned bit13:1; unsigned bit14:1; unsigned bit15:1;
unsigned bit16:1; unsigned bit17:1; unsigned bit18:1; unsigned bit19:1;
unsigned bit20:1; unsigned bit21:1; unsigned bit22:1; unsigned bit23:1;
unsigned bit24:1; unsigned bit25:1; unsigned bit26:1; unsigned bit27:1;
unsigned bit28:1; unsigned bit29:1; unsigned bit30:1; unsigned bit31:1;
}bit;
}uint32_BitTypeDef;
typedef union
{
uint64_t all;
struct
{
unsigned bit0:1; unsigned bit1:1; unsigned bit2:1; unsigned bit3:1;
unsigned bit4:1; unsigned bit5:1; unsigned bit6:1; unsigned bit7:1;
unsigned bit8:1; unsigned bit9:1; unsigned bit10:1; unsigned bit11:1;
unsigned bit12:1; unsigned bit13:1; unsigned bit14:1; unsigned bit15:1;
unsigned bit16:1; unsigned bit17:1; unsigned bit18:1; unsigned bit19:1;
unsigned bit20:1; unsigned bit21:1; unsigned bit22:1; unsigned bit23:1;
unsigned bit24:1; unsigned bit25:1; unsigned bit26:1; unsigned bit27:1;
unsigned bit28:1; unsigned bit29:1; unsigned bit30:1; unsigned bit31:1;
unsigned bit32:1; unsigned bit33:1; unsigned bit34:1; unsigned bit35:1;
unsigned bit36:1; unsigned bit37:1; unsigned bit38:1; unsigned bit39:1;
unsigned bit40:1; unsigned bit41:1; unsigned bit42:1; unsigned bit43:1;
unsigned bit44:1; unsigned bit45:1; unsigned bit46:1; unsigned bit47:1;
unsigned bit48:1; unsigned bit49:1; unsigned bit50:1; unsigned bit51:1;
unsigned bit52:1; unsigned bit53:1; unsigned bit54:1; unsigned bit55:1;
unsigned bit56:1; unsigned bit57:1; unsigned bit58:1; unsigned bit59:1;
unsigned bit60:1; unsigned bit61:1; unsigned bit62:1; unsigned bit63:1;
}bit;
}uint64_BitTypeDef;
/**
* @brief Получить n-й бит из uint8_t
* @param _uint8_ Переменная типа uint8_t
* @param _bit_ Константный номер бита (0..7)
* @return Значение выбранного бита (0 или 1)
* @note Индекс бита должен быть известен на этапе компиляции!
*/
#define uint8_bit(_uint8_, _bit_) (*(uint8_BitTypeDef *)(&(_uint8_))).bit.bit##_bit_
/**
* @brief Получить n-й бит из uint16_t
* @param _uint16_ Переменная типа uint16_t
* @param _bit_ Константный номер бита (0..15)
* @return Значение выбранного бита (0 или 1)
* @note Индекс бита должен быть известен на этапе компиляции!
*/
#define uint16_bit(_uint8_, _bit_) (*(uint16_BitTypeDef *)(&(_uint8_))).bit.bit##_bit_
/**
* @brief Получить n-й бит из uint32_t
* @param _uint32_ Переменная типа uint32_t
* @param _bit_ Константный номер бита (0..31)
* @return Значение выбранного бита (0 или 1)
* @note Индекс бита должен быть известен на этапе компиляции!
*/
#define uint32_bit(_uint8_, _bit_) (*(uint32_BitTypeDef *)(&(_uint8_))).bit.bit##_bit_
/**
* @brief Получить n-й бит из uint64_t
* @param _uint64_ Переменная типа uint64_t
* @param _bit_ Константный номер бита (0..63)
* @return Значение выбранного бита (0 или 1)
* @note Индекс бита должен быть известен на этапе компиляции!
*/
#define uint64_bit(_uint8_, _bit_) (*(uint64_BitTypeDef *)(&(_uint8_))).bit.bit##_bit_
#endif //__BIT_ACCESS_H_
/** BIT_ACCESS_DEFINES
* @}
*/

View File

@@ -0,0 +1,175 @@
/**
**************************************************************************
* @file general_gpio.h
* @brief Заголовочный файл для модуля инициализации портов.
**************************************************************************
* @defgroup MY_LIBS_GPIO GPIO Tools
* @ingroup MYLIBS_PERIPHERAL
* @brief Функции и макросы для удобной работы с GPIO.
*************************************************************************/
#ifndef __GPIO_GENERAL_H_
#define __GPIO_GENERAL_H_
#include "mylibs_defs.h"
/**
* @addtogroup GPIO_INIT Init defines
* @ingroup GPIO_GENERAL
* @brief Настройка состояний кнопок и количества тиков в периоде ШИМ
* @{
*/
#ifndef LED_PWM_TICKS
#define LED_PWM_TICKS 15 ///< Количество тиков в периоде ШИМ
#endif
#ifndef LED_ON
#define LED_ON 1 ///< Состояние пина для включения светодиода
#endif
#ifndef LED_OFF
#define LED_OFF 0 ///< Состояние пина для выключения светодиода
#endif
#ifndef SW_ON
#define SW_ON 1 ///< Состояние пина при нажатой кнопке
#endif
#ifndef SW_OFF
#define SW_OFF 0 ///< Состояние пина при отжатой кнопке
#endif
/** GPIO_INIT
* @}
*/
// /**
// * @brief Маппинг альтернативной функции SPI между GPIO
// * @ingroup GPIO_GENERAL
// */
// #define SPI_Alternate_Mapping(INSTANCE) \
// ((((INSTANCE) == TIM1) || ((INSTANCE) == TIM2))? GPIO_AF1_TIM1: \
// (((INSTANCE) == TIM3) || ((INSTANCE) == TIM4) || ((INSTANCE) == TIM5))? GPIO_AF2_TIM3: \
// (((INSTANCE) == TIM8) || ((INSTANCE) == TIM9) || ((INSTANCE) == TIM10) || ((INSTANCE) == TIM11))? GPIO_AF3_TIM8: \
// (((INSTANCE) == TIM12) || ((INSTANCE) == TIM13) || ((INSTANCE) == TIM14))? GPIO_AF9_TIM12: \
// (0))
/**
* @brief Маппинг альтернативной функции TIM между GPIO
* @ingroup GPIO_GENERAL
*/
#define TIM_Alternate_Mapping(INSTANCE) \
((((INSTANCE) == TIM1) || ((INSTANCE) == TIM2))? GPIO_AF1_TIM1: \
(((INSTANCE) == TIM3) || ((INSTANCE) == TIM4) || ((INSTANCE) == TIM5))? GPIO_AF2_TIM3: \
(((INSTANCE) == TIM8) || ((INSTANCE) == TIM9) || ((INSTANCE) == TIM10) || ((INSTANCE) == TIM11))? GPIO_AF3_TIM8: \
(((INSTANCE) == TIM12) || ((INSTANCE) == TIM13) || ((INSTANCE) == TIM14))? GPIO_AF9_TIM12: \
(0))
/**
* @brief Режимы работы светодиода
* @ingroup GPIO_LEDS
*/
typedef enum
{
LED_IS_OFF = 0, ///< Светодиод выключен
LED_IS_ON = 1, ///< Светодиод включен
LED_IS_BLINKING = 2, ///< Моргание светодиодом
LED_IS_FADING = 3, ///< Плавное моргание светодиодом
}GPIO_LEDStateTypeDef;
/**
* @brief Структура светодиода
* @ingroup GPIO_LEDS
*/
typedef struct
{
GPIO_LEDStateTypeDef state; ///< Текущий режим работы светодиода
GPIO_TypeDef *LED_Port; ///< GPIO порт ножки светодиода
uint32_t LED_Pin; ///< GPIO пин ножки светодиода
uint8_t LED_ActiveLvl; ///< Активный уровень ножки (при котором светодиод горит)
uint32_t LED_Period; ///< Период моргания светодиода
uint32_t tickprev;///< Период моргания светодиода
}GPIO_LEDTypeDef;
/**
* @brief Структура кнопки
* @ingroup GPIO_SWITCH
*/
typedef struct
{
GPIO_TypeDef *Sw_Port; ///< GPIO порт ножки кнопки
uint32_t Sw_Pin; ///< GPIO пин ножки кнопки
uint8_t Sw_ActiveLvl; ///< Активный уровень ножки (при котором кнопка нажата)
uint32_t Sw_PrevState; ///< Предыдущее состояние кнопки
uint32_t Sw_FilterDelay; ///< Фильтр от дребезга (в мс)
uint32_t tickprev;///< Период моргания светодиода
}GPIO_SwitchTypeDef;
/////////////////////////////////////////////////////////////////////
///////////////////////////---FUNCTIONS---///////////////////////////
/**
* @addtogroup GPIO_GENERAL General tools
* @ingroup MY_LIBS_GPIO
* @brief Общие функции/макросы для работы с GPIO
* @{
*/
HAL_StatusTypeDef GPIO_Clock_Enable(GPIO_TypeDef *GPIOx);
/** GPIO_GENERAL
* @}
*/
/**
* @addtogroup GPIO_SWITCH Switch tools
* @ingroup MY_LIBS_GPIO
* @brief Функции для работы с GPIO, как с кнопкой
* @{
*/
/* Инициализировать кнопку (структуру кнопки) */
HAL_StatusTypeDef GPIO_Switch_Init(GPIO_SwitchTypeDef *sw, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t SW_On_State);
/* Считать состоянии кнопки запуска */
uint8_t GPIO_Read_Switch(GPIO_SwitchTypeDef *swstart);
/** GPIO_SWITCH
* @}
*/
/**
* @addtogroup GPIO_LEDS LED tools
* @ingroup MY_LIBS_GPIO
* @brief Функции для работы с GPIO, для управления светодиодом
* @{
*/
/* Инициализировать светодиод (структуру светодиода) */
HAL_StatusTypeDef GPIO_LED_Init(GPIO_LEDTypeDef *led, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t LED_On_State);
/* Включить светодиод */
HAL_StatusTypeDef GPIO_LED_On(GPIO_LEDTypeDef *led);
/* Выключить светодиод */
HAL_StatusTypeDef GPIO_LED_Off(GPIO_LEDTypeDef *led);
/* Выставить светодиод по переменной */
HAL_StatusTypeDef GPIO_LED_Set(GPIO_LEDTypeDef *led, uint8_t led_state);
/* Активировать моргание светодиодом */
HAL_StatusTypeDef GPIO_LED_Blink_Start(GPIO_LEDTypeDef *led, uint32_t period);
/* Активировать моргание светодиодом */
HAL_StatusTypeDef GPIO_LED_Fading_Start(GPIO_LEDTypeDef *led, uint32_t period);
/* Управление динамическими режимами свечения светодиода */
void GPIO_LED_Dynamic_Handle(GPIO_LEDTypeDef *led);
/** GPIO_LEDS
* @}
*/
///////////////////////////---FUNCTIONS---///////////////////////////
#endif // __GPIO_GENERAL_H_

View File

@@ -0,0 +1,82 @@
/**
**************************************************************************
* @file mylibs_config.h
* @brief Конфигурации для библиотек MyLibs
**************************************************************************
* @defgroup MYLIBS_CONFIG Configs
* @ingroup MYLIBS_ALL
* @brief Конфигурации для библиотек MyLibs
@{
*************************************************************************/
#ifndef __MYLIBS_CONFIG_H_
#define __MYLIBS_CONFIG_H_
#include "stm32f4xx_hal.h"
// user includes
#include "mzkt_config.h"
#include "mzkt_trace_config.h"
#include "interface_config.h"
/**
* @addtogroup TRACE_CONFIG Trace configs
* @ingroup MYLIBS_CONFIG
* @brief Конфигурация трекеров и трассировки
* @{
*/
#define TRACKERS_ENABLE ///< Включить трекеры
#define SERIAL_TRACE_ENABLE ///< Включить serial трассировку
#define RTT_TRACE_ENABLE ///< Включить serial трассировку через RTT
#define SWO_TRACE_ENABLE ///< Включить serial трассировку через SWO
/**
* @brief Уровень log serial трассировки @ref log_printf
* - LOG_LEVEL == 0 - логирование отключено (макрос пустой)
* - LOG_LEVEL == 1 - выводится время и TAG
* - LOG_LEVEL >= 2 - выводится время, TAG, имя файла и номер строки
*/
#define LOG_LEVEL 1
#define RTT_FLASH_BUFFER_SIZE 1024 ///< Размер буфера RTT в Flash
#define RTT_FLASH_SECTOR FLASH_SECTOR_11 ///< Сектор FLASH куда положится RTT буфер
#define RTT_FLASH_SECTOR_START 0x080E0000 ///< Начало сектора RTT_FLASH_SECTOR
#define RTT_FLASH_SECTOR_END 0x080FFFFF ///< Конец сектора RTT_FLASH_SECTOR
#define HARDFAULT_SERIAL_TRACE ///< Включить обработку и serial трассировку Hardfault
#define HF_RTT_TAG_BASE 0xDEAD0000 ///< базовый тег для HardFault
#define HF_RTT_TAIL_SIZE RTT_FLASH_BUFFER_SIZE ///< Размер буфера RTT, который сохранится при Hardfault
#define HF_STACK_DUMP_WORDS 32 ///< Сколько слов стека будет проанализировано во время Hardfault
#define HF_FLASH_ADDR ((uint32_t)0x080FF000) ///< Адрес FLASH куда положится RTT буфер
#define HF_RAM_END 0x20030000 ///< Конец RAM памяти (чтобы во время анализа стека не выйти за пределы)
#define GPIO_TRACE_ENABLE ///< Включить GPIO трассировку
/** TRACE_CONFIG
* @}
*/
/**
* @addtogroup LIBS_CONFIG Libraries configs
* @ingroup MYLIBS_CONFIG
* @brief Включенные трекеры и трассировки в МЗКТЭ
* @{
*/
#define INCLUDE_BIT_ACCESS_LIB ///< Подключить библиотеку с typedef с битовыми полями
#define INCLUDE_TRACKERS_LIB ///< Подключить библиотеку с трекерами
#define INCLUDE_TRACE_LIB ///< Подключить библиотеку с трейсами
#define INCLUDE_GENERAL_PERIPH_LIBS ///< Подключить библиотеку с периферией
//#define FREERTOS_DELAY ///< Использовать FreeRTOS задержку, вместо HAL
/** LIBS_CONFIG
* @}
*/
/** MYLIBS_CONFIG
* @}
*/
#endif //__MYLIBS_CONFIG_H_

View File

@@ -0,0 +1,183 @@
/**
**************************************************************************
* @file mylibs_defs.h
* @brief Заголочный файл для дефайнов библиотеки MyLibsGeneral.
**************************************************************************
* @defgroup MYLIBS_DEFINES General Defines
* @ingroup MYLIBS_ALL
* @brief Общие макросы и typedef'ы, используемые по всему проекту
*
*************************************************************************/
#ifndef __MYLIBS_DEFINES_H_
#define __MYLIBS_DEFINES_H_
#include "mylibs_config.h"
/***************************************************************************
******************************ERROR_HANDLER********************************/
/**
* @addtogroup ERROR_HANDLER_DEFINES Error Handler defines
* @ingroup MYLIBS_DEFINES
* @brief Дефайны для обработки ошибок
* @{
*/
/* extern Error_Handler from main.h */
extern void Error_Handler(void);
/**
* @brief Error_Handler который будет вызыватся в библиотеке
*/
#define MyLibs_Error_Handler(params) Error_Handler(params)
/* If error handler not defined - set void */
#ifndef MyLibs_Error_Handler
#define MyLibs_Error_Handler(...)
#endif // MyLibs_Error_Handler
/** @brief Проверить указатель на NULL */
#define check_null_ptr_1(_p1_) (_p1_ == NULL)
/** @brief Проверить два указателя на NULL */
#define check_null_ptr_2(_p1_, _p2_) ((_p1_ == NULL) || (_p2_ == NULL))
/** @brief Проверить три указателя на NULL */
#define check_null_ptr_3(_p1_, _p2_, _p3_) ((_p1_ == NULL) || (_p2_ == NULL) || (_p3_ == NULL))
/** @brief Проверить четыре указателя на NULL */
#define check_null_ptr_4(_p1_, _p2_, _p3_, _p4_) ((_p1_ == NULL) || (_p2_ == NULL) || (_p3_ == NULL) || (_p4_ == NULL))
/** @brief Проверить пять указателей на NULL */
#define check_null_ptr_5(_p1_, _p2_, _p3_, _p4_, _p5_) ((_p1_ == NULL) || (_p2_ == NULL) || (_p3_ == NULL) || (_p4_ == NULL) || (_p5_ == NULL))
/** ERROR_HANDLER_DEFINES
* @}
*/
/***************************************************************************
********************************ACCESS_DEFINES*****************************/
/***************************************************************************
******************************DELAYS_DEFINES*******************************/
/**
* @addtogroup DELAYS_DEFINES Delays defines
* @ingroup MYLIBS_DEFINES
* @brief Макросы и определения для работы с задержками в миллисекундах.
* @details
* Этот блок содержит макросы для реализации задержек с использованием HAL или FreeRTOS:
* - @ref msDelay — простая задержка заданной длительности;
* - @ref msDelayStart — сохранение текущего времени начала задержки;
* - @ref msDelayWhileActive — проверка, активна ли задержка;
* - @ref msDelayWaitDone — проверка, завершена ли задержка.
* Эти макросы удобны для реализации неблокирующих задержек.
* @{
*/
/**
* @def msDelay(_ms_)
* @brief Задержка на указанное количество миллисекунд.
* @param _ms_ Время задержки в миллисекундах.
* @note Использует HAL_Delay или osDelay в зависимости от @ref FREERTOS_DELAY.
*/
#ifdef FREERTOS_DELAY
#define msDelay(_ms_) osDelay(_ms_)
#else
#define msDelay(_ms_) HAL_Delay(_ms_)
#endif
/**
* @brief Начать отсчет задержки.
* @param _pvar_ Указатель на переменную типа uint32_t для хранения времени старта.
* @details После вызова этого макроса переменная _pvar_ содержит текущее количество миллисекунд
* с момента запуска системы (HAL_GetTick).
*
* Используется для реализации неблокирующих задержек.
*/
#define msDelayStart(_pvar_) *(_pvar_) = HAL_GetTick()
/**
* @brief Проверяет, активна ли задержка.
* @param _ms_ Длительность задержки в миллисекундах.
* @param _pvar_ Указатель на переменную, в которой сохранено время начала (@ref msDelayStart).
* @retval 1 Задержка еще активна.
* @retval 0 Задержка завершена.
* @details
* Возвращает true, пока время задержки не истекло. Используется в проверках,
* когда нужно **действовать, пока задержка выполняется**. Пример:
* @code
* while(msDelayWhileActive(1000, &tick)) {
* // выполняем другие задачи, задержка не блокирует поток
* }
* @endcode
*/
#define msDelayWhileActive(_ms_, _pvar_) (HAL_GetTick() - *(_pvar_) < _ms_)
/**
* @brief Проверяет, завершилась ли задержка.
* @param _ms_ Длительность задержки в миллисекундах.
* @param _pvar_ Указатель на переменную, в которой сохранено время начала (msDelayStart).
* @retval 1 Задержка завершена.
* @retval 0 Задержка еще активна.
* @details
* Возвращает true, когда задержка уже завершена. Используется в проверках,
* когда нужно **выполнить действие только после окончания задержки**. Пример:
* @code
* if(msDelayWaitDone(1000, &tick)) {
* // выполняем действие после завершения задержки
* }
* @endcode
*/
#define msDelayWaitDone(_ms_, _pvar_) (HAL_GetTick() - *(_pvar_) >= _ms_)
/** DELAYS_DEFINES
* @}
*/
/***************************************************************************
*******************************MATH_DEFINES********************************/
/**
* @addtogroup UTILS_DEFINES Utils defines
* @ingroup MYLIBS_DEFINES
* @brief Общие вспомогательные макросы
* @{
*/
/**
* @brief Обнуление структуры.
* @param _struct_ Структура, которую нужно обнулить.
* @details Макрос использует memset для обнуления всей памяти структуры.
* Используется для быстрой и безопасной инициализации переменных структур до нуля.
*/
#define ClearStruct(_struct_) memset(&(_struct_), 0, sizeof(_struct_))
/**
* @brief Деление с округлением вверх
* @param _val_ Делимое.
* @param _div_ Делитель.
* @return Результат деления, округленный вверх.
* @details Если результат деления без остатка: он возвращается как есть
Если с остатком - округляется вверх
*/
//#define Divide_Up(_val_, _div_) (((_val_)%(_div_))? (_val_)/(_div_)+1 : (_val_)/_div_) /* через тернарный оператор */
#define Divide_Up(_val_, _div_) ((_val_ - 1) / _div_) + 1 /* через мат выражение */
/**
* @brief Swap between Little Endian and Big Endian
* @param v Исходное 16-битное значение.
* @return Результат с поменяными местами старшим и младшим байтом.
* @details Переключения между двумя типами хранения слова: HI-LO байты и LO-HI байты.
*/
#define ByteSwap16(v) (((v&0xFF00) >> (8)) | ((v&0x00FF) << (8)))
/**
* @brief Абсолютное значение числа
* @param x Число.
* @return Абсолютное значение числа x.
* @details Берет число по модулю. Хз как работает библиотечный abs в stdlib.h, мб это быстрее, но вряд ли конечно.
*/
#define ABS(x) ( ((x) > 0)? (x) : -(x))
/** UTILS_DEFINES
* @}
*/
#endif //__MYLIBS_DEFINES_H_

View File

@@ -0,0 +1,70 @@
/**
**************************************************************************
* @file mylibs_include.h
* @brief Заголочный файл для всех библиотек
**************************************************************************
@details
Здесь нужно собрать библиотеки и дефайны, которые должны быть видны во всем проекте,
чтобы не подключать 100 инклюдов в каждом ".c" файле
**************************************************************************
* @defgroup MYLIBS_ALL My Libs
* @brief Все используемые MyLibs библиотеки
* @defgroup MYLIBS_PERIPHERAL Peripheral
* @ingroup MYLIBS_ALL
* @brief Модули для управления периферией
*
*************************************************************************/
#ifndef __MYLIBS_INCLUDE_H_
#define __MYLIBS_INCLUDE_H_
#include "mylibs_defs.h"
#ifdef ARM_MATH_CM4
#include "arm_math.h"
#endif
#ifdef INCLUDE_BIT_ACCESS_LIB
#include "bit_access.h"
#endif
#ifdef INCLUDE_TRACKERS_LIB
#include "trackers.h"
#endif
#ifdef INCLUDE_TRACE_LIB
#include "trace.h"
#endif
#ifdef INCLUDE_GENERAL_PERIPH_LIBS
#include "general_flash.h"
#include "general_gpio.h"
#ifdef HAL_SPI_MODULE_ENABLED
#include "general_spi.h"
#endif
#ifdef HAL_UART_MODULE_ENABLED
#include "general_uart.h"
#endif
#ifdef HAL_TIM_MODULE_ENABLED
#include "general_tim.h"
#endif
#endif //INCLUDE_GENERAL_PERIPH_LIBS
/////////////////////////---USER SETTINGS---/////////////////////////
// user includes
// user settings
/////////////////////////---USER SETTINGS---/////////////////////////
#endif // __MYLIBS_INCLUDE_H_

558
MyLibsGeneral/Inc/trace.h Normal file
View File

@@ -0,0 +1,558 @@
/**
**************************************************************************
* @file trace.h
* @brief Заголочный файл для работы с трассировкой.
**************************************************************************
* @addtogroup TRACE Trace defines
* @ingroup MYLIBS_DEFINES
* @brief Дефайны для работы с трассировкой
*************************************************************************/
#ifndef __TRACE_H_
#define __TRACE_H_
#include "mylibs_defs.h"
#include <string.h>
/**
* @addtogroup TRACE_SERIAL Serial trace defines
* @ingroup TRACE
* @brief Дефайны для работы с serial трассировкой (SWO, RTT)
* @details Определяется дефайн @ref my_printf() и @ref log_printf() для работы с serial трассировкой:
- для RTT это будет вызов функции SEGGER_RTT_printf(), с подключением библиотеки SEGGER_RTT.h
- для SWO это будет просто printf()
Но библиотеку STDOUT надо подключить самостоятельно:
@verbatim
Manage Run-Time Environment -> Compiler -> I/O -> STDOUT
@endverbatim
Для SWO также надо включить трассировку:
@verbatim
Options For Target -> Debug -> Debugger Settings
@endverbatim
В вкладке Debug:
- Port = SW
В вкладке Trace:
- Указать Core Clock
- Выставить Trace Port = SWO
- ITM - выбрать нужный порт (для Keil нулевой порт)
- Если трассировка @ref SERIAL_TRACE_ENABLE отключена, то все дефайны определяются как 'ничего'
и на производительность кода не влияют
Если трассировка отключена, все макросы пустые и не влияют на производительность
* @{
*
* @def my_printf(...)
* @brief Универсальный макрос для вывода трассировки
* @details Варианты реализации:
* - RTT_TRACE_ENABLE `SEGGER_RTT_printf(0, ...)`
* - SWO_TRACE_ENABLE - `printf(...)`
* - NO_TRACE - пустой макрос
*
* @def log_printf(TAG, fmt, ...)
* @brief Макрос логирования с поддержкой уровней LOG_LEVEL
* @param TAG Тэг лога
* @param fmt, ... Форматируемая строка
* @details Варианты реализации:
* - LOG_LEVEL == 0 - логирование отключено (макрос пустой)
* - LOG_LEVEL == 1 - выводится время и TAG
* - LOG_LEVEL >= 2 - выводится время, TAG, имя файла и номер строки
*/
#ifdef SERIAL_TRACE_ENABLE
#if defined(RTT_TRACE_ENABLE)
#undef SWO_TRACE_ENABLE
#include "SEGGER_RTT.h"
#define my_printf(...) SEGGER_RTT_printf(0, __VA_ARGS__)
#elif defined(SWO_TRACE_ENABLE)
#undef RTT_TRACE_ENABLE
#define my_printf(...) printf(__VA_ARGS__)
#else // NO_TRACE
#define my_printf(...)
#warning No trace is selected. Serial debug wont work.
#endif // RTT_TRACE_ENABLE/SWO_TRACE_ENABLE/NO_TRACE
#else //SERIAL_TRACE_ENABLE
#define my_printf(...)
#undef RTT_TRACE_ENABLE
#undef SWO_TRACE_ENABLE
#endif //SERIAL_TRACE_ENABLE
#ifndef LOG_LEVEL
#define LOG_LEVEL 1 ///< @brief Уровень логирования (по умолчанию == 1)
#endif
#if LOG_LEVEL == 0 // лог отключен
#define \
log_printf(TAG, fmt, ...)
#elif LOG_LEVEL == 1 // только тэг
#define log_printf(TAG, fmt, ...) \
my_printf("\n[%lu] [%s] " fmt, \
(unsigned long)uwTick, TAG, ##__VA_ARGS__)
#elif LOG_LEVEL >= 2 // всё
#define log_printf(TAG, fmt, ...) \
my_printf("\n[%lu] [%s] (%s:%d) " fmt, \
(unsigned long)uwTick, TAG, __FILE__, __LINE__, ##__VA_ARGS__)
#endif
/** TRACE_SERIAL
* @}
*/
/**
* @addtogroup TRACE_GPIO GPIO trace defines
* @ingroup TRACE
* @brief Дефайны для работы с GPIO трассировкой
* @details Определяется дефайны для работы с GPIO трассировкой:
- TRACE_GPIO_RESET() - для сброса ножки GPIO (через BSRR)
- TRACE_GPIO_SET() - для выставления ножки GPIO (через BSRR)
- Если трассировка @ref GPIO_TRACE_ENABLE отключена, то все дефайны определяются как 'ничего'
и на производительность кода не влияют
* @{
*
* @def TRACE_GPIO_RESET(_gpio_, _pin_)
* @brief Сбросить указанную ножку GPIO
* @param _gpio_ Указатель на структуру GPIO (напр. GPIOA)
* @param _pin_ Номер ножки (напр. GPIO_PIN_0)
* @details Варианты реализации:
* - GPIO_TRACE_ENABLE не определён - макрос пустой
* - GPIO_TRACE_ENABLE определён - устанавливает бит сброса через BSRR ((_pin_)<<16)
*
* @def TRACE_GPIO_SET(_gpio_, _pin_)
* @brief Установить указанную ножку GPIO
* @param _gpio_ Указатель на структуру GPIO (например GPIOA)
* @param _pin_ Номер ножки (напр. GPIO_PIN_0)
* @details Варианты реализации:
* - GPIO_TRACE_ENABLE не определён - макрос пустой
* - GPIO_TRACE_ENABLE определён - устанавливает бит установки через BSRR (_pin_)
*/
#ifndef GPIO_TRACE_ENABLE
#define TRACE_GPIO_SET(_gpio_,_pin_)
#define TRACE_GPIO_RESET(_gpio_,_pin_)
#else
#define TRACE_GPIO_SET(_gpio_,_pin_) (_gpio_)->BSRR = (((_pin_)))
#define TRACE_GPIO_RESET(_gpio_,_pin_) (_gpio_)->BSRR = ((_pin_)<<16)
#endif //GPIO_TRACE_ENABLE
/** TRACE_GPIO
* @}
*/
#if defined(HAL_MODULE_ENABLED) && defined(RTT_TRACE_ENABLE)
/**
* @addtogroup TRACE_RTT_FLASH Flash RTT Buffer
* @ingroup TRACE
* @brief Макросы и функции для сохранения/чтения RTT буфера в Flash
* @details Модуль позволяет сохранять данные RTT буфера во Flash и читать их обратно по тегам.
* Теги работают следующим образом:
* - Базовый тег (младший байт = 0): модуль сам выбирает первый свободный слот во Flash;
* новые записи получают автоинкрементированный младший байт тега (от 0x00 до 0xFF).
* - Конкретный тег (младший байт != 0): запись или чтение происходит строго с указанным тегом;
* если слот с таким тегом уже занят, запись не выполняется.
* - Автоинкремент позволяет хранить несколько последовательных записей в пределах одного базового тега,
* без необходимости вручную отслеживать адреса Flash или позиции буферов.
* @{
*/
/**
* @brief Структура RTT, которая будет положена в Flash
*/
typedef struct {
uint32_t tag; ///< Уникальный идентификатор буфера
uint32_t size; ///< Размер данных
char data[RTT_FLASH_BUFFER_SIZE]; ///< Буфер RTT
} RTT_FlashHeader_t;
/**
* @brief Подготовка Flash к записи
* @details Сбрасывает ошибки Flash и ожидает готовности перед записью
*/
__STATIC_FORCEINLINE void RTT_FlashPrepare(void)
{
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR | FLASH_FLAG_WRPERR | FLASH_FLAG_OPERR);
while (__HAL_FLASH_GET_FLAG(FLASH_FLAG_BSY)) {
__NOP();
}
}
/**
* @brief Сохраняет последние символы RTT-буфера в Flash по тегу
* @param tag Базовый или конкретный идентификатор буфера.
* @param tail_size Количество последних символов RTT для копирования
* @param buf_num Указатель на переменную в которую запишется номер буфера для конкретного тега
* @return >=0 — номер буфера (тег) для записи, <0 — ошибка (нет места, тег уже занят, ошибка записи в флеш)
*
* @details Автоматически копирует последние tail_size символов из RTT-буфера
* и записывает их во Flash.
* Тег может быть базовым или конкретным:
* - Если базовый (младший байт == 0) — будет выбран первый свободный слот с автоинкрементом.
* Автоинкремент формируется в пределах от 0x1 до 0xFF
* - Если конкретный (младший байт != 0) — запись выполняется только с этим тегом, иначе ошибка.
*/
__STATIC_FORCEINLINE int RTT_SaveToFlash(uint32_t tag, uint32_t tail_size)
{
if (tag == 0xFFFFFFFF)
return -1; // Неверный тег
SEGGER_RTT_BUFFER_UP *up = &_SEGGER_RTT.aUp[0];
unsigned buf_size = up->SizeOfBuffer;
unsigned wr = up->WrOff;
// Ограничиваем по размеру буфера RTT и RTT_FLASH_BUFFER_SIZE
unsigned n = (tail_size > buf_size) ? buf_size : tail_size;
if (n > RTT_FLASH_BUFFER_SIZE)
n = RTT_FLASH_BUFFER_SIZE;
uint32_t addr = RTT_FLASH_SECTOR_START;
RTT_FlashHeader_t *flash_hdr = NULL;
uint32_t base_tag = tag & 0xFFFFFF00;
uint32_t next_tag = (tag & 0xFF) == 0 ? tag + 1 : tag;
// Ищем первый свободный слот, параллельно автоинкрементируем тег
while ((addr + sizeof(RTT_FlashHeader_t)) <= RTT_FLASH_SECTOR_END)
{
flash_hdr = (RTT_FlashHeader_t *)addr;
if (flash_hdr->tag == 0xFFFFFFFF)
break; // Нашли свободное место
if((flash_hdr->tag & 0xFFFFFF00) == base_tag) // выбраный тег
{
if ((tag & 0xFF) == 0) // если он базовый - ищем последний
next_tag = flash_hdr->tag + 1; // автоинкремент
else
if(flash_hdr->tag == tag) // если он конкретный и уже существует - то ошибка
return -1; // конкретный тег уже занят
}
if(next_tag - tag > 0xFF)
return -1; // автоинкремент слишком большой
addr += sizeof(RTT_FlashHeader_t);
}
if ((addr + sizeof(RTT_FlashHeader_t)) > RTT_FLASH_SECTOR_END)
return -1; // Нет свободного места
// Копируем последние n символов из RTT
char temp[RTT_FLASH_BUFFER_SIZE];
unsigned valid_count = 0;
for (unsigned i = 0; i < n; i++)
{
unsigned idx = (wr + buf_size - n + i) % buf_size;
char c = up->pBuffer[idx];
if (c != 0)
temp[valid_count++] = c;
}
RTT_FlashPrepare();
// Формируем структуру в RAM
RTT_FlashHeader_t flash_data;
flash_data.tag = next_tag;
flash_data.size = valid_count;
memcpy(flash_data.data, temp, valid_count);
// Записываем структуру во Flash (по 4 байта)
const uint32_t *p = (const uint32_t *)&flash_data;
for (unsigned i = 0; i < sizeof(RTT_FlashHeader_t) / 4; i++)
{
if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr + i * 4, p[i]) != HAL_OK)
return -1;
}
HAL_FLASH_Lock();
__DSB();
__ISB();
return (int)(next_tag&0xFF);
}
/**
* @brief Читает последние символы RTT-буфера из Flash по тегу
* @param tag Базовый или конкретный идентификатор буфера.
* @param Buffer Буфер назначения для копирования данных
* @param tail_size Количество последних символов, которые нужно прочитать
* @param read_size Количество считанных символов
* @return >=0 — номер буфера (тег) для записи, <0 — ошибка (тег не найден или структура повреждена)
*
* @details Копирует последние tail_size символов из найденной записи Flash в Buffer.
* Тег может быть базовым или конкретным:
* - Если базовый (младший байт == 0) — будет прочитана последняя запись из группы.
* - Если конкретный (младший байт != 0) — прочитывается именно эта запись.
*/
__STATIC_FORCEINLINE int RTT_ReadFromFlash(uint32_t tag, char *Buffer, uint32_t tail_size, uint32_t *read_size)
{
if (!Buffer || tail_size == 0)
return -1; // Неверные параметры
if (tag == 0xFFFFFFFF)
return -1; // Недопустимый тег
uint32_t addr = RTT_FLASH_SECTOR_START;
RTT_FlashHeader_t *flash_hdr = NULL;
RTT_FlashHeader_t *target_hdr = NULL;
uint32_t base_tag = tag & 0xFFFFFF00;
// Поиск записи по тегу
while ((addr + sizeof(RTT_FlashHeader_t)) <= RTT_FLASH_SECTOR_END)
{
flash_hdr = (RTT_FlashHeader_t *)addr;
if (flash_hdr->tag == 0xFFFFFFFF)
break; // Достигнут конец записанных структур
// выбраный тег
if((flash_hdr->tag & 0xFFFFFF00) == base_tag)
{
if ((tag & 0xFF) == 0) // если он базовый - ищем последний
target_hdr = flash_hdr; // сохраняем последний в группе
else
if(flash_hdr->tag == tag) // если он конкретный и найден - берем его
{
target_hdr = flash_hdr;
break; // конкретный тег найден
}
}
addr += sizeof(RTT_FlashHeader_t);
}
if (!target_hdr) return -1; // Тег не найден
// Проверка корректности размера
if (target_hdr->size > RTT_FLASH_BUFFER_SIZE)
return -1; // Повреждённая запись
// Определяем количество читаемых символов
uint32_t n = (tail_size > target_hdr->size) ? target_hdr->size : tail_size;
// Начальная позиция для чтения последних tail_size символов
uint32_t start = target_hdr->size - n;
// Копируем данные из Flash в RAM
memcpy(Buffer, &target_hdr->data[start], n);
if(read_size != NULL)
{
*read_size = n;
}
__DSB();
__ISB();
return (int)(target_hdr->tag & 0xFF);
}
/**
* @brief Стирание сектора Flash с RTT-буфером
*/
__STATIC_FORCEINLINE int RTT_EraseFlash(void)
{
FLASH_EraseInitTypeDef eraseInit;
uint32_t pageError = 0;
RTT_FlashPrepare();
eraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
eraseInit.Sector = RTT_FLASH_SECTOR;
eraseInit.NbSectors = 1;
if (HAL_FLASHEx_Erase(&eraseInit, &pageError) != HAL_OK)
{
return -1;
}
return 0;
HAL_FLASH_Lock();
}
/** TRACE_RTT_FLASH
* @}
*/
#else // HAL_MODULE_ENABLED && RTT_TRACE_ENABLE
#define RTT_FlashPrepare()
#define RTT_EraseFlash() 0
#define RTT_SaveToFlash() 0
#define RTT_ReadFromFlash() 0
#endif // HAL_MODULE_ENABLED && RTT_TRACE_ENABLE
/**
* @addtogroup TRACE_HARDFAULT Hardfault trace defines
* @ingroup TRACE
* @brief Модуль трассировки HardFault с возможностью сохранения RTT буфера во Flash
* @details
* Этот модуль позволяет сохранять контекст процессора и последние символы RTT буфера при возникновении HardFault.
*
* Механизм работы:
* - При срабатывании HardFault вызывается HF_HandleFault(), который:
* 1. Получает указатель на стек, где произошёл HardFault (MSP или PSP).
* 2. Выводит значения регистров R0-R3, R12, LR, PC, PSR и системных регистров SCB.
* 3. Формирует строку с регистрами и копирует последние символы RTT буфера.
* 4. Сохраняет данные во Flash с базовым тегом HF_RTT_TAG_BASE.
* - Для восстановления последнего HardFault используется HF_CheckRecovered(), который:
* 1. Читает запись во Flash по базовому тегу.
* 2. Выводит сохранённый RTT буфер и контекст регистров.
* 3. Опционально стирает Flash после восстановления.
@code
void Hardfault()
{
HF_HandleFault();
NVIC_SystemReset();
}
int main()
{
if(HF_CheckRecovered(0))
{
//set hardfault error
RTT_EraseFlash(); // erase rtt flash after message readed
}
}
@endcode
* @{
*/
#if defined(HAL_MODULE_ENABLED) && defined(HARDFAULT_SERIAL_TRACE)
#ifndef HF_RTT_TAIL_SIZE
#define HF_RTT_TAIL_SIZE RTT_FLASH_BUFFER_SIZE ///< Размер буфера RTT, который сохранится при Hardfault
#endif
/**
* @brief Контекст стек-фрейма процессора при HardFault
* @details Сохраняет регистры R0-R3, R12, LR, PC, PSR для последующего анализа.
*/
typedef struct {
uint32_t r0; ///< Регистр R0
uint32_t r1; ///< Регистр R1
uint32_t r2; ///< Регистр R2
uint32_t r3; ///< Регистр R3
uint32_t r12; ///< Регистр R12
uint32_t lr; ///< Link Register
uint32_t pc; ///< Program Counter
uint32_t psr; ///< Program Status Register
} HF_StackFrame_t;
/**
* @brief Проверка и вывод последнего HardFault-трейса из Flash
* @details
* Функция ищет последнюю запись HardFault по базовому тегу HF_RTT_TAG_BASE
* и выводит её содержимое в консоль. После успешного вывода Flash можно опционально очистить.
*
* @return int
* - 1 — данные HardFault найдены и выведены
* - 0 — данные отсутствуют или тег не найден
*
* @note Вызов рекомендуется при инициализации приложения для анализа предыдущего сбоя.
*/
__STATIC_FORCEINLINE int HF_CheckRecovered(int erase)
{
char buffer[RTT_FLASH_BUFFER_SIZE];
uint32_t read_size = 0;
int n_hardfault = RTT_ReadFromFlash(HF_RTT_TAG_BASE, buffer, HF_RTT_TAIL_SIZE, &read_size);
if (n_hardfault > 0)
{
my_printf("\n--- Recovered HardFault RTT buffer #%u ---\n", n_hardfault);
for (int i = 0; i < read_size; i++)
{
char c = buffer[i];
if (c == 0 || c == (char)0xFF) break;
my_printf("%c", c);
}
if(erase)
RTT_EraseFlash();
my_printf("\n--------- HardFault Dump End ---------\n");
return 1;
}
return 0;
}
static HF_StackFrame_t *stack_frame;
static uint32_t stack_dump[HF_STACK_DUMP_WORDS];
static void *ret_adr[10] = {0};
/**
* @brief Обработчик HardFault
* @details
* Вызывается из прерывания HardFault или в любом месте где понятно что ошибка критическая.
* Последовательно выполняет:
* 1. Определяет активный стек (MSP или PSP) на момент сбоя.
* 2. Сохраняет значения регистров R0-R3, R12, LR, PC, PSR.
* 3. Выводит системные регистры CFSR, HFSR, DFSR, AFSR, MMFAR, BFAR.
* 4. Формирует stack trace с 3 уровнями возврата.
* 5. Копирует последние символы RTT буфера.
* 6. Сохраняет все данные во Flash через RTT_SaveToFlash с базовым тегом HF_RTT_TAG_BASE.
*
* @note Функция защищена, так как вызывается в контексте сбоя — минимизирует использование вызовов HAL.
*/
__STATIC_FORCEINLINE void HF_HandleFault(void)
{
// Получаем указатель на стек, где произошёл HardFault
__ASM volatile(
"TST lr, #4 \n"
"ITE EQ \n"
"MRSEQ %[ptr], MSP\n"
"MRSNE %[ptr], PSP\n"
: [ptr] "=r"(stack_frame)
);
my_printf("\n===== HardFault occurred! =====\n");
my_printf("R0 = 0x%08X\n", stack_frame->r0);
my_printf("R1 = 0x%08X\n", stack_frame->r1);
my_printf("R2 = 0x%08X\n", stack_frame->r2);
my_printf("R3 = 0x%08X\n", stack_frame->r3);
my_printf("R12 = 0x%08X\n", stack_frame->r12);
my_printf("LR = 0x%08X\n", stack_frame->lr);
my_printf("PC = 0x%08X\n", stack_frame->pc);
my_printf("PSR = 0x%08X\n", stack_frame->psr);
my_printf("CFSR = 0x%08X\n", SCB->CFSR);
my_printf("HFSR = 0x%08X\n", SCB->HFSR);
my_printf("DFSR = 0x%08X\n", SCB->DFSR);
my_printf("AFSR = 0x%08X\n", SCB->AFSR);
my_printf("MMFAR = 0x%08X\n", SCB->MMFAR);
my_printf("BFAR = 0x%08X\n", SCB->BFAR);
// --- Stack trace ---
my_printf("--- Stack trace ---\n");
ret_adr[0] = __builtin_return_address(0);
ret_adr[1] = __builtin_return_address(1);
ret_adr[2] = __builtin_return_address(2);
for (int i = 0; i < 3; i++) // развернуть n уровней
{
if(ret_adr[i])
my_printf(" #%d: 0x%08lX\r\n", i, ret_adr[i]); // -1 для Thumb
}
RTT_SaveToFlash(HF_RTT_TAG_BASE, HF_RTT_TAIL_SIZE);
}
#else // HAL_MODULE_ENABLED && HARDFAULT_SERIAL_TRACE
#define HF_CheckRecovered() 0
#define HF_HandleFault()
#endif // HAL_MODULE_ENABLED && HARDFAULT_SERIAL_TRACE
/** TRACE_HARDFAULT
* @}
*/
#endif //__TRACE_H_

View File

@@ -0,0 +1,155 @@
/**
**************************************************************************
* @file trackers.h
* @brief Заголочный файл для работы с трекерами @ref TRACKERS.
**************************************************************************
* @addtogroup TRACKERS Trackers defines
* @ingroup MYLIBS_DEFINES
* @brief Дефайны для работы с трекерами
* @details Есть дефайн для объявления структуры трекера: TrackerTypeDef(num_user_vars).
Структура состоит из следующих элементов:
- cnt_ok
- cnt_err
- cnt_warn
- user[num_user_vars]
Также есть ряд функций (дефайнов) для обращения к элементам этой структуры.
Если трекеры @ref TRACKERS_ENABLE отключены, то все дефайны определяются как ничего
и на производительность кода не влияют
@par Пример:
Определяем typedef трекера измерений Measure_TrackerTypeDef
@verbatim
typedef TrackerTypeDef(MEASURE_USER_VARS_NUMB) Measure_TrackerTypeDef;
@endverbatim
И через @ref Measure_TrackerTypeDef структура подключается в другие структуры
Для работы с структурой можно использовать функции:
- Для получения значения:
- TrackerGet_Ok()
- TrackerGet_Err()
- TrackerGet_Warn()
- TrackerGet_User(n)
- Для записи значения:
- TrackerCnt_Ok()
- TrackerCnt_Err()
- TrackerCnt_Warn()
- TrackerCnt_User()
- TrackerWrite_User(n)
- Для очищения значения:
- TrackerClear_All()
- TrackerClear_Ok()
- TrackerClear_Err()
- TrackerClear_Warn()
- TrackerClear_User(n)
- TrackerClear_UserAll()
* @{
*************************************************************************/
#ifndef __TRACKERS_H_
#define __TRACKERS_H_
#include "mylibs_defs.h"
#ifdef TRACKERS_ENABLE
/**
* @brief Структура для счетчиков отладки
* @param num_user_vars - количество пользовательских переменных
* @details Содержит счетчик для успешных событый (cnt_ok),
* счетчик для ошибок (cnt_err), счетчик для предупреждений (cnt_warn).
*
* Также есть возможность объявить пользовательские переменные в
* количестве <num_user_vars> штук.
*/
#define TrackerTypeDef(num_user_vars) \
struct \
{ \
uint32_t cnt_ok; \
uint32_t cnt_err; \
uint32_t cnt_warn; \
uint32_t user[num_user_vars]; \
}
/** @brief Получить количетство пользовательских переменных */
#define num_of_usercnts(_user_) (sizeof(_user_) / sizeof(uint32_t))
/** @brief Проверка существует ли указанная пользовательская переменная */
#define assert_usertracker(_cntstruct_, _uservarnumb_) ((_uservarnumb_) < num_of_usercnts((_cntstruct_).user))
/** @brief Условие для проверки существует ли указанная пользовательская переменная */
#define if_assert_usertracker(_cntstruct_, _uservarnumb_) if(assert_usertracker(_cntstruct_, _uservarnumb_))
/** @brief Тернарный оператор для проверки существует ли указанная пользовательская переменная */
#define tern_assert_usertracker(_cntstruct_, _uservarnumb_) (assert_usertracker(_cntstruct_, _uservarnumb_)) ? _uservarnumb_ : 0
/** @brief Считать счетчик успешных событий */
#define TrackerGet_Ok(_cntstruct_) (_cntstruct_).cnt_ok
/** @brief Считать счетчик ошибок */
#define TrackerGet_Err(_cntstruct_) (_cntstruct_).cnt_err
/** @brief Считать счетчик предупреждений */
#define TrackerGet_Warn(_cntstruct_) (_cntstruct_).cnt_warn
/**
* @brief Считать пользовательскую переменную
* @note Здесь нет проверки - существует ли пользовательская переменная!
* Есть возможность выйти за границы структуры!!!
* Чтобы этого избежать можно использовать дефайн #ref assert_usertracker()
@verbatim
if(assert_usertracker(struct, 0)) {
TrackerGet_User(struct, 0)
}
@endverbatim
*/
#define TrackerGet_User(_cntstruct_, _uservarnumb_) (_cntstruct_).user[tern_assert_usertracker(_cntstruct_, _uservarnumb_)]
/** @brief Инкрементирование счетчика успешных событий */
#define TrackerCnt_Ok(_cntstruct_) (_cntstruct_).cnt_ok++
/** @brief Инкрементирование счетчика ошибок */
#define TrackerCnt_Err(_cntstruct_) (_cntstruct_).cnt_err++
/** @brief Инкрементирование счетчика предупреждений */
#define TrackerCnt_Warn(_cntstruct_) (_cntstruct_).cnt_warn++
/** @brief Инкрементирование пользовательской переменной */
#define TrackerCnt_User(_cntstruct_, _uservarnumb_) if_assert_usertracker(_cntstruct_, _uservarnumb_) (_cntstruct_).user[_uservarnumb_]++;
/** @brief Запись числа в пользовательскую переменную */
#define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_) if_assert_usertracker(_cntstruct_, _uservarnumb_) (_cntstruct_).user[_uservarnumb_] = (_val_)
/** @brief Очистка всей структуры */
#define TrackerClear_All(_cntstruct_) memset(&(_cntstruct_), 0, sizeof(_cntstruct_))
/** @brief Очистка счетчика успешных событий */
#define TrackerClear_Ok(_cntstruct_) (_cntstruct_).cnt_ok = 0
/** @brief Очистка счетчика ошибок */
#define TrackerClear_Err(_cntstruct_) (_cntstruct_).cnt_err = 0
/** @brief Очистка счетчика предупреждений */
#define TrackerClear_Warn(_cntstruct_) (_cntstruct_).cnt_warn = 0
/** @brief Очистка пользовательской переменной */
#define TrackerClear_User(_cntstruct_, _uservarnumb_) if_assert_usertracker(_cntstruct_, _uservarnumb_) (_cntstruct_).user[_uservarnumb_] = 0;
/** @brief Очистка всех пользовательских переменных */
#define TrackerClear_UserAll(_cntstruct_) memset(&(_cntstruct_).user, 0, sizeof((_cntstruct_).user))
#else //TRACKERS_ENABLE
#define TrackerTypeDef(num_user_vars) void *
#define num_of_usercnts(_user_)
#define assert_tracecnt(_cntstruct_, _uservarnumb_)
#define TrackerCnt_Ok(_cntstruct_)
#define TrackerCnt_Err(_cntstruct_)
#define TrackerCnt_Warn(_cntstruct_)
#define TrackerCnt_User(_cntstruct_, _uservarnumb_)
#define TrackerWrite_User(_cntstruct_, _uservarnumb_, _val_)
/** @brief Очистка всей структуры */
#define TrackerClear_All(_cntstruct_)
#define TrackerClear_Ok(_cntstruct_)
#define TrackerClear_Err(_cntstruct_)
#define TrackerClear_Warn(_cntstruct_)
#define TrackerClear_User(_cntstruct_)
#define TrackerClear_UserAll(_cntstruct_)
#endif //TRACKERS_ENABLE
#endif //__TRACKERS_H_

View File

@@ -0,0 +1,192 @@
#include "general_flash.h"
FLASH_EraseInitTypeDef EraseInitStruct;
extern HAL_StatusTypeDef res_hal;
unsigned CRC_Update;
//uint32_t PAGE_OFFSET = ((uint32_t)((4-1) * 0x0400));
uint32_t PAGE_NUMB = 127;
/* Записать в память данные, произвольного размера */
HAL_StatusTypeDef FLASH_Write_Data(uint32_t* Address, uint8_t* Data, int Data_size)
{
HAL_StatusTypeDef res_hal;
int data_cnt = 0;
uint32_t adr;
uint32_t word_data;
res_hal = HAL_FLASH_Unlock();
if (res_hal != HAL_OK) return res_hal;
for (adr = *Address; adr < *Address + Data_size; adr = adr + 4)
{
word_data = (
Data[data_cnt] |
Data[data_cnt + 1] << 8 |
Data[data_cnt + 2] << 16 |
Data[data_cnt + 3] << 24);
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, adr, word_data);
if (res_hal != HAL_OK) return res_hal;
data_cnt += 4;
}
*Address += Data_size;
res_hal = HAL_FLASH_Lock();
return res_hal;
}
HAL_StatusTypeDef FLASH_Enable_DualBankMode(void)
{
HAL_StatusTypeDef res_hal;
FLASH_AdvOBProgramInitTypeDef OB_DualBank;
res_hal = HAL_FLASH_Unlock();
if (res_hal != HAL_OK)
return res_hal;
res_hal = HAL_FLASH_OB_Unlock();
if (res_hal != HAL_OK)
return res_hal;
FLASH->OPTCR |= FLASH_OPTCR_DB1M;
res_hal = HAL_FLASH_OB_Launch();
if (res_hal != HAL_OK)
return res_hal;
res_hal = HAL_FLASH_OB_Lock();
if (res_hal != HAL_OK)
return res_hal;
res_hal = HAL_FLASH_Lock();
if (res_hal != HAL_OK)
return res_hal;
return res_hal;
}
/* Убрать защиту */
HAL_StatusTypeDef FLASH_WriteProtection(uint32_t BankN, uint32_t WriteProtection)
{
HAL_StatusTypeDef res_hal;
FLASH_OBProgramInitTypeDef OBInit;
// Очистка всех возможных ошибок
FLASH->SR |= FLASH_FLAG_WRPERR // Write Protection Error
| FLASH_FLAG_PGSERR // Programming Sequence Error
| FLASH_FLAG_PGAERR // Programming Alignment Error
| FLASH_FLAG_OPERR; // Operation Error
res_hal = HAL_FLASH_Unlock();
if (res_hal != HAL_OK)
return res_hal;
res_hal = HAL_FLASH_OB_Unlock(); // Разблокировка Option Bytes
if (res_hal != HAL_OK)
return res_hal;
// Считываем текущую конфигурацию Option Bytes
HAL_FLASHEx_OBGetConfig(&OBInit);
// Отключаем защиту на всех секторах второго банка
OBInit.OptionType = OPTIONBYTE_WRP;
OBInit.WRPState = WriteProtection; // Снять защиту
OBInit.WRPSector = OB_WRP_SECTOR_12; // Снять защиту
OBInit.Banks = BankN; // Указываем второй банк
res_hal = HAL_FLASHEx_OBProgram(&OBInit);
if (res_hal != HAL_OK)
return res_hal;
// Записываем изменения и перезагружаем чип
res_hal = HAL_FLASH_OB_Launch();
if (res_hal != HAL_OK)
return res_hal;
// Считываем текущую конфигурацию Option Bytes
HAL_FLASHEx_OBGetConfig(&OBInit);
// Блокировка Option Bytes
res_hal = HAL_FLASH_OB_Lock();
if (res_hal != HAL_OK)
return res_hal;
res_hal = HAL_FLASH_Lock();
if (res_hal != HAL_OK)
return res_hal;
return res_hal;
}
//-----------------ELEMENTARY FUNCTIONS---------------------
/* functions for reading bytes/halswords/words */
uint8_t FLASH_Read_Byte(uint32_t add)
{
return (*(__IO uint8_t*)(add));
}
uint16_t FLASH_Read_HalfWord(uint32_t add)
{
return (*(__IO uint16_t*)(add));
}
uint32_t FLASH_Read_Word(uint32_t add)
{
return (*(__IO uint32_t*)(add));
}
/* functions for writing bytes/halswords/words */
HAL_StatusTypeDef FLASH_Write_Byte(uint32_t Address, uint8_t Data)
{
HAL_StatusTypeDef res_hal;
res_hal = HAL_FLASH_Unlock();
if (res_hal != HAL_OK) return res_hal;
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, Address, (uint8_t)(Data));
if (res_hal != HAL_OK) return res_hal;
res_hal = HAL_FLASH_Lock();
return res_hal;
}
HAL_StatusTypeDef FLASH_Write_HalfWord(uint32_t Address, uint16_t Data)
{
HAL_StatusTypeDef res_hal;
res_hal = HAL_FLASH_Unlock();
if (res_hal != HAL_OK) return res_hal;
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, Address, (uint16_t)(Data));
if (res_hal != HAL_OK) return res_hal;
res_hal = HAL_FLASH_Lock();
return res_hal;
}
HAL_StatusTypeDef FLASH_Write_Word(uint32_t Address, uint32_t Data)
{
HAL_StatusTypeDef res_hal;
res_hal = HAL_FLASH_Unlock();
if (res_hal != HAL_OK) return res_hal;
res_hal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, Address, (uint32_t)(Data));
if (res_hal != HAL_OK) return res_hal;
res_hal = HAL_FLASH_Lock();
return res_hal;
}
//----------------------------------------------------------

View File

@@ -0,0 +1,292 @@
/**
**************************************************************************
* @file general_spi.c
* @brief Модуль для инициализации SPI.
**************************************************************************
* //-------------------Функции-------------------//
* @verbatim
* Functions: users
* - SPI_Base_Init Инициализация SPI
*
* Functions: spi initialize
* - SPI_GPIO_Init Инициализация GPIO для SPI
* - SPI_DMA_Init Инициализация DMA для SPI
* - SPI_MspInit Аналог HAL_MspInit для SPI
* - SPI_MspDeInit Аналог HAL_MspDeInit для SPI
* @endverbatim
*************************************************************************/
#include "general_spi.h"
#include "general_gpio.h"
//-------------------------------------------------------------------
//------------------------SPI INIT FUNCTIONS------------------------
/**
* @brief Initialize SPI with SPI_SettingsTypeDef structure.
* @param sspi - указатель на структуру с настройками SPI.
* @return HAL status.
* @note SPI_SettingsTypeDef структура содержит хендл SPI и настройки перефирии (GPIO)
*/
HAL_StatusTypeDef SPI_Base_Init(SPI_SettingsTypeDef *sspi)
{ // function takes setting structure for init
// check is settings are valid
if(Check_SPI_Init_Struct(sspi) != HAL_OK)
return HAL_ERROR;
SPI_MspInit(&sspi->hspi);
if (HAL_SPI_Init(&sspi->hspi) != HAL_OK)
{
MyLibs_Error_Handler();
return HAL_ERROR;
}
// init gpio from SPISettings structure
SPI_GPIO_Init(sspi);
// // init dma from SPISettings structure if need
// if (sspi->DMAChannel != 0)
// SPI_DMA_Init(&sspi->hspi, sspi->hspi.hdmarx, sspi->DMAChannel, sspi->DMA_CHANNEL_X);
return HAL_OK;
}
/**
* @brief Initialize GPIO for SPI.
* @param GPIOx - порт для настройки.
* @param GPIO_PIN_RX - пин для настройки на прием.
* @param GPIO_PIN_TX - пин для настройки на передачу.
*/
void SPI_GPIO_Init(SPI_SettingsTypeDef *sspi)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// GPIO INIT
GPIO_Clock_Enable(sspi->CLK_GPIOx);
GPIO_Clock_Enable(sspi->MISO_GPIOx);
GPIO_Clock_Enable(sspi->MOSI_GPIOx);
// CLK PIN INIT
GPIO_InitStruct.Pin = sspi->CLK_PIN;
GPIO_InitStruct.Alternate = sspi->CLK_GPIO_AlternageFunc;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(sspi->CLK_GPIOx, &GPIO_InitStruct);
// MISO PIN INIT
GPIO_InitStruct.Pin = sspi->MISO_PIN;
GPIO_InitStruct.Alternate = sspi->MISO_GPIO_AlternageFunc;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(sspi->MISO_GPIOx, &GPIO_InitStruct);
// MOSI PIN INIT
GPIO_InitStruct.Pin = sspi->MOSI_PIN;
GPIO_InitStruct.Alternate = sspi->MOSI_GPIO_AlternageFunc;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(sspi->MOSI_GPIOx, &GPIO_InitStruct);
}
/**
* @brief Initialize DMA for SPI.
* @param hspi - указатель на хендл SPI для настройки DMA.
* @param hdma_rx - указатель на хендл DMA для линии приема SPI.
* @param DMAChannel - указатель на канал DMA/поток DMA в STM32F407.
* @param DMA_CHANNEL_X - канал DMA.
*/
void SPI_DMA_Init(SPI_HandleTypeDef *hspi, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X)
{ // function takes spi and dma handlers and dmachannel for spi
// // for now only dma rx is supported, tx maybe later if needed
// // calc defines on boot_project_setup.h
// /* SPI3 DMA Init */
// /* SPI3_RX Init */
//
// hdma_rx->Instance = DMAChannel;
//#if defined(STM32F407xx) // dma channel choose for 407
// hdma_rx->Init.Channel = DMA_CHANNEL_X;
//#endif
// hdma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY;
// hdma_rx->Init.PeriphInc = DMA_PINC_DISABLE;
// hdma_rx->Init.MemInc = DMA_MINC_ENABLE;
// hdma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
// hdma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
// hdma_rx->Init.Mode = DMA_CIRCULAR;
// hdma_rx->Init.Priority = DMA_PRIORITY_LOW;
// if (HAL_DMA_Init(hdma_rx) != HAL_OK)
// {
// MyLibs_Error_Handler();
// }
// __USER_LINKDMA(hspi,hdmarx,hdma_rx);
//
// // __USER_LINKDMA is need because __HAL_LINKDMA is written for global defined hdma_rx
// // so you get error because hal uses . insted of ->
}
/**
* @brief Initialize SPI & DMA clock and interrupt.
* @param hspi - указатель на хендл SPI для инициализации.
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых SPI,
дефайнами в general_spi.h определяются используемые SPI.
*/
void SPI_MspInit(SPI_HandleTypeDef *hspi) // analog for hal function
{
// rcc, dma and interrupt init for SPIs
// GPIO init was moved to own functions SPI_GPIO_Init
if(0);
#ifdef USE_SPI1
else if(hspi->Instance==SPI1)
{
// /* DMA2 clock enable */
// __HAL_RCC_DMA2_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
/* SPI1 clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
}
#endif // USE_SPI1
#ifdef USE_SPI2
else if(hspi->Instance==SPI2)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
/* SPI2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
/* SPI2 interrupt Init */
HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI2_IRQn);
}
#endif // USE_SPI2
#ifdef USE_SPI3
else if(hspi->Instance==SPI3)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
/* SPI3 clock enable */
__HAL_RCC_SPI3_CLK_ENABLE();
/* SPI3 interrupt Init */
HAL_NVIC_SetPriority(SPI3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI3_IRQn);
}
#endif // USE_SPI3
}
/**
* @brief Deinitialize SPI & DMA clock and interrupt.
* @param hspi - указатель на хендл SPI для деинициализации.
* @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых SPI,
дефайнами определяются используемые SPI.
*/
void SPI_MspDeInit(SPI_HandleTypeDef *hspi) // analog for hal function
{
// rcc, dma and interrupt init for SPIs
// GPIO init was moved to own functions SPI_GPIO_Init
if(0);
#ifdef USE_SPI1
else if(hspi->Instance==SPI1)
{
// /* DMA2 clock enable */
// __HAL_RCC_DMA2_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
/* SPI1 clock reset */
__HAL_RCC_SPI1_FORCE_RESET();
__HAL_RCC_SPI1_RELEASE_RESET();
}
#endif // USE_SPI1
#ifdef USE_SPI2
else if(hspi->Instance==SPI2)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
/* SPI2 clock reset */
__HAL_RCC_SPI2_FORCE_RESET();
__HAL_RCC_SPI2_RELEASE_RESET();
}
#endif // USE_SPI2
#ifdef USE_SPI3
else if(hspi->Instance==SPI3)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
/* SPI3 clock reset */
__HAL_RCC_SPI3_FORCE_RESET();
__HAL_RCC_SPI3_RELEASE_RESET();
}
#endif // USE_SPI3
}
/**
* @brief Check that spi init structure have correct values.
* @param sspi - указатель на структуру с настройками SPI.
* @return HAL status.
*/
HAL_StatusTypeDef Check_SPI_Init_Struct(SPI_SettingsTypeDef *sspi)
{
// check is settings are valid
if (!IS_SPI_ALL_INSTANCE(sspi->hspi.Instance))
return HAL_ERROR;
// check init settings
if (!IS_SPI_MODE(sspi->hspi.Init.Mode))
return HAL_ERROR;
if (!IS_SPI_DIRECTION(sspi->hspi.Init.Direction))
return HAL_ERROR;
if (!IS_SPI_DATASIZE(sspi->hspi.Init.DataSize))
return HAL_ERROR;
if (!IS_SPI_BAUDRATE_PRESCALER(sspi->hspi.Init.BaudRatePrescaler))
return HAL_ERROR;
if (!IS_SPI_CPOL(sspi->hspi.Init.CLKPolarity))
return HAL_ERROR;
if (!IS_SPI_CPHA(sspi->hspi.Init.CLKPhase))
return HAL_ERROR;
if (!IS_SPI_NSS(sspi->hspi.Init.NSS))
return HAL_ERROR;
if (!IS_SPI_FIRST_BIT(sspi->hspi.Init.FirstBit))
return HAL_ERROR;
if (!IS_SPI_CRC_CALCULATION(sspi->hspi.Init.CRCCalculation))
return HAL_ERROR;
if (!IS_SPI_CRC_POLYNOMIAL(sspi->hspi.Init.NSS) &&
(sspi->hspi.Init.CRCCalculation != SPI_CRCCALCULATION_DISABLE))
return HAL_ERROR;
if (!IS_SPI_TIMODE(sspi->hspi.Init.TIMode))
return HAL_ERROR;
// check gpio
if (!IS_GPIO_ALL_INSTANCE(sspi->CLK_GPIOx) || !IS_GPIO_ALL_INSTANCE(sspi->MISO_GPIOx) || !IS_GPIO_ALL_INSTANCE(sspi->MOSI_GPIOx))
return HAL_ERROR;
if (!IS_GPIO_PIN(sspi->CLK_PIN) && !IS_GPIO_PIN(sspi->MISO_PIN) && !IS_GPIO_PIN(sspi->MOSI_PIN)) // if both pins arent set up
return HAL_ERROR;
return HAL_OK;
}

View File

@@ -0,0 +1,657 @@
/**
**************************************************************************
* @file general_tim.c
* @brief Модуль для инициализации таймеров.
**************************************************************************
@verbatim
//-------------------Функции-------------------//
Functions: user init
- TIM_Base_Init Инициализация TIM
- TIM_Encoder_Init Инициализация режима энкодера
- TIM_Output_PWM_Init Инициализация PWM с выводом на GPIO
- TIM_OC_Comparator_Init Инициализация TIM как компаратора
Functions: user
- TIM_Delay Задержка с помощью TIM
Functions: tim initialize
- TIM_Base_MspInit Аналог HAL_MspInit для таймера
- TIM_Base_MspDeInit Аналог HAL_MspDeInit для таймера
@endverbatim
*************************************************************************/
#include "general_tim.h"
#include "general_gpio.h"
//-------------------------------------------------------------------
//-------------------------TIM INIT FUNCTIONS------------------------
/**
* @brief Initialize TIM with TIM_SettingsTypeDef structure.
* @param stim - указатель на структуру с настройками таймера.
* @return HAL status.
* @note Данная структура содержит хендл таймера и структуры для его настройки.
*/
HAL_StatusTypeDef TIM_Base_Init(TIM_SettingsTypeDef *stim)
{ // function takes structure for init
// check that htim is defined
if (stim->htim.Instance == NULL)
return HAL_ERROR;
if(stim->sTickBaseUS) // if tickbase isnt disable
{
if(stim->sTimAHBFreqMHz == NULL)
return HAL_ERROR;
stim->htim.Init.Prescaler = (stim->sTimAHBFreqMHz*stim->sTickBaseUS) - 1;
if ((stim->sTimFreqHz != NULL))
stim->htim.Init.Period = ((1000000/stim->sTickBaseUS) / stim->sTimFreqHz) - 1;
else if (stim->htim.Init.Period == NULL)
stim->htim.Init.Period = 0xFFFF;
if(stim->sTickBasePrescaler)
{
stim->htim.Init.Prescaler = (stim->htim.Init.Prescaler + 1)/stim->sTickBasePrescaler - 1;
stim->htim.Init.Period = (stim->htim.Init.Period + 1)*stim->sTickBasePrescaler - 1;
}
else
stim->sTickBasePrescaler = 1;
}
// fix overflow of presc and period if need
for(int i = 0; (stim->htim.Init.Prescaler > 0xFFFF) || (stim->htim.Init.Period > 0xFFFF); i++)
{
if (i>10) // if it isnt fixed after 10 itteration - return HAL_ERRPOR
{
return HAL_ERROR;
}
// if timbase is too big (prescaller too big for choosen base from MHZ)
if(stim->htim.Init.Prescaler > 0xFFFF)
{
// переносим часть пресскалера в период
stim->htim.Init.Prescaler = ((stim->htim.Init.Prescaler + 1)/2) - 1;
stim->htim.Init.Period = ((stim->htim.Init.Period + 1)*2) - 1;
// обновляем TickBase, если есть куда обновлять
if(stim->sTickBaseUS > 1)
stim->sTickBaseUS /= 2;
// обновляем sTickBasePrescaler, если sTickBaseUS - уже в минимуме
else if (stim->sTickBaseUS == 1)
stim->sTickBasePrescaler *= 2;
else // if TickBase = 0 - return error
return HAL_ERROR;
}
// if freq is too low (period too big for choosen base)
if(stim->htim.Init.Period > 0xFFFF)
{
// переносим часть периода в прескалер
stim->htim.Init.Period = ((stim->htim.Init.Period + 1)/2) - 1;
stim->htim.Init.Prescaler = ((stim->htim.Init.Prescaler + 1)*2) - 1;
// обновляем TickBase
stim->sTickBaseUS *= 2;
}
}
//-------------TIM BASE INIT----------------
// tim base init
TIM_Base_MspInit(&stim->htim, stim->sTimMode);
if (HAL_TIM_Base_Init(&stim->htim) != HAL_OK)
{
MyLibs_Error_Handler();
return HAL_ERROR;
}
//-------------CLOCK SRC INIT---------------
// fill sClockSourceConfig if its NULL
if (stim->sClockSourceConfig.ClockSource == NULL)
stim->sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
// clock source init
if (HAL_TIM_ConfigClockSource(&stim->htim, &stim->sClockSourceConfig) != HAL_OK)
{
MyLibs_Error_Handler();
return HAL_ERROR;
}
//--------------SLAVE INIT------------------
// if slave mode enables - config it
if (stim->sSlaveConfig.SlaveMode)
{
// slave mode init
if (HAL_TIM_SlaveConfigSynchro(&stim->htim, &stim->sSlaveConfig) != HAL_OK)
{
MyLibs_Error_Handler();
return HAL_ERROR;
}
}
//--------------MASTER INIT-----------------
// master mode init
if (HAL_TIMEx_MasterConfigSynchronization(&stim->htim, &stim->sMasterConfig) != HAL_OK)
{
MyLibs_Error_Handler();
return HAL_ERROR;
}
//--------------BDTR INIT-----------------
if (HAL_TIMEx_ConfigBreakDeadTime(&stim->htim, &stim->sBreakDeadTimeConfig) != HAL_OK)
{
MyLibs_Error_Handler();
return HAL_ERROR;
}
//----------------IT CLEAR-------------------
__HAL_TIM_CLEAR_IT(&stim->htim, TIM_IT_UPDATE);
// обновляем TickBase
#ifdef UPDATE_TIM_PARAMS_AFTER_INITIALIZATION
stim->sTickBaseUS = (stim->htim.Instance->PSC+1)*stim->sTickBasePrescaler/(stim->sTimAHBFreqMHz);
if(stim->sTickBaseUS == 0) // if prescaler is too high
{ // recalc what is prescaler irl
stim->sTickBaseUS = 1;
stim->sTickBasePrescaler = stim->sTimAHBFreqMHz/(stim->htim.Instance->PSC+1);
}
#endif
stim->htim.Instance->CNT = 0;
return HAL_OK;
}
/**
* @brief Initialize TIM Encoder functional.
* @param htim - указатель на хендл таймера.
* @param sConfigOC - указатель на настрйоки канала таймера.
* @param GPIOx - порт для приема енкодера.
* @param GPIO_PIN1 - первый пин для енкодера.
* @param GPIO_PIN2 - второй пин для енкодера.
* @param GPIO_PIN_SW - пин для кнопки енкодера.
* @return HAL status.
*/
HAL_StatusTypeDef TIM_Encoder_Init(TIM_EncoderTypeDef *henc, TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_StatusTypeDef RES = HAL_ERROR;
henc->htim = htim;
// setup channel for pwm
RES = HAL_TIM_Encoder_Init(henc->htim, &henc->sConfig);
if (RES != HAL_OK)
{
MyLibs_Error_Handler();
return RES;
}
// choose port for enable clock
RES = GPIO_Clock_Enable(henc->GPIOx);
if(RES != HAL_OK)
{
MyLibs_Error_Handler();
return RES;
}
GPIO_InitStruct.Pin = henc->GPIO_PIN_TI1|henc->GPIO_PIN_TI2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = TIM_Alternate_Mapping(henc->htim->Instance);
if(GPIO_InitStruct.Alternate)
HAL_GPIO_Init(henc->GPIOx, &GPIO_InitStruct);
if(henc->GPIO_PIN_SW)
{
/*Configure switch pin */
GPIO_InitStruct.Pin = henc->GPIO_PIN_SW;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
return HAL_OK;
}
/**
* @brief Initialize PWM Channel and GPIO for output.
* @param htim - указатель на хендл таймера.
* @param sConfigOC - указатель на настрйоки канала таймера.
* @param TIM_CHANNEL - канал таймера для настройки.
* @param GPIOx - порт для вывода ШИМ.
* @param GPIO_PIN - пин для вывода ШИМ.
* @return HAL status.
*/
HAL_StatusTypeDef TIM_Output_PWM_Init(TIM_HandleTypeDef *htim, TIM_OC_InitTypeDef *sConfigOC, uint32_t TIM_CHANNEL, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_StatusTypeDef RES = HAL_ERROR;
// setup channel for pwm
RES = HAL_TIM_PWM_ConfigChannel(htim, sConfigOC, TIM_CHANNEL);
if (RES != HAL_OK)
{
MyLibs_Error_Handler();
return RES;
}
// choose port for enable clock
RES = GPIO_Clock_Enable(GPIOx);
if(RES != HAL_OK)
{
MyLibs_Error_Handler();
return RES;
}
GPIO_InitStruct.Pin = GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
if(sConfigOC->OCPolarity == TIM_OCNPOLARITY_HIGH)
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
else
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = TIM_Alternate_Mapping(htim->Instance);
if(GPIO_InitStruct.Alternate)
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
return HAL_OK;
}
/**
* @brief Initialize OC Comparator.
* @param htim - указатель на хендл таймера.
* @param TIM_CHANNEL - канал таймера для настройки.
* @return HAL status.
*/
HAL_StatusTypeDef TIM_OC_Comparator_Init(TIM_HandleTypeDef *htim, uint32_t TIM_CHANNEL)
{
TIM_OC_InitTypeDef sConfigOC = {0};
HAL_StatusTypeDef RES = HAL_ERROR;
sConfigOC.OCMode = TIM_OCMODE_ACTIVE;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
RES = HAL_TIM_OC_ConfigChannel(htim, &sConfigOC, TIM_CHANNEL);
if (RES != HAL_OK)
{
MyLibs_Error_Handler();
return RES;
}
return RES;
}
//-------------------------------------------------------------------
//-------------------------TIM USER FUNCTIONS------------------------
/**
* @brief Delay via TIM.
* @param htim - указатель на хендл таймера.
* @param delay - задержка в тиках таймера.
* @return HAL status.
* @note Таймер должен быть уже запущен.
*/
HAL_StatusTypeDef TIM_Delay(TIM_HandleTypeDef *htim, uint16_t delay)
{
if(delay >= htim->Instance->ARR)
{
return HAL_ERROR;
}
htim->Instance->CNT = 0;
while(1)
{
if(htim->Instance->CNT > delay)
{
return HAL_OK;
}
}
}
/**
* @brief Start delay via TIM.
* @param htim - указатель на хендл таймера.
* @return HAL status.
* @note Таймер должен быть уже запущен.
*/
HAL_StatusTypeDef TIM_Delay_Start(TIM_HandleTypeDef *htim)
{
htim->Instance->CNT = 0;
return HAL_OK;
}
/**
* @brief Wait Delay via TIM without blocking app.
* @param htim - указатель на хендл таймера.
* @param delay - задержка в тиках таймера.
* @return HAL status.
* @note Перед ожиданием задержки надо запутстить таймер её @ref TIM_Delay_Start
* @note Таймер не должен использоваться на время этой задержки
*/
HAL_StatusTypeDef TIM_Delay_NonBlocking(TIM_HandleTypeDef *htim, uint16_t delay)
{
if(delay >= htim->Instance->ARR)
{
return HAL_ERROR;
}
if(htim->Instance->CNT <= delay)
{
return HAL_BUSY;
}
else
{
return HAL_OK;
}
}
/**
* @brief Initialize TIMs clock and interrupt.
* @param htim - указатель на хендл таймера.
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых таймеров,
дефайнами в general_tim.h определяются используемые таймеры.
*/
void TIM_Base_MspInit(TIM_HandleTypeDef* htim, TIM_ITModeTypeDef it_mode)
{
it_mode = it_mode&TIM_IT_CONF;
#ifdef USE_TIM1
if(htim->Instance==TIM1)
{
/* TIM2 clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* TIM2 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
}
}
#endif
#ifdef USE_TIM2
if(htim->Instance==TIM2)
{
/* TIM2 clock enable */
__HAL_RCC_TIM2_CLK_ENABLE();
/* TIM2 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
}
#endif
#ifdef USE_TIM3
if(htim->Instance==TIM3)
{
/* TIM3 clock enable */
__HAL_RCC_TIM3_CLK_ENABLE();
/* TIM3 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM3_IRQn);
}
}
#endif
#ifdef USE_TIM4
if(htim->Instance==TIM4)
{
/* TIM4 clock enable */
__HAL_RCC_TIM4_CLK_ENABLE();
/* TIM4 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM4_IRQn);
}
}
#endif
#ifdef USE_TIM5
if(htim->Instance==TIM5)
{
/* TIM5 clock enable */
__HAL_RCC_TIM5_CLK_ENABLE();
/* TIM5 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM5_IRQn);
}
}
#endif
#ifdef USE_TIM6
if(htim->Instance==TIM6)
{
/* TIM6 clock enable */
__HAL_RCC_TIM6_CLK_ENABLE();
/* TIM6 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
}
}
#endif
#ifdef USE_TIM7
if(htim->Instance==TIM7)
{
/* TIM7 clock enable */
__HAL_RCC_TIM7_CLK_ENABLE();
/* TIM7 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM7_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM7_IRQn);
}
}
#endif
#ifdef USE_TIM8
if(htim->Instance==TIM8)
{
/* TIM8 clock enable */
__HAL_RCC_TIM8_CLK_ENABLE();
/* TIM8 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
}
}
#endif
#ifdef USE_TIM9
if(htim->Instance==TIM9)
{
/* TIM9 clock enable */
__HAL_RCC_TIM9_CLK_ENABLE();
/* TIM9 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM1_BRK_TIM9_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn);
}
}
#endif
#ifdef USE_TIM10
if(htim->Instance==TIM10)
{
/* TIM10 clock enable */
__HAL_RCC_TIM10_CLK_ENABLE();
/* TIM10 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn);
}
}
#endif
#ifdef USE_TIM11
if(htim->Instance==TIM11)
{
/* TIM11 clock enable */
__HAL_RCC_TIM11_CLK_ENABLE();
/* TIM11 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM1_TRG_COM_TIM11_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM1_TRG_COM_TIM11_IRQn);
}
}
#endif
#ifdef USE_TIM12
if(htim->Instance==TIM12)
{
/* TIM12 clock enable */
__HAL_RCC_TIM12_CLK_ENABLE();
/* TIM12 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
}
}
#endif
#ifdef USE_TIM13
if(htim->Instance==TIM13)
{
/* TIM13 clock enable */
__HAL_RCC_TIM13_CLK_ENABLE();
/* TIM13 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
}
}
#endif
#ifdef USE_TIM14
if(htim->Instance==TIM14)
{
/* TIM14 clock enable */
__HAL_RCC_TIM14_CLK_ENABLE();
/* TIM14 interrupt Init */
if(it_mode)
{
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
}
}
#endif
}
/**
* @brief DeInitialize TIMs clock and interrupt.
* @param htim - указатель на хендл таймера.
* @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых таймеров,
дефайнами в general_tim.h определяются используемые таймеры.
*/
void TIM_Base_MspDeInit(TIM_HandleTypeDef* htim)
{
#ifdef USE_TIM1
if(htim->Instance==TIM1)
{
__HAL_RCC_TIM1_FORCE_RESET();
__HAL_RCC_TIM1_RELEASE_RESET();
}
#endif
#ifdef USE_TIM2
if(htim->Instance==TIM2)
{
__HAL_RCC_TIM2_FORCE_RESET();
__HAL_RCC_TIM2_RELEASE_RESET();
}
#endif
#ifdef USE_TIM3
if(htim->Instance==TIM3)
{
__HAL_RCC_TIM3_FORCE_RESET();
__HAL_RCC_TIM3_RELEASE_RESET();
}
#endif
#ifdef USE_TIM4
if(htim->Instance==TIM4)
{
__HAL_RCC_TIM4_FORCE_RESET();
__HAL_RCC_TIM4_RELEASE_RESET();
}
#endif
#ifdef USE_TIM5
if(htim->Instance==TIM5)
{
__HAL_RCC_TIM5_FORCE_RESET();
__HAL_RCC_TIM5_RELEASE_RESET();
}
#endif
#ifdef USE_TIM6
if(htim->Instance==TIM6)
{
__HAL_RCC_TIM6_FORCE_RESET();
__HAL_RCC_TIM6_RELEASE_RESET();
}
#endif
#ifdef USE_TIM7
if(htim->Instance==TIM7)
{
__HAL_RCC_TIM7_FORCE_RESET();
__HAL_RCC_TIM7_RELEASE_RESET();
}
#endif
#ifdef USE_TIM8
if(htim->Instance==TIM8)
{
__HAL_RCC_TIM8_FORCE_RESET();
__HAL_RCC_TIM8_RELEASE_RESET();
}
#endif
#ifdef USE_TIM9
if(htim->Instance==TIM9)
{
__HAL_RCC_TIM9_FORCE_RESET();
__HAL_RCC_TIM9_RELEASE_RESET();
}
#endif
#ifdef USE_TIM10
if(htim->Instance==TIM10)
{
__HAL_RCC_TIM10_FORCE_RESET();
__HAL_RCC_TIM10_RELEASE_RESET();
}
#endif
#ifdef USE_TIM11
if(htim->Instance==TIM11)
{
__HAL_RCC_TIM11_FORCE_RESET();
__HAL_RCC_TIM11_RELEASE_RESET();
}
#endif
#ifdef USE_TIM12
if(htim->Instance==TIM12)
{
__HAL_RCC_TIM12_FORCE_RESET();
__HAL_RCC_TIM12_RELEASE_RESET();
}
#endif
#ifdef USE_TIM13
if(htim->Instance==TIM13)
{
__HAL_RCC_TIM13_FORCE_RESET();
__HAL_RCC_TIM13_RELEASE_RESET();
}
#endif
#ifdef USE_TIM14
if(htim->Instance==TIM14)
{
__HAL_RCC_TIM14_FORCE_RESET();
__HAL_RCC_TIM14_RELEASE_RESET();
}
#endif
}
//-------------------------TIM INIT FUNCTIONS------------------------
//-------------------------------------------------------------------

View File

@@ -0,0 +1,380 @@
/**
**************************************************************************
* @file general_uart.c
* @brief Модуль для инициализации UART.
**************************************************************************
* //-------------------Функции-------------------//
* @verbatim
* Functions: users
* - UART_Base_Init Инициализация UART
*
* Functions: uart initialize
* - UART_GPIO_Init Инициализация GPIO для UART
* - UART_DMA_Init Инициализация DMA для UART
* - UART_MspInit Аналог HAL_MspInit для UART
* - UART_MspDeInit Аналог HAL_MspDeInit для UART
* @endverbatim
***************************************************************************/
#include "general_uart.h"
#include "general_gpio.h"
//-------------------------------------------------------------------
//------------------------UART INIT FUNCTIONS------------------------
/**
* @brief Initialize UART with UART_SettingsTypeDef structure.
* @param suart - указатель на структуру с настройками UART.
* @return HAL status.
* @note Данная структура содержит хендл ЮАРТ и настройки перефирии (GPIO)
*/
HAL_StatusTypeDef UART_Base_Init(UART_SettingsTypeDef *suart)
{ // function takes setting structure for init
// check is settings are valid
if(Check_UART_Init_Struct(suart) != HAL_OK)
return HAL_ERROR;
suart->huart.Init.Mode = UART_MODE_TX_RX;
UART_MspInit(&suart->huart);
if (HAL_UART_Init(&suart->huart) != HAL_OK)
{
MyLibs_Error_Handler();
return HAL_ERROR;
}
// init gpio from UARTSettings structure
UART_GPIO_Init(suart->GPIOx, suart->GPIO_PIN_RX, suart->GPIO_PIN_TX);
__HAL_UART_ENABLE_IT(&suart->huart, UART_IT_IDLE);
// init dma from UARTSettings structure if need
if (suart->DMAChannel != 0)
UART_DMA_Init(&suart->huart, suart->huart.hdmarx, suart->DMAChannel, suart->DMA_CHANNEL_X);
return HAL_OK;
}
/**
* @brief Initialize GPIO for UART.
* @param GPIOx - порт для настройки.
* @param GPIO_PIN_RX - пин для настройки на прием.
* @param GPIO_PIN_TX - пин для настройки на передачу.
*/
void UART_GPIO_Init(GPIO_TypeDef *GPIOx, uint16_t GPIO_PIN_RX, uint16_t GPIO_PIN_TX)
{ // function takes port and pins (for rx and tx)
GPIO_InitTypeDef GPIO_InitStruct = {0};
// choose port for enable clock
GPIO_Clock_Enable(GPIOx);
//USART3 GPIO Configuration
//GPIO_PIN_TX ------> USART_TX
//GPIO_PIN_RX ------> USART_RX
#if defined(STM32F407xx) // gpio init for 407
GPIO_InitStruct.Pin = GPIO_PIN_TX|GPIO_PIN_RX;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF7_USART3;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
#elif defined(STM32F103xG) // gpio init for atm403/stm103
//GPIO_PIN_TX ------> USART_TX
GPIO_InitStruct.Pin = GPIO_PIN_TX;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
// GPIO_PIN_RX ------> USART_RX
GPIO_InitStruct.Pin = GPIO_PIN_RX;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
#endif
}
/**
* @brief Initialize DMA for UART.
* @param huart - указатель на хендл UART для настройки DMA.
* @param hdma_rx - указатель на хендл DMA для линии приема UART.
* @param DMAChannel - указатель на канал DMA/поток DMA в STM32F407.
* @param DMA_CHANNEL_X - канал DMA.
*/
void UART_DMA_Init(UART_HandleTypeDef *huart, DMA_HandleTypeDef *hdma_rx, DMA_Stream_TypeDef *DMAChannel, uint32_t DMA_CHANNEL_X)
{ // function takes uart and dma handlers and dmachannel for uart
// for now only dma rx is supported, tx maybe later if needed
// calc defines on boot_project_setup.h
/* USART3 DMA Init */
/* USART3_RX Init */
hdma_rx->Instance = DMAChannel;
#if defined(STM32F407xx) // dma channel choose for 407
hdma_rx->Init.Channel = DMA_CHANNEL_X;
#endif
hdma_rx->Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx->Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx->Init.MemInc = DMA_MINC_ENABLE;
hdma_rx->Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx->Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx->Init.Mode = DMA_CIRCULAR;
hdma_rx->Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(hdma_rx) != HAL_OK)
{
MyLibs_Error_Handler();
}
__USER_LINKDMA(huart,hdmarx,hdma_rx);
// __USER_LINKDMA is need because __HAL_LINKDMA is written for global defined hdma_rx
// so you get error because hal uses . insted of ->
}
/**
* @brief Initialize UART & DMA clock and interrupt.
* @param huart - указатель на хендл UART для инициализации.
* @note Чтобы не генерировать функцию с иницилизацией неиспользуемых UART,
дефайнами в rs_message.h определяются используемые UART.
*/
void UART_MspInit(UART_HandleTypeDef *huart) // analog for hal function
{
// __RCC_DMA_UART_CLK_ENABLE();
// /* DMA interrupt init */
// /* DMA1_Stream1_IRQn interrupt configuration */
// HAL_NVIC_SetPriority(DMA_UART_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA_UART_IRQn);
// rcc, dma and interrupt init for USARTs
// GPIO init was moved to own functions UART_GPIO_Init
if(0);
#ifdef USE_USART1
else if(huart->Instance==USART1)
{
/* DMA2 clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
/* USART1 clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
}
#endif // USE_USART1
#ifdef USE_USART2
else if(huart->Instance==USART2)
{
/* DMA1 clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
/* USART2 clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
/* USART2 interrupt Init */
HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART2_IRQn);
}
#endif // USE_USART2
#ifdef USE_USART3
else if(huart->Instance==USART3)
{
/* DMA1 clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
/* USART3 clock enable */
__HAL_RCC_USART3_CLK_ENABLE();
/* USART3 interrupt Init */
HAL_NVIC_SetPriority(USART3_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART3_IRQn);
}
#endif // USE_USART3
#ifdef USE_UART4
else if(huart->Instance==UART4)
{
/* DMA1 clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
/* UART4 clock enable */
__HAL_RCC_UART4_CLK_ENABLE();
/* UART4 interrupt Init */
HAL_NVIC_SetPriority(UART4_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(UART4_IRQn);
}
#endif // USE_UART4
#ifdef USE_UART5
else if(huart->Instance==UART5)
{
/* DMA1 clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
/* UART5 clock enable */
__HAL_RCC_DMA1_CLK_ENABLE();
/* UART5 interrupt Init */
HAL_NVIC_SetPriority(UART5_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(UART5_IRQn);
}
#endif // USE_UART5
#ifdef USE_USART6
else if(huart->Instance==USART6)
{
/* DMA2 clock enable */
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
/* USART6 clock enable */
__HAL_RCC_USART6_CLK_ENABLE();
/* USART6 interrupt Init */
HAL_NVIC_SetPriority(USART6_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART6_IRQn);
}
#endif // USE_USART6
}
/**
* @brief Deinitialize UART & DMA clock and interrupt.
* @param huart - указатель на хендл UART для деинициализации.
* @note Чтобы не генерировать функцию с деиницилизацией неиспользуемых UART,
дефайнами определяются используемые UART.
*/
void UART_MspDeInit(UART_HandleTypeDef *huart) // analog for hal function
{
// rcc, dma and interrupt init for USARTs
// GPIO init was moved to own functions UART_GPIO_Init
if(0);
#ifdef USE_USART1
else if(huart->Instance==USART1)
{
// /* DMA2 clock enable */
// __HAL_RCC_DMA2_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn);
/* USART1 clock reset */
__HAL_RCC_USART1_FORCE_RESET();
__HAL_RCC_USART1_RELEASE_RESET();
}
#endif // USE_USART1
#ifdef USE_USART2
else if(huart->Instance==USART2)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);
/* USART2 clock reset */
__HAL_RCC_USART2_FORCE_RESET();
__HAL_RCC_USART2_RELEASE_RESET();
}
#endif // USE_USART2
#ifdef USE_USART3
else if(huart->Instance==USART3)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
/* USART3 clock reset */
__HAL_RCC_USART3_FORCE_RESET();
__HAL_RCC_USART3_RELEASE_RESET();
}
#endif // USE_USART3
#ifdef USE_UART4
else if(huart->Instance==UART4)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
/* UART4 clock reset */
__HAL_RCC_UART4_FORCE_RESET();
__HAL_RCC_UART4_RELEASE_RESET();
}
#endif // USE_UART4
#ifdef USE_UART5
else if(huart->Instance==UART5)
{
// /* DMA1 clock enable */
// __HAL_RCC_DMA1_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
/* UART5 clock reset */
__HAL_RCC_UART5_FORCE_RESET();
__HAL_RCC_UART5_RELEASE_RESET();
}
#endif // USE_UART5
#ifdef USE_USART6
else if(huart->Instance==USART6)
{
// /* DMA2 clock enable */
// __HAL_RCC_DMA2_CLK_ENABLE();
// /* DMA interrupt init */
// HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
// HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
/* USART6 clock reset */
__HAL_RCC_USART6_FORCE_RESET();
__HAL_RCC_USART6_RELEASE_RESET();
}
#endif // USE_USART6
}
/**
* @brief Check that uart init structure have correct values.
* @param suart - указатель на структуру с настройками UART.
* @return HAL status.
*/
HAL_StatusTypeDef Check_UART_Init_Struct(UART_SettingsTypeDef *suart)
{
// check is settings are valid
if (!IS_UART_INSTANCE(suart->huart.Instance))
return HAL_ERROR;
if (!IS_UART_BAUDRATE(suart->huart.Init.BaudRate) || (suart->huart.Init.BaudRate == NULL))
return HAL_ERROR;
if (!IS_GPIO_ALL_INSTANCE(suart->GPIOx))
return HAL_ERROR;
if (!IS_GPIO_PIN(suart->GPIO_PIN_RX) && !IS_GPIO_PIN(suart->GPIO_PIN_TX)) // if both pins arent set up
return HAL_ERROR;
return HAL_OK;
}
//------------------------UART INIT FUNCTIONS------------------------
//-------------------------------------------------------------------

View File

@@ -0,0 +1,324 @@
/**
**************************************************************************
* @file general_gpio.c
* @brief Модуль для инициализации портов.
**************************************************************************
* @details Реализация функций для работы с GPIO:
* - Включение тактирования портов
* - Инициализация светодиодов и кнопок
* - Управление светодиодами: включение, выключение, моргание, плавное затухание
* - Чтение состояния кнопок с фильтром от дребезга
***************************************************************************/
#include "general_gpio.h"
//-------------------------------------------------------------------
//------------------------GPIO INIT FUNCTIONS------------------------
/**
* @brief Включить тактирование порта GPIO
*/
HAL_StatusTypeDef GPIO_Clock_Enable(GPIO_TypeDef *GPIOx)
{
HAL_StatusTypeDef status = HAL_OK;
// choose port for enable clock
if (GPIOx==GPIOA)
__HAL_RCC_GPIOA_CLK_ENABLE();
else if (GPIOx==GPIOB)
__HAL_RCC_GPIOB_CLK_ENABLE();
#ifdef GPIOC
else if (GPIOx==GPIOC)
__HAL_RCC_GPIOC_CLK_ENABLE();
#endif
#ifdef GPIOD
else if (GPIOx==GPIOD)
__HAL_RCC_GPIOD_CLK_ENABLE();
#endif
#ifdef GPIOE
else if (GPIOx==GPIOE)
__HAL_RCC_GPIOE_CLK_ENABLE();
#endif
#ifdef GPIOF
else if (GPIOx==GPIOF)
__HAL_RCC_GPIOF_CLK_ENABLE();
#endif
#ifdef GPIOH
else if (GPIOx==GPIOF)
__HAL_RCC_GPIOH_CLK_ENABLE();
#endif
else
status = HAL_ERROR;
return status;
}
//------------------------GPIO INIT FUNCTIONS------------------------
//-------------------------------------------------------------------
//-------------------------------------------------------------------
//------------------------GPIO LED FUNCTIONS-------------------------
/**
* @brief Инициализировать светодиод (структуру светодиода)
* @param led Указатель на структуру светодиода
* @param GPIOx Указатель на структуру порта для светодиода
* @param GPIO_PIN_X Пин для светодиода
* @param LED_ActiveLevel Состояния пина, при котором светодиод будет включен
*/
HAL_StatusTypeDef GPIO_LED_Init(GPIO_LEDTypeDef *led, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t LED_ActiveLevel)
{
if(check_null_ptr_2(led, GPIOx))
return HAL_ERROR;
led->LED_Port = GPIOx;
led->LED_Pin = GPIO_PIN_X;
led->LED_ActiveLvl = LED_ActiveLevel;
GPIO_LED_Off(led);
return HAL_OK;
}
/**
* @brief Включить светодиод
* @param led Указатель на структуру светодиода
* @return HAL Status
*/
HAL_StatusTypeDef GPIO_LED_On(GPIO_LEDTypeDef *led)
{
if(check_null_ptr_1(led))
return HAL_ERROR;
led->state = LED_IS_ON;
if(led->LED_Port != NULL)
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl);
else
return HAL_ERROR;
return HAL_OK;
}
/**
* @brief Выключить светодиод
* @param led Указатель на структуру светодиода
* @return HAL Status
*/
HAL_StatusTypeDef GPIO_LED_Off(GPIO_LEDTypeDef *led)
{
if(check_null_ptr_1(led))
return HAL_ERROR;
led->state = LED_IS_OFF;
if(led->LED_Port != NULL)
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, !led->LED_ActiveLvl);
else
return HAL_ERROR;
return HAL_OK;
}
/**
* @brief Выставить светодиод по переменной
* @param led Указатель на структуру светодиода
* @param led_state Состояние светодиода
* @return HAL Status
*/
HAL_StatusTypeDef GPIO_LED_Set(GPIO_LEDTypeDef *led, uint8_t led_state)
{
if(check_null_ptr_1(led))
return HAL_ERROR;
if(led_state)
{
return GPIO_LED_On(led);
}
else
{
return GPIO_LED_Off(led);
}
}
/**
* @brief Активировать моргание светодиодом
* @param led Указатель на структуру светодиода
* @param period Период плавного моргания светодиода
* @return HAL Status
* @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle
*/
HAL_StatusTypeDef GPIO_LED_Blink_Start(GPIO_LEDTypeDef *led, uint32_t period)
{
if(check_null_ptr_2(led, led->LED_Port))
return HAL_ERROR;
led->state = LED_IS_BLINKING;
led->LED_Period = period;
return HAL_OK;
}
/**
* @brief Активировать моргание светодиодом
* @param led Указатель на структуру светодиода
* @param period Период плавного моргания светодиода
* @return HAL Status
* @details Функция ставит режим моргания, который после управляется в @ref GPIO_LED_Dynamic_Handle
*/
HAL_StatusTypeDef GPIO_LED_Fading_Start(GPIO_LEDTypeDef *led, uint32_t period)
{
if(check_null_ptr_2(led, led->LED_Port))
return HAL_ERROR;
led->state = LED_IS_FADING;
led->LED_Period = period;
return HAL_OK;
}
//uint8_t LED_PWM_FADING_DUTYS[LED_PWM_TICKS] = {0 1 2 3 4 5 6 7 8 9 10 11 12 }
/**
* @brief Управление динамическими режимами свечения светодиода
* @param Указатель на структуру светодиода
* @details Функция моргает/плавно моргает светодиодом в неблокирующем режиме
* Т.е. функцию надо вызывать постоянно, чтобы она мониторила тики
* и в нужный момент переключала светодиод
*/
void GPIO_LED_Dynamic_Handle(GPIO_LEDTypeDef *led)
{
if(check_null_ptr_2(led, led->LED_Port))
return;
/* Режим моргания светодиода */
if(led->state == LED_IS_BLINKING)
{
uint32_t tickcurrent = HAL_GetTick();
/* Ожидание истечения периода моргания */
if((tickcurrent - led->tickprev) > led->LED_Period)
{
/* Моргание */
HAL_GPIO_TogglePin(led->LED_Port, led->LED_Pin);
led->tickprev = tickcurrent;
}
}
/* Режим плавного моргания светодиода */
else if(led->state == LED_IS_FADING)
{
static unsigned direction = 0;
static int duty = 0;
uint32_t tickcurrent = HAL_GetTick();
/* Ожидание момента изменения яркости */
/* Период ШИМ 20 мс, поэтому менять яроксть надо 40 раз за период (туда обратно) */
if((tickcurrent - led->tickprev) > led->LED_Period/(LED_PWM_TICKS*2))
{
/* Формирование разтухания */
if(direction == 0)
{
if(++duty >= LED_PWM_TICKS)
{
direction = 1;
duty = LED_PWM_TICKS;
}
}
/* Формирование затухания */
else
{
if(--duty <= 0)
{
direction = 0;
duty = 0;
}
}
led->tickprev = tickcurrent;
}
/* Формирование ШИМ для изменения яркости */
int duty_crt = (duty*duty/LED_PWM_TICKS);
if(tickcurrent%LED_PWM_TICKS < duty_crt)
{
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, led->LED_ActiveLvl);
}
else
{
HAL_GPIO_WritePin(led->LED_Port, led->LED_Pin, !led->LED_ActiveLvl);
}
}
}
//------------------------GPIO LED FUNCTIONS-------------------------
//-------------------------------------------------------------------
//-------------------------------------------------------------------
//------------------------GPIO SW FUNCTIONS-------------------------
/**
* @brief Инициализировать кнопку (структуру кнопки)
* @param sw Указатель на структуру кнопки
* @param GPIOx Указатель на структуру порта для кнопки
* @param GPIO_PIN_X Пин для кнопки
* @param SW_ActiveLevel Состояния пина, когда кнопка нажата
* @return HAL Status
*/
HAL_StatusTypeDef GPIO_Switch_Init(GPIO_SwitchTypeDef *sw, GPIO_TypeDef *GPIOx, uint32_t GPIO_PIN_X, uint8_t SW_ActiveLevel)
{
if(check_null_ptr_2(sw, GPIOx))
return HAL_ERROR;
sw->Sw_Port = GPIOx;
sw->Sw_Pin = GPIO_PIN_X;
sw->Sw_ActiveLvl = SW_ActiveLevel;
return HAL_OK;
}
/**
* @brief Считать состоянии кнопки
* @param sw Указатель на структуру кнопки
* @return 1 - если кнопка нажата, 0 - если отжата
* @details Функция включает в себя неблокирующую проверку на дребезг
* Т.е. функцию надо вызывать постоянно, чтобы она мониторила состояние кнопки
*/
uint8_t GPIO_Read_Switch(GPIO_SwitchTypeDef *sw)
{
if(check_null_ptr_1(sw))
return 0;
if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl)
{
sw->Sw_PrevState = 1;
if(sw->Sw_FilterDelay) // если включена защита от дребезга
{
if(sw->tickprev == 0)
sw->tickprev = HAL_GetTick();
if((HAL_GetTick() - sw->tickprev) >= sw->Sw_FilterDelay)
{
if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl)
{
return 1;
}
else
{
sw->tickprev = 0;
return 0;
}
}
}
else // если нет защиты от дребезга
{
if(HAL_GPIO_ReadPin(sw->Sw_Port, sw->Sw_Pin) == sw->Sw_ActiveLvl)
{
return 1;
}
else
{
sw->tickprev = 0;
return 0;
}
}
}
else
{
sw->Sw_PrevState = 0;
}
return 0;
}
//------------------------GPIO SW FUNCTIONS-------------------------
//-------------------------------------------------------------------