Initial snapshot: Aliro applet, harness, Nucleo NFC10A1 reader port

Three components, all bench-validated to varying depths:

- applet/: CSA Aliro v1.0 Java Card applet for J3R180. AUTH0 + AUTH1
  expedited-standard flow end-to-end green via PC/SC bench reader
  (aliro-bench-test). Userland AES-256-GCM and HMAC-SHA-256 layered
  on top of J3R180's primitives because the card lacks both natively.
  P-256 curve params seeded explicitly per J3R180's quirk.

- harness/: Python orchestrator (aliro-trustgen, aliro-personalize,
  aliro-bench-test) for trust-bundle generation, card personalization
  via PersonalizationApplet, and PC/SC AUTH0+AUTH1 transactions. 126
  pytest cases passing.

- reader/STM32CubeExpansion_ALIRO_V1_0_0/: ST X-CUBE-ALIRO V1.0.0
  with our NFC10A1 port (NUCLEO-U545RE-Q + X-NUCLEO-NFC10A1, ST25R200
  shared with NFC09A1). nfc10-only/ project, NFC10A1 BSP shim,
  ALIRO_TRUST_OVERRIDE include into vendor's provisioning.c, and an
  ALIRO_APDU_TRACE wrapper around demoTransceiveBlocking. Boots,
  detects the J3R180, completes SELECT + AUTH0; AUTH1 currently fails
  with RFAL ERR_PROTO (0xB) — under investigation, see
  docs/plans/2026-04-20-nucleo-nfc10a1-port.md and bench-notes/.

Excluded: x-cube-aliro.zip vendor archive, harness/.venv, build dirs,
generated aliro_trust.h (contains private reader scalar), all PEMs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-02 10:17:46 -07:00
commit 782074f6ae
8786 changed files with 2902373 additions and 0 deletions

View File

@@ -0,0 +1,203 @@
/**
******************************************************************************
* @file adv_trace_usart_if.c
* @author MCD Application Team
* @brief : Source file for interfacing the stm32_adv_trace to hardware
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "app_conf.h"
#include "stm32_adv_trace.h"
#include "adv_trace_usart_if.h"
/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* list all the driver interface used by the trace application. */
const UTIL_ADV_TRACE_Driver_s UTIL_TraceDriver =
{
UART_Init,
UART_DeInit,
UART_StartRx,
UART_TransmitDMA
};
/* Private variables ---------------------------------------------------------*/
/* Whether the UART should be in RX after a Transmit */
uint8_t receive_after_transmit = 0;
/* Buffer to receive 1 character */
static uint8_t cCharRx;
/* Exported macro ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
static void (*TxCpltCallback) ( void * );
static void (*RxCpltCallback) ( uint8_t * pData, uint16_t iSize, uint8_t cError );
static void UsartIf_TxCpltCallback ( UART_HandleTypeDef *huart );
static void UsartIf_RxCpltCallback ( UART_HandleTypeDef *huart );
static IRQn_Type get_IRQn_Type_from_DMA_HandleTypeDef (DMA_HandleTypeDef * hDmaHandler );
/* Private user code ---------------------------------------------------------*/
/**
*
*/
UTIL_ADV_TRACE_Status_t UART_Init( void (*pCallbackFunction)(void *))
{
TxCpltCallback = pCallbackFunction;
LOG_UART_HANDLER.TxCpltCallback = UsartIf_TxCpltCallback;
return UTIL_ADV_TRACE_OK;
}
/**
*
*/
UTIL_ADV_TRACE_Status_t UART_DeInit( void )
{
HAL_StatusTypeDef eResult;
eResult = HAL_UART_DeInit( &LOG_UART_HANDLER );
if ( eResult != HAL_OK )
{
LOG_UART_HANDLER.TxCpltCallback = NULL;
return UTIL_ADV_TRACE_UNKNOWN_ERROR;
}
return UTIL_ADV_TRACE_OK;
}
/**
*
*/
UTIL_ADV_TRACE_Status_t UART_StartRx( void (*pCallbackFunction)(uint8_t * pData, uint16_t iSize, uint8_t cError ) )
{
/* Configure UART in Receive mode */
HAL_UART_Receive_IT( &LOG_UART_HANDLER, &cCharRx, 1 );
LOG_UART_HANDLER.RxCpltCallback = &UsartIf_RxCpltCallback;
if ( pCallbackFunction != NULL )
{
RxCpltCallback = pCallbackFunction;
}
return UTIL_ADV_TRACE_OK;
}
/**
*
*/
UTIL_ADV_TRACE_Status_t UART_TransmitDMA ( uint8_t * pData, uint16_t iSize )
{
UTIL_ADV_TRACE_Status_t eStatus = UTIL_ADV_TRACE_OK;
HAL_StatusTypeDef eResult;
IRQn_Type eUseDmaTx;
eUseDmaTx = get_IRQn_Type_from_DMA_HandleTypeDef( LOG_UART_HANDLER.hdmatx );
if ( ( eUseDmaTx == GPDMA1_Channel0_IRQn ) || ( eUseDmaTx == GPDMA1_Channel1_IRQn ) ||
( eUseDmaTx == GPDMA1_Channel2_IRQn ) || ( eUseDmaTx == GPDMA1_Channel3_IRQn ) ||
( eUseDmaTx == GPDMA1_Channel4_IRQn ) || ( eUseDmaTx == GPDMA1_Channel5_IRQn ) ||
( eUseDmaTx == GPDMA1_Channel6_IRQn ) || ( eUseDmaTx == GPDMA1_Channel7_IRQn ) )
{
eResult = HAL_UART_Transmit_DMA( &LOG_UART_HANDLER, pData, iSize );
}
else
{
eResult = HAL_UART_Transmit_IT( &LOG_UART_HANDLER, pData, iSize );
}
if ( eResult != HAL_OK )
{
eStatus = UTIL_ADV_TRACE_HW_ERROR;
}
/* Check whether the UART should return in Receiver mode */
if ( receive_after_transmit )
{
HAL_UART_Receive_IT( &LOG_UART_HANDLER, &cCharRx, 1 );
}
return eStatus;
}
/**
*
*/
static void UsartIf_TxCpltCallback(UART_HandleTypeDef *huart)
{
/* ADV Trace callback */
TxCpltCallback(NULL);
}
/**
*
*/
static void UsartIf_RxCpltCallback(UART_HandleTypeDef *huart)
{
RxCpltCallback( &cCharRx, 1, 0 );
HAL_UART_Receive_IT( &LOG_UART_HANDLER, &cCharRx, 1 );
}
/**
* The purpose of this function is to match a DMA_HandleTypeDef as key with the corresponding IRQn_Type as value.
*
* TAKE CARE : in case of an invalid parameter or e.g. an usart/lpuart not initialized, this will lead to hard fault.
* it is up to the user to ensure the serial link is in a valid state.
*/
static IRQn_Type get_IRQn_Type_from_DMA_HandleTypeDef( DMA_HandleTypeDef * hDmaHandler )
{
if ( hDmaHandler->Instance == GPDMA1_Channel0 )
{ return GPDMA1_Channel0_IRQn; }
if ( hDmaHandler->Instance == GPDMA1_Channel1 )
{ return GPDMA1_Channel1_IRQn; }
if ( hDmaHandler->Instance == GPDMA1_Channel2 )
{ return GPDMA1_Channel2_IRQn; }
if ( hDmaHandler->Instance == GPDMA1_Channel3 )
{ return GPDMA1_Channel3_IRQn; }
if ( hDmaHandler->Instance == GPDMA1_Channel4 )
{ return GPDMA1_Channel4_IRQn; }
if ( hDmaHandler->Instance == GPDMA1_Channel5 )
{ return GPDMA1_Channel5_IRQn; }
if (hDmaHandler->Instance == GPDMA1_Channel6 )
{ return GPDMA1_Channel6_IRQn; }
if ( hDmaHandler->Instance == GPDMA1_Channel7 )
{ return GPDMA1_Channel7_IRQn; }
/* Values from (-1) to (-15) are already in used. This value isn't used so it should be safe.
So, if you see this value, it means you used an invalid DMA handler as input. */
return (IRQn_Type)(-666);
}

View File

@@ -0,0 +1,114 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usart_if.h
* @author MCD Application Team
* @brief : Header file for stm32_adv_trace interface file
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef USART_IF_H
#define USART_IF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_adv_trace.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Exported types ------------------------------------------------------------*/
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* External variables --------------------------------------------------------*/
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Exported macro ------------------------------------------------------------*/
/* USER CODE BEGIN EM */
/* USER CODE END EM */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Exported functions prototypes ---------------------------------------------*/
/**
* @brief Init the UART and associated DMA.
* @param cb tx function callback.
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_Init(void (*cb)(void *));
/**
* @brief DeInit the UART and associated DMA.
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_DeInit(void);
/**
* @brief send buffer to UART using DMA
* @param pdata data to be sent
* @param size of buffer p_data to be sent
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_TransmitDMA(uint8_t *pdata, uint16_t size);
/**
* @brief start Rx process
* @param cb callback to receive the data
* @return @ref UTIL_ADV_TRACE_Status_t
*/
UTIL_ADV_TRACE_Status_t UART_StartRx(void (*cb)(uint8_t *pdata, uint16_t size, uint8_t error));
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* USART_IF_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,179 @@
/**
******************************************************************************
* @file app_bsp.h
* @author MCD Application Team
* @brief Interface to manage BSP.
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef APP_BSP_H
#define APP_BSP_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "app_conf.h"
#include "stm32_rtos.h"
#ifdef STM32WBA55xx
#ifdef CFG_BSP_ON_DISCOVERY
#include "stm32wba55g_discovery.h"
#if (CFG_LCD_SUPPORTED == 1)
#include "stm32wba55g_discovery_lcd.h"
#include "stm32_lcd.h"
#endif /* (CFG_LCD_SUPPORTED == 1) */
#endif /* CFG_BSP_ON_DISCOVERY */
#endif /* STM32WBA55xx */
#ifdef STM32WBA65xx
#ifdef CFG_BSP_ON_DISCOVERY
#include "stm32wba65i_discovery.h"
#if (CFG_LCD_SUPPORTED == 1)
#include "stm32wba65i_discovery_lcd.h"
#include "stm32_lcd.h"
#endif /* (CFG_LCD_SUPPORTED == 1) */
#endif /* CFG_BSP_ON_DISCOVERY */
#endif /* STM32WBA65xx */
#ifdef CFG_BSP_ON_CEB
#ifdef STM32WBA5Mxx
#include "b_wba5m_wpan.h"
#endif
#ifdef STM32WBA6Mxx
#include "b_wba6m_wpan.h"
#endif
#endif /* CFG_BSP_ON_CEB */
#ifdef CFG_BSP_ON_NUCLEO
#include "stm32wbaxx_nucleo.h"
#endif /* CFG_BSP_ON_CEB */
#ifdef CFG_COAP_MSG
#include "coap.h"
#endif
/* Private includes ----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
#if (CFG_LCD_SUPPORTED == 1)
#define LCD1 (0u)
#endif /* (CFG_LCD_SUPPORTED == 1) */
#if (defined CFG_BSP_ON_DISCOVERY) && (defined STM32WBA65xx)
/* No Led Blue on Discovery for STM32WBA65I. Replaced by Red Led */
#define LED_BLUE LED_RED
#endif /* (defined CFG_BSP_ON_DISCOVERY) && (defined STM32WBA65xx) */
#if (CFG_JOYSTICK_SUPPORTED == 1)
#define JOYSTICK_USE_AS_JOYSTICK (0u) /* When Joystick is not 'none', call according 'Joystick Action' every JOYSTICK_PRESS_SAMPLE_MS. */
#define JOYSTICK_USE_AS_BUTTON (1u) /* When Joystick is pressed, call according 'Joystick Action' one time. */
#define JOYSTICK_USE_AS_BUTTON_WITH_TIME (2u) /* When Joystick is pressed, it wait the release or the end of JOYSTICK_LONG_PRESS_THRESHOLD_MS
before call according 'Joystick Action'. */
#define JOYSTICK_USE_AS_CHANGE (3u) /* When Joystcik is pressed according 'Joystick Action' is called. When the Joystick is released, 'JoystickNoneAction' is called. */
#define JOYSTICK_USE_AS_MATTER (4u) /* When Joystick is pressed, according 'Joystick Action' is called. When the Joystick is released or the end
of JOYSTICK_LONG_PRESS_THRESHOLD_MS occurs, according 'Joystick Action' is called (same as when pressed). */
#endif /* (CFG_JOYSTICK_SUPPORTED == 1) */
/* Exported variables --------------------------------------------------------*/
#ifdef CFG_COAP_MSG
extern uint32_t APP_Thread_TransmitPeriod_ms;
extern uint32_t APP_Thread_CoapPayloadLength_byte;
extern otCoapType APP_Thread_CoapType;
#endif
#if (CFG_BUTTON_SUPPORTED == 1)
#ifdef CFG_BSP_ON_THREADX
extern TX_SEMAPHORE ButtonB1Semaphore, ButtonB2Semaphore, ButtonB3Semaphore;
#endif /* CFG_BSP_ON_THREADX */
#ifdef CFG_BSP_ON_FREERTOS
extern osSemaphoreId_t ButtonB1Semaphore, ButtonB2Semaphore, ButtonB3Semaphore;
#endif /* CFG_BSP_ON_FREERTOS */
#endif /* (CFG_BUTTON_SUPPORTED == 1) */
#if (CFG_JOYSTICK_SUPPORTED == 1)
#ifdef CFG_BSP_ON_THREADX
extern TX_SEMAPHORE JoystickUpSemaphore, JoystickRightSemaphore, JoystickDownSemaphore, JoystickLeftSemaphore, JoystickSelectSemaphore, JoystickNoneSemaphore;
#endif /* CFG_BSP_ON_THREADX */
#ifdef CFG_BSP_ON_FREERTOS
extern osSemaphoreId_t JoystickUpSemaphore, JoystickRightSemaphore, JoystickDownSemaphore, JoystickLeftSemaphore, JoystickSelectSemaphore, JoystickNoneSemaphore;
#endif /* CFG_BSP_ON_FREERTOS */
#endif /* (CFG_JOYSTICK_SUPPORTED == 1) */
/* Exported macros ------------------------------------------------------------*/
#if ( CFG_LED_SUPPORTED == 1 )
#define APP_BSP_LED_On( LED ) BSP_LED_On( LED )
#define APP_BSP_LED_Off( LED ) BSP_LED_Off( LED )
#define APP_BSP_LED_Toggle( LED ) BSP_LED_Toggle( LED )
#else /* ( CFG_LED_SUPPORTED == 1 ) */
#define APP_BSP_LED_On( LED )
#define APP_BSP_LED_Off( LED )
#define APP_BSP_LED_Toggle( LED )
#endif /* ( CFG_LED_SUPPORTED == 1 ) */
/* Exported functions prototypes ---------------------------------------------*/
void APP_BSP_Init ( void );
void APP_BSP_PostIdle ( void );
void APP_BSP_StandbyExit ( void );
uint8_t APP_BSP_SerialCmdExecute ( uint8_t * pRxBuffer, uint16_t iRxBufferSize );
#if (CFG_LED_SUPPORTED == 1)
void APP_BSP_LedInit ( void );
#endif /* (CFG_LED_SUPPORTED == 1) */
#if (CFG_LCD_SUPPORTED == 1)
void APP_BSP_LcdInit ( void );
#endif /* (CFG_LCD_SUPPORTED == 1) */
#if ( CFG_BUTTON_SUPPORTED == 1 )
void APP_BSP_ButtonInit ( void );
uint8_t APP_BSP_ButtonIsLongPressed ( uint16_t btnIdx );
void APP_BSP_SetButtonIsLongPressed ( uint16_t btnIdx );
void APP_BSP_Button1Action ( void );
void APP_BSP_Button2Action ( void );
void APP_BSP_Button3Action ( void );
void BSP_PB_Callback ( Button_TypeDef button );
#endif /* ( CFG_BUTTON_SUPPORTED == 1 ) */
#if ( CFG_JOYSTICK_SUPPORTED == 1 )
void APP_BSP_JoystickInit ( void );
uint8_t APP_BSP_JoystickIsLongPressed ( void );
uint8_t APP_BSP_JoystickIsShortReleased ( void );
uint8_t APP_BSP_JoystickIsInitialPress ( void );
void APP_BSP_JoystickUpAction ( void );
void APP_BSP_JoystickRightAction ( void );
void APP_BSP_JoystickDownAction ( void );
void APP_BSP_JoystickLeftAction ( void );
void APP_BSP_JoystickSelectAction ( void );
void APP_BSP_JoystickNoneAction ( void );
void BSP_JOY_Callback ( JOY_TypeDef joyNb, JOYPin_TypeDef joyPin );
#endif /* CFG_JOYSTICK_SUPPORTED */
void APP_BSP_CliInit ( void );
void APP_BSP_CoapMsgRateAction ( void );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*APP_BSP_H */

View File

@@ -0,0 +1,562 @@
/**
******************************************************************************
* @file hw.h
* @author MCD Application Team
* @brief This file contains the interface of STM32 HW drivers.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef HW_H__
#define HW_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32wbaxx.h"
#include "app_conf.h"
/* ---------------------------------------------------------------------------
* General
* ---------------------------------------------------------------------------
*/
#ifndef CFG_HW_ERROR_OFFSET
#define CFG_HW_ERROR_OFFSET 0
#endif
/* Return values definition */
enum
{
HW_OK = 0,
HW_BUSY = 1
};
/*
* HW_Init
*
* This function must be called once after reset before calling any of the
* other HW functions.
*/
extern void HW_Init( void );
/*
* HW_Delay
*
* This function is used internally for minimum delays.
* The input is given in microseconds and must be strictly higher than 0 (> 0)
* and lower than 16000000 (= 16 s).
* Be careful that the actual delay can be higher than the one programmed
* if the function is interrupted.
* The function is declared "weak" and can be overloaded by the user.
*/
extern void HW_Delay( uint32_t delay_us );
/*
* HW_GetPackageType
*
* Returns the package type (cf Package Data Register in STM32WB UM)
*/
extern uint32_t HW_GetPackageType( void );
/*
* HW_Config_HSE
*/
void HW_Config_HSE( uint8_t hsetune );
/* ---------------------------------------------------------------------------
* AES
* ---------------------------------------------------------------------------
*/
/* Mode definitions used for HW_AES_SetKey() function */
enum
{
HW_AES_DEC = 0,
HW_AES_ENC = 1,
HW_AES_REV = 2,
HW_AES_SWAP = 4
};
extern int CRYP_MutexTake(void);
extern int CRYP_MutexRelease(void);
/*
* HW_AES_Enable
*
* Enables the AES hardware block.
* If the AES was already in use, the function does nothing and returns 0;
* otherwise it returns 1.
* Be careful: no re-entrance is ensured for the HW_AES functions
*/
extern int HW_AES_Enable( void );
/*
* HW_AES_SetKey
*
* Sets the key used for encryption/decryption.
* The "mode" parameter must be set to HW_AES_ENC for encryption and to
* HW_AES_DEC for decryption. It can be or-ed with HW_AES_REV for a reveresd
* oreder of key bytes, and with HW_AES_SWAP to use data byte swapping mode.
*/
extern void HW_AES_SetKey( uint32_t mode,
const uint8_t* key );
/*
* HW_AES_Crypt
*
* Encrypts/decrypts the 16-byte input data ("input"). Result is written in the
* 16-byte buffer ("output") allocated by the user.
*/
extern void HW_AES_Crypt( const uint32_t* input,
uint32_t* output );
/*
* HW_AES_Crypt
*
* Encrypts/decrypts the 16-byte input data ("input").
* Result is written in the 16-byte buffer ("output") allocated by the user.
*
* Note : input & output are 8 bits aligned.
*/
extern void HW_AES_Crypt8( const uint8_t* input, uint8_t* output );
/*
* HW_AES_Disable
*
* Disables the AES hardware block.
*/
extern void HW_AES_Disable( void );
/*
* HW_AES_InitCcm
*
* Initilaizes AES for CCM encryption (decrypt = 0) or decryption (decrypt = 1)
* Note: B0 and B1 4-word blocks must be provided by user.
*
*/
extern void HW_AES_InitCcm( uint8_t decrypt,
const uint8_t* key,
const uint32_t* b0,
const uint32_t* b1 );
/*
* HW_AES_EndCcm
*
* Completes CCM processing by computing the authentication tag
*
*/
extern void HW_AES_EndCcm( uint8_t tag_length,
uint8_t* tag );
/*
* HW_AES_SetLast
*
* Function used in CCM processing to indicate the last block of data in
* case of decryption
*
*/
extern void HW_AES_SetLast( uint8_t left_length );
/* ---------------------------------------------------------------------------
* PKA
* ---------------------------------------------------------------------------
*/
extern int PKA_MutexTake(void);
extern int PKA_MutexRelease(void);
/*
* HW_PKA_Enable
*
* Enables the PKA hardware block.
* If the driver is already in used, the function returns 0 immediately.
* If the PKA semaphore is available, this function locks the PKA semaphore,
* otherwise it returns 0.
* Then, when PKA semaphore is locked, the function enables PKA security,
* PKA clock and the block itself.
* This function must not be directly called when using P-256 elliptic curve
* dedicated functions.
* Be careful: no re-entrance is ensured for the HW_PKA functions
*/
extern int HW_PKA_Enable( void );
/*
* HW_PKA_WriteSingleInput
*
* Writes one single word into the PKA memory.
* This function must not be directly called when using P-256 elliptic curve
* dedicated functions.
*/
extern void HW_PKA_WriteSingleInput( uint32_t index,
uint32_t word );
/*
* HW_PKA_WriteOperand
*
* Writes one operand of size 'n' 32-bit words into the PKA memory.
* This function must not be directly called when using P-256 elliptic curve
* dedicated functions.
*/
extern void HW_PKA_WriteOperand( uint32_t index,
int size,
const uint32_t* in );
/*
* HW_PKA_Start
*
* Starts the PKA operation with mode defined by the parameter "mode".
* This function must not be directly called when using P-256 elliptic curve
* dedicated functions.
*
* "mode" can be one of the LL_PKA_MODE... definitions that can be found
* in "stm32wbxx_ll_pka.h" file.
*/
extern void HW_PKA_Start( uint32_t mode );
/*
* HW_PKA_EndOfOperation
*
* Returns 0 if the PKA processing is still active.
* Returns a value different from 0 when the PKA processing is complete.
*/
extern int HW_PKA_EndOfOperation( void );
/*
* HW_PKA_ReadSingleOutput
*
* Reads one 32-bit word result from the PKA memory.
* This function must not be directly called when using P-256 elliptic curve
* dedicated functions.
*/
extern uint32_t HW_PKA_ReadSingleOutput( uint32_t index );
/*
* HW_PKA_ReadResult
*
* Reads one multi-word result ("size" x 32-bit words) from the PKA memory.
* This function must not be directly called when using P-256 elliptic curve
* dedicated functions.
*/
extern void HW_PKA_ReadResult( uint32_t index,
int size,
uint32_t* out );
/*
* HW_PKA_Disable
*
* Disables the PKA hardware block.
* This function disables also the PKA clock and the PKA security.
* It then releases the PKA semaphore.
*/
extern void HW_PKA_Disable( void );
/*
* Notes:
*
* - this driver uses a semaphore to handle access to the PKA. The index of
* the semaphore must be configured with CFG_HW_PKA_SEMID.
*/
/* ---------------------------------------------------------------------------
* PKA_P256
* ---------------------------------------------------------------------------
*/
/*
* HW_PKA_P256_StartRangeCheck
*
* Starts the range check of a point coordinate for P-256 elliptic curve.
*
* This function sets the parameters in PKA memory and then starts the
* processing. The PKA has to be enabled before with HW_PKA_Enable( ).
* The user must poll on the result availability by calling the
* HW_PKA_EndOfOperation() function.
*
* The input parameter is one the point coordinate. It must be a vector of
* 8 x 32-bit words (32 bytes).
*
* The check result is retrieved by calling HW_PKA_P256_IsRangeCheckOk().
*/
extern void HW_PKA_P256_StartRangeCheck( const uint32_t* coord );
/*
* HW_PKA_P256_IsRangeCheckOk
*
* Reads the result of P-256 range check. This function must only be called
* when HW_PKA_EndOfOperation() returns a non-zero value.
*
* Returns 0 if the check fails ; 1 otherwise.
*/
extern uint32_t HW_PKA_P256_IsRangeCheckOk( void );
/*
* HW_PKA_P256_StartPointCheck
*
* Starts the check of a point for P-256 elliptic curve.
*
* This function sets the parameters in PKA memory and then starts the
* processing. The PKA has to be enabled before with HW_PKA_Enable( ).
* The user must poll on the result availability by calling the
* HW_PKA_EndOfOperation() function.
*
* The input parameters are the point coordinates. Each parameter must be a
* vector of 8 x 32-bit words (32 bytes).
*
* The check result is retrieved by calling HW_PKA_P256_IsPointCheckOk().
*/
extern void HW_PKA_P256_StartPointCheck( const uint32_t* x,
const uint32_t* y );
/*
* HW_PKA_P256_IsPointCheckOk
*
* Reads the result of P-256 point check. This function must only be called
* when HW_PKA_EndOfOperation() returns a non-zero value.
*
* Returns 0 if the check fails ; 1 otherwise.
*/
extern uint32_t HW_PKA_P256_IsPointCheckOk( void );
/*
* HW_PKA_P256_StartEccScalarMul
*
* Starts the PKA scalar multiplication using the P-256 elliptic curve.
*
* This function sets the parameters in PKA memory and then starts the
* processing. The PKA has to be enabled before with HW_PKA_Enable( ).
* The user must poll on the result availability by calling the
* HW_PKA_EndOfOperation() function.
*
* The input parameter is the starting point P defined by its 2 coordinates
* p_x and p_y, and the scalar k. Each parameter must be a vector of 8 x 32-bit
* words (32 bytes).
*/
extern void HW_PKA_P256_StartEccScalarMul( const uint32_t* k,
const uint32_t* p_x,
const uint32_t* p_y );
/*
* HW_PKA_P256_ReadEccScalarMul
*
* Reads the result of PKA scalar multiplication using the P-256 elliptic
* curve. This function must only be called when HW_PKA_EndOfOperation()
* returns a non-zero value.
*
* This function retrieves the result from PKA memory: coordinates of point P,
* p_x and p_y, 8 x 32-bit words each (2 times 32 bytes).
* Before returning, it disables the PKA block, releasing the PKA semaphore.
*/
extern void HW_PKA_P256_ReadEccScalarMul( uint32_t* p_x,
uint32_t* p_y );
/* ---------------------------------------------------------------------------
* RNG
* ---------------------------------------------------------------------------
*/
/*
* The RNG driver is made to generate the random numbers in background instead
* of generating them each time they are needed by the application.
* Thus, the function HW_RNG_Process() must be called regularly in background
* loop to generate a pool of random numbers. The function HW_RNG_Get() reads
* the random numbers from the pool.
* The size of the pool must be configured with HW_RNG_POOL_SIZE.
*/
/* Error codes definition for HW_RNG return values */
enum
{
HW_RNG_CLOCK_ERROR = CFG_HW_ERROR_OFFSET + 0x101,
HW_RNG_NOISE_ERROR = CFG_HW_ERROR_OFFSET + 0x102,
HW_RNG_UFLOW_ERROR = CFG_HW_ERROR_OFFSET + 0x103,
};
/* RNG pool size */
#define HW_RNG_POOL_SIZE (CFG_HW_RNG_POOL_SIZE)
/* Default threshold to refill RNG pool */
#define HW_RNG_POOL_DEFAULT_THRESHOLD (12)
extern int RNG_MutexTake(void);
extern int RNG_MutexRelease(void);
/* RNG_KERNEL_CLK_ON
*
* Enable RNG kernel clock.
*/
void RNG_KERNEL_CLK_ON(void);
/* RNG_KERNEL_CLK_OFF
*
* Called when RNG kernel clock may be disabled.
* Weak function to be implemented by user.
*/
void RNG_KERNEL_CLK_OFF(void);
/* HW_RNG_Disable
*
* Disables the RNG peripheral and switch off its clock in RCC.
*/
extern void HW_RNG_Disable( void );
/* HW_RNG_Start
*
* Starts the generation of random numbers using the RNG IP. This function has
* to be called only once at reset before calling HW_RNG_Get() to retrieve
* the generated random values.
*/
extern void HW_RNG_Start( void );
/*
* HW_RNG_Get
*
* Retrieves "n" random 32-bit words.
* "n" must be in the range [1, CFG_HW_RNG_POOL_SIZE].
* The random numbers are written in memory from "val" pointer.
* "val" must point to a sufficient memory buffer allocated by the caller.
*/
extern void HW_RNG_Get( uint8_t n,
uint32_t* val );
/*
* HW_RNG_Process
*
* This function must be called in a separate task or in "background" loop.
* It implements a simple state machine that enables the RNG block,
* generates random numbers and then disables the RNG.
* It returns 0 (HW_OK) if the low power mode can be entered.
* It returns HW_BUSY as long as this function must be called.
* In error conditions, it returns one of the following error codes:
* - HW_RNG_CLOCK_ERROR for clock error,
* - HW_RNG_NOISE_ERROR for noise source error;
* the hardware must then be reset.
* - HW_RNG_UFLOW_ERROR in case of pool underflow error.
*/
extern int HW_RNG_Process( void );
/*
* HW_RNG_EnableClock
*
* This function enables the RNG clock for "other user" than RNG driver itself
*/
extern void HW_RNG_EnableClock( uint8_t user_mask );
/*
* HW_RNG_DisableClock
*
* This function disables the RNG clock for "other user" than RNG driver itself
*/
extern void HW_RNG_DisableClock( uint8_t user_mask );
extern void HWCB_RNG_Process( void );
/*
* HW_RNG_Init
*
* This function initializes RNG (clock, configuration ...)
*/
extern void HW_RNG_Init(void);
/*
* HW_RNG_Init
*
* Sets RNG pool threshold (for refill)
*/
extern void HW_RNG_SetPoolThreshold(uint8_t threshold);
/* ---------------------------------------------------------------------------
* GPIO
* ---------------------------------------------------------------------------
*/
/* Index definitions used for all GPIO functions */
enum
{
HW_GPIO_DBG = 0,
HW_GPIO_GREEN_LED = 13,
HW_GPIO_RED_LED = 14,
HW_GPIO_BLUE_LED = 15,
};
/*
* HW_GPIO_Init
*
* This function initilaizes the GPIO pins used for debug.
*/
extern void HW_GPIO_Init( const uint32_t* dbg_pins );
/*
* HW_GPIO_Read
*
* This function reads the output pin which index is given in parameter.
* It returns 0 if the pin is low, 1 if the pin is high.
*/
extern uint8_t HW_GPIO_Read( uint8_t index );
/*
* HW_GPIO_Set
*
* This function sets to high level the output pin which index is given
* in parameter.
*/
extern void HW_GPIO_Set( uint8_t index );
/*
* HW_GPIO_Reset
*
* This function resets to low level the output pin which index is given
* in parameter.
*/
extern void HW_GPIO_Reset( uint8_t index );
extern void GPIO_SetDebug( int gpio_pin,
int pin_value );
/* ---------------------------------------------------------------------------
* OTP
* ---------------------------------------------------------------------------
*/
typedef __PACKED_STRUCT
{
uint8_t additional_data[8]; /*!< 64 bits of data to fill OTP slot */
uint8_t bd_address[6]; /*!< Bluetooth Device Address*/
uint8_t hsetune; /*!< Load capacitance to be applied on HSE pad */
uint8_t index; /*!< Structure index */
} HW_OTP_data_t;
/*
* HW_OTP_Read
*
* Read the OTP
*
*/
int HW_OTP_Read( uint8_t index,
HW_OTP_data_t** data );
/*
* HW_OTP_Write
*
* ReadWrite the OTP
*
*/
int HW_OTP_Write( uint8_t* additional_data,
uint8_t* bd_address,
uint8_t hsetune,
uint8_t index );
#ifdef __cplusplus
}
#endif
#endif /* HW_H__ */

View File

@@ -0,0 +1,332 @@
/**
******************************************************************************
* @file hw_aes.c
* @author MCD Application Team
* @brief This file contains the AES driver for STM32WBA
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "app_common.h"
#include "stm32wbaxx_ll_bus.h"
/*****************************************************************************/
extern void Error_Handler(void);
/*****************************************************************************/
#define HW_AESX AES
#define HW_AES_CLOCK_ENABLE( ) LL_AHB2_GRP1_EnableClock( LL_AHB2_GRP1_PERIPH_AES )
#define HW_AES_CLOCK_DISABLE( ) LL_AHB2_GRP1_DisableClock( LL_AHB2_GRP1_PERIPH_AES )
#define HW_AES_CLOCK_IS_ENABLE( ) LL_AHB2_GRP1_IsEnabledClock( LL_AHB2_GRP1_PERIPH_AES )
#define AES_BLOCK_SIZE_WORD (4U)
#define AES_BLOCK_SIZE_BYTE (16U)
/*****************************************************************************/
typedef struct
{
uint8_t run;
} HW_AES_VAR_T;
/*****************************************************************************/
static HW_AES_VAR_T HW_AES_var;
/*****************************************************************************/
__WEAK int CRYP_MutexTake(void)
{
return 0; /* This shall be implemented by user */
}
__WEAK int CRYP_MutexRelease(void)
{
return 0; /* This shall be implemented by user */
}
/*****************************************************************************/
int HW_AES_Enable( void )
{
HW_AES_VAR_T* av = &HW_AES_var;
if (0 != CRYP_MutexTake())
{
return FALSE;
}
/* Test if the driver is not already in use */
if ( HW_AES_CLOCK_IS_ENABLE() )
{
if (0 != CRYP_MutexRelease())
{
Error_Handler();
}
return FALSE;
}
av->run = TRUE;
UTILS_ENTER_CRITICAL_SECTION( );
/* Enable AES clock */
HW_AES_CLOCK_ENABLE( );
UTILS_EXIT_CRITICAL_SECTION( );
return TRUE;
}
/*****************************************************************************/
void HW_AES_SetKey( uint32_t mode,
const uint8_t* key )
{
uint32_t tmp[4];
/* Retrieve all bytes of key */
memcpy( tmp, key, 16 );
/* Initialize the AES peripheral with default values:
- Processing: disabled
- Data type: 32-bit
- Operating mode: encryption
- Chaining mode: ECB
- Key size: 128-bit
*/
HW_AESX->CR = 0;
/* Copy key bytes to the AES registers */
if ( mode & HW_AES_REV )
{
HW_AESX->KEYR0 = tmp[0];
HW_AESX->KEYR1 = tmp[1];
HW_AESX->KEYR2 = tmp[2];
HW_AESX->KEYR3 = tmp[3];
}
else
{
HW_AESX->KEYR3 = __REV( tmp[0] );
HW_AESX->KEYR2 = __REV( tmp[1] );
HW_AESX->KEYR1 = __REV( tmp[2] );
HW_AESX->KEYR0 = __REV( tmp[3] );
}
if ( !(mode & HW_AES_ENC) )
{
/* Set key preparation mode */
HW_AESX->CR = AES_CR_MODE_0;
/* Enable AES processing */
HW_AESX->CR |= AES_CR_EN;
/* Wait for CCF flag to be raised */
while ( ! (HW_AESX->ISR & AES_ISR_CCF) );
/* Clear CCF Flag */
HW_AESX->ICR |= AES_ICR_CCF;
/* Set decryption mode */
HW_AESX->CR = AES_CR_MODE_1;
}
/* Enable byte swapping if needed */
if ( mode & HW_AES_SWAP )
HW_AESX->CR |= AES_CR_DATATYPE_1;
/* Wait until KEYVALID is set */
while ( !(HW_AESX->SR & AES_SR_KEYVALID) );
/* Enable AES processing */
HW_AESX->CR |= AES_CR_EN;
}
/*****************************************************************************/
void HW_AES_Crypt( const uint32_t* input,
uint32_t* output )
{
/* Write the input block into the input FIFO */
HW_AESX->DINR = input[0];
HW_AESX->DINR = input[1];
HW_AESX->DINR = input[2];
HW_AESX->DINR = input[3];
/* Wait for CCF flag to be raised */
while ( !(HW_AESX->ISR & AES_ISR_CCF) );
/* Read the output block from the output FIFO */
output[0] = HW_AESX->DOUTR;
output[1] = HW_AESX->DOUTR;
output[2] = HW_AESX->DOUTR;
output[3] = HW_AESX->DOUTR;
/* Clear CCF Flag */
HW_AESX->ICR |= AES_ICR_CCF;
}
/*****************************************************************************/
void HW_AES_Disable( void )
{
HW_AES_VAR_T* av = &HW_AES_var;
if ( av->run )
{
/* Disable AES processing */
HW_AESX->CR = 0;
UTILS_ENTER_CRITICAL_SECTION( );
/* Disable AES clock */
HW_AES_CLOCK_DISABLE( );
UTILS_EXIT_CRITICAL_SECTION( );
if (0 != CRYP_MutexRelease())
{
Error_Handler();
}
av->run = FALSE;
}
}
/*****************************************************************************/
void HW_AES_Crypt8( const uint8_t * pInput, uint8_t * pOutput )
{
uint32_t pTemp[AES_BLOCK_SIZE_WORD];
// Transfer 8 -> 32 bits */
memcpy( pTemp, pInput, AES_BLOCK_SIZE_BYTE );
/* Write the input block into the input FIFO */
HW_AESX->DINR = __REV( pTemp[0] );
HW_AESX->DINR = __REV( pTemp[1] );
HW_AESX->DINR = __REV( pTemp[2] );
HW_AESX->DINR = __REV( pTemp[3] );
// -- Wait for CCF flag to be raised /
while ( (HW_AESX->ISR & AES_ISR_CCF) == 0x00u )
{ }
/* Read the output block from the output FIFO */
pTemp[0] = __REV( HW_AESX->DOUTR );
pTemp[1] = __REV( HW_AESX->DOUTR );
pTemp[2] = __REV( HW_AESX->DOUTR );
pTemp[3] = __REV( HW_AESX->DOUTR );
/* Transfer 32 -> 8 bits */
memcpy( pOutput, pTemp, AES_BLOCK_SIZE_BYTE );
/* Clear CCF Flag */
HW_AESX->ICR |= AES_ICR_CCF;
}
/*****************************************************************************/
void HW_AES_InitCcm( uint8_t decrypt,
const uint8_t* key,
const uint32_t* b0,
const uint32_t* b1 )
{
uint32_t tmp[4], mode = decrypt ? AES_CR_MODE_1 : 0;
/* CCM init phase */
HW_AESX->CR = AES_CR_CHMOD_2 | mode;
/* Copy key bytes to the AES registers */
memcpy( tmp, key, 16 );
HW_AESX->KEYR0 = tmp[0];
HW_AESX->KEYR1 = tmp[1];
HW_AESX->KEYR2 = tmp[2];
HW_AESX->KEYR3 = tmp[3];
/* Copy B0 bytes to the AES registers */
HW_AESX->IVR3 = __REV( b0[0] );
HW_AESX->IVR2 = __REV( b0[1] );
HW_AESX->IVR1 = __REV( b0[2] );
HW_AESX->IVR0 = __REV( b0[3] );
/* Enable AES processing */
HW_AESX->CR |= AES_CR_EN;
/* Wait for CCF flag to be raised */
while ( ! (HW_AESX->ISR & AES_ISR_CCF) );
/* Clear CCF Flag */
HW_AESX->ICR |= AES_ICR_CCF;
/* CCM header phase */
HW_AESX->CR = AES_CR_CHMOD_2 | AES_CR_GCMPH_0 | AES_CR_DATATYPE_1;
/* Enable AES processing */
HW_AESX->CR |= AES_CR_EN;
/* Write the header block B1 into the input FIFO */
HW_AESX->DINR = b1[0];
HW_AESX->DINR = b1[1];
HW_AESX->DINR = b1[2];
HW_AESX->DINR = b1[3];
/* Wait for CCF flag to be raised */
while ( !(HW_AESX->ISR & AES_ISR_CCF) );
/* Clear CCF Flag */
HW_AESX->ICR |= AES_ICR_CCF;
/* CCM payload phase */
HW_AESX->CR = (AES_CR_EN | AES_CR_CHMOD_2 |
AES_CR_GCMPH_1 | AES_CR_DATATYPE_1 | mode);
}
/*****************************************************************************/
void HW_AES_EndCcm( uint8_t tag_length,
uint8_t* tag )
{
uint32_t tmp[4];
/* CCM final phase */
HW_AESX->CR = (AES_CR_EN | AES_CR_CHMOD_2 |
AES_CR_GCMPH_0 | AES_CR_GCMPH_1 | AES_CR_DATATYPE_1);
/* Wait for CCF flag to be raised */
while ( !(HW_AESX->ISR & AES_ISR_CCF) );
/* Read the output block from the output FIFO */
tmp[0] = HW_AESX->DOUTR;
tmp[1] = HW_AESX->DOUTR;
tmp[2] = HW_AESX->DOUTR;
tmp[3] = HW_AESX->DOUTR;
memcpy( tag, tmp, tag_length );
/* Clear CCF Flag */
HW_AESX->ICR |= AES_ICR_CCF;
}
/*****************************************************************************/
void HW_AES_SetLast( uint8_t left_length )
{
HW_AESX->CR |= (16UL - left_length) << AES_CR_NPBLB_Pos;
}
/*****************************************************************************/

View File

@@ -0,0 +1,67 @@
/**
******************************************************************************
* @file hw_if.h
* @author MCD Application Team
* @brief Hardware Interface
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef HW_IF_H
#define HW_IF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32wbaxx.h"
#include "stm32wbaxx_hal_conf.h"
#include "stm32wbaxx_hal_def.h"
#include "stm32wbaxx_ll_exti.h"
#include "stm32wbaxx_ll_system.h"
#include "stm32wbaxx_ll_rcc.h"
#include "stm32wbaxx_ll_bus.h"
#include "stm32wbaxx_ll_pwr.h"
#include "stm32wbaxx_ll_cortex.h"
#include "stm32wbaxx_ll_utils.h"
#include "stm32wbaxx_ll_gpio.h"
#include "stm32wbaxx_ll_rtc.h"
/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
#ifdef __cplusplus
}
#endif
#endif /*HW_IF_H */

View File

@@ -0,0 +1,101 @@
/**
******************************************************************************
* @file hw_otp.c
* @author MCD Application Team
* @brief This file contains the OTP driver.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "app_common.h"
#include "stm32wbaxx_hal.h"
/*****************************************************************************/
int HW_OTP_Read( uint8_t index, HW_OTP_data_t ** otp_ptr )
{
/* OTP data:
* additional_data 8 bytes LSB
* bd_address 6 bytes
* hsetune 1 byte
* index 1 byte MSB
*/
*otp_ptr = (HW_OTP_data_t*)(FLASH_OTP_BASE + FLASH_OTP_SIZE - 16);
while ( ( (*otp_ptr)->index != index ) &&
( (*otp_ptr) != (HW_OTP_data_t*) FLASH_OTP_BASE ) )
{
(*otp_ptr) -= 1;
}
if ( (*otp_ptr)->index != index )
{
return 1; /* error */
}
return HW_OK;
}
/*****************************************************************************/
int HW_OTP_Write( uint8_t* additional_data,
uint8_t* bd_address,
uint8_t hsetune,
uint8_t index )
{
int err = 1; /* error */
HW_OTP_data_t otp;
int i;
/* Fill OTP_Data_s structure */
for ( i = 0; i < sizeof(otp.additional_data); i++ )
{
otp.additional_data[i] = additional_data[i];
}
for ( i = 0; i < sizeof(otp.bd_address); i++ )
{
otp.bd_address[i] = bd_address[i];
}
otp.hsetune = hsetune;
otp.index = index;
/* Find free space */
uint32_t free_address = FLASH_OTP_BASE;
while ( ( *(uint64_t*)(free_address) != 0xFFFFFFFFFFFFFFFFUL ) &&
( *(uint64_t*)(free_address + 8u) != 0xFFFFFFFFFFFFFFFFUL ) &&
( (free_address + 16u) != FLASH_OTP_BASE + FLASH_OTP_SIZE ) )
{
free_address += 16;
}
if ( ( *(uint64_t*)(free_address) != 0xFFFFFFFFFFFFFFFFUL ) &&
( *(uint64_t*)(free_address + 8u) != 0xFFFFFFFFFFFFFFFFUL ) )
{
return 1; /* error */
}
/* Store OTP structure in OTP area */
/* Clear all Flash flags before write operation*/
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
err = HAL_FLASH_Unlock( );
err |= HAL_FLASH_Program( FLASH_NSCR1_PG,
free_address, (uint32_t)&otp );
err |= HAL_FLASH_Lock( );
return err;
}
/*****************************************************************************/

View File

@@ -0,0 +1,196 @@
/**
******************************************************************************
* @file hw_pka.c
* @author MCD Application Team
* @brief This file contains the PKA driver for STM32WBA
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "app_common.h"
#include "stm32wbaxx_ll_bus.h"
#include "stm32wbaxx_ll_pka.h"
/*****************************************************************************/
extern void Error_Handler(void);
/*****************************************************************************/
typedef struct
{
uint8_t run;
} HW_PKA_VAR_T;
/*****************************************************************************/
static HW_PKA_VAR_T HW_PKA_var;
/*****************************************************************************/
__WEAK int PKA_MutexTake(void)
{
return 0; /* This shall be implemented by user */
}
__WEAK int PKA_MutexRelease(void)
{
return 0; /* This shall be implemented by user */
}
/*****************************************************************************/
int HW_PKA_Enable( void )
{
HW_PKA_VAR_T* pv = &HW_PKA_var;
/* Test if the driver is not already in use */
if ( pv->run )
{
return FALSE;
}
if (0 != PKA_MutexTake())
{
return FALSE;
}
pv->run = TRUE;
/* Enable the RNG clock as it is needed.
* See PKA chapter in IUM: the RNG peripheral must be clocked.
*/
HW_RNG_EnableClock( 2 );
UTILS_ENTER_CRITICAL_SECTION( );
/* Enable the PKA clock */
LL_AHB2_GRP1_EnableClock( LL_AHB2_GRP1_PERIPH_PKA );
UTILS_EXIT_CRITICAL_SECTION( );
/* Enable the PKA block */
LL_PKA_Enable( PKA );
/* Wait for PKA initialization OK */
while ( !(PKA->SR & PKA_SR_INITOK) );
/* Reset any pending flag */
SET_BIT(PKA->CLRFR, (PKA_CLRFR_PROCENDFC | PKA_CLRFR_RAMERRFC |
PKA_CLRFR_ADDRERRFC | PKA_CLRFR_OPERRFC));
/* Disable the RNG clock as it is no more needed ???
*/
HW_RNG_DisableClock( 2 );
return TRUE;
}
/*****************************************************************************/
void HW_PKA_WriteSingleInput( uint32_t index, uint32_t word )
{
/* Write the single word into PKA RAM */
PKA->RAM[index] = word;
}
/*****************************************************************************/
void HW_PKA_WriteOperand( uint32_t index, int size, const uint32_t* in )
{
uint32_t* pka_ram = (uint32_t*)&PKA->RAM[index];
/* Write the input data into PKA RAM */
for ( ; size > 0; size-- )
{
*pka_ram++ = *in++;
}
/* Write extra zeros into PKA RAM */
*pka_ram = 0;
}
/*****************************************************************************/
void HW_PKA_Start( uint32_t mode )
{
/* Set the configuration */
LL_PKA_Config( PKA, mode );
/* Start the PKA processing */
LL_PKA_ClearFlag_PROCEND( PKA );
LL_PKA_Start( PKA );
}
/*****************************************************************************/
int HW_PKA_EndOfOperation( void )
{
/* Return 0 if the processing is still active */
return LL_PKA_IsActiveFlag_PROCEND( PKA );
}
/*****************************************************************************/
uint32_t HW_PKA_ReadSingleOutput( uint32_t index )
{
/* Read a single word from PKA RAM */
return PKA->RAM[index];
}
/*****************************************************************************/
void HW_PKA_ReadResult( uint32_t index, int size, uint32_t* out )
{
uint32_t* pka_ram = (uint32_t*)&PKA->RAM[index];
/* Read from PKA RAM */
for ( ; size > 0; size-- )
{
*out++ = *pka_ram++;
}
}
/*****************************************************************************/
void HW_PKA_Disable( void )
{
HW_PKA_VAR_T* pv = &HW_PKA_var;
if ( pv->run )
{
/* Disable the PKA block */
LL_PKA_Disable( PKA );
UTILS_ENTER_CRITICAL_SECTION( );
/* Disable the PKA clock */
LL_AHB2_GRP1_DisableClock( LL_AHB2_GRP1_PERIPH_PKA );
UTILS_EXIT_CRITICAL_SECTION( );
if (0 != PKA_MutexRelease())
{
Error_Handler();
}
pv->run = FALSE;
}
}
/*****************************************************************************/

View File

@@ -0,0 +1,235 @@
/**
******************************************************************************
* @file hw_pka_p256.c
* @author MCD Application Team
* @brief This file is an optional part of the PKA driver for STM32WBA.
* It is dedicated to the P256 elliptic curve.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "app_common.h"
#include "stm32wbaxx_ll_pka.h"
/*****************************************************************************/
static const uint32_t HW_PKA_P256_gfp[8] =
{
0xFFFFFFFF, /* LSB */
0xFFFFFFFF,
0xFFFFFFFF,
0x00000000,
0x00000000,
0x00000000,
0x00000001,
0xFFFFFFFF,
};
static const uint32_t HW_PKA_P256_r2[8] =
{
0x00000002, /* LSB */
0x00000005,
0x00000003,
0xFFFFFFFE,
0xFFFFFFF9,
0xFFFFFFFB,
0xFFFFFFFC,
0xFFFFFFFC,
};
static const uint32_t HW_PKA_P256_p_x[8] =
{
0xD898C296, /* LSB */
0xF4A13945,
0x2DEB33A0,
0x77037D81,
0x63A440F2,
0xF8BCE6E5,
0xE12C4247,
0x6B17D1F2,
};
static const uint32_t HW_PKA_P256_p_y[8] =
{
0x37BF51F5, /* LSB */
0xCBB64068,
0x6B315ECE,
0x2BCE3357,
0x7C0F9E16,
0x8EE7EB4A,
0xFE1A7F9B,
0x4FE342E2,
};
static const uint32_t HW_PKA_P256_a[8] =
{
0x00000003, /* LSB */
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
0x00000000,
};
static const uint32_t HW_PKA_P256_b[8] =
{
0x27D2604B, /* LSB */
0x3BCE3C3E,
0xCC53B0F6,
0x651D06B0,
0x769886BC,
0xB3EBBD55,
0xAA3A93E7,
0x5AC635D8,
};
static const uint32_t HW_PKA_P256_n[8] =
{
0XFC632551, /* LSB */
0XF3B9CAC2,
0XA7179E84,
0XBCE6FAAD,
0XFFFFFFFF,
0XFFFFFFFF,
0X00000000,
0XFFFFFFFF
};
/*****************************************************************************/
void HW_PKA_P256_StartRangeCheck( const uint32_t* coord )
{
/* Set the muber of bits of P */
HW_PKA_WriteSingleInput( PKA_COMPARISON_IN_OP_NB_BITS, 256 );
/* Set the coordinate */
HW_PKA_WriteOperand( PKA_COMPARISON_IN_OP1, 8, coord );
/* Set the modulus value p */
HW_PKA_WriteOperand( PKA_COMPARISON_IN_OP2, 8, HW_PKA_P256_gfp );
/* Start PKA hardware */
HW_PKA_Start( LL_PKA_MODE_COMPARISON );
}
/*****************************************************************************/
uint32_t HW_PKA_P256_IsRangeCheckOk( void )
{
return (HW_PKA_ReadSingleOutput( PKA_COMPARISON_OUT_RESULT ) == 0x916AUL);
}
/*****************************************************************************/
void HW_PKA_P256_StartPointCheck( const uint32_t* x,
const uint32_t* y )
{
/* Set the muber of bits of p */
HW_PKA_WriteSingleInput( PKA_POINT_CHECK_IN_MOD_NB_BITS, 256 );
/* Set the coefficient a sign */
HW_PKA_WriteSingleInput( PKA_POINT_CHECK_IN_A_COEFF_SIGN, 1 );
/* Set the coefficient |a| */
HW_PKA_WriteOperand( PKA_POINT_CHECK_IN_A_COEFF, 8, HW_PKA_P256_a );
/* Set the coefficient b */
HW_PKA_WriteOperand( PKA_POINT_CHECK_IN_B_COEFF, 8, HW_PKA_P256_b );
/* Set the modulus value p */
HW_PKA_WriteOperand( PKA_POINT_CHECK_IN_MOD_GF, 8, HW_PKA_P256_gfp );
/* Set the point coordinate x */
HW_PKA_WriteOperand( PKA_POINT_CHECK_IN_INITIAL_POINT_X, 8, x );
/* Set the point coordinate y */
HW_PKA_WriteOperand( PKA_POINT_CHECK_IN_INITIAL_POINT_Y, 8, y );
/* Set the Montgomery parameter */
HW_PKA_WriteOperand( PKA_POINT_CHECK_IN_MONTGOMERY_PARAM,
8, HW_PKA_P256_r2 );
/* Start PKA hardware */
HW_PKA_Start( LL_PKA_MODE_POINT_CHECK );
}
/*****************************************************************************/
uint32_t HW_PKA_P256_IsPointCheckOk( void )
{
return (HW_PKA_ReadSingleOutput( PKA_POINT_CHECK_OUT_ERROR ) == 0xD60DUL);
}
/*****************************************************************************/
void HW_PKA_P256_StartEccScalarMul( const uint32_t* k,
const uint32_t* p_x,
const uint32_t* p_y )
{
/* Set the scalar multiplier k length */
HW_PKA_WriteSingleInput( PKA_ECC_SCALAR_MUL_IN_EXP_NB_BITS, 256 );
/* Set the modulus length */
HW_PKA_WriteSingleInput( PKA_ECC_SCALAR_MUL_IN_OP_NB_BITS, 256 );
/* Set the coefficient a sign */
HW_PKA_WriteSingleInput( PKA_ECC_SCALAR_MUL_IN_A_COEFF_SIGN, 1 );
/* Set the coefficient |a| */
HW_PKA_WriteOperand( PKA_ECC_SCALAR_MUL_IN_A_COEFF, 8, HW_PKA_P256_a );
/* Set the coefficient b */
HW_PKA_WriteOperand( PKA_ECC_SCALAR_MUL_IN_B_COEFF, 8, HW_PKA_P256_b );
/* Set the modulus value p */
HW_PKA_WriteOperand( PKA_ECC_SCALAR_MUL_IN_MOD_GF, 8, HW_PKA_P256_gfp );
/* Set the scalar multiplier k */
HW_PKA_WriteOperand( PKA_ECC_SCALAR_MUL_IN_K, 8, k );
/* Set the point P coordinate x */
HW_PKA_WriteOperand( PKA_ECC_SCALAR_MUL_IN_INITIAL_POINT_X,
8, p_x ? p_x : HW_PKA_P256_p_x );
/* Set the point P coordinate y */
HW_PKA_WriteOperand( PKA_ECC_SCALAR_MUL_IN_INITIAL_POINT_Y,
8, p_y ? p_y : HW_PKA_P256_p_y );
/* Set the prime order n */
HW_PKA_WriteOperand( PKA_ECC_SCALAR_MUL_IN_N_PRIME_ORDER,
8, HW_PKA_P256_n );
/* Start PKA hardware */
HW_PKA_Start( LL_PKA_MODE_ECC_MUL );
}
/*****************************************************************************/
void HW_PKA_P256_ReadEccScalarMul( uint32_t* p_x,
uint32_t* p_y )
{
/* Read the output point X */
if ( p_x )
{
HW_PKA_ReadResult( PKA_ECC_SCALAR_MUL_OUT_RESULT_X, 8, p_x );
}
/* Read the output point Y as the second half of the result */
if ( p_y )
{
HW_PKA_ReadResult( PKA_ECC_SCALAR_MUL_OUT_RESULT_Y, 8, p_y );
}
}
/*****************************************************************************/

View File

@@ -0,0 +1,388 @@
/**
******************************************************************************
* @file hw_rng.c
* @author MCD Application Team
* @brief This file contains the RNG driver for STM32WBA
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "app_common.h"
#include "stm32wbaxx_ll_bus.h"
#include "stm32wbaxx_ll_rng.h"
#include "RTDebug.h"
/*****************************************************************************/
extern void Error_Handler(void);
/*****************************************************************************/
__WEAK int RNG_MutexTake(void)
{
return 0; /* This shall be implemented by user */
}
__WEAK int RNG_MutexRelease(void)
{
return 0; /* This shall be implemented by user */
}
/*****************************************************************************/
__weak void RNG_KERNEL_CLK_ON(void)
{
/* NOTE : This function should not be modified, when the callback is needed,
the RNG_KERNEL_CLK_ON could be implemented in the user file
*/
LL_RCC_HSI_Enable();
while(LL_RCC_HSI_IsReady() == 0)
{
LL_RCC_HSI_Enable();
}
}
__weak void RNG_KERNEL_CLK_OFF(void)
{
/* NOTE : This function should not be modified, when the callback is needed,
the RNG_KERNEL_CLK_OFF could be implemented in the user file
*/
}
/*****************************************************************************/
typedef struct
{
uint32_t pool[HW_RNG_POOL_SIZE];
uint8_t size;
uint8_t run;
uint8_t clock_en;
int error;
} HW_RNG_VAR_T;
/*****************************************************************************/
static HW_RNG_VAR_T HW_RNG_var;
static uint8_t hw_rng_pool_threshold = HW_RNG_POOL_DEFAULT_THRESHOLD;
/*****************************************************************************/
static void HW_RNG_WaitingClockSynchronization( void );
/*****************************************************************************/
void HW_RNG_Disable( void )
{
SYSTEM_DEBUG_SIGNAL_SET(RNG_DISABLE);
LL_RNG_Disable( RNG );
/* Disable RNG clocks */
HW_RNG_DisableClock( 1 );
SYSTEM_DEBUG_SIGNAL_RESET(RNG_DISABLE);
}
/*****************************************************************************/
void HW_RNG_EnableClock( uint8_t user_mask )
{
HW_RNG_VAR_T* pv = &HW_RNG_var;
RNG_KERNEL_CLK_ON();
UTILS_ENTER_CRITICAL_SECTION( );
if ( pv->clock_en == 0 )
{
LL_AHB2_GRP1_EnableClock( LL_AHB2_GRP1_PERIPH_RNG );
}
pv->clock_en |= user_mask;
UTILS_EXIT_CRITICAL_SECTION( );
}
/*****************************************************************************/
void HW_RNG_DisableClock( uint8_t user_mask )
{
HW_RNG_VAR_T* pv = &HW_RNG_var;
{
UTILS_ENTER_CRITICAL_SECTION( );
pv->clock_en &= ~user_mask;
UTILS_EXIT_CRITICAL_SECTION( );
}
/* It does not matter much if the temporisation is executed even though
* in the meantime pv->clock_en has been updated and is not more equal to 0
*/
if ( pv->clock_en == 0 )
{
HW_RNG_WaitingClockSynchronization( );
}
{
UTILS_ENTER_CRITICAL_SECTION( );
if ( pv->clock_en == 0 )
{
LL_AHB2_GRP1_DisableClock( LL_AHB2_GRP1_PERIPH_RNG );
}
UTILS_EXIT_CRITICAL_SECTION( );
}
RNG_KERNEL_CLK_OFF();
}
/*****************************************************************************/
/*
* Wait for 2 RNG kernel clock.
* Loop is sized with worst case : RNG kernel clock = 32Khz
*/
static void HW_RNG_WaitingClockSynchronization( void )
{
/* RNG busy flag is not available in STM32WBA5xxx */
#if defined(STM32WBA52xx) || defined(STM32WBA54xx) || defined(STM32WBA55xx) || defined(STM32WBA5Mxx)
volatile unsigned int cpt;
for(cpt = 178 ; cpt!=0 ; --cpt);
#else
/* wait until RNG_SR_BUSY (bit 4) is cleared */
while(RNG->SR & (1 << 4));
#endif /* defined(STM32WBA52xx) || defined(STM32WBA54xx) || defined(STM32WBA55xx) || defined(STM32WBA5Mxx) */
}
/*****************************************************************************/
/*
* HW_RNG_Run: this function must be called in loop.
* It implenments a simple state machine that enables the RNG,
* fills the pool with generated random numbers and then disables the RNG.
* It always returns 0 in normal conditions. In error conditions, it returns
* an error code different from 0.
*/
static int HW_RNG_Run(HW_RNG_VAR_T* pv)
{
int i, error = HW_OK;
/* check for RNG clock error */
if (LL_RNG_IsActiveFlag_CECS(RNG))
{
/* Clear RNG clock error interrupt status flags */
LL_RNG_ClearFlag_CEIS(RNG);
error = HW_RNG_CLOCK_ERROR;
}
/* check for RNG seed error */
if (LL_RNG_IsActiveFlag_SEIS(RNG))
{
/* Clear RNG seed error interrupt status flags */
LL_RNG_ClearFlag_SEIS(RNG);
/* Discard 12 words from RNG_DR in order to clean the pipeline */
for ( i = 12; i > 0; i-- )
{
LL_RNG_ReadRandData32(RNG);
}
error = HW_RNG_NOISE_ERROR;
}
/* if the pool is not full, read the H/W generated values until the pool is full */
UTILS_ENTER_CRITICAL_SECTION();
SYSTEM_DEBUG_SIGNAL_SET(RNG_GEN_RAND_NUM);
while (pv->size < HW_RNG_POOL_SIZE)
{
if (LL_RNG_IsActiveFlag_DRDY(RNG))
{
pv->pool[pv->size] = LL_RNG_ReadRandData32(RNG);
pv->size++;
}
}
SYSTEM_DEBUG_SIGNAL_RESET(RNG_GEN_RAND_NUM);
UTILS_EXIT_CRITICAL_SECTION( );
/* pool is full, disable the RNG and its RCC clock */
HW_RNG_Disable( );
/* Reset flag indicating that the RNG is ON */
pv->run = FALSE;
return error;
}
/*****************************************************************************/
void HW_RNG_Start( void )
{
HW_RNG_VAR_T* pv = &HW_RNG_var;
/* Reset global variables */
pv->size = 0;
pv->run = FALSE;
pv->error = HW_OK;
pv->clock_en = 0;
if (0 != RNG_MutexTake())
{
Error_Handler();
}
/* Fill the random numbers pool by calling the "run" function */
do
{
pv->error = HW_RNG_Run( pv );
}
while ( pv->run && !pv->error );
if (0 != RNG_MutexRelease())
{
Error_Handler();
}
}
/*****************************************************************************/
void HW_RNG_Get( uint8_t n, uint32_t* val )
{
HW_RNG_VAR_T* pv = &HW_RNG_var;
uint32_t pool_value;
while ( n-- )
{
UTILS_ENTER_CRITICAL_SECTION( );
if ( pv->size == 0 )
{
pv->error = HW_RNG_UFLOW_ERROR;
pool_value = ~pv->pool[HW_RNG_POOL_SIZE - n];
}
else
{
pool_value = pv->pool[--pv->size];
}
UTILS_EXIT_CRITICAL_SECTION( );
*val++ = pool_value;
}
/* Call the process callback function to fill the pool offline */
HWCB_RNG_Process( );
}
/*****************************************************************************/
int HW_RNG_Process( void )
{
HW_RNG_VAR_T* pv = &HW_RNG_var;
int status = HW_OK;
if (0 != RNG_MutexTake())
{
status = HW_BUSY;
}
else
{
/* Check if the process is not done or if the pool is not full */
if (pv->size < hw_rng_pool_threshold)
{
HW_RNG_Init();
UTILS_ENTER_CRITICAL_SECTION( );
/* Check if an error occurred during a previous call to HW_RNG API */
status = pv->error;
pv->error = HW_OK;
UTILS_EXIT_CRITICAL_SECTION( );
if ( status == HW_OK )
{
/* Call the "run" function that generates random data */
status = HW_RNG_Run( pv );
/* If the process is not done, return "busy" status */
if ( (status == HW_OK) && pv->run )
{
status = HW_BUSY;
}
}
}
if (0 != RNG_MutexRelease())
{
Error_Handler();
}
}
if (status != HW_OK)
{
HWCB_RNG_Process( );
}
/* Return status */
return status;
}
void HW_RNG_Init(void)
{
HW_RNG_VAR_T* pv = &HW_RNG_var;
SYSTEM_DEBUG_SIGNAL_SET(RNG_ENABLE);
LL_RCC_SetRNGClockSource(LL_RCC_RNG_CLKSOURCE_HSI);
LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_RNG);
LL_RNG_Disable(RNG);
while(LL_RNG_IsEnabled(RNG));
/* Recommended value for NIST compliance, refer to application note AN4230 */
/* Using LL macros to set these values is not convenient as it's split
in 3 parts and need some bit polling at each step to check completion.
So, for efficiency, register direct access */
WRITE_REG(RNG->CR, RNG_CR_NIST_VALUE | RNG_CR_CONDRST | RNG_CED_DISABLE);
/* Recommended value for NIST compliance, refer to application note AN4230 */
LL_RNG_DisableClkErrorDetect(RNG);
LL_RNG_DisableCondReset(RNG);
#if !(defined(STM32WBA52xx) || defined(STM32WBA54xx) || defined(STM32WBA55xx) || defined(STM32WBA5Mxx))
while((RNG->SR & (1 << 4)));
#endif
while(LL_RNG_IsEnabledCondReset(RNG));
LL_RNG_SetHealthConfig(RNG,RNG_HTCR_NIST_VALUE);
LL_RNG_Enable(RNG);
while(!LL_RNG_IsActiveFlag_DRDY(RNG)); /*wait for data to be ready*/
pv->run = TRUE;
SYSTEM_DEBUG_SIGNAL_RESET(RNG_ENABLE);
}
void HW_RNG_SetPoolThreshold(uint8_t threshold)
{
if(threshold < HW_RNG_POOL_SIZE)
{
hw_rng_pool_threshold = threshold;
}
}

View File

@@ -0,0 +1,352 @@
/**
******************************************************************************
* @file timer_if.c
* @author MCD Application Team
* @brief Configure RTC Alarm, Tick and Calendar manager
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <math.h>
#include "stm32wbaxx_hal.h"
#include "stm32wbaxx_hal_conf.h"
#include "stm32wbaxx_ll_rtc.h"
#include "timer_if.h"
/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/**
* @brief Minimum timeout delay of Alarm in ticks
*/
#define MIN_ALARM_DELAY 3
/**
* @brief Backup seconds register
*/
#define RTC_BKP_SECONDS RTC_BKP_DR0
/**
* @brief Backup subseconds register
*/
#define RTC_BKP_SUBSECONDS RTC_BKP_DR1
/**
* @brief Backup msbticks register
*/
#define RTC_BKP_MSBTICKS RTC_BKP_DR2
/* #define RTIF_DEBUG */
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/**
* @brief Timer driver callbacks handler
*/
const UTIL_TIMER_Driver_s UTIL_TimerDriver =
{
TIMER_IF_Init,
NULL,
TIMER_IF_StartTimer,
TIMER_IF_StopTimer,
TIMER_IF_SetTimerContext,
TIMER_IF_GetTimerContext,
TIMER_IF_GetTimerElapsedTime,
TIMER_IF_GetTimerValue,
TIMER_IF_GetMinimumTimeout,
TIMER_IF_Convert_ms2Tick,
TIMER_IF_Convert_Tick2ms,
};
/**
* @brief SysTime driver callbacks handler
*/
const UTIL_SYSTIM_Driver_s UTIL_SYSTIMDriver =
{
TIMER_IF_BkUp_Write_Seconds,
TIMER_IF_BkUp_Read_Seconds,
TIMER_IF_BkUp_Write_SubSeconds,
TIMER_IF_BkUp_Read_SubSeconds,
TIMER_IF_GetTime,
};
/* External variables --------------------------------------------------------*/
/**
* @brief RTC handle
*/
extern RTC_HandleTypeDef hrtc;
/* Private variables ---------------------------------------------------------*/
/**
* @brief Indicates if the RTC is already Initialized or not
*/
static bool RTC_Initialized = 0;
/**
* @brief RtcTimerContext
*/
static uint32_t RtcTimerContext = 0;
/* Exported macro ------------------------------------------------------------*/
#ifdef RTIF_DEBUG
#include "sys_app.h" /*for app_log*/
/**
* @brief Post the RTC log string format to the circular queue for printing in using the polling mode
*/
#define TIMER_IF_DBG_PRINTF(...) do{ {UTIL_ADV_TRACE_COND_FSend(VLEVEL_ALWAYS, T_REG_OFF, TS_OFF, __VA_ARGS__);} }while(0);
#else
/**
* @brief not used
*/
#define TIMER_IF_DBG_PRINTF(...)
#endif /* RTIF_DEBUG */
/* Private function prototypes -----------------------------------------------*/
/**
* @brief Get rtc timer Value in rtc tick
* @return val the rtc timer value (upcounting)
*/
static inline uint32_t GetTimerTicks(void);
/**
* @brief Writes MSBticks to backup register
* Absolute RTC time in tick is (MSBticks)<<32 + (32bits binary counter)
* @note MSBticks incremented every time the 32bits RTC timer wraps around (~44days)
* @param[in] MSBticks
* @return none
*/
static void TIMER_IF_BkUp_Write_MSBticks(uint32_t MSBticks);
/**
* @brief Reads MSBticks from backup register
* Absolute RTC time in tick is (MSBticks)<<32 + (32bits binary counter)
* @note MSBticks incremented every time the 32bits RTC timer wraps around (~44days)
* @retval MSBticks
*/
static uint32_t TIMER_IF_BkUp_Read_MSBticks(void);
/* Private user code ---------------------------------------------------------*/
UTIL_TIMER_Status_t TIMER_IF_Init(void)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
if (RTC_Initialized == false)
{
/* Stop Timer */
TIMER_IF_StopTimer();
/* DeActivate the Alarm A enabled by MX during MX_RTC_Init() */
HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
/* Enable Direct Read of the calendar registers (not through Shadow) */
HAL_RTCEx_EnableBypassShadow(&hrtc);
/* Initialise MSB ticks */
TIMER_IF_BkUp_Write_MSBticks(0);
TIMER_IF_SetTimerContext();
RTC_Initialized = true;
}
return ret;
}
UTIL_TIMER_Status_t TIMER_IF_StartTimer(uint32_t timeout)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
RTC_AlarmTypeDef sAlarm = {0};
/* Stop timer if one is already started */
TIMER_IF_StopTimer();
timeout += RtcTimerContext;
TIMER_IF_DBG_PRINTF("Start timer: time=%d, alarm=%d\n\r", GetTimerTicks(), timeout);
/* Starts timer */
sAlarm.BinaryAutoClr = RTC_ALARMSUBSECONDBIN_AUTOCLR_NO;
sAlarm.AlarmTime.SubSeconds = UINT32_MAX - timeout;
sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDBINMASK_NONE;
sAlarm.Alarm = RTC_ALARM_A;
if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
{
/* Initialization Error */
while(1);
}
return ret;
}
UTIL_TIMER_Status_t TIMER_IF_StopTimer(void)
{
UTIL_TIMER_Status_t ret = UTIL_TIMER_OK;
/* Clear RTC Alarm Flag */
__HAL_RTC_ALARM_CLEAR_FLAG(&hrtc, RTC_FLAG_ALRAF);
/* Disable the Alarm A interrupt */
HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
return ret;
}
uint32_t TIMER_IF_SetTimerContext(void)
{
/* Store time context */
RtcTimerContext = GetTimerTicks();
TIMER_IF_DBG_PRINTF("TIMER_IF_SetTimerContext=%d\n\r", RtcTimerContext);
/* Return time context */
return RtcTimerContext;
}
uint32_t TIMER_IF_GetTimerContext(void)
{
TIMER_IF_DBG_PRINTF("TIMER_IF_GetTimerContext=%d\n\r", RtcTimerContext);
/* Return time context */
return RtcTimerContext;
}
uint32_t TIMER_IF_GetTimerElapsedTime(void)
{
return ((uint32_t)(GetTimerTicks() - RtcTimerContext));
}
uint32_t TIMER_IF_GetTimerValue(void)
{
if (RTC_Initialized == true)
{
return GetTimerTicks();
}
else
{
return 0;
}
}
uint32_t TIMER_IF_GetMinimumTimeout(void)
{
return (MIN_ALARM_DELAY);
}
uint32_t TIMER_IF_Convert_ms2Tick(uint32_t timeMilliSec)
{
return ((uint32_t)( ( ( (uint64_t) timeMilliSec ) << RTC_N_PREDIV_S ) / 1000U ) );
}
uint32_t TIMER_IF_Convert_Tick2ms(uint32_t tick)
{
return ((uint32_t)( ( ( ( int64_t)( tick ) ) * 1000U ) >> RTC_N_PREDIV_S ) );
}
void TIMER_IF_DelayMs(uint32_t delay)
{
uint32_t delayTicks = TIMER_IF_Convert_ms2Tick(delay);
uint32_t timeout = GetTimerTicks();
/* Wait delay ms */
while (((GetTimerTicks() - timeout)) < delayTicks)
{
__NOP();
}
}
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
UTIL_TIMER_IRQ_Handler();
}
void HAL_RTCEx_SSRUEventCallback(RTC_HandleTypeDef *hrtc)
{
/* Called every 48 days with 1024 ticks per seconds */
TIMER_IF_DBG_PRINTF(">>Handler SSRUnderflow at %d\n\r", GetTimerTicks());
/* Increment MSBticks */
uint32_t MSB_ticks = TIMER_IF_BkUp_Read_MSBticks();
TIMER_IF_BkUp_Write_MSBticks(MSB_ticks + 1);
}
uint32_t TIMER_IF_GetTime(uint16_t *mSeconds)
{
uint64_t ticks;
uint32_t timerValueLsb = GetTimerTicks();
uint32_t timerValueMSB = TIMER_IF_BkUp_Read_MSBticks();
ticks = (((uint64_t) timerValueMSB) << 32) + timerValueLsb;
uint32_t seconds = (uint32_t)(ticks >> RTC_N_PREDIV_S);
ticks = (uint32_t) ticks & RTC_PREDIV_S;
*mSeconds = TIMER_IF_Convert_Tick2ms(ticks);
return seconds;
}
void TIMER_IF_BkUp_Write_Seconds(uint32_t Seconds)
{
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_SECONDS, Seconds);
}
void TIMER_IF_BkUp_Write_SubSeconds(uint32_t SubSeconds)
{
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_SUBSECONDS, SubSeconds);
}
uint32_t TIMER_IF_BkUp_Read_Seconds(void)
{
return HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_SECONDS);
}
uint32_t TIMER_IF_BkUp_Read_SubSeconds(void)
{
return HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_SUBSECONDS);
}
static void TIMER_IF_BkUp_Write_MSBticks(uint32_t MSBticks)
{
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_MSBTICKS, MSBticks);
}
static uint32_t TIMER_IF_BkUp_Read_MSBticks(void)
{
uint32_t MSBticks;
MSBticks = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_MSBTICKS);
return MSBticks;
}
static inline uint32_t GetTimerTicks(void)
{
uint32_t ssr = LL_RTC_TIME_GetSubSecond(RTC);
/* read twice to make sure value it valid*/
while (ssr != LL_RTC_TIME_GetSubSecond(RTC))
{
ssr = LL_RTC_TIME_GetSubSecond(RTC);
}
return UINT32_MAX - ssr;
}

View File

@@ -0,0 +1,162 @@
/**
******************************************************************************
* @file timer_if.h
* @author MCD Application Team
* @brief configuration of the timer_if.c instances
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef TIMER_IF_H
#define TIMER_IF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_timer.h"
#include "stm32_systime.h"
/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define RTC_N_PREDIV_S (10U)
#define RTC_PREDIV_S ( ( 1U << RTC_N_PREDIV_S ) - 1U )
#define RTC_PREDIV_A ( ( 1U << ( 15U - RTC_N_PREDIV_S ) ) - 1U )
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
/**
* @brief Init RTC hardware
* @return Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t TIMER_IF_Init(void);
/**
* @brief Set the alarm
* @note The alarm is set at timeout from timer Reference (TimerContext)
* @param timeout Duration of the Timer in ticks
* @return Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t TIMER_IF_StartTimer(uint32_t timeout);
/**
* @brief Stop the Alarm
* @return Status based on @ref UTIL_TIMER_Status_t
*/
UTIL_TIMER_Status_t TIMER_IF_StopTimer(void);
/**
* @brief set timer Reference (TimerContext)
* @return Timer Reference Value in Ticks
*/
uint32_t TIMER_IF_SetTimerContext(void);
/**
* @brief Get the RTC timer Reference
* @return Timer Value in Ticks
*/
uint32_t TIMER_IF_GetTimerContext(void);
/**
* @brief Get the timer elapsed time since timer Reference (TimerContext) was set
* @return RTC Elapsed time in ticks
*/
uint32_t TIMER_IF_GetTimerElapsedTime(void);
/**
* @brief Get the timer value
* @return RTC Timer value in ticks
*/
uint32_t TIMER_IF_GetTimerValue(void);
/**
* @brief Return the minimum timeout in ticks the RTC is able to handle
* @return minimum value for a timeout in ticks
*/
uint32_t TIMER_IF_GetMinimumTimeout(void);
/**
* @brief a delay of delay ms by polling RTC
* @param delay in ms
*/
void TIMER_IF_DelayMs(uint32_t delay);
/**
* @brief converts time in ms to time in ticks
* @param[in] timeMilliSec time in milliseconds
* @return time in timer ticks
*/
uint32_t TIMER_IF_Convert_ms2Tick(uint32_t timeMilliSec);
/**
* @brief converts time in ticks to time in ms
* @param[in] tick time in timer ticks
* @return time in timer milliseconds
*/
uint32_t TIMER_IF_Convert_Tick2ms(uint32_t tick);
/**
* @brief Get rtc time
* @param[out] subSeconds in ticks
* @return time seconds
*/
uint32_t TIMER_IF_GetTime(uint16_t *subSeconds);
/**
* @brief write seconds in backUp register
* @note Used to store seconds difference between RTC time and Unix time
* @param[in] Seconds time in seconds
*/
void TIMER_IF_BkUp_Write_Seconds(uint32_t Seconds);
/**
* @brief reads seconds from backUp register
* @note Used to store seconds difference between RTC time and Unix time
* @return Time in seconds
*/
uint32_t TIMER_IF_BkUp_Read_Seconds(void);
/**
* @brief writes SubSeconds in backUp register
* @note Used to store SubSeconds difference between RTC time and Unix time
* @param[in] SubSeconds time in SubSeconds
*/
void TIMER_IF_BkUp_Write_SubSeconds(uint32_t SubSeconds);
/**
* @brief reads SubSeconds from backUp register
* @note Used to store SubSeconds difference between RTC time and Unix time
* @return Time in SubSeconds
*/
uint32_t TIMER_IF_BkUp_Read_SubSeconds(void);
#ifdef __cplusplus
}
#endif
#endif /* TIMER_IF_H */

View File

@@ -0,0 +1,81 @@
/**
******************************************************************************
* @file baes.h
* @author MCD Application Team
* @brief This file contains the interface of the basic AES software module.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef BAES_H__
#define BAES_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/* Basic AES module dedicated to BLE stack with the following features:
* - AES ECB encryption
* - AES CMAC computation
*
* Configuration: the file "app_common.h" is included in this module.
* It must define:
* - CFG_BAES_SW equals to 1 for software implementation
* - CFG_BAES_SW equals to 0 for use of hardware accelerator
*
* Notes:
* - only 128-bit key is supported
* - re-entrance is not supported
*/
/* General interface */
extern void BAES_Reset( void );
/* AES ECB interface */
extern void BAES_EcbCrypt( const uint8_t* key,
const uint8_t* input,
uint8_t* output,
int enc );
/* AES CMAC interface */
extern void BAES_CmacSetKey( const uint8_t* key );
extern void BAES_CmacSetVector( const uint8_t * pIV );
extern void BAES_CmacCompute( const uint8_t* input,
uint32_t size,
uint8_t* output );
/* AES CCM interface */
extern int BAES_CcmCrypt( uint8_t mode,
const uint8_t* key,
uint8_t iv_length,
const uint8_t* iv,
uint16_t add_length,
const uint8_t* add,
uint16_t input_length,
const uint8_t* input,
uint8_t tag_length,
uint8_t* tag,
uint8_t* output );
#ifdef __cplusplus
}
#endif
#endif /* BAES_H__ */

View File

@@ -0,0 +1,120 @@
/*****************************************************************************
* @file baes_ccm.c
*
* @brief This file contains the AES CCM implementation.
*****************************************************************************
* @attention
*
* Copyright (c) 2018-2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
*****************************************************************************
*/
#include "baes_global.h"
/*****************************************************************************/
/* ---------------------------------------------------------------------------
* Byte/word manipulation macro definitions
* ---------------------------------------------------------------------------
*/
/* Returns the least significant byte from a word */
#define BYTE0(w) ((uint8_t)((w) >> 0))
/* Returns the second least significant byte from a word */
#define BYTE1(w) ((uint8_t)((w) >> 8))
/* Macro to set a 16-bit word into a byte table in big endian */
#define SET_U16_BE( b, i, v ) M_BEGIN uint16_t v_ = (uint16_t)(v); \
uint8_t *b_ = &((uint8_t*)(b))[i]; \
b_[1] = BYTE0(v_); \
b_[0] = BYTE1(v_); M_END
int BAES_CcmCrypt( uint8_t mode,
const uint8_t* key,
uint8_t iv_length,
const uint8_t* iv,
uint16_t add_length,
const uint8_t* add,
uint16_t input_length,
const uint8_t* input,
uint8_t tag_length,
uint8_t* tag,
uint8_t* output )
{
#if CFG_BAES_SW == 0
/* This implementation of AES CCM only supports HW AES and it also only
* supports the following range for input parameters:
* - tag_length: 4..16 (multiple of 2)
* - iv_length: 7..13
* - add_length: 1..14
*/
uint32_t left_len, b0[4], bx[4];
uint8_t len, *b;
/* Build B0 */
b = (uint8_t*)b0;
memset( b0, 0, 16 );
b[0] = (1U << 6) | (((tag_length - 2) / 2) << 3) | (14U - iv_length);
memcpy( b + 1, iv, iv_length );
SET_U16_BE( b, 14, input_length );
/* Build B1 */
b = (uint8_t*)bx;
memset( bx, 0, 16 );
b[1] = add_length;
memcpy( b + 2, add, add_length );
/* Start CCM process with Init and Header phases */
HW_AES_Enable( );
HW_AES_InitCcm( mode, key, b0, bx );
/* Continue CCM process with Payload Phase */
left_len = input_length;
while ( left_len > 0 )
{
len = 16;
if ( left_len < 16 )
{
len = (uint8_t)left_len;
memset( bx, 0, 16 );
if ( mode )
HW_AES_SetLast( len );
}
memcpy( b, input, len );
HW_AES_Crypt( bx, bx );
memcpy( output, b, len );
input += len;
output += len;
left_len -= len;
}
/* End CCM process with Final Phase */
HW_AES_EndCcm( tag_length, mode ? b : tag );
HW_AES_Disable( );
/* Verification of the tag in case of decryption */
if ( mode )
{
uint8_t diff = 0;
for ( int i = 0; i < tag_length; i++ )
diff |= tag[i] ^ b[i];
return (int)diff;
}
#endif /* CFG_BAES_SW == 0 */
return 0;
}
/*****************************************************************************/

View File

@@ -0,0 +1,213 @@
/**
******************************************************************************
* @file baes_cmac.c
* @author MCD Application Team
* @brief This file contains the AES CMAC implementation.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "baes_global.h"
/*****************************************************************************/
typedef struct
{
uint32_t iv[4]; /* Temporary result/IV */
#if CFG_BAES_SW != 0
uint32_t exp_key[44]; /* Expanded AES key */
#endif /* CFG_BAES_SW != 0 */
} BAES_CMAC_t;
/*****************************************************************************/
BAES_CMAC_t BAES_CMAC_var;
/*****************************************************************************/
/*
* AES key roll for CMAC Mode
*
*/
static void BAES_CmacKeyRoll( uint32_t* key )
{
uint32_t carry = ((key[0] >> 31) & 1) * 0x87UL;
key[0] = (key[0] << 1) | (key[1] >> 31);
key[1] = (key[1] << 1) | (key[2] >> 31);
key[2] = (key[2] << 1) | (key[3] >> 31);
key[3] = (key[3] << 1) ^ carry;
}
/*****************************************************************************/
/*
* AES ECB encryption for CMAC Mode
*
*/
static void BAES_CmacRawEncrypt( const uint32_t* input,
uint32_t* output )
{
#if CFG_BAES_SW == 0
HW_AES_Crypt( input, output );
#else /* CFG_BAES_SW != 0 */
BAES_CMAC_t *av = &BAES_CMAC_var;
BAES_RawEncrypt( input, output, av->exp_key );
#endif /* CFG_BAES_SW != 0 */
}
/*****************************************************************************/
/*
* Initialization for AES-CMAC for Authentication TAG Generation.
* Must be called each time a new CMAC has to be computed.
*/
void BAES_CmacSetKey( const uint8_t* key )
{
BAES_CMAC_t *av = &BAES_CMAC_var;
/* Initialize for ECB encoding */
#if CFG_BAES_SW == 0
HW_AES_Enable( );
HW_AES_SetKey( HW_AES_ENC, key );
#else /* CFG_BAES_SW != 0 */
uint32_t tmp[4];
memcpy( tmp, key, 16 );
BAES_COPY_REV( av->exp_key, tmp );
BAES_EncKeySchedule( av->exp_key );
#endif /* CFG_BAES_SW != 0 */
/* set IV to zero */
av->iv[0] = av->iv[1] = av->iv[2] = av->iv[3] = 0;
}
/*
* Initialization for AES-CMAC for Authentication TAG Generation.
* Must be called each time a new CMAC has to be computed.
*/
void BAES_CmacSetVector( const uint8_t * pIV )
{
BAES_CMAC_t * av = &BAES_CMAC_var;
// -- Update IV if exist else set to zero --
if ( pIV != NULL )
{ memcpy( av->iv, pIV, AES_BLOCK_SIZE_BYTE ); }
else
{ memset( av->iv, 0x00, AES_BLOCK_SIZE_BYTE ); }
}
/*****************************************************************************/
/*
* AES Encryption in CMAC Mode
*
* This function can be called multiple times with "size" multiple of 16 and
* "output" parameter set to NULL. However, in the last call to this function,
* any positive value for "size" is allowed and the "output" parameter must not
* be NULL.
*/
void BAES_CmacCompute( const uint8_t* input,
uint32_t size,
uint8_t* output )
{
BAES_CMAC_t *av = &BAES_CMAC_var;
uint32_t i;
uint32_t last_size = 0;
uint32_t tmp[4], key[4];
const uint8_t* ptr = input;
if ( output )
{
/* In case of final append, compute size of last block */
last_size = size % 16;
if ( (size != 0) && (last_size == 0) )
last_size = 16;
size -= last_size;
}
while ( size )
{
/* Load the input of all blocks but the last one
and xor data with previous tag */
memcpy( tmp, ptr, 16 );
BAES_REV_XOR( tmp, av->iv );
/* Encrypt block */
BAES_CmacRawEncrypt( tmp, av->iv );
/* Next block */
ptr += 16;
size -= 16;
}
if ( output )
{
/* Load the input bytes left with 0 padding */
tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
for ( i = 0; i < last_size; i++ )
{
BAES_OR_BYTE_BE( tmp, i, ptr[i] );
}
/* Compute K1 */
key[0] = key[1] = key[2] = key[3] = 0;
BAES_CmacRawEncrypt( key, key );
BAES_CmacKeyRoll( key );
/* Add padding and compute K2 if the last block is not full */
if ( last_size < 16 )
{
BAES_OR_BYTE_BE( tmp, last_size, 0x80 );
BAES_CmacKeyRoll( key );
}
/* Xor data with previous tag and key */
for ( i = 0; i < 4; i++ )
{
tmp[i] ^= av->iv[i] ^ key[i];
}
/* Encrypt block */
BAES_CmacRawEncrypt( tmp, av->iv );
#if CFG_BAES_SW == 0
HW_AES_Disable( );
#endif /* CFG_BAES_SW == 0 */
/* Write the tag */
BAES_COPY_REV( tmp, av->iv );
memcpy( output, tmp, 16 );
}
}
/*****************************************************************************/

View File

@@ -0,0 +1,89 @@
/**
******************************************************************************
* @file baes_ecb.c
* @author MCD Application Team
* @brief This file contains the AES ECB functions implementation.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "baes_global.h"
/*****************************************************************************/
void BAES_Reset( void )
{
#if CFG_BAES_SW == 0
HW_AES_Disable( );
#endif
}
/*****************************************************************************/
void BAES_EcbCrypt( const uint8_t* key,
const uint8_t* input,
uint8_t* output,
int enc )
{
uint32_t tmp[4];
#if CFG_BAES_SW == 0
HW_AES_Enable( );
HW_AES_SetKey( (enc ? (HW_AES_ENC | HW_AES_REV) : (HW_AES_DEC | HW_AES_REV)),
key );
#else /* CFG_BAES_SW != 0 */
uint32_t exp_key[44];
/* Retrieve all bytes from key */
memcpy( exp_key, key, 16 );
BAES_SWAP( exp_key );
#if CFG_BAES_SW_DECRYPTION != 0
if ( !enc )
BAES_DecKeySchedule( exp_key );
else
#endif /* CFG_BAES_SW_DECRYPTION != 0 */
BAES_EncKeySchedule( exp_key );
#endif /* CFG_BAES_SW != 0 */
/* Retrieve all bytes from input */
memcpy( tmp, input, 16 );
BAES_SWAP( tmp );
#if CFG_BAES_SW == 0
HW_AES_Crypt( tmp, tmp );
HW_AES_Disable( );
#else /* CFG_BAES_SW != 0 */
#if CFG_BAES_SW_DECRYPTION != 0
if ( !enc )
BAES_RawDecrypt( tmp, tmp, exp_key );
else
#endif /* CFG_BAES_SW_DECRYPTION != 0 */
BAES_RawEncrypt( tmp, tmp, exp_key );
#endif /* CFG_BAES_SW != 0 */
/* Write all bytes to output */
BAES_SWAP( tmp );
memcpy( output, tmp, 16 );
}
/*****************************************************************************/

View File

@@ -0,0 +1,127 @@
/**
******************************************************************************
* @file baes_global.h
* @author MCD Application Team
* @brief This file contains the internal definitions of the AES software
* module.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef BAES_GLOBAL_H__
#define BAES_GLOBAL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "app_common.h"
#include "baes.h"
/* Default software configuration */
#define AES_BLOCK_SIZE_BIT 128u /* AES Size in Bits */
#define AES_BLOCK_SIZE_BYTE 16u /* AES Size in Bytes */
#define AES_BLOCK_SIZE_WORD 4u /* AES Size in Words */
#define AES_EXPANDED_KEY_SIZE 44u
/* By default, use of AES H/W implementation instead of S/W */
#ifndef CFG_BAES_SW
#define CFG_BAES_SW 0
#endif
#if CFG_BAES_SW == 1
/* Enables to include AES S/W decryption when set to 1 */
#ifndef CFG_BAES_SW_DECRYPTION
#define CFG_BAES_SW_DECRYPTION 0
#endif
/* Choice of the AES S/W algorithm version:
* 1: slow version with 522 bytes of look-up tables
* 2: fast version with 2048 bytes of look-up tables */
#ifndef CFG_BAES_SW_ALGORITHM
#define CFG_BAES_SW_ALGORITHM 1
#endif
#endif /* CFG_BAES_SW == 1 */
/* Internal macros */
/* Reverse the words in a 4-word array */
#define BAES_SWAP( w ) \
M_BEGIN uint32_t t_; \
t_ = (w)[0]; (w)[0] = (w)[3]; (w)[3] = t_; \
t_ = (w)[1]; (w)[1] = (w)[2]; (w)[2] = t_; \
M_END
/* Reverse the bytes and words in a 4-word array */
#define BAES_SWAP_REV( w ) \
M_BEGIN uint32_t t_; \
t_ = (w)[0]; (w)[0] = __REV((w)[3]); (w)[3] = __REV(t_); \
t_ = (w)[1]; (w)[1] = __REV((w)[2]); (w)[2] = __REV(t_); \
M_END
/* Reverse the words of a 4-word array and xor the result */
#define BAES_SWAP_XOR( w, x ) \
M_BEGIN uint32_t t_; \
t_ = (w)[0]; (w)[0] = (w)[3] ^ ((x)[0]); (w)[3] = t_ ^ ((x)[3]); \
t_ = (w)[1]; (w)[1] = (w)[2] ^ ((x)[1]); (w)[2] = t_ ^ ((x)[2]); \
M_END
/* Reverse the bytes of a 4-word array and xor the result */
#define BAES_REV_XOR( w, x ) \
M_BEGIN \
(w)[0] = __REV((w)[0]) ^ ((x)[0]); (w)[1] = __REV((w)[1]) ^ ((x)[1]); \
(w)[2] = __REV((w)[2]) ^ ((x)[2]); (w)[3] = __REV((w)[3]) ^ ((x)[3]); \
M_END
/* Copy and reverse the words of a 4-word array */
#define BAES_COPY_SWAP( d, s ) \
M_BEGIN \
(d)[0] = (s)[3]; (d)[1] = (s)[2]; \
(d)[2] = (s)[1]; (d)[3] = (s)[0]; \
M_END
/* Copy and reverse the bytes of a 4-word array */
#define BAES_COPY_REV( d, s ) \
M_BEGIN \
(d)[0] = __REV((s)[0]); (d)[1] = __REV((s)[1]); \
(d)[2] = __REV((s)[2]); (d)[3] = __REV((s)[3]); \
M_END
/* Modifies a byte in a word array in Big Endian */
#define BAES_OR_BYTE_BE( w, n, b ) \
(w)[(n)/4] |= ((uint32_t)(b)) << (8 * (3-((n)%4)))
/* Note: BYTE0, BYTE1, BYTE2, BYTE3 and BTOW macros are also used
but they should be defined in "common.h" */
/* Internal functions */
extern void BAES_EncKeySchedule( uint32_t* p_exp_key );
extern void BAES_DecKeySchedule( uint32_t* p_exp_key );
extern void BAES_RawEncrypt( const uint32_t* p_in,
uint32_t* p_out,
const uint32_t *p_exp_key );
extern void BAES_RawDecrypt( const uint32_t* p_in,
uint32_t* p_out,
const uint32_t* p_exp_key );
#ifdef __cplusplus
}
#endif
#endif /* BAES_GLOBAL_H__ */

View File

@@ -0,0 +1,151 @@
/**
******************************************************************************
* @file flash_driver.c
* @author MCD Application Team
* @brief The Flash Driver module is the interface layer between Flash
* management modules and HAL Flash drivers
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "flash_driver.h"
#include "utilities_conf.h"
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
#define FD_CTRL_NO_BIT_SET (0UL) /* value used to reset the Flash Control status */
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/**
* @brief variable used to represent the Flash Control status
*/
static volatile FD_Flash_ctrl_bm_t FD_Flash_Control_status = FD_CTRL_NO_BIT_SET;
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
/**
* @brief Update Flash Control status
* @param Flags_bm: Bit mask identifying the caller (1 bit per user)
* @param Status: Action requested (enable or disable flash access)
* @retval None
*/
void FD_SetStatus(FD_Flash_ctrl_bm_t Flags_bm, FD_FLASH_Status_t Status)
{
UTILS_ENTER_CRITICAL_SECTION();
switch (Status)
{
case LL_FLASH_DISABLE:
{
FD_Flash_Control_status |= (1u << Flags_bm);
break;
}
case LL_FLASH_ENABLE:
{
FD_Flash_Control_status &= ~(1u << Flags_bm);
break;
}
default :
{
break;
}
}
UTILS_EXIT_CRITICAL_SECTION();
}
/**
* @brief Write a block of 128 bits (4 32-bit words) in Flash
* @param Dest: Address where to write in Flash (128-bit aligned)
* @param Payload: Address of data to be written in Flash (32-bit aligned)
* @retval FD_FlashOp_Status_t: Success or failure of Flash write operation
*/
FD_FlashOp_Status_t FD_WriteData(uint32_t Dest, uint32_t Payload)
{
FD_FlashOp_Status_t status = FD_FLASHOP_FAILURE;
/* Check if RFTS OR Application allow flash access */
if ((FD_Flash_Control_status & (1u << FD_FLASHACCESS_RFTS)) &&
(FD_Flash_Control_status & (1u << FD_FLASHACCESS_RFTS_BYPASS)))
{ /* Access not allowed */
return status;
}
/* Wait for system to allow flash access */
while (FD_Flash_Control_status & (1u << FD_FLASHACCESS_SYSTEM));
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, Dest, Payload) == HAL_OK)
{
status = FD_FLASHOP_SUCCESS;
}
return status;
}
/**
* @brief Erase one sector of Flash
* @param Sect: Identifier of the sector to erase
* @retval FD_FlashOp_Status_t: Success or failure of Flash erase operation
*/
FD_FlashOp_Status_t FD_EraseSectors(uint32_t Sect)
{
FD_FlashOp_Status_t status = FD_FLASHOP_FAILURE;
uint32_t page_error;
FLASH_EraseInitTypeDef p_erase_init;
#ifndef FLASH_DBANK_SUPPORT
if (FLASH_PAGE_NB < Sect)
#else
if ((FLASH_PAGE_NB * 2u) < Sect)
#endif
{
return status;
}
/* Check if LL allows flash access */
if ((FD_Flash_Control_status & (1u << FD_FLASHACCESS_RFTS)) &&
(FD_Flash_Control_status & (1u << FD_FLASHACCESS_RFTS_BYPASS)))
{ /* Access not allowed */
return status;
}
/* Wait for system to allow flash access */
while (FD_Flash_Control_status & (1u << FD_FLASHACCESS_SYSTEM));
p_erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
p_erase_init.Page = (Sect & (FLASH_PAGE_NB - 1u));
p_erase_init.NbPages = 1;
#if defined(FLASH_DBANK_SUPPORT)
/* Verify which Bank is impacted */
if ((FLASH_PAGE_NB <= Sect) ^ (OB_SWAP_BANK_ENABLE == READ_BIT (FLASH->OPTR, FLASH_OPTR_SWAP_BANK_Msk)))
{
p_erase_init.Banks = FLASH_BANK_2;
}
else
{
p_erase_init.Banks = FLASH_BANK_1;
}
#endif
if (HAL_FLASHEx_Erase(&p_erase_init, &page_error) == HAL_OK)
{
status = FD_FLASHOP_SUCCESS;
}
return status;
}

View File

@@ -0,0 +1,88 @@
/**
******************************************************************************
* @file flash_driver.h
* @author MCD Application Team
* @brief Header for flash_driver.c module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef FLASH_DRIVER_H
#define FLASH_DRIVER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
/* Exported types ------------------------------------------------------------*/
/* Bit mask to modify Flash Control status */
typedef uint32_t FD_Flash_ctrl_bm_t;
/* Flash operation status */
typedef enum
{
FD_FLASHOP_SUCCESS,
FD_FLASHOP_FAILURE
} FD_FlashOp_Status_t;
/* Flash Driver commands to enable or disable flash access */
typedef enum
{
LL_FLASH_ENABLE,
LL_FLASH_DISABLE,
} FD_FLASH_Status_t;
/**
* @brief Bit mask to modify Flash Control status
*
* @details Those bitmasks are used to enable/disable access to the flash:
* - System:
* -# FD_FLASHACCESS_SYSTEM: Determine whether or not the flash access is allowed from a system POV.
* This bit has a predominance over all the other bit masks, ie: No flash operation can
* be achieved without this to be set to 0, ie: LL_FLASH_ENABLE.
* - RFTS:
* -# FD_FLASHACCESS_RFTS: Determine whether or not the RF Timing Synchro allows flash access. This bit is set
* once a window has been allowed by the BLE LL, ie: set to 0.
* This bit has no impact when FD_FLASHACCESS_RFTS_BYPASS is set, ie: set to 0.
* -# FD_FLASHACCESS_RFTS_BYPASS: Nullify the impact of FD_FLASHACCESS_RFTS when enabled, ie: set to 0. Its role is
* to allow flash operation without the need to request a timing window to the RFTS,
* ie: Executing flash operation without the BLE LL.
*
*/
typedef enum FD_FlashAccess_bm
{
/* System flash access bitfield */
FD_FLASHACCESS_SYSTEM,
/* RF Timing Synchro flash access bitfield */
FD_FLASHACCESS_RFTS,
/* Bypass of RF Timing Synchro flash access bitfield */
FD_FLASHACCESS_RFTS_BYPASS,
}FD_FlashAccess_bm_t;
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void FD_SetStatus(FD_Flash_ctrl_bm_t Flags_bm, FD_FLASH_Status_t Status);
FD_FlashOp_Status_t FD_WriteData(uint32_t Dest, uint32_t Payload);
FD_FlashOp_Status_t FD_EraseSectors(uint32_t Sect);
#ifdef __cplusplus
}
#endif
#endif /*FLASH_DRIVER_H */

View File

@@ -0,0 +1,516 @@
/**
******************************************************************************
* @file flash_manager.c
* @author MCD Application Team
* @brief The Flash Manager module provides an interface to write raw data
* from SRAM to FLASH
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <stdbool.h>
#include "flash_manager.h"
#include "rf_timing_synchro.h"
#include "flash_driver.h"
#include "utilities_conf.h"
#include "stm32wbaxx_hal.h"
/* Debug */
#include "log_module.h"
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* State of the background process */
typedef enum FM_BackGround_States
{
FM_BKGND_NOWINDOW_FLASHOP,
FM_BKGND_WINDOWED_FLASHOP,
}FM_BackGround_States_t;
/* Flash operation type */
typedef enum
{
FM_WRITE_OP,
FM_ERASE_OP
} FM_FlashOp_t;
/**
* @brief Flash operation configuration struct
*/
typedef struct FM_FlashOpConfig
{
uint32_t *writeSrc;
uint32_t *writeDest;
int32_t writeSize;
uint32_t eraseFirstSect;
uint32_t eraseNbrSect;
}FM_FlashOpConfig_t;
/* Private defines -----------------------------------------------------------*/
#define FLASH_PAGE_NBR (FLASH_SIZE / FLASH_PAGE_SIZE)
#define FLASH_WRITE_BLOCK_SIZE 4U
#define ALIGNMENT_32 0x00000003
#define ALIGNMENT_128 0x0000000F
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/**
* @brief Semaphore on Flash
*/
static bool busy_flash_sem = FALSE;
/**
* @brief Indicates if the flash manager module is available or not
*/
static bool flash_manager_busy = FALSE;
/**
* @brief Parameters for Flash Write command
*/
static bool fm_window_granted = FALSE;
/**
* @brief Callback node list for pending flash operation request
*/
static tListNode fm_cb_pending_list;
/**
* @brief Pointer to current flash operation requester's callback
*/
static void (*fm_running_cb)(FM_FlashOp_Status_t);
/**
* @brief Type of current flash operation (Write/Erase)
*/
static FM_FlashOp_t fm_flashop;
/**
* @brief Parameters for Flash operation
*/
static FM_FlashOpConfig_t fm_flashop_parameters;
/**
* @brief State of the Background process
*/
static FM_BackGround_States_t FM_CurrentBackGroundState;
/* Private function prototypes -----------------------------------------------*/
static FM_Cmd_Status_t FM_CheckFlashManagerState(FM_CallbackNode_t *CallbackNode);
static void FM_WindowAllowed_Callback(void);
/* Functions Definition ------------------------------------------------------*/
/**
* @brief Initialize the Flash manager module
*/
void FM_Init (void)
{
static bool fm_cb_pending_list_init = false;
/* Initialize pending list if not done */
if (fm_cb_pending_list_init == false)
{
LST_init_head(&fm_cb_pending_list);
fm_cb_pending_list_init = true;
}
}
/**
* @brief Request the Flash Manager module to initiate a Flash Write operation
* @param Src: Address of the data to be stored in FLASH. It shall be 32bits aligned
* @param Dest: Address where the data shall be written. It shall be 128bits aligned
* @param Size: This is the size of data to be written in Flash.
The size is a multiple of 32bits (size = 1 means 32bits)
* @param CallbackNode: Pointer to the callback node for storage in list
* @retval FM_Cmd_Status_t: Status of the Flash Manager module
*/
FM_Cmd_Status_t FM_Write(uint32_t *Src, uint32_t *Dest, int32_t Size, FM_CallbackNode_t *CallbackNode)
{
FM_Cmd_Status_t status;
if (((uint32_t)Dest < FLASH_BASE) || ((uint32_t)Dest > (FLASH_BASE + FLASH_SIZE))
|| (((uint32_t)Dest + Size) > (FLASH_BASE + FLASH_SIZE)))
{
LOG_ERROR_SYSTEM("\r\nFM_Write - Destination address not part of the flash");
/* Destination address not part of the flash */
return FM_ERROR;
}
if (((uint32_t) Src & ALIGNMENT_32) || ((uint32_t) Dest & ALIGNMENT_128))
{
LOG_ERROR_SYSTEM("\r\nFM_Write - Source or destination address not properly aligned");
/* Source or destination address not properly aligned */
return FM_ERROR;
}
status = FM_CheckFlashManagerState(CallbackNode);
if (status == FM_OK)
{ /* Flash manager is available */
/* Save Write parameters */
fm_flashop_parameters.writeSrc = Src;
fm_flashop_parameters.writeDest = Dest;
fm_flashop_parameters.writeSize = Size;
fm_flashop = FM_WRITE_OP;
FM_CurrentBackGroundState = FM_BKGND_NOWINDOW_FLASHOP;
/* Window request to be executed in background */
FM_ProcessRequest();
}
LOG_DEBUG_SYSTEM("\r\nFM_Write - Returned value : %d", status);
return status;
}
/**
* @brief Request the Flash Manager module to initiate a Flash Erase operation
* @param FirstSect: Index of the first sector to erase
* @param NbrSect: Number of sector to erase
* @param CallbackNode: Pointer to the callback node for storage in list
* @retval FM_Cmd_Status_t: Status of the Flash Manager module
*/
FM_Cmd_Status_t FM_Erase(uint32_t FirstSect, uint32_t NbrSect, FM_CallbackNode_t *CallbackNode)
{
FM_Cmd_Status_t status;
if ((FirstSect > FLASH_PAGE_NBR) || ((FirstSect + NbrSect) > FLASH_PAGE_NBR))
{
LOG_ERROR_SYSTEM("\r\nFM_Erase - Inconsistent request");
/* Inconsistent request */
return FM_ERROR;
}
if (NbrSect == 0)
{
LOG_ERROR_SYSTEM("\r\nFM_Erase - Inconsistent request");
/* Inconsistent request */
return FM_ERROR;
}
status = FM_CheckFlashManagerState(CallbackNode);
if (status == FM_OK)
{ /* Flash manager is available */
/* Save Erase parameters */
fm_flashop_parameters.eraseFirstSect = FirstSect;
fm_flashop_parameters.eraseNbrSect = NbrSect;
fm_flashop = FM_ERASE_OP;
FM_CurrentBackGroundState = FM_BKGND_NOWINDOW_FLASHOP;
/* Window request to be executed in background */
FM_ProcessRequest();
}
LOG_DEBUG_SYSTEM("\r\nFM_Erase - Returned value : %d", status);
return status;
}
/**
* @brief Execute Flash Manager background tasks
* @param None
* @retval None
*/
void FM_BackgroundProcess (void)
{
static uint32_t duration;
bool flashop_complete = false;
FD_FlashOp_Status_t fdReturnValue = FD_FLASHOP_SUCCESS;
FM_CallbackNode_t *pCbNode = NULL;
switch (FM_CurrentBackGroundState)
{
case FM_BKGND_NOWINDOW_FLASHOP:
{
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP");
if (fm_flashop == FM_WRITE_OP)
{
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP - Write operation");
/* Update duration time value */
duration = TIME_WINDOW_WRITE_REQUEST;
/* Set the next possible state - App could stop at anytime no window operation */
FM_CurrentBackGroundState = FM_BKGND_WINDOWED_FLASHOP;
HAL_FLASH_Unlock();
while((fm_flashop_parameters.writeSize > 0) &&
(fdReturnValue == FD_FLASHOP_SUCCESS))
{
fdReturnValue = FD_WriteData((uint32_t) fm_flashop_parameters.writeDest,
(uint32_t) fm_flashop_parameters.writeSrc);
if (fdReturnValue == FD_FLASHOP_SUCCESS)
{
fm_flashop_parameters.writeDest += FLASH_WRITE_BLOCK_SIZE;
fm_flashop_parameters.writeSrc += FLASH_WRITE_BLOCK_SIZE;
fm_flashop_parameters.writeSize -= FLASH_WRITE_BLOCK_SIZE;
}
}
HAL_FLASH_Lock();
/* Is write over ? */
if (fm_flashop_parameters.writeSize <= 0)
{
flashop_complete = true;
}
}
else
{
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_NOWINDOW_FLASHOP - Erase operation");
/* Update duration time value */
duration = TIME_WINDOW_ERASE_REQUEST;
/* Set the next possible state */
FM_CurrentBackGroundState = FM_BKGND_WINDOWED_FLASHOP;
HAL_FLASH_Unlock();
while((fm_flashop_parameters.eraseNbrSect > 0) &&
(fdReturnValue == FD_FLASHOP_SUCCESS))
{
fdReturnValue = FD_EraseSectors(fm_flashop_parameters.eraseFirstSect);
if (fdReturnValue == FD_FLASHOP_SUCCESS)
{
fm_flashop_parameters.eraseNbrSect--;
fm_flashop_parameters.eraseFirstSect++;
}
}
HAL_FLASH_Lock();
if (fm_flashop_parameters.eraseNbrSect == 0)
{
flashop_complete = true;
}
}
break;
}
case FM_BKGND_WINDOWED_FLASHOP:
{
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP");
if (fm_window_granted == false)
{
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - No time window granted yet, request one");
/* No time window granted yet, request one */
RFTS_ReqWindow(duration, &FM_WindowAllowed_Callback);
}
else
{
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Time window granted");
if (fm_flashop == FM_WRITE_OP)
{
/* Flash Write operation */
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Write operation");
HAL_FLASH_Unlock();
while((fm_flashop_parameters.writeSize > 0) &&
(FD_WriteData((uint32_t) fm_flashop_parameters.writeDest,
(uint32_t) fm_flashop_parameters.writeSrc) == FD_FLASHOP_SUCCESS))
{
fm_flashop_parameters.writeDest += FLASH_WRITE_BLOCK_SIZE;
fm_flashop_parameters.writeSrc += FLASH_WRITE_BLOCK_SIZE;
fm_flashop_parameters.writeSize -= FLASH_WRITE_BLOCK_SIZE;
}
if (fm_flashop_parameters.writeSize <= 0)
{
flashop_complete = true;
}
HAL_FLASH_Lock();
}
else
{
/* Flash Erase operation */
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Case FM_BKGND_WINDOWED_FLASHOP - Erase operation");
HAL_FLASH_Unlock();
/* Erase only one sector in a single time window */
if (FD_EraseSectors(fm_flashop_parameters.eraseFirstSect) == FD_FLASHOP_SUCCESS)
{
fm_flashop_parameters.eraseNbrSect--;
fm_flashop_parameters.eraseFirstSect++;
}
if (fm_flashop_parameters.eraseNbrSect == 0)
{
flashop_complete = true;
}
HAL_FLASH_Lock();
}
/* Release the time window */
RFTS_RelWindow();
/* Indicate that there is no more window */
fm_window_granted = false;
}
break;
}
default:
{
/* Nothing to do here */
break;
}
}
if (flashop_complete == true)
{
UTILS_ENTER_CRITICAL_SECTION();
/* Release semaphore on flash */
busy_flash_sem = false;
/* Set Flash Manager busy */
flash_manager_busy = false;
UTILS_EXIT_CRITICAL_SECTION();
/* Invoke the running callback if present */
if (fm_running_cb != NULL)
{
fm_running_cb(FM_OPERATION_COMPLETE);
}
/* notify pending requesters */
while((LST_is_empty (&fm_cb_pending_list) == false) &&
(busy_flash_sem == false) && (flash_manager_busy == false))
{
LST_remove_head (&fm_cb_pending_list, (tListNode**)&pCbNode);
pCbNode->Callback(FM_OPERATION_AVAILABLE);
}
}
else
{
/* Flash operation not complete yet */
LOG_DEBUG_SYSTEM("\r\nFM_BackgroundProcess - Flash operation not complete yet, request a new time window");
/* Request a new time window */
RFTS_ReqWindow(duration, &FM_WindowAllowed_Callback);
}
}
/**
* @brief Check if the Flash Manager is busy or available
* @param CallbackNode: Pointer to the callback node for storage in list
* @retval FM_Cmd_Status_t: Status of the Flash Manager module
*/
static FM_Cmd_Status_t FM_CheckFlashManagerState(FM_CallbackNode_t *CallbackNode)
{
bool fm_process_cmd = false;
FM_Cmd_Status_t status = FM_ERROR;
/* Check if semaphore on flash is available */
UTILS_ENTER_CRITICAL_SECTION();
/* Check if semaphore on flash is available */
if (busy_flash_sem == false)
{ /* Check if Flash Manager is already busy */
if (flash_manager_busy == false)
{
busy_flash_sem = true; /* Get semaphore on flash */
flash_manager_busy = true; /* Set Flash Manager busy */
fm_process_cmd = true;
}
else
{
fm_process_cmd = false;
}
}
else
{
fm_process_cmd = false;
}
UTILS_EXIT_CRITICAL_SECTION();
if (fm_process_cmd == false)
{ /* Flash manager busy */
/* Append callback to the pending list */
if ((CallbackNode != NULL) && (CallbackNode->Callback != NULL))
{
LST_insert_tail(&fm_cb_pending_list, &(CallbackNode->NodeList));
}
status = FM_BUSY;
}
else
{ /* Flash manager is available */
if ((CallbackNode != NULL) && (CallbackNode->Callback != NULL))
{
UTILS_ENTER_CRITICAL_SECTION();
fm_running_cb = CallbackNode->Callback;
UTILS_EXIT_CRITICAL_SECTION();
}
else
{
UTILS_ENTER_CRITICAL_SECTION();
fm_running_cb = NULL;
UTILS_EXIT_CRITICAL_SECTION();
}
status = FM_OK;
}
return status;
}
/**
* @brief Callback called by RF Timing Synchro module when a time window is available
* @param None
* @retval None
*/
static void FM_WindowAllowed_Callback(void)
{
fm_window_granted = true;
LOG_DEBUG_SYSTEM("\r\nFM_WindowAllowed_Callback");
/* Flash operation to be executed in background */
FM_ProcessRequest();
}

View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* @file flash_manager.h
* @author MCD Application Team
* @brief Header for flash_manager.c module
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef FLASH_MANAGER_H
#define FLASH_MANAGER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
#include "stm_list.h"
/* Exported types ------------------------------------------------------------*/
/* Flash Manager command status */
typedef enum
{
FM_OK, /* The Flash Manager is available and a window request is scheduled */
FM_BUSY, /* The Flash Manager is busy and the caller will be called back when it is available */
FM_ERROR /* An error occurred while processing the command */
} FM_Cmd_Status_t;
/* Flash operation status */
typedef enum
{
FM_OPERATION_COMPLETE, /* The requested flash operation is complete */
FM_OPERATION_AVAILABLE /* A flash operation can be requested */
} FM_FlashOp_Status_t;
/**
* @brief Flash Manager callback node type to store them in a chained list
*/
typedef struct FM_CallbackNode
{
tListNode NodeList; /* Next and previous nodes in the list */
void (*Callback)(FM_FlashOp_Status_t Status); /* Callback function pointer for Flash Manager caller */
}FM_CallbackNode_t;
/* Exported constants --------------------------------------------------------*/
#define TIME_WINDOW_ERASE_DURATION 4000U /* Duration in us of the time window requested for Flash Erase */
#define TIME_WINDOW_WRITE_DURATION 1000U /* Duration in us of the time window requested for Flash Write */
#define TIME_WINDOW_MARGIN 100U /* Time margin added so to ensure timeout protection before actual closure */
/* As timers use ms, amount below 1000 is removed at conversion */
#define TIME_WINDOW_ERASE_REQUEST (TIME_WINDOW_ERASE_DURATION + TIME_WINDOW_MARGIN)
#define TIME_WINDOW_WRITE_REQUEST (TIME_WINDOW_WRITE_DURATION + TIME_WINDOW_MARGIN)
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void FM_Init (void);
FM_Cmd_Status_t FM_Write(uint32_t *Src, uint32_t *Dest, int32_t Size, FM_CallbackNode_t *CallbackNode);
FM_Cmd_Status_t FM_Erase(uint32_t FirstSect, uint32_t NbrSect, FM_CallbackNode_t *CallbackNode);
void FM_BackgroundProcess (void);
void FM_ProcessRequest (void);
#ifdef __cplusplus
}
#endif
#endif /*FLASH_MANAGER_H */

View File

@@ -0,0 +1,216 @@
/**
******************************************************************************
* @file rf_timing_synchro.c
* @author MCD Application Team
* @brief The RF Timing Synchronization module provides an interface to
* synchronize the flash processing versus the RF activity to make
* sure the RF timing is not broken
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include <stdbool.h>
#include "rf_timing_synchro.h"
#include "evnt_schdlr_gnrc_if.h"
#include "utilities_conf.h"
#include "stm32_timer.h"
#include "flash_driver.h"
/* Global variables ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#if (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u)
/**
* @brief Pointer to time window requester's callback
*/
static void (*req_callback)(void);
/**
* @brief Indicates if a time window has already been requested or not
*/
static bool rfts_window_req_pending = FALSE;
/**
* @brief Timer used by the RFTS module to prevent time window overrun
*/
static UTIL_TIMER_Object_t rfts_timer;
/**
* @brief Firmware Link Layer external event handler
*/
static ext_evnt_hndl_t ext_event_handler;
/* Private function prototypes -----------------------------------------------*/
static void RFTS_WindowAllowed_Callback(void);
static void RFTS_Timeout_Callback(void* Argument);
static uint32_t event_started_callback(ext_evnt_hndl_t evnt_hndl, uint32_t slot_durn, void* priv_data_ptr);
#endif /* (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u) */
/* Functions Definition ------------------------------------------------------*/
/**
* @brief Request a time window to the Firmware Link Layer
* @param duration: Duration in us of the time window requested
* @param Callback: Callback to be called when time window is allocated
* @retval RFTS_Cmd_Status_t: Success or failure of the window request
*/
RFTS_Cmd_Status_t RFTS_ReqWindow(uint32_t Duration, void (*Callback)(void))
{
#if (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u)
extrnl_evnt_st_t extrnl_evnt_config;
bool req_pending = false;
if (Callback == NULL)
{ /* Prevent use of uninitialized callback */
return RFTS_WINDOW_REQ_FAILED;
}
/* Check no request is already pending */
UTILS_ENTER_CRITICAL_SECTION();
if (rfts_window_req_pending == true)
{
req_pending = true;
}
else
{
rfts_window_req_pending = true;
}
UTILS_EXIT_CRITICAL_SECTION();
if (req_pending == true)
{ /* A window request is already pending */
return RFTS_WINDOW_REQ_FAILED;
}
/* Register requester's callback */
req_callback = Callback;
/* Submit request to Firmware Link Layer */
extrnl_evnt_config.deadline = 0;
extrnl_evnt_config.strt_min = 0;
extrnl_evnt_config.strt_max = 0;
extrnl_evnt_config.durn_min = Duration;
extrnl_evnt_config.durn_max = 0;
extrnl_evnt_config.prdc_intrvl = 0;
extrnl_evnt_config.priority = PRIORITY_DEFAULT;
extrnl_evnt_config.blocked = STATE_NOT_BLOCKED;
extrnl_evnt_config.ptr_priv = NULL;
extrnl_evnt_config.evnt_strtd_cbk = &event_started_callback;
extrnl_evnt_config.evnt_blckd_cbk = NULL;
extrnl_evnt_config.evnt_abortd_cbk = NULL;
UTIL_TIMER_Create(&rfts_timer,
(Duration/1000),
UTIL_TIMER_ONESHOT,
&RFTS_Timeout_Callback,
NULL);
ext_event_handler = evnt_schdlr_rgstr_gnrc_evnt(&extrnl_evnt_config);
if (ext_event_handler == NULL)
{
UTILS_ENTER_CRITICAL_SECTION();
rfts_window_req_pending = false;
UTILS_EXIT_CRITICAL_SECTION();
return RFTS_WINDOW_REQ_FAILED;
}
#endif /* (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u) */
return RFTS_CMD_OK;
}
/**
* @brief Execute necessary tasks to allow the time window to be released
* @param None
* @retval RFTS_Cmd_Status_t: Success or error in the window release procedure
*/
RFTS_Cmd_Status_t RFTS_RelWindow(void)
{
#if (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u)
RFTS_Cmd_Status_t status;
/* Stop RFTS module window overrun control timer */
UTIL_TIMER_Stop(&rfts_timer);
/* Inform Firmware Link Layer that time window can be released */
if (evnt_schdlr_gnrc_evnt_cmplt(ext_event_handler) == 0)
{
status = RFTS_CMD_OK;
}
else
{
status = RFTS_WINDOW_REL_ERROR;
}
/* Forbid flash operation */
FD_SetStatus(FD_FLASHACCESS_RFTS, LL_FLASH_DISABLE);
UTILS_ENTER_CRITICAL_SECTION();
rfts_window_req_pending = false;
UTILS_EXIT_CRITICAL_SECTION();
return status;
#else
return RFTS_CMD_OK;
#endif /* (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u) */
}
#if (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u)
/**
* @brief Callback called by Firmware Link Layer when a time window is available
* @note This callback is supposed to be called under interrupt
* @param None
* @retval None
*/
static void RFTS_WindowAllowed_Callback(void)
{
/* Allow flash operation */
FD_SetStatus(FD_FLASHACCESS_RFTS, LL_FLASH_ENABLE);
/* Start timer preventing window overrun */
UTIL_TIMER_Start(&rfts_timer);
/* Call back requester to inform time window is available */
req_callback();
}
/**
* @brief Callback triggered by a timeout when the allocated window time is elapsed
* @note This callback is supposed to be called under interrupt
* @param None
* @retval None
*/
static void RFTS_Timeout_Callback(void* Argument)
{
/* Forbid flash operation */
FD_SetStatus(FD_FLASHACCESS_RFTS, LL_FLASH_DISABLE);
UTILS_ENTER_CRITICAL_SECTION();
rfts_window_req_pending = false;
UTILS_EXIT_CRITICAL_SECTION();
}
static uint32_t event_started_callback(ext_evnt_hndl_t evnt_hndl, uint32_t slot_durn, void* priv_data_ptr)
{
RFTS_WindowAllowed_Callback();
return 0;
}
#endif /* (DISABLE_RFTS_EXT_EVNT_HNDLR == 0u) */

View File

@@ -0,0 +1,54 @@
/**
******************************************************************************
* @file rf_timing_synchro.h
* @author MCD Application Team
* @brief Header for rf_timing_synchro.c module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef RF_TIMING_SYNCHRO_H
#define RF_TIMING_SYNCHRO_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
/* Exported types ------------------------------------------------------------*/
/* RFTS command status */
typedef enum
{
RFTS_CMD_OK, /* The RF Timing synchronization command was successfully executed */
RFTS_WINDOW_REQ_FAILED, /* The RF Timing synchronization module failed to register the window request */
RFTS_WINDOW_REL_ERROR /* An error occurred during the window release procedure */
} RFTS_Cmd_Status_t;
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
RFTS_Cmd_Status_t RFTS_ReqWindow(uint32_t Duration, void (*Callback)(void));
RFTS_Cmd_Status_t RFTS_RelWindow(void);
#ifdef __cplusplus
}
#endif
#endif /*RF_TIMING_SYNCHRO_H */

View File

@@ -0,0 +1,130 @@
/**
******************************************************************************
* @file simple_nvm_arbiter.h
* @author MCD Application Team
* @brief Header for simple_nvm_arbiter.c module
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SIMPLE_NVM_ARBITER_H
#define SIMPLE_NVM_ARBITER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "simple_nvm_arbiter_common.h"
#include "simple_nvm_arbiter_conf.h"
#include "utilities_common.h"
/* Exported constants --------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief Initialize the Simple NVM Arbiter
*
* @param p_NvmStartAddress: Start address of the NVM to work with - Shall be aligned 128 bits
*
* @return Status of the command
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_OK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NOK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_ALREADY_INIT
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NVM_NULL
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NVM_NOT_ALIGNED
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NVM_OVERLAP_FLASH
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_CRC_INIT
*/
SNVMA_Cmd_Status_t SNVMA_Init (const uint32_t * p_NvmStartAddress);
/**
* @brief Register a user buffer to a NVM
*
* @details Buffer IDs are hardcoded, please refer to SNVMA_BufferId_t enumeration
*
* @param BufferId: Id of the user which ask for buffer registration
* @param p_BufferAddress: Address of the buffer to be registered - Shall be aligned 32 bits
* @param BufferSize: Size of the buffer to be registered - Shall be a multiple of 32bits
*
* @return Status of the command
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_OK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NOK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NOT_INIT
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_CMD_PENDING
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFERID_NOT_KNOWN
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFER_NULL
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFER_NOT_ALIGNED
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFER_SIZE
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NVM_BUFFER_FULL
*/
SNVMA_Cmd_Status_t SNVMA_Register (const SNVMA_BufferId_t BufferId,
const uint32_t * p_BufferAddress,
const uint32_t BufferSize);
/**
* @brief Restore a user buffer from a NVM
*
* @details The user buffer information shall first be provided by calling SNVMA_Register
*
* @details Buffer IDs are hardcoded, please refer to SNVMA_BufferId_t enumeration
*
* @param BufferId: Id of the user which ask for buffer registration
*
* @return Status of the command
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_OK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NOK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NOT_INIT
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_CMD_PENDING
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFERID_NOT_KNOWN
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFERID_NOT_REGISTERED
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NVM_BANK_EMPTY
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NVM_BANK_CORRUPTED
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFER_CONFIG_MISSMATCH
*/
SNVMA_Cmd_Status_t SNVMA_Restore (const SNVMA_BufferId_t BufferId);
/**
* @brief Register a user buffer to a NVM
*
* @details The user buffer information shall first be provided by calling SNVMA_Register
*
* @details Buffer IDs are hardcoded, please refer to SNVMA_BufferId_t enumeration
*
* @details A buffer write request cannot be scheduled once its NVM is already on a write operation. This will lead
* to a SNVMA_OPERATION_FAILED callback status.
*
* @param BufferId: Id of the user which ask for buffer registration
* @param Callback: Callback function for operation status return - Can be NULL
*
* @return Status of the command
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_OK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NOK
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_NOT_INIT
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFERID_NOT_KNOWN
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_BUFFERID_NOT_REGISTERED
* @retval SNVMA_Cmd_Status_t::SNVMA_ERROR_FLASH_ERROR
*/
SNVMA_Cmd_Status_t SNVMA_Write (const SNVMA_BufferId_t BufferId,
void (* Callback) (SNVMA_Callback_Status_t));
#ifdef __cplusplus
}
#endif
#endif /*SIMPLE_NVM_ARBITER_H */

View File

@@ -0,0 +1,135 @@
/**
******************************************************************************
* @file simple_nvm_arbiter_common.h
* @author MCD Application Team
* @brief Common header of simple_nvm_arbiter.c module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SIMPLE_NVM_ARBITER_COMMON_H
#define SIMPLE_NVM_ARBITER_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
/* Exported constants --------------------------------------------------------*/
/* Maximum number of different NVM Identifiers */
#define SNVMA_MAX_NUMBER_NVM 32u
/* Maximum number of buffer per NVM */
#define SNVMA_MAX_NUMBER_BUFFER 4u
/* Minimum number of bank per NVM */
#define SNVMA_MIN_NUMBER_BANK 2u
/* Exported types ------------------------------------------------------------*/
/* SNVMA command status */
typedef enum SNVMA_Cmd_Status
{
SNVMA_ERROR_OK,
SNVMA_ERROR_NOK,
SNVMA_ERROR_NOT_INIT,
SNVMA_ERROR_ALREADY_INIT,
SNVMA_ERROR_CMD_PENDING,
SNVMA_ERROR_BANK_OP_ONGOING,
SNVMA_ERROR_NVM_NULL,
SNVMA_ERROR_NVM_NOT_ALIGNED,
SNVMA_ERROR_NVM_OVERLAP_FLASH,
SNVMA_ERROR_NVM_BUFFER_FULL,
SNVMA_ERROR_NVM_BANK_EMPTY,
SNVMA_ERROR_NVM_BANK_CORRUPTED,
SNVMA_ERROR_CRC_INIT,
SNVMA_ERROR_BANK_NUMBER,
SNVMA_ERROR_BANK_SIZE,
SNVMA_ERROR_BUFFERID_NOT_KNOWN,
SNVMA_ERROR_BUFFERID_NOT_REGISTERED,
SNVMA_ERROR_BUFFER_NULL,
SNVMA_ERROR_BUFFER_NOT_ALIGNED,
SNVMA_ERROR_BUFFER_SIZE,
SNVMA_ERROR_BUFFER_CONFIG_MISSMATCH,
SNVMA_ERROR_FLASH_ERROR,
SNVMA_ERROR_UNKNOWN,
} SNVMA_Cmd_Status_t;
/* SNVMA callback status */
typedef enum SNVMA_Callback_Status
{
SNVMA_OPERATION_COMPLETE,
SNVMA_OPERATION_FAILED
}SNVMA_Callback_Status_t;
/* Buffer Element */
typedef struct SNVMA_BufferElt
{
/* Buffer address */
uint32_t * p_Addr;
/* Buffer size */
uint32_t Size;
}SNVMA_BufferElt_t;
/* Bank Element */
typedef struct SNVMA_BankElt
{
/* Pointer onto the start address of the bank */
uint32_t * p_StartAddr;
/* Pointer onto the buffer address in the bank */
uint32_t * ap_BufferAddr[SNVMA_MAX_NUMBER_BUFFER];
}SNVMA_BankElt_t;
/* NVM Element */
typedef struct SNVMA_NvmElt
{
/* Bank number */
uint8_t BankNumber;
/* Bank size */
uint8_t BankSize;
/*
* Pending buffer write operations bit mask
*
* ----------------------------------------
* + 4 bits | 4 bits +
* + ------------------------------------ +
* + Active Request | New Request +
* ----------------------------------------
*
*/
uint8_t PendingBufferWriteOp;
/* Pointer onto the bank list */
SNVMA_BankElt_t * p_BankList;
/* Pointer onto the bank being used for write operation */
SNVMA_BankElt_t * p_BankForWrite;
/* Pointer onto the bank being used for restore operation */
SNVMA_BankElt_t * p_BankForRestore;
/* Callback pointer array */
void (* a_Callback [SNVMA_MAX_NUMBER_BUFFER]) (SNVMA_Callback_Status_t);
/* Array of buffers in use */
SNVMA_BufferElt_t a_Buffers [SNVMA_MAX_NUMBER_BUFFER];
}SNVMA_NvmElt_t;
/* Exported variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
#ifdef __cplusplus
}
#endif
#endif /*SIMPLE_NVM_ARBITER_COMMON_H */

View File

@@ -0,0 +1,298 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file log_module.c
* @author MCD Application Team
* @brief Source file of the log module.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include <stdio.h> /* vsnprintf */
#include "log_module.h"
#include "stm32_adv_trace.h"
#include "utilities_conf.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* Definition of 'End Of Line' */
#define ENDOFLINE_SIZE (0x01u)
#define ENDOFLINE_CHAR '\n'
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Exported constants --------------------------------------------------------*/
/* Global const struct variables to make the life of the user easier */
const Log_Module_t LOG_MODULE_DEFAULT_CONFIGURATION =
{
.verbose_level = LOG_VERBOSE_ERROR,
.region_mask = (LOG_REGION_ALL_REGIONS)
};
const Log_Verbose_Level_t LOG_VERBOSE_DEFAULT = LOG_VERBOSE_ERROR;
const Log_Region_t LOG_REGION_MASK_DEFAULT = LOG_REGION_ALL_REGIONS;
const Log_Color_t LOG_COLOR_DEFAULT_CONFIGURATION[] =
{
LOG_COLOR_CODE_DEFAULT, // For Region BLE
LOG_COLOR_CODE_DEFAULT, // For Region System
LOG_COLOR_CODE_DEFAULT, // For Region APP
LOG_COLOR_CODE_RED, // For Region LinkLayer
LOG_COLOR_CODE_YELLOW, // For Region MAC
LOG_COLOR_CODE_GREEN, // For Region Zigbee
LOG_COLOR_CODE_GREEN, // For Region Thread
LOG_COLOR_CODE_DEFAULT, // For Region RTOS
/* USER CODE BEGIN LOG_COLOR_DEFAULT_CONFIGURATION */
/* USER CODE END LOG_COLOR_DEFAULT_CONFIGURATION */
};
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Private variables ---------------------------------------------------------*/
static uint32_t current_region_mask;
static Log_Verbose_Level_t current_verbose_level;
static Log_Color_t current_color_list[32];
CallBack_TimeStamp * log_timestamp_function;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
static uint32_t Get_Region_Mask(Log_Region_t Region);
#if (LOG_INSERT_COLOR_INSIDE_THE_TRACE != 0)
static uint16_t RegionToColor(char * TextBuffer, uint16_t SizeMax, Log_Region_t Region);
#endif /* LOG_INSERT_COLOR_INSIDE_THE_TRACE != 0 */
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Functions Definition ------------------------------------------------------*/
#if (LOG_INSERT_COLOR_INSIDE_THE_TRACE != 0)
/**
* @brief Add the color (in function of Region) on the start of Log sentence.
*
* @param TextBuffer Pointer on the log buffer
* @param SizeMax The maximum number of bytes that will be written to the buffer.
* @param Region Region of the log to apply its corresponding color.
*
* @return Length of the new Log.
*/
static uint16_t RegionToColor(char * TextBuffer, uint16_t SizeMax, Log_Region_t Region)
{
uint16_t text_length = 0;
Log_Color_t color;
static Log_Color_t previous_color = LOG_COLOR_NONE;
if (Region != LOG_MODULE_ALL_REGION_MASK)
{
color = current_color_list[Region];
}
else
{
color = LOG_COLOR_CODE_DEFAULT;
}
/* Insert Color code only if previous is not the same */
if (color != previous_color)
{
if (color == LOG_COLOR_CODE_DEFAULT)
{
snprintf(TextBuffer, SizeMax, "\x1b[0m");
}
else
{
snprintf(TextBuffer, SizeMax, "\x1b[0;%02dm", color);
}
previous_color = color;
text_length = strlen(TextBuffer);
}
return text_length;
}
#endif /* LOG_INSERT_COLOR_INSIDE_THE_TRACE != 0 */
void Log_Module_PrintWithArg(Log_Verbose_Level_t VerboseLevel, Log_Region_t Region, const char * Text, va_list Args)
{
uint16_t tmp_size = 0;
uint16_t buffer_size = 0;
char full_text[UTIL_ADV_TRACE_TMP_BUF_SIZE + 1u];
/* USER CODE BEGIN Log_Module_PrintWithArg_1 */
/* USER CODE END Log_Module_PrintWithArg_1 */
/* If the verbose level of the given log is not enabled, then we do not print the log */
if (VerboseLevel > current_verbose_level)
{
return;
}
/* If the region for the given log is not enabled, then we do not print the log */
if ((Get_Region_Mask(Region) & current_region_mask) == 0u)
{
return;
}
#if (LOG_INSERT_COLOR_INSIDE_THE_TRACE != 0)
/* Add to full_text the color matching the region */
tmp_size = RegionToColor(&full_text[buffer_size], (UTIL_ADV_TRACE_TMP_BUF_SIZE - buffer_size), Region);
buffer_size += tmp_size;
#endif /* LOG_INSERT_COLOR_INSIDE_THE_TRACE != 0 */
#if (LOG_INSERT_TIME_STAMP_INSIDE_THE_TRACE != 0)
if (log_timestamp_function != NULL)
{
tmp_size = UTIL_ADV_TRACE_TMP_BUF_SIZE - buffer_size;
log_timestamp_function(&full_text[buffer_size], tmp_size, &tmp_size);
buffer_size += tmp_size;
}
#endif /* LOG_INSERT_TIME_STAMP_INSIDE_THE_TRACE != 0 */
/* Copy the data */
tmp_size = (uint16_t)vsnprintf(&full_text[buffer_size], (UTIL_ADV_TRACE_TMP_BUF_SIZE - buffer_size), Text, Args);
buffer_size += tmp_size;
/* USER CODE BEGIN Log_Module_PrintWithArg_2 */
/* USER CODE END Log_Module_PrintWithArg_2 */
#if (LOG_INSERT_EOL_INSIDE_THE_TRACE != 0)
/* Add End Of Line if needed */
if (buffer_size > 1)
{
if ((full_text[buffer_size - 1] != ENDOFLINE_CHAR) && (full_text[buffer_size - 2] != ENDOFLINE_CHAR))
{
full_text[buffer_size++] = ENDOFLINE_CHAR;
full_text[buffer_size] = 0;
}
}
#endif /* LOG_INSERT_EOL_INSIDE_THE_TRACE != 0 */
/* USER CODE BEGIN Log_Module_PrintWithArg_3 */
/* USER CODE END Log_Module_PrintWithArg_3 */
/* Send full_text to ADV Traces */
UTIL_ADV_TRACE_Send((const uint8_t *)full_text, buffer_size);
}
void Log_Module_Print(Log_Verbose_Level_t VerboseLevel, Log_Region_t Region, const char * Text, ...)
{
#if (CFG_LOG_SUPPORTED != 0)
va_list variadic_args;
va_start(variadic_args, Text);
Log_Module_PrintWithArg(VerboseLevel, Region, Text, variadic_args);
va_end(variadic_args);
#else /* (CFG_LOG_SUPPORTED != 0) */
UNUSED(VerboseLevel);
UNUSED(Region);
UNUSED(Text);
#endif /* (CFG_LOG_SUPPORTED != 0) */
}
void Log_Module_Init(Log_Module_t LogConfiguration)
{
UTIL_ADV_TRACE_Init();
memcpy(&current_color_list, &LOG_COLOR_DEFAULT_CONFIGURATION, sizeof(LOG_COLOR_DEFAULT_CONFIGURATION));
Log_Module_Set_Verbose_Level(LogConfiguration.verbose_level);
Log_Module_Set_Multiple_Regions(LogConfiguration.region_mask);
log_timestamp_function = NULL;
}
void Log_Module_DeInit(void)
{
UTIL_ADV_TRACE_DeInit();
}
void Log_Module_Set_Verbose_Level(Log_Verbose_Level_t NewVerboseLevel)
{
current_verbose_level = NewVerboseLevel;
}
void Log_Module_Set_Region(Log_Region_t NewRegion)
{
current_region_mask = Get_Region_Mask(NewRegion);
}
void Log_Module_Add_Region(Log_Region_t NewRegion)
{
current_region_mask |= Get_Region_Mask(NewRegion);
}
void Log_Module_Remove_Region(Log_Region_t Region)
{
current_region_mask &= ~Get_Region_Mask(Region);
}
void Log_Module_Enable_All_Regions(void)
{
Log_Module_Set_Region(LOG_REGION_ALL_REGIONS);
}
static uint32_t Get_Region_Mask(Log_Region_t Region)
{
if (Region == LOG_REGION_ALL_REGIONS)
{
/* Return the full mask */
return ((uint32_t)LOG_MODULE_ALL_REGION_MASK);
}
else
{
/* Return the bit matching the region */
return ((uint32_t)(1U << ((uint32_t)Region)));
}
}
void Log_Module_Set_Multiple_Regions(uint32_t NewRegionMask)
{
current_region_mask = NewRegionMask;
}
void Log_Module_Set_Color(Log_Region_t Region, Log_Color_t Color)
{
if ( Region != LOG_MODULE_ALL_REGION_MASK )
{
current_color_list[Region] = Color;
}
}
void Log_Module_RegisterTimeStampFunction(CallBack_TimeStamp * TimeStampFunction)
{
log_timestamp_function = TimeStampFunction;
}
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */

View File

@@ -0,0 +1,220 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file log_module.h
* @author MCD Application Team
* @brief Header file of the log module.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef LOG_MODULE_H
#define LOG_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include <stdarg.h>
#include <stdint.h>
#include <stdbool.h>
#include "log_module_conf.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
/* Log module types */
/**
* @brief Data type to initialize the module by calling Log_Module_Init.
* verbose_level : A value of type Log_Verbose_Level_t.
* region_mask : A mask based on Log_Region_t.
* You can directly assign it to LOG_REGION_ALL_REGIONS,
* or select only some regions :
* (1U << LOG_REGION_BLE | 1U << LOG_REGION_APP)
*/
typedef struct
{
Log_Verbose_Level_t verbose_level;
uint32_t region_mask;
} Log_Module_t;
/**
* @brief Callback function to insert Time Stamp.
*
* @param Data The data into which to insert the TimeStamp.
* @param SizeMax The maximum size for the TimeStamp insert.
* @param TimeStampSize Pointer to update with the size of the TimeStamp inserted into data.
*/
typedef void CallBack_TimeStamp(char * Data, uint16_t SizeMax, uint16_t * TimeStampSize);
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported constants --------------------------------------------------------*/
/* Global const struct variables to make the life of the user easier */
/**
* @brief A const struct with default parameters for the log module.
* Its main use is to pass it as parameter to Log_Module_Init.
*/
extern const Log_Module_t LOG_MODULE_DEFAULT_CONFIGURATION;
/**
* @brief A const enum variable with the verbose level set to LOG_VERBOSE_ERROR.
* The levels include the lower levels in the logs.
*
* E.g. LOG_VERBOSE_ERROR means LOG_VERBOSE_ERROR logs will be printed,
* as well as LOG_VERBOSE_INFO, but not the others with higher values.
*/
extern const Log_Verbose_Level_t LOG_VERBOSE_DEFAULT;
/**
* @brief A const enum variable to include all regions in the logs.
*/
extern const Log_Region_t LOG_REGION_MASK_DEFAULT;
/* USER CODE BEGIN EC */
/* USER CODE END EC */
/* Exported functions prototypes ---------------------------------------------*/
/* Module API - Module configuration */
/**
* @brief Initialization of the log module.
*
* @param LogConfiguration The configuration of the log module, of type Log_Module_t.
* @return None.
*/
void Log_Module_Init(Log_Module_t LogConfiguration);
/**
* @brief DeInitialization of the log module.
*
* @param None.
* @return None.
*/
void Log_Module_DeInit(void);
/**
* @brief Set the verbose level of the log.
* The levels include the lower levels in the logs.
*
* E.g. LOG_VERBOSE_ERROR means LOG_VERBOSE_ERROR logs will be printed,
* as well as LOG_VERBOSE_INFO, but not the others with higher values.
*
* @param NewVerboseLevel The new verbose level to be set, of type Log_Verbose_Level_t
* @return None
*/
void Log_Module_Set_Verbose_Level(Log_Verbose_Level_t NewVerboseLevel);
/**
* @brief Replace the current regions in use and only set the given region.
*
* @param NewRegion The new region to use, of type Log_Region_t.
* @return None.
*/
void Log_Module_Set_Region(Log_Region_t NewRegion);
/**
* @brief Replace the current regions in use and set one or several as replacement.
*
* @param NewRegionMask A mask, of type uint32_t, where each bit corresponds to a region.
* You can directly assign it to LOG_REGION_ALL_REGIONS to enable all of them,
* or select only some regions, e.g. (1U << LOG_REGION_BLE | 1U << LOG_REGION_APP)
* @return None.
*/
void Log_Module_Set_Multiple_Regions(uint32_t NewRegionMask);
/**
* @brief Add to the current region mask the given region.
*
* @param NewRegion The new region to use, alongside the others, of type Log_Region_t.
* @return None.
*/
void Log_Module_Add_Region(Log_Region_t NewRegion);
/**
* @brief Remove from the current region mask the given region.
*
* @param Region The region to remove, of type Log_Region_t.
* @return None.
*/
void Log_Module_Remove_Region(Log_Region_t Region);
/**
* @brief Enable all the regions.
*
* @param None.
* @return None.
*/
void Log_Module_Enable_All_Regions(void);
/**
* @brief Set the color for a region.
*
* @param Region The region where apply the color, type Log_Region_t.
* @param Color The color to apply to selected region, of type Log_Color_t.
* @return None.
*/
void Log_Module_Set_Color(Log_Region_t Region, Log_Color_t Color);
/**
* @brief Register a callback function to insert the TimeStamp into the data.
*
* @param TimeStampFunction Callback function to insert TimeStamp.
* This function is typedef void (char * data, uint16_t size_max, uint16_t * timestamp_size);
* Where data is the location where to insert the new TimeStamp, and timestamp_size is the size of this insertion.
* @return None.
*/
void Log_Module_RegisterTimeStampFunction(CallBack_TimeStamp * TimeStampFunction);
/* Module API - Wrapper function */
/**
* @brief Underlying function of all the LOG_xxx macros.
*
* @param VerboseLevel The level of verbose used for this Log, of type Log_Verbose_Level_t.
* @param Region The region set for this log, of type Log_Region_t.
* @param Text The text to be printed.
* @param ... Any other parameters to be printed with the text.
* E.g. an int variable. as 3rd parameter, as long as %d is in text.
*
* @return None.
*/
void Log_Module_Print(Log_Verbose_Level_t VerboseLevel, Log_Region_t Region, const char * Text, ...);
/**
* @brief Function of log with already a arg list.
*
* @param VerboseLevel The level of verbose used for this Log, of type Log_Verbose_Level_t.
* @param Region The region set for this log, of type Log_Region_t.
* @param Text The text to be printed
* @param Args Arguments list, of type va_list.
*
* @return None.
*/
void Log_Module_PrintWithArg(Log_Verbose_Level_t VerboseLevel, Log_Region_t Region, const char * Text, va_list Args);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */
#ifdef __cplusplus
}
#endif
#endif /* LOG_MODULE_H */

View File

@@ -0,0 +1,294 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file log_module_conf.h
* @author MCD Application Team
* @brief Header file of the log module.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef LOG_MODULE_CONF_H
#define LOG_MODULE_CONF_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "app_conf.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Module configuration ------------------------------------------------------*/
/**
* @brief When this define is set to 0, there is no time stamp added to the trace data.
* When this define is set to 1, the time stamp is added to the trace data,
* according to the function registered with Log_Module_RegisterTimeStampFunction.
*/
#define LOG_INSERT_TIME_STAMP_INSIDE_THE_TRACE CFG_LOG_INSERT_TIME_STAMP_INSIDE_THE_TRACE
/**
* @brief When this define is set to 0, the color of the trace data remains the same for all regions.
* When this define is set to 1, the color added to the trace data is based on LOG_COLOR_DEFAULT_CONFIGURATION.
*/
#define LOG_INSERT_COLOR_INSIDE_THE_TRACE CFG_LOG_INSERT_COLOR_INSIDE_THE_TRACE
/**
* @brief When this define is set to 0, the trace data is not modified.
* When this define is set to 1, if there is no ENDOFLINE_CHAR as last
* character in the trace data, then one is added.
*/
#define LOG_INSERT_EOL_INSIDE_THE_TRACE CFG_LOG_INSERT_EOL_INSIDE_THE_TRACE
/* USER CODE BEGIN Module configuration */
/* USER CODE END Module configuration */
/* Private defines -----------------------------------------------------------*/
/* These defines are related to the UTIL_ADV_TRACE. Do not modify them please. */
#define LOG_MODULE_MIN_VERBOSE_LEVEL (0)
#define LOG_MODULE_MAX_VERBOSE_LEVEL (0xFFFFFFFF)
#define LOG_MODULE_MIN_REGION_VALUE (0)
#define LOG_MODULE_ALL_REGION_MASK (0xFFFFFFFF)
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Exported types ------------------------------------------------------------*/
/* Log module types */
/**
* @brief Customizable enum describing the verbose levels used by the log module.
* The levels include the lower levels in the logs.
*
* E.g. LOG_VERBOSE_ERROR means LOG_VERBOSE_ERROR logs will be printed,
* as well as LOG_VERBOSE_INFO, but not the others with higher values.
*
* The min and max ranges are defined by LOG_MODULE_MIN_VERBOSE_LEVEL
* and LOG_MODULE_MAX_VERBOSE_LEVEL.
*
* The user can add its own levels but must NOT add a value to the said
* levels. Verbose levels are handled by the UTIL_ADV_TRACE.
*/
typedef enum
{
LOG_VERBOSE_INFO = LOG_MODULE_MIN_VERBOSE_LEVEL,
/* USER CODE BEGIN Log_Verbose_Level_t_0 */
/* USER CODE END Log_Verbose_Level_t_0 */
LOG_VERBOSE_ERROR,
/* USER CODE BEGIN Log_Verbose_Level_t_1 */
/* USER CODE END Log_Verbose_Level_t_1 */
LOG_VERBOSE_WARNING,
/* USER CODE BEGIN Log_Verbose_Level_t_2 */
/* USER CODE END Log_Verbose_Level_t_2 */
LOG_VERBOSE_DEBUG,
/* USER CODE BEGIN Log_Verbose_Level_t_3 */
/* USER CODE END Log_Verbose_Level_t_3 */
LOG_VERBOSE_ALL_LOGS = LOG_MODULE_MAX_VERBOSE_LEVEL,
} Log_Verbose_Level_t;
/**
* @brief Customizable enum describing the regions used by the log module.
* Regions are used to separate the logs into different places.
*
* Let's say you have a Task 1 and a Task 2.
* Both of them have Info and Debug logs.
*
* By using them as such, i.e. with the same regions, you'll
* print the logs of the 2 tasks as long as the verbose is Info or Debug.
*
* If you create a region for Task 1 and another for Task 2, you can
* split the logs between them, and, if needed, only print the Debug
* logs for Task 1 only (i.e. Task 1 logs for Info and Debug).
*
* Behind the scenes is a mask into which each region is a bit.
* The user can add its own regions but must NOT add a value to them.
* The log module handles the mask on its own.
*/
typedef enum
{
LOG_REGION_BLE = LOG_MODULE_MIN_REGION_VALUE,
LOG_REGION_SYSTEM,
LOG_REGION_APP,
LOG_REGION_LINKLAYER,
LOG_REGION_MAC,
LOG_REGION_ZIGBEE,
LOG_REGION_THREAD,
LOG_REGION_RTOS,
/* USER CODE BEGIN Log_Region_t */
/* USER CODE END Log_Region_t */
LOG_REGION_ALL_REGIONS = LOG_MODULE_ALL_REGION_MASK,
} Log_Region_t;
typedef enum
{
LOG_COLOR_NONE = 0, /* Initialization */
LOG_COLOR_CODE_DEFAULT = 37, /* White */
LOG_COLOR_CODE_RED = 91,
LOG_COLOR_CODE_GREEN = 92,
LOG_COLOR_CODE_YELLOW = 93,
LOG_COLOR_CODE_CYAN = 96,
/* USER CODE BEGIN Log_Color_t */
/* USER CODE END Log_Color_t */
} Log_Color_t;
/* USER CODE BEGIN ET */
/* USER CODE END ET */
/* Exported macro ------------------------------------------------------------*/
/* Display 64 bits number for all compiler. */
/* Example : LOG_INFO_APP( "New Device : " LOG_DISPLAY64() " installed in %d seconds", LOG_NUMBER64( dlDevice ), iTime ); */
#define LOG_DISPLAY64() "0x%08X%08X"
#define LOG_NUMBER64( number ) (uint32_t)( number >> 32u ), (uint32_t)( number )
/* Module API - Log macros for each region */
/* LOG_REGION_BLE */
#if (CFG_LOG_SUPPORTED != 0)
#define LOG_INFO_BLE(...) Log_Module_Print( LOG_VERBOSE_INFO, LOG_REGION_BLE, __VA_ARGS__)
#define LOG_ERROR_BLE(...) Log_Module_Print( LOG_VERBOSE_ERROR, LOG_REGION_BLE, __VA_ARGS__)
#define LOG_WARNING_BLE(...) Log_Module_Print( LOG_VERBOSE_WARNING, LOG_REGION_BLE, __VA_ARGS__)
#define LOG_DEBUG_BLE(...) Log_Module_Print( LOG_VERBOSE_DEBUG, LOG_REGION_BLE, __VA_ARGS__)
#else /* (CFG_LOG_SUPPORTED != 0) */
#define LOG_INFO_BLE(...) do {} while(0)
#define LOG_ERROR_BLE(...) do {} while(0)
#define LOG_WARNING_BLE(...) do {} while(0)
#define LOG_DEBUG_BLE(...) do {} while(0)
#endif /* (CFG_LOG_SUPPORTED != 0) */
/* USER CODE BEGIN LOG_REGION_BLE */
/**
* Add inside this user section your defines to match the new verbose levels you
* created into Log_Verbose_Level_t.
* Example :
* #define LOG_CUSTOM_BLE(...) Log_Module_Print( LOG_VERBOSE_CUSTOM, LOG_REGION_BLE, __VA_ARGS__);
*
* You don't need to update all regions with your custom values.
* Do it accordingly to your needs. E.g you might not need LOG_VERBOSE_CUSTOM for a System region.
*/
/* USER CODE END LOG_REGION_BLE */
/* LOG_REGION_SYSTEM */
#if (CFG_LOG_SUPPORTED != 0)
#define LOG_INFO_SYSTEM(...) Log_Module_Print( LOG_VERBOSE_INFO, LOG_REGION_SYSTEM, __VA_ARGS__)
#define LOG_ERROR_SYSTEM(...) Log_Module_Print( LOG_VERBOSE_ERROR, LOG_REGION_SYSTEM, __VA_ARGS__)
#define LOG_WARNING_SYSTEM(...) Log_Module_Print( LOG_VERBOSE_WARNING, LOG_REGION_SYSTEM, __VA_ARGS__)
#define LOG_DEBUG_SYSTEM(...) Log_Module_Print( LOG_VERBOSE_DEBUG, LOG_REGION_SYSTEM, __VA_ARGS__)
#else /* (CFG_LOG_SUPPORTED != 0) */
#define LOG_INFO_SYSTEM(...) do {} while(0)
#define LOG_ERROR_SYSTEM(...) do {} while(0)
#define LOG_WARNING_SYSTEM(...) do {} while(0)
#define LOG_DEBUG_SYSTEM(...) do {} while(0)
#endif /* (CFG_LOG_SUPPORTED != 0) */
/* USER CODE BEGIN LOG_REGION_SYSTEM */
/**
* Add inside this user section your defines to match the new verbose levels you
* created into Log_Verbose_Level_t.
* Example :
* #define LOG_CUSTOM_SYSTEM(...) Log_Module_Print( LOG_VERBOSE_CUSTOM, LOG_REGION_SYSTEM, __VA_ARGS__);
*
* You don't need to update all regions with your custom values.
* Do it accordingly to your needs. E.g you might not need LOG_VERBOSE_CUSTOM for a System region.
*/
/* USER CODE END LOG_REGION_SYSTEM */
/* LOG_REGION_APP */
#if (CFG_LOG_SUPPORTED != 0)
#define LOG_INFO_APP(...) Log_Module_Print( LOG_VERBOSE_INFO, LOG_REGION_APP, __VA_ARGS__)
#define LOG_ERROR_APP(...) Log_Module_Print( LOG_VERBOSE_ERROR, LOG_REGION_APP, __VA_ARGS__)
#define LOG_WARNING_APP(...) Log_Module_Print( LOG_VERBOSE_WARNING, LOG_REGION_APP, __VA_ARGS__)
#define LOG_DEBUG_APP(...) Log_Module_Print( LOG_VERBOSE_DEBUG, LOG_REGION_APP, __VA_ARGS__)
#else /* (CFG_LOG_SUPPORTED != 0) */
#define LOG_INFO_APP(...) do {} while(0)
#define LOG_ERROR_APP(...) do {} while(0)
#define LOG_WARNING_APP(...) do {} while(0)
#define LOG_DEBUG_APP(...) do {} while(0)
#endif /* (CFG_LOG_SUPPORTED != 0) */
/* USER CODE BEGIN LOG_REGION_APP */
/**
* Add inside this user section your defines to match the new verbose levels you
* created into Log_Verbose_Level_t.
* Example :
* #define LOG_CUSTOM_APP(...) Log_Module_Print( LOG_VERBOSE_CUSTOM, LOG_REGION_APP, __VA_ARGS__);
*
* You don't need to update all regions with your custom values.
* Do it accordingly to your needs. E.g you might not need LOG_VERBOSE_CUSTOM for a System region.
*/
/* USER CODE END LOG_REGION_APP */
/* LOG_REGION_LINKLAYER */
#if (CFG_LOG_SUPPORTED != 0)
#define LOG_INFO_LINKLAYER(...) Log_Module_Print( LOG_VERBOSE_INFO, LOG_REGION_LINKLAYER, __VA_ARGS__)
#define LOG_ERROR_LINKLAYER(...) Log_Module_Print( LOG_VERBOSE_ERROR, LOG_REGION_LINKLAYER, __VA_ARGS__)
#define LOG_WARNING_LINKLAYER(...)Log_Module_Print( LOG_VERBOSE_WARNING, LOG_REGION_LINKLAYER, __VA_ARGS__)
#define LOG_DEBUG_LINKLAYER(...) Log_Module_Print( LOG_VERBOSE_DEBUG, LOG_REGION_LINKLAYER, __VA_ARGS__)
#else /* (CFG_LOG_SUPPORTED != 0) */
#define LOG_INFO_LINKLAYER(...) do {} while(0)
#define LOG_ERROR_LINKLAYER(...) do {} while(0)
#define LOG_WARNING_LINKLAYER(...)do {} while(0)
#define LOG_DEBUG_LINKLAYER(...) do {} while(0)
#endif /* (CFG_LOG_SUPPORTED != 0) */
/* USER CODE BEGIN LOG_REGION_LINKLAYER */
/**
* Add inside this user section your defines to match the new verbose levels you
* created into Log_Verbose_Level_t.
* Example :
* #define LOG_CUSTOM_LINKLAYER(...) Log_Module_Print( LOG_VERBOSE_CUSTOM, LOG_REGION_LINKLAYER, __VA_ARGS__);
*
* You don't need to update all regions with your custom values.
* Do it accordingly to your needs. E.g you might not need LOG_VERBOSE_CUSTOM for a System region.
*/
/* USER CODE END LOG_REGION_LINKLAYER */
/* USER CODE BEGIN APP_LOG_USER_DEFINES */
/**
* Add inside this user section your defines to match the new regions you
* created into Log_Region_t.
* Example :
#if (CFG_LOG_SUPPORTED != 0)
#define LOG_INFO_CUSTOM(...) Log_Module_Print( LOG_VERBOSE_INFO, LOG_REGION_CUSTOM, __VA_ARGS__)
#define LOG_ERROR_CUSTOM(...) Log_Module_Print( LOG_VERBOSE_ERROR, LOG_REGION_CUSTOM, __VA_ARGS__)
#define LOG_WARNING_CUSTOM(...) Log_Module_Print( LOG_VERBOSE_WARNING, LOG_REGION_CUSTOM, __VA_ARGS__)
#define LOG_DEBUG_CUSTOM(...) Log_Module_Print( LOG_VERBOSE_DEBUG, LOG_REGION_CUSTOM, __VA_ARGS__)
#else
#define LOG_INFO_CUSTOM(...) do {} while(0)
#define LOG_ERROR_CUSTOM(...) do {} while(0)
#define LOG_WARNING_CUSTOM(...) do {} while(0)
#define LOG_DEBUG_CUSTOM(...) do {} while(0)
#endif
*/
/* USER CODE END APP_LOG_USER_DEFINES */
#ifdef __cplusplus
}
#endif
#endif /* LOG_MODULE_CONF_H */

View File

@@ -0,0 +1,716 @@
/**
******************************************************************************
* @file advanced_memory_manager.c
* @author MCD Application Team
* @brief Memory Manager
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm_list.h"
#include "utilities_conf.h"
#include "advanced_memory_manager.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/* Defines that the module is not initialized */
#define NOT_INITIALIZED 0x00u
/* Defines that the module is initialized */
#define INITIALIZED 0x01u
/* Defines the bit to check for 32bits aligned values */
#define MASK_ALIGNED_32BITS 0x03u
/*
Defines the length of the Virtual Memory Header in 32bits
----------------------------------------
| +++ 8bits +++ | +++++++ 24bits +++++++ |
| VirtualMem ID | Buffer Size (n*32bits) |
----------------------------------------
*/
#define VIRTUAL_MEMORY_HEADER_SIZE 0x01
/* Position of the ID field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_ID_POS 0x18
/* Mask of the ID field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_ID_MASK 0xFF000000
/* Position of the Buffer Size field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS 0x00
/* Mask of the Buffer Size field in Virtual Memory Header */
#define VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK 0x00FFFFFF
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* AMM Initialized flag */
static uint8_t AmmInitialized = NOT_INITIALIZED;
/* AMM pool address */
static uint32_t * p_AmmPoolAddress;
/* AMM pool size */
static uint32_t AmmPoolSize;
/* AMM occupied shared pool size */
static uint32_t AmmOccupiedSharedPoolSize;
#if (AMM_USE_MEMORY_STATISTICS == 1)
/* AMM peak shared pool size */
static uint32_t AmmPeakSharedPoolSize;
#endif /* AMM_USE_MEMORY_STATISTICS */
/* AMM needed virtual memory */
static uint32_t AmmRequiredVirtualMemorySize;
/* AMM virtual memory number */
static uint32_t AmmVirtualMemoryNumber;
/* List of Virtual Memories info */
static VirtualMemoryInfo_t * p_AmmVirtualMemoryList;
/* Handler of the Basic Memory Manager functions */
static AMM_BasicMemoryManagerFunctions_t AmmBmmFunctionsHandler;
/* Pointer on the first element of the pending callbacks */
static AMM_VirtualMemoryCallbackHeader_t AmmPendingCallback;
/* Pointer on the first element of the active callbacks */
static AMM_VirtualMemoryCallbackHeader_t AmmActiveCallback;
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/**
* @brief Push a callback structure into the Pending FIFO
* @param p_CallbackElt: Pointer onto the callback to push
* @return None
*/
static inline void pushPending (AMM_VirtualMemoryCallbackFunction_t * const p_CallbackElt);
/**
* @brief Push the Pending callback(s) into the Active FIFO
* @return None
*/
static inline void passPendingToActive (void);
/**
* @brief Pop a callback structure from the Active FIFO
* @return Pointer onto the popped callback
*/
static inline AMM_VirtualMemoryCallbackFunction_t * popActive (void);
/* Functions Definition ------------------------------------------------------*/
#if (AMM_USE_MEMORY_STATISTICS == 1)
uint32_t GetCurrentOccupation (const uint8_t VirtualMemoryId)
{
uint32_t currentOccupation = 0x00;
if (AmmInitialized == INITIALIZED)
{
/* Shared memory use case */
if (VirtualMemoryId == AMM_NO_VIRTUAL_ID)
{
currentOccupation = AmmOccupiedSharedPoolSize;
}
else
{
/* Check virtual memory info */
for (uint32_t memIdx = 0x00;
(memIdx < AmmVirtualMemoryNumber) && (currentOccupation == 0x00);
memIdx++)
{
/* Check if ID is known */
if (VirtualMemoryId == p_AmmVirtualMemoryList[memIdx].Id)
{
currentOccupation = p_AmmVirtualMemoryList[memIdx].OccupiedSize;
}
}
}
}
return currentOccupation;
}
uint32_t GetPeakOccupation (const uint8_t VirtualMemoryId)
{
uint32_t peakOccupation = 0x00;
if (AmmInitialized == INITIALIZED)
{
/* Shared memory use case */
if (VirtualMemoryId == AMM_NO_VIRTUAL_ID)
{
peakOccupation = AmmPeakSharedPoolSize;
}
else
{
/* Check virtual memory info */
for (uint32_t memIdx = 0x00;
(memIdx < AmmVirtualMemoryNumber) && (peakOccupation == 0x00);
memIdx++)
{
/* Check if ID is known */
if (VirtualMemoryId == p_AmmVirtualMemoryList[memIdx].Id)
{
peakOccupation = p_AmmVirtualMemoryList[memIdx].PeakOccupationSize;
}
}
}
}
return peakOccupation;
}
#endif /* AMM_USE_MEMORY_STATISTICS */
AMM_Function_Error_t AMM_Init (const AMM_InitParameters_t * const p_InitParams)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
uint32_t neededPoolSize = 0x00;
/* Check if not already initialized */
if (AmmInitialized == INITIALIZED)
{
error = AMM_ERROR_ALREADY_INIT;
}
/* Check parameter null pointer */
else if (p_InitParams == NULL)
{
error = AMM_ERROR_BAD_POINTER;
}
/* Check Pool address null pointer */
else if (p_InitParams->p_PoolAddr == NULL)
{
error = AMM_ERROR_BAD_POOL_CONFIG;
}
/* Check if Pool address is 32bits aligned */
else if ((MASK_ALIGNED_32BITS & (uint32_t)p_InitParams->p_PoolAddr) != 0)
{
error = AMM_ERROR_BAD_POOL_CONFIG;
}
/* Check Pool size shall be non zero */
else if (p_InitParams->PoolSize == 0)
{
error = AMM_ERROR_BAD_POOL_CONFIG;
}
/* Check that Virtual memories can not be declared without a proper configuration list */
else if ((p_InitParams->VirtualMemoryNumber != 0x00) &&
(p_InitParams->p_VirtualMemoryConfigList == NULL))
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
else
{
neededPoolSize = p_InitParams->VirtualMemoryNumber * AMM_VIRTUAL_INFO_ELEMENT_SIZE;
/* Check the parameters relative to virtual memories */
for (uint32_t memIdx = 0x00;
(memIdx < p_InitParams->VirtualMemoryNumber) && (error == AMM_ERROR_NOK);
memIdx++)
{
/* Add the amount of needed space for this virtual memory */
neededPoolSize = neededPoolSize + p_InitParams->p_VirtualMemoryConfigList[memIdx].BufferSize;
/* Check the virtual memory ID. Shall not be zero */
if (p_InitParams->p_VirtualMemoryConfigList[memIdx].Id == 0)
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
/* Check if size is not zero */
else if (p_InitParams->p_VirtualMemoryConfigList[memIdx].BufferSize == 0)
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
/* Check if amount of needed memory has overlapped current pool size */
else if (p_InitParams->PoolSize < neededPoolSize)
{
error = AMM_ERROR_BAD_VIRTUAL_CONFIG;
}
else
{
/* Do nothing, all ok yet */
}
}
/* Check if parameters are still ok */
if (error == AMM_ERROR_NOK)
{
/* Init all private variables: Pool relative */
p_AmmPoolAddress = NULL;
AmmPoolSize = 0x00;
AmmOccupiedSharedPoolSize = 0x00;
AmmRequiredVirtualMemorySize = 0x00;
/* Init all private variables: Virtual Memory relative */
AmmVirtualMemoryNumber = 0x00;
p_AmmVirtualMemoryList = NULL;
/* Init all private variables: BMM relative */
AmmBmmFunctionsHandler.Init = NULL;
AmmBmmFunctionsHandler.Allocate = NULL;
AmmBmmFunctionsHandler.Free = NULL;
/* Init all private variables: Callbacks relative */
AmmPendingCallback.next = NULL;
AmmPendingCallback.prev = NULL;
AmmActiveCallback.next = NULL;
AmmActiveCallback.prev = NULL;
/* First get the Basic Memory Manager functions back */
AMM_RegisterBasicMemoryManager (&AmmBmmFunctionsHandler);
if ((AmmBmmFunctionsHandler.Init == NULL)
|| (AmmBmmFunctionsHandler.Allocate == NULL)
|| (AmmBmmFunctionsHandler.Free == NULL))
{
error = AMM_ERROR_BAD_BMM_REGISTRATION;
}
else
{
/* Store the pool info */
p_AmmPoolAddress = p_InitParams->p_PoolAddr;
AmmPoolSize = p_InitParams->PoolSize;
/* First init the Basic Memory Manager */
AmmBmmFunctionsHandler.Init (p_AmmPoolAddress,
AmmPoolSize);
/* Allocate memory for the virtual memories info */
p_AmmVirtualMemoryList = (VirtualMemoryInfo_t *)
(AmmBmmFunctionsHandler. Allocate (AMM_VIRTUAL_INFO_ELEMENT_SIZE
* p_InitParams->VirtualMemoryNumber));
/* Check if allocation is OK*/
if ((p_AmmVirtualMemoryList == NULL) && (p_InitParams->VirtualMemoryNumber > 0))
{
error = AMM_ERROR_BAD_BMM_ALLOCATION;
}
else
{
/* Init Critical section */
UTIL_SEQ_INIT_CRITICAL_SECTION ();
/* Init both pending and active list */
LST_init_head (&AmmPendingCallback);
LST_init_head (&AmmActiveCallback);
/* Keep going on init, fulfill the virtual memories info */
AmmVirtualMemoryNumber = p_InitParams->VirtualMemoryNumber;
/* Actualize actual shared pool occupied size */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize + (AMM_VIRTUAL_INFO_ELEMENT_SIZE
* AmmVirtualMemoryNumber);
#if (AMM_USE_MEMORY_STATISTICS == 1)
AmmPeakSharedPoolSize = AmmOccupiedSharedPoolSize;
#endif /* AMM_USE_MEMORY_STATISTICS */
for (uint32_t memIdx = 0x00;
memIdx < AmmVirtualMemoryNumber;
memIdx++)
{
p_AmmVirtualMemoryList[memIdx].Id = p_InitParams->p_VirtualMemoryConfigList[memIdx].Id;
p_AmmVirtualMemoryList[memIdx].RequiredSize = p_InitParams->p_VirtualMemoryConfigList[memIdx].BufferSize;
p_AmmVirtualMemoryList[memIdx].OccupiedSize = 0x00;
#if (AMM_USE_MEMORY_STATISTICS == 1)
p_AmmVirtualMemoryList[memIdx].PeakOccupationSize = 0x00;
#endif /* AMM_USE_MEMORY_STATISTICS */
AmmRequiredVirtualMemorySize = AmmRequiredVirtualMemorySize + p_AmmVirtualMemoryList[memIdx].RequiredSize;
}
/* Set init flag */
AmmInitialized = INITIALIZED;
/* All info are stored and AMM is initialized */
error = AMM_ERROR_OK;
}
}
}
}
return error;
}
AMM_Function_Error_t AMM_DeInit (void)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
/* Check if initialized */
if (AmmInitialized == INITIALIZED)
{
/* Free resources */
AmmBmmFunctionsHandler.Free ((uint32_t *)p_AmmVirtualMemoryList);
/* Reset all the variables */
AmmBmmFunctionsHandler.Init = NULL;
AmmBmmFunctionsHandler.Allocate = NULL;
AmmBmmFunctionsHandler.Free = NULL;
p_AmmPoolAddress = 0x00;
AmmPoolSize = 0x00;
AmmOccupiedSharedPoolSize = 0x00;
AmmRequiredVirtualMemorySize = 0x00;
AmmVirtualMemoryNumber = 0x00;
/* Unset the flag */
AmmInitialized = 0x00;
error = AMM_ERROR_OK;
}
else
{
error = AMM_ERROR_NOT_INIT;
}
return error;
}
AMM_Function_Error_t AMM_Alloc (const uint8_t VirtualMemoryId,
const uint32_t BufferSize,
uint32_t ** pp_AllocBuffer,
AMM_VirtualMemoryCallbackFunction_t * const p_CallBackFunction)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
uint32_t selfAvailable = 0x00;
uint32_t * p_TmpAllocAddr = NULL;
/* Set pointer to NULL */
*pp_AllocBuffer = NULL;
if (AmmInitialized == NOT_INITIALIZED)
{
error = AMM_ERROR_NOT_INIT;
}
/* Check if buffer size is not zero */
else if (BufferSize == 0)
{
error = AMM_ERROR_BAD_ALLOCATION_SIZE;
}
/* Check if no virtual ID requested */
else if (VirtualMemoryId == AMM_NO_VIRTUAL_ID)
{
/* Enter critical section */
UTIL_SEQ_ENTER_CRITICAL_SECTION ();
/* Check for enough space in the shared pool */
if (BufferSize < (AmmPoolSize - AmmOccupiedSharedPoolSize - AmmRequiredVirtualMemorySize))
{
/* Try Allocation. Do not forget the header */
p_TmpAllocAddr = AmmBmmFunctionsHandler.Allocate (BufferSize + VIRTUAL_MEMORY_HEADER_SIZE);
/* Check if allocation is OK */
if (p_TmpAllocAddr != NULL)
{
/* Fulfill the header */
*p_TmpAllocAddr = (uint32_t)(((uint32_t)VirtualMemoryId << VIRTUAL_MEMORY_HEADER_ID_POS)
& VIRTUAL_MEMORY_HEADER_ID_MASK)
| ((BufferSize << VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS)
& VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK);
/* Provide the right address to user, ie without the header */
*pp_AllocBuffer = (uint32_t *)(p_TmpAllocAddr + VIRTUAL_MEMORY_HEADER_SIZE);
/* Actualize the current memory occupation of the shared space */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize + BufferSize + VIRTUAL_MEMORY_HEADER_SIZE;
#if (AMM_USE_MEMORY_STATISTICS == 1)
/* Check if peak occupation has to be updated */
if (AmmOccupiedSharedPoolSize > AmmPeakSharedPoolSize)
{
AmmPeakSharedPoolSize = AmmOccupiedSharedPoolSize;
}
#endif /* AMM_USE_MEMORY_STATISTICS */
error = AMM_ERROR_OK;
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_ALLOCATION_FAILED;
}
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_BAD_ALLOCATION_SIZE;
}
/* Exit critical section */
UTIL_SEQ_EXIT_CRITICAL_SECTION ();
}
/* A specific ID is requested */
else
{
error = AMM_ERROR_UNKNOWN_ID;
/* Enter critical section */
UTIL_SEQ_ENTER_CRITICAL_SECTION ();
/* Check virtual memory info */
for (uint32_t memIdx = 0x00;
(memIdx < AmmVirtualMemoryNumber) && (error == AMM_ERROR_UNKNOWN_ID);
memIdx++)
{
/* Check if ID is known */
if (VirtualMemoryId == p_AmmVirtualMemoryList[memIdx].Id)
{
/* Check if all the reserved memory has been consumed */
if (p_AmmVirtualMemoryList[memIdx].OccupiedSize < p_AmmVirtualMemoryList[memIdx].RequiredSize)
{
/* Compute what is remaining */
selfAvailable = p_AmmVirtualMemoryList[memIdx].RequiredSize
- p_AmmVirtualMemoryList[memIdx].OccupiedSize;
}
/* Check if there is enough space in the shared pool plus in our virtual memory pool */
if (BufferSize < (AmmPoolSize - AmmOccupiedSharedPoolSize - AmmRequiredVirtualMemorySize + selfAvailable))
{
/* Try Allocation. Do not forget the header */
p_TmpAllocAddr = AmmBmmFunctionsHandler.Allocate ((BufferSize + VIRTUAL_MEMORY_HEADER_SIZE));
/* Check if allocation is OK */
if (p_TmpAllocAddr != NULL)
{
/* Fulfill the header */
*p_TmpAllocAddr = (uint32_t)(((uint32_t)VirtualMemoryId << VIRTUAL_MEMORY_HEADER_ID_POS)
& VIRTUAL_MEMORY_HEADER_ID_MASK)
| ((BufferSize << VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS)
& VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK);
/* Provide the right address to user, ie without the header */
*pp_AllocBuffer = (uint32_t *)(p_TmpAllocAddr + VIRTUAL_MEMORY_HEADER_SIZE);
/* Actualize our current memory occupation */
p_AmmVirtualMemoryList[memIdx].OccupiedSize = p_AmmVirtualMemoryList[memIdx].OccupiedSize
+ BufferSize
+ VIRTUAL_MEMORY_HEADER_SIZE;
#if (AMM_USE_MEMORY_STATISTICS == 1)
/* Check if peak occupation has to be updated */
if (p_AmmVirtualMemoryList[memIdx].OccupiedSize > p_AmmVirtualMemoryList[memIdx].PeakOccupationSize)
{
p_AmmVirtualMemoryList[memIdx].PeakOccupationSize = p_AmmVirtualMemoryList[memIdx].OccupiedSize;
}
#endif /* AMM_USE_MEMORY_STATISTICS */
/* Check for overlapping the reserved memory */
if (p_AmmVirtualMemoryList[memIdx].RequiredSize < p_AmmVirtualMemoryList[memIdx].OccupiedSize)
{
/* Actualize the shared memory occupation */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize
+ BufferSize - selfAvailable
+ VIRTUAL_MEMORY_HEADER_SIZE;
#if (AMM_USE_MEMORY_STATISTICS == 1)
/* Check if peak occupation has to be updated */
if (AmmOccupiedSharedPoolSize > AmmPeakSharedPoolSize)
{
AmmPeakSharedPoolSize = AmmOccupiedSharedPoolSize;
}
#endif /* AMM_USE_MEMORY_STATISTICS */
}
error = AMM_ERROR_OK;
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_ALLOCATION_FAILED;
}
}
else
{
/* Register the callback for a future retry */
pushPending (p_CallBackFunction);
error = AMM_ERROR_BAD_ALLOCATION_SIZE;
}
}
}
/* Exit critical section */
UTIL_SEQ_EXIT_CRITICAL_SECTION ();
}
return error;
}
AMM_Function_Error_t AMM_Free (uint32_t * const p_BufferAddr)
{
AMM_Function_Error_t error = AMM_ERROR_NOK;
uint8_t virtualId = 0x00;
int32_t occupiedOverRequired = 0x00;
uint32_t allocatedSize = 0x00;
uint32_t * p_TmpAllocAddr = NULL;
if (AmmInitialized == NOT_INITIALIZED)
{
error = AMM_ERROR_NOT_INIT;
}
else if (p_BufferAddr == NULL)
{
error = AMM_ERROR_BAD_POINTER;
}
else if ((MASK_ALIGNED_32BITS & (uint32_t)p_BufferAddr) != 0)
{
error = AMM_ERROR_NOT_ALIGNED;
}
/* Check if address is managed by this AMM */
else if ((p_BufferAddr > (p_AmmPoolAddress + AmmPoolSize))
|| (p_BufferAddr < p_AmmPoolAddress))
{
error = AMM_ERROR_OUT_OF_RANGE;
}
else
{
/* Enter critical section */
UTIL_SEQ_ENTER_CRITICAL_SECTION ();
/* First correct the address by adding the header */
p_TmpAllocAddr = (uint32_t *)(p_BufferAddr - VIRTUAL_MEMORY_HEADER_SIZE);
/* Get the virtual memory information */
virtualId = (*p_TmpAllocAddr & VIRTUAL_MEMORY_HEADER_ID_MASK) >> VIRTUAL_MEMORY_HEADER_ID_POS;
allocatedSize = (*p_TmpAllocAddr & VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_MASK) >> VIRTUAL_MEMORY_HEADER_BUFFER_SIZE_POS;
/* Add header size to allocated size */
allocatedSize = allocatedSize + VIRTUAL_MEMORY_HEADER_SIZE;
/* Free the allocated memory */
AmmBmmFunctionsHandler.Free(p_TmpAllocAddr);
/* Update the occupation counters depending on the ID */
if (virtualId == AMM_NO_VIRTUAL_ID)
{
/* Update the occupation size */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize - allocatedSize;
error = AMM_ERROR_OK;
}
else
{
error = AMM_ERROR_UNKNOWN_ID;
for (uint32_t memIdx = 0x00;
(memIdx < AmmVirtualMemoryNumber) && (error == AMM_ERROR_UNKNOWN_ID);
memIdx++)
{
/* Check if it is the right ID */
if (virtualId == p_AmmVirtualMemoryList[memIdx].Id)
{
occupiedOverRequired = (p_AmmVirtualMemoryList[memIdx].OccupiedSize - p_AmmVirtualMemoryList[memIdx].RequiredSize);
/* Check whether the occupied size has overlaped the required or not */
if (occupiedOverRequired > 0x00)
{
/* Check if reserved memory is overlapped */
if (allocatedSize > occupiedOverRequired)
{
/* Update the occupation size */
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize
- (p_AmmVirtualMemoryList[memIdx].OccupiedSize
- p_AmmVirtualMemoryList[memIdx].RequiredSize);
}
else
{
AmmOccupiedSharedPoolSize = AmmOccupiedSharedPoolSize - allocatedSize;
}
}
/* Update the occupation size */
p_AmmVirtualMemoryList[memIdx].OccupiedSize = p_AmmVirtualMemoryList[memIdx].OccupiedSize
- allocatedSize;
error = AMM_ERROR_OK;
}
}
}
/* Pop pending callbacks and add them to the active fifo */
passPendingToActive ();
/* Exit critical section */
UTIL_SEQ_EXIT_CRITICAL_SECTION ();
/* Ask the user task to proceed to a background process call */
AMM_ProcessRequest();
}
return error;
}
void AMM_BackgroundProcess (void)
{
AMM_VirtualMemoryCallbackFunction_t * p_tmpCallback = NULL;
do
{
/* Pop an active callback request */
p_tmpCallback = popActive();
if (p_tmpCallback != NULL)
{
/* Invoke the callback for an alloc retry */
p_tmpCallback->Callback();
}
}while (p_tmpCallback != NULL);
}
/* Private Functions Definition ------------------------------------------------------*/
void pushPending (AMM_VirtualMemoryCallbackFunction_t * const p_CallbackElt)
{
if (p_CallbackElt != NULL)
{
/* Add the new callback */
LST_insert_tail (&AmmPendingCallback, (tListNode *)p_CallbackElt);
}
}
void passPendingToActive (void)
{
AMM_VirtualMemoryCallbackFunction_t * p_TmpElt = NULL;
while (LST_is_empty (&AmmPendingCallback) == FALSE)
{
/* Remove the head element */
LST_remove_head (&AmmPendingCallback, (tListNode**)&p_TmpElt);
/* Add at the bottom */
LST_insert_tail (&AmmActiveCallback, (tListNode *)p_TmpElt);
}
}
AMM_VirtualMemoryCallbackFunction_t * popActive (void)
{
AMM_VirtualMemoryCallbackFunction_t * p_error = NULL;
if (LST_is_empty (&AmmActiveCallback) == FALSE)
{
/* Remove last element */
LST_remove_head (&AmmActiveCallback, (tListNode**)&p_error);
}
return p_error;
}

View File

@@ -0,0 +1,281 @@
/**
******************************************************************************
* @file advance_memory_manager.h
* @author MCD Application Team
* @brief Header for advance_memory_manager.c module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef ADVANCED_MEMORY_MANAGER_H
#define ADVANCED_MEMORY_MANAGER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm_list.h"
/* Exported defines -----------------------------------------------------------*/
/**
* @brief Define for No Virtual Memory ID
*
* @details This ID can be used to allocate memory from the shared pool
*/
#define AMM_NO_VIRTUAL_ID 0x00u
/**
* @brief Size of a virtual memory information element in 32bits
*
* @details At initialization, the Advance Memory Manager allocate as many VM info element as there
* is Virtual Memory to manage.
* Thus user shall provide at the initialization more space for the pool.
*
* ie:
* - sizeOfDesiredPool = 8092
* - numberOfVirtualMemory = 3
* - actualSizeOfThePoolToGive = sizeOfDesiredPool + numberOfVirtualMemory * AMM_VIRTUAL_INFO_ELEMENT_SIZE
*/
#define AMM_VIRTUAL_INFO_ELEMENT_SIZE (uint32_t)(sizeof (VirtualMemoryInfo_t) / sizeof (uint32_t))
/* Exported types ------------------------------------------------------------*/
/* Redefine the header for chained list */
typedef tListNode AMM_VirtualMemoryCallbackHeader_t;
/* Function error enumeration */
typedef enum AMM_Function_Error
{
/* No error code */
AMM_ERROR_OK,
/* Error that occurred before any check */
AMM_ERROR_NOK,
/*Bad pointer error */
AMM_ERROR_BAD_POINTER,
/* Bad pool configuration error */
AMM_ERROR_BAD_POOL_CONFIG,
/* Bad virtual memory configuration error */
AMM_ERROR_BAD_VIRTUAL_CONFIG,
/* Bad BMM registration error */
AMM_ERROR_BAD_BMM_REGISTRATION,
/* Bad BMM allocation error */
AMM_ERROR_BAD_BMM_ALLOCATION,
/* Not aligned address error */
AMM_ERROR_NOT_ALIGNED,
/* Out of range error */
AMM_ERROR_OUT_OF_RANGE,
/* Unknown virtual memory manager ID error */
AMM_ERROR_UNKNOWN_ID,
/* Bad allocation size error */
AMM_ERROR_BAD_ALLOCATION_SIZE,
/* Allocation failed error */
AMM_ERROR_ALLOCATION_FAILED,
/* Already initialized AMM error */
AMM_ERROR_ALREADY_INIT,
/* Not initialized AMM error */
AMM_ERROR_NOT_INIT
} AMM_Function_Error_t;
/**
* @brief Virtual Memory information struct
*/
typedef struct __attribute__((packed, aligned(4))) VirtualMemoryInfo
{
/* Identifier of the Virtual Memory */
uint8_t Id;
/* Size required for this Virtual Memory buffer with a multiple of 32bits */
uint32_t RequiredSize;
/* Current occupation of the Virtual Memory buffer with a multiple of 32bits */
uint32_t OccupiedSize;
#if (AMM_USE_MEMORY_STATISTICS == 1)
/* Peak occupation of the Virtual Memory buffer with a multiple of 32bits */
uint32_t PeakOccupationSize;
#endif /* AMM_USE_MEMORY_STATISTICS */
}VirtualMemoryInfo_t;
/**
* @brief Virtual Memory configuration struct
*/
typedef struct AMM_VirtualMemoryConfig
{
/* ID of the Virtual Memory */
uint8_t Id;
/* Size of the Virtual Memory buffer with a multiple of 32bits.
ie: BufferSize = 4; TotalSize = BufferSize * 32bits
= 4 * 32bits
= 128 bits */
uint32_t BufferSize;
}AMM_VirtualMemoryConfig_t;
/**
* @brief Basic Memory Manager functions struct
*
* @details Structure that handles all the required functions of the Basic Memory Manager.
*/
typedef struct AMM_BasicMemoryManagerFunctions
{
/* Basic Memory Manager Init function - Shall be in bytes - */
void (* Init) (uint32_t * const p_PoolAddr, const uint32_t PoolSize);
/* Basic Memory Manager Allocate function - Shall be in bytes - */
uint32_t * (* Allocate) (const uint32_t BufferSize);
/* Basic Memory Manager Free function */
void (* Free) (uint32_t * const p_BufferAddr);
}AMM_BasicMemoryManagerFunctions_t;
/**
* @brief Advance Memory Manager init struct
*
* @details Structure that contains all the needed parameters to initialize the
* Advance Memory Manager.
*/
typedef struct AMM_InitParameters
{
/* Address of the pool of memory to manage */
uint32_t * p_PoolAddr;
/* Size of the pool with a multiple of 32bits.
ie: PoolSize = 4; TotalSize = PoolSize * 32bits
= 4 * 32bits
= 128 bits */
uint32_t PoolSize;
/* Number of Virtual Memory to create */
uint32_t VirtualMemoryNumber;
/* List of the Virtual Memory configurations */
AMM_VirtualMemoryConfig_t * p_VirtualMemoryConfigList;
}AMM_InitParameters_t;
/**
* @brief Virtual Memory Callback function struct
*/
typedef struct AMM_VirtualMemoryCallbackFunction
{
/* Next and previous callbacks in the list */
AMM_VirtualMemoryCallbackHeader_t Header;
/* Callback function pointer to invoke once memory has been freed */
void (* Callback) (void);
}AMM_VirtualMemoryCallbackFunction_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
#if (AMM_USE_MEMORY_STATISTICS == 1)
/**
* @brief Get the Current Occupation of the required virtual memory
* @details @ref AMM_NO_VIRTUAL_ID can be used to get the shared pool occupation
* @param VirtualMemoryId: ID of the Virtual Memory
* @return Value of the current occupation in 32bits words
*/
uint32_t GetCurrentOccupation (const uint8_t VirtualMemoryId);
/**
* @brief Get the Peak Occupation of the required virtual memory
* @details @ref AMM_NO_VIRTUAL_ID can be used to get the shared pool peak occupation
* @param VirtualMemoryId: ID of the Virtual Memory
* @return Value of the peak occupation in 32bits words
*/
uint32_t GetPeakOccupation (const uint8_t VirtualMemoryId);
#endif /* AMM_USE_MEMORY_STATISTICS */
/**
* @brief Initialize the Advance Memory Manager Pool
* @param p_InitParams: Struct of init parameters
* @return Status of the initialization
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_ALREADY_INIT
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POINTER
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POOL_CONFIG
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_VIRTUAL_CONFIG
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_BMM_REGISTRATION
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_BMM_ALLOCATION
*/
AMM_Function_Error_t AMM_Init (const AMM_InitParameters_t * const p_InitParams);
/**
* @brief DeInitialize the Advance Memory Manager Pool
* @details This function shall be called once every allocated memory has been freed
* @return Status of the initialization
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_INIT
*/
AMM_Function_Error_t AMM_DeInit (void);
/**
* @brief Allocate a buffer from the Advance Memory Manager Pool
* @param VirtualMemoryId: Virtual Memory Identifier - AMM_NO_VIRTUAL_ID Can be used -
* @param BufferSize: Size of the pool with a multiple of 32bits.
ie: BufferSize = 4; TotalSize = BufferSize * 32bits
= 4 * 32bits
= 128 bits
* @param p_CallBackFunction: Pointer onto the Callback to call in case of failure - Can be NULL -
* @param pp_AllocBuffer: Pointer onto the allocated buffer
* @return Status of the allocation
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_INIT
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POINTER
* @retval AMM_Function_Error_t::AMM_ERROR_UNKNOWN_ID
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_ALLOCATION_SIZE
* @retval AMM_Function_Error_t::AMM_ERROR_ALLOCATION_FAILED
*/
AMM_Function_Error_t AMM_Alloc (const uint8_t VirtualMemoryId,
const uint32_t BufferSize,
uint32_t ** pp_AllocBuffer,
AMM_VirtualMemoryCallbackFunction_t * const p_CallBackFunction);
/**
* @brief Free the allocated buffer from the Advance Memory Manager Pool
* @param p_BufferAddr: Address of the buffer to free
* @return Status of the free
* @retval AMM_Function_Error_t::AMM_ERROR_OK
* @retval AMM_Function_Error_t::AMM_ERROR_NOK
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_INIT
* @retval AMM_Function_Error_t::AMM_ERROR_BAD_POINTER
* @retval AMM_Function_Error_t::AMM_ERROR_NOT_ALIGNED
* @retval AMM_Function_Error_t::AMM_ERROR_OUT_OF_RANGE
* @retval AMM_Function_Error_t::AMM_ERROR_UNKNOWN_ID
*/
AMM_Function_Error_t AMM_Free (uint32_t * const p_BufferAddr);
/**
* @brief Background routine
* @details Background routine that aims to call registered callbacks for an allocation retry
* @return None
*/
void AMM_BackgroundProcess (void);
/* Exported functions to be implemented by the user if required ------------- */
/**
* @brief Register the Basic Memory Manager functions to use
* @param p_BasicMemoryManagerFunctions: Address of the basic memory manager functions
* @return None
*/
void AMM_RegisterBasicMemoryManager (AMM_BasicMemoryManagerFunctions_t * const p_BasicMemoryManagerFunctions);
/**
* @brief Request to application for a Background process run
* @return None
*/
void AMM_ProcessRequest (void);
#ifdef __cplusplus
}
#endif
#endif /* ADVANCED_MEMORY_MANAGER_H */

View File

@@ -0,0 +1,288 @@
/**
******************************************************************************
* @file memory_manager.c
* @author MCD Application Team
* @brief Memory Manager
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
#include "memory_manager.h"
#include "stm_list.h"
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
/**
* The average timing is @32Mhz :
* Legacy MM
* + Alloc = 3.5us
* + Free = 2.5us
* New MM
* + Alloc = 6.5us
* + Free = 4.5us
*/
#define USE_NEW_MM 1
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#if(USE_NEW_MM == 0)
#pragma default_variable_attributes = @"MM_CONTEXT"
static uint8_t QueueSize;
static tListNode BufferPool;
static MM_pCb_t BufferFreeCb;
static uint8_t *p_StartPoolAdd;
static uint8_t *p_EndPoolAdd;
#pragma default_variable_attributes =
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
/**
* @brief Initialize the Pools
* @param p_pool: The pool of memory to manage
* @param pool_size: The size of the pool
* @param elt_size: The size of one element in the pool
* @retval None
*/
void MM_Init(uint8_t *p_pool, uint32_t pool_size, uint32_t elt_size)
{
uint32_t elt_size_corrected;
QueueSize = 0;
elt_size_corrected = 4*DIVC( elt_size, 4 );
/**
* Save the first and last address of the pool of memory
*/
p_StartPoolAdd = p_pool;
p_EndPoolAdd = p_pool + pool_size - 1;
/**
* Initialize list
*/
LST_init_head (&BufferPool);
/**
* Initialize the queue
*/
while(pool_size >= elt_size_corrected)
{
LST_insert_tail(&BufferPool, (tListNode *)p_pool);
p_pool += elt_size_corrected;
QueueSize++;
pool_size -= elt_size_corrected;
}
return;
}
/**
* @brief Provide a buffer
* @note The buffer allocated to the user shall be at least sizeof(tListNode) bytes
* to store the memory manager chaining information
*
* @param size: The size of the buffer requested
* @param cb: The callback to be called when a buffer is made available later on
* if there is no buffer currently available when this API is called
* @retval The buffer address when available or NULL when there is no buffer
*/
MM_pBufAdd_t MM_GetBuffer( uint32_t size, MM_pCb_t cb )
{
MM_pBufAdd_t buffer_address;
uint32_t primask_bit;
uint8_t allocation_exit = FALSE;
while( allocation_exit == FALSE )
{
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
if ( QueueSize )
{
QueueSize--;
LST_remove_head( &BufferPool, ( tListNode ** )&buffer_address );
if((buffer_address >= p_StartPoolAdd) && (buffer_address <= (p_EndPoolAdd - size + 1)))
{
/* The buffer is in a valid range */
BufferFreeCb = 0;
allocation_exit = TRUE;
}
else
{
/**
* The buffer is not in a valid range.
* Keep the reference out of the memory pool and try again
*/
}
}
else
{
BufferFreeCb = cb;
buffer_address = 0;
allocation_exit = TRUE;
}
__set_PRIMASK( primask_bit ); /**< Restore PRIMASK bit*/
}
return buffer_address;
}
/**
* @brief Release a buffer
* @param p_buffer: The data buffer address
* @retval None
*/
void MM_ReleaseBuffer( MM_pBufAdd_t p_buffer )
{
uint32_t primask_bit;
if((p_buffer >= p_StartPoolAdd) && (p_buffer <= p_EndPoolAdd))
{
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
LST_insert_tail( &BufferPool, ( tListNode * )p_buffer );
QueueSize++;
__set_PRIMASK( primask_bit ); /**< Restore PRIMASK bit*/
if( BufferFreeCb )
{
/**
* The application is waiting for a free buffer
*/
BufferFreeCb();
}
}
return;
}
#else
#include "stm32_mm.h"
static uint8_t *p_StartPoolAdd __attribute__((section("MM_CONTEXT")));
static uint8_t *p_EndPoolAdd __attribute__((section("MM_CONTEXT")));
static MM_pCb_t BufferFreeCb __attribute__((section("MM_CONTEXT")));
/* Functions Definition ------------------------------------------------------*/
void MM_Init(uint8_t *p_pool, uint32_t pool_size, uint32_t elt_size)
{
/**
* Save the first and last address of the pool of memory
*/
p_StartPoolAdd = p_pool;
p_EndPoolAdd = p_pool + pool_size - 1;
UTIL_MM_Init(p_pool, pool_size);
return;
}
/**
* @brief Provide a buffer
* @note The buffer allocated to the user shall be at least sizeof(tListNode) bytes
* to store the memory manager chaining information
* During execution, this API shall not be interrupted with a call to either
* MM_GetBuffer() or MM_ReleaseBuffer()
* MM_GetBuffer() is called only from background so this will never happen
* MM_ReleaseBuffer() is called from IPCC interrupt. Masking IPCC interrupt is
* enough to comply to the requirement
* Note that the primask bit cannot be used as the length of the critical section is too long compare to
* the maximum latency of the BLE Irq. Therefore, the BLE Irq shall not be masked.
*
* @param size: The size of the buffer requested
* @param cb: The callback to be called when a buffer is made available later on
* if there is no buffer currently available when this API is called
* @retval The buffer address when available or NULL when there is no buffer
*/
MM_pBufAdd_t MM_GetBuffer( uint32_t size, MM_pCb_t cb )
{
MM_pBufAdd_t buffer_address;
/* uint32_t nvic_ipcc_status; */
uint8_t allocation_exit = FALSE;
while( allocation_exit == FALSE )
{
/* nvic_ipcc_status = NVIC_GetEnableIRQ(IPCC_C2_RX_C2_TX_HSEM_IRQn); */ /**< backup IPCC just in case it has been disabled by the user */
/* NVIC_DisableIRQ(IPCC_C2_RX_C2_TX_HSEM_IRQn); */
__disable_irq();
buffer_address = (MM_pBufAdd_t)UTIL_MM_GetBuffer( size );
__enable_irq();
/*
if(nvic_ipcc_status != 0)
{
NVIC_EnableIRQ(IPCC_C2_RX_C2_TX_HSEM_IRQn);
}
*/
if(buffer_address != 0)
{
if((buffer_address >= p_StartPoolAdd) && (buffer_address <= (p_EndPoolAdd - size + 1)))
{
/* The buffer is in a valid range */
BufferFreeCb = 0;
allocation_exit = TRUE;
}
else
{
/**
* The buffer is not in a valid range.
* Keep the reference out of the memory pool and try again
*/
}
}
else
{
BufferFreeCb = cb;
allocation_exit = TRUE;
}
}
return buffer_address;
}
/**
* @brief Release a buffer
* During execution, this API shall not be interrupted with a call to either
* MM_GetBuffer() or MM_ReleaseBuffer()
* MM_GetBuffer() is called only from background so this will never happen
* MM_ReleaseBuffer() is called from IPCC interrupt so it cannot be nested.
* There is no need of a critical section
* Note that anyway, the primask bit cannot be used as the length of the critical section
* is too long compare to the maximum latency of the BLE Irq. Therefore, the BLE Irq shall not be masked.
*
* @param p_buffer: The data buffer address
* @retval None
*/
void MM_ReleaseBuffer( MM_pBufAdd_t p_buffer )
{
if((p_buffer >= p_StartPoolAdd) && (p_buffer <= p_EndPoolAdd))
{
UTIL_MM_ReleaseBuffer( p_buffer );
if( BufferFreeCb )
{
/**
* The application is waiting for a free buffer
*/
BufferFreeCb();
}
}
return;
}
#endif

View File

@@ -0,0 +1,49 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file memory_manager.h
* @author MCD Application Team
* @brief Header for memory_manager.c module
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef MEMORY_MANAGER_H
#define MEMORY_MANAGER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported defines -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
typedef void (*MM_pCb_t)( void );
typedef uint8_t (*MM_pBufAdd_t);
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void MM_Init(uint8_t *p_pool, uint32_t pool_size, uint32_t elt_size);
MM_pBufAdd_t MM_GetBuffer(uint32_t size, MM_pCb_t cb );
void MM_ReleaseBuffer( MM_pBufAdd_t p_buffer );
/* Exported functions to be implemented by the user if required ------------- */
#ifdef __cplusplus
}
#endif
#endif /* MEMORY_MANAGER_H */

View File

@@ -0,0 +1,576 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
******************************************************************************
* @file stm32_mm.c
* @author MCD Application Team
* @brief Memory Manager Utility
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/*
* A sample implementation of pvPortMalloc() and vPortFree() that combines
* (coalescences) adjacent memory blocks as they are freed, and in so doing
* limits memory fragmentation.
*
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
* memory management pages of https://www.FreeRTOS.org for more information.
*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
#include <stdlib.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers. That should only be done when
* task.h is included from an application file. */
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#include "FreeRTOS.h"
#include "task.h"
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
#endif
#else
#include "utilities_common.h"
#include "stm32_mm.h"
#undef PRIVILEGED_DATA
#define PRIVILEGED_DATA
#undef PRIVILEGED_FUNCTION
#define PRIVILEGED_FUNCTION
#undef portBYTE_ALIGNMENT
#define portBYTE_ALIGNMENT (8)
#undef portBYTE_ALIGNMENT_MASK
#if portBYTE_ALIGNMENT == 8
#define portBYTE_ALIGNMENT_MASK ( 0x0007 )
#endif
#if portBYTE_ALIGNMENT == 4
#define portBYTE_ALIGNMENT_MASK ( 0x0003 )
#endif
/* No test marker by default. */
#undef mtCOVERAGE_TEST_MARKER
#define mtCOVERAGE_TEST_MARKER()
#undef configASSERT
#define configASSERT( x )
/* No tracing by default. */
#undef traceMALLOC
#define traceMALLOC( pvReturn, xWantedSize )
#undef traceFREE
#define traceFREE( pvAddress, uiSize )
#undef vTaskSuspendAll
#define vTaskSuspendAll()
#undef xTaskResumeAll
#define xTaskResumeAll() (0)
#endif
/* Block sizes must not get too small. */
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
/* Allocate the memory for the heap. */
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
/* The application writer has already defined the array used for the RTOS
* heap - probably so it can be placed in a special segment or address. */
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#else
PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
#endif /* configAPPLICATION_ALLOCATED_HEAP */
#endif
/* Define the linked list structure. This is used to link free blocks in order
* of their memory address. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} BlockLink_t;
/*-----------------------------------------------------------*/
/*
* Inserts a block of memory that is being freed into the correct position in
* the list of free memory blocks. The block being freed will be merged with
* the block in front it and/or the block behind it if the memory blocks are
* adjacent to each other.
*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) PRIVILEGED_FUNCTION;
/*
* Called automatically to setup the required heap structures the first time
* pvPortMalloc() is called.
*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
static void prvHeapInit( void ) PRIVILEGED_FUNCTION;
#endif
/*-----------------------------------------------------------*/
/* The size of the structure placed at the beginning of each allocated memory
* block must by correctly byte aligned. */
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
/* Create a couple of list links to mark the start and end of the list. */
PRIVILEGED_DATA static BlockLink_t xStart, * pxEnd = NULL;
/* Keeps track of the number of calls to allocate and free memory as well as the
* number of free bytes remaining, but says nothing about fragmentation. */
PRIVILEGED_DATA static size_t xFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = 0U;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = 0;
PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = 0;
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
* member of an BlockLink_t structure is set then the block belongs to the
* application. When the bit is free the block is still part of the free heap
* space. */
PRIVILEGED_DATA static size_t xBlockAllocatedBit = 0;
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0)
void * UTIL_MM_GetBuffer( size_t xWantedSize )
#else
void * pvPortMalloc( size_t xWantedSize )
#endif
{
BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
void * pvReturn = NULL;
vTaskSuspendAll();
{
/* If this is the first call to malloc then the heap will require
* initialisation to setup the list of free blocks. */
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
if( pxEnd == NULL )
{
prvHeapInit();
}
else
#endif
{
mtCOVERAGE_TEST_MARKER();
}
/* Check the requested block size is not so large that the top bit is
* set. The top bit of the block size member of the BlockLink_t structure
* is used to determine who owns the block - the application or the
* kernel, so it must be free. */
if( ( xWantedSize & xBlockAllocatedBit ) == 0 )
{
/* The wanted size is increased so it can contain a BlockLink_t
* structure in addition to the requested amount of bytes. */
if( xWantedSize > 0 )
{
xWantedSize += xHeapStructSize;
/* Ensure that blocks are always aligned to the required number
* of bytes. */
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
{
/* Byte alignment required. */
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
{
/* Traverse the list from the start (lowest address) block until
* one of adequate size is found. */
pxPreviousBlock = &xStart;
pxBlock = xStart.pxNextFreeBlock;
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
{
pxPreviousBlock = pxBlock;
pxBlock = pxBlock->pxNextFreeBlock;
}
/* If the end marker was reached then a block of adequate size
* was not found. */
if( pxBlock != pxEnd )
{
/* Return the memory space pointed to - jumping over the
* BlockLink_t structure at its start. */
pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );
/* This block is being returned for use so must be taken out
* of the list of free blocks. */
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
/* If the block is larger than required it can be split into
* two. */
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
{
/* This block is to be split into two. Create a new
* block following the number of bytes requested. The void
* cast is used to prevent byte alignment warnings from the
* compiler. */
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
/* Calculate the sizes of two blocks split from the
* single block. */
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
pxBlock->xBlockSize = xWantedSize;
/* Insert the new block into the list of free blocks. */
prvInsertBlockIntoFreeList( pxNewBlockLink );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
xFreeBytesRemaining -= pxBlock->xBlockSize;
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
{
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* The block is being returned - it is allocated and owned
* by the application and has no "next" block. */
pxBlock->xBlockSize |= xBlockAllocatedBit;
pxBlock->pxNextFreeBlock = NULL;
xNumberOfSuccessfulAllocations++;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
traceMALLOC( pvReturn, xWantedSize );
}
( void ) xTaskResumeAll();
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
{
if( pvReturn == NULL )
{
extern void vApplicationMallocFailedHook( void );
vApplicationMallocFailedHook();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
return pvReturn;
}
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS == 0)
void UTIL_MM_ReleaseBuffer( void * pv )
#else
void vPortFree( void * pv )
#endif
{
uint8_t * puc = ( uint8_t * ) pv;
BlockLink_t * pxLink;
if( pv != NULL )
{
/* The memory being freed will have an BlockLink_t structure immediately
* before it. */
puc -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
pxLink = ( void * ) puc;
/* Check the block is actually allocated. */
configASSERT( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 );
configASSERT( pxLink->pxNextFreeBlock == NULL );
if( ( pxLink->xBlockSize & xBlockAllocatedBit ) != 0 )
{
if( pxLink->pxNextFreeBlock == NULL )
{
/* The block is being returned to the heap - it is no longer
* allocated. */
pxLink->xBlockSize &= ~xBlockAllocatedBit;
vTaskSuspendAll();
{
/* Add this block to the list of free blocks. */
xFreeBytesRemaining += pxLink->xBlockSize;
traceFREE( pv, pxLink->xBlockSize );
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
xNumberOfSuccessfulFrees++;
}
( void ) xTaskResumeAll();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
size_t xPortGetFreeHeapSize( void )
{
return xFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
size_t xPortGetMinimumEverFreeHeapSize( void )
{
return xMinimumEverFreeBytesRemaining;
}
/*-----------------------------------------------------------*/
void vPortInitialiseBlocks( void )
{
/* This just exists to keep the linker quiet. */
}
/*-----------------------------------------------------------*/
static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
#else
void UTIL_MM_Init(uint8_t *p_pool, uint32_t pool_size)
#endif
{
BlockLink_t * pxFirstFreeBlock;
uint8_t * pucAlignedHeap;
size_t uxAddress;
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
#else
size_t xTotalHeapSize;
xTotalHeapSize = pool_size;
#endif
/* Ensure the heap starts on a correctly aligned boundary. */
uxAddress = ( size_t ) p_pool;
if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
uxAddress += ( portBYTE_ALIGNMENT - 1 );
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
xTotalHeapSize -= uxAddress - ( size_t ) p_pool;
}
pucAlignedHeap = ( uint8_t * ) uxAddress;
/* xStart is used to hold a pointer to the first item in the list of free
* blocks. The void cast is used to prevent compiler warnings. */
xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
xStart.xBlockSize = ( size_t ) 0;
/* pxEnd is used to mark the end of the list of free blocks and is inserted
* at the end of the heap space. */
uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
uxAddress -= xHeapStructSize;
uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
pxEnd = ( void * ) uxAddress;
pxEnd->xBlockSize = 0;
pxEnd->pxNextFreeBlock = NULL;
/* To start with there is a single free block that is sized to take up the
* entire heap space, minus the space taken by pxEnd. */
pxFirstFreeBlock = ( void * ) pucAlignedHeap;
pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
pxFirstFreeBlock->pxNextFreeBlock = pxEnd;
/* Only one block exists - and it covers the entire usable heap space. */
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
/* Work out the position of the top bit in a size_t variable. */
xBlockAllocatedBit = ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 );
}
/*-----------------------------------------------------------*/
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
{
BlockLink_t * pxIterator;
uint8_t * puc;
/* Iterate through the list until a block is found that has a higher address
* than the block being inserted. */
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; pxIterator = pxIterator->pxNextFreeBlock )
{
/* Nothing to do here, just iterate to the right position. */
}
/* Do the block being inserted, and the block it is being inserted after
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxIterator;
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
{
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
pxBlockToInsert = pxIterator;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Do the block being inserted, and the block it is being inserted before
* make a contiguous block of memory? */
puc = ( uint8_t * ) pxBlockToInsert;
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) pxIterator->pxNextFreeBlock )
{
if( pxIterator->pxNextFreeBlock != pxEnd )
{
/* Form one big block from the two blocks. */
pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize;
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock;
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxEnd;
}
}
else
{
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
}
/* If the block being inserted plugged a gab, so was merged with the block
* before and the block after, then it's pxNextFreeBlock pointer will have
* already been set, and should not be set here as that would make it point
* to itself. */
if( pxIterator != pxBlockToInsert )
{
pxIterator->pxNextFreeBlock = pxBlockToInsert;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
/*-----------------------------------------------------------*/
#if (KEEP_ORIGINAL_CODE_FROM_FREERTOS != 0)
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
{
BlockLink_t * pxBlock;
size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
vTaskSuspendAll();
{
pxBlock = xStart.pxNextFreeBlock;
/* pxBlock will be NULL if the heap has not been initialised. The heap
* is initialised automatically when the first allocation is made. */
if( pxBlock != NULL )
{
do
{
/* Increment the number of blocks and record the largest block seen
* so far. */
xBlocks++;
if( pxBlock->xBlockSize > xMaxSize )
{
xMaxSize = pxBlock->xBlockSize;
}
if( pxBlock->xBlockSize < xMinSize )
{
xMinSize = pxBlock->xBlockSize;
}
/* Move to the next block in the chain until the last block is
* reached. */
pxBlock = pxBlock->pxNextFreeBlock;
} while( pxBlock != pxEnd );
}
}
( void ) xTaskResumeAll();
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
taskENTER_CRITICAL();
{
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
}
taskEXIT_CRITICAL();
}
#endif

View File

@@ -0,0 +1,64 @@
/**
******************************************************************************
* @file stm32_mm.h
* @author MCD Application Team
* @brief Header for stm32_mm.c module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef STM32_MM_H
#define STM32_MM_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported defines -----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/**
* @brief Initialize the Pool
* @param p_pool: The pool of memory to manage
* @param pool_size: The size of the pool
* @retval None
*/
void UTIL_MM_Init(uint8_t *p_pool, uint32_t pool_size);
/**
* @brief Provide a buffer
* @param xWantedSize: The size of the buffer requested
* @retval The buffer address when available or NULL when there is no buffer
*/
void * UTIL_MM_GetBuffer(size_t xWantedSize);
/**
* @brief Release a buffer
* @param pv: The data buffer address
* @retval None
*/
void UTIL_MM_ReleaseBuffer( void * pv );
/* Exported functions to be implemented by the user if required ------------- */
#ifdef __cplusplus
}
#endif
#endif /* STM32_MM_H */

View File

@@ -0,0 +1,85 @@
/**
******************************************************************************
* @file rf_antenna_switch.c
* @author MCD Application Team
* @brief RF related module to handle dedictated GPIOs for antenna switch
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "rf_antenna_switch.h"
#include "ll_intf.h"
#include "app_conf.h"
#if (SUPPORT_AOA_AOD == 1) || (SUPPORT_ANT_DIV == 1)
static void RF_CONTROL_AntennaSwitch_Enable(void);
static void RF_CONTROL_AntennaSwitch_Disable(void);
static void RF_CONTROL_AntennaSwitch_Enable(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
uint32_t table_size = sizeof(rt_antenna_switch_gpio_table)/sizeof(rt_antenna_switch_gpio_table[0]);
for(unsigned int cpt = 0; cpt<table_size; cpt++)
{
GPIO_InitStruct.Pin = rt_antenna_switch_gpio_table[cpt].GPIO_pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = rt_antenna_switch_gpio_table[cpt].GPIO_alternate;
HAL_GPIO_Init(rt_antenna_switch_gpio_table[cpt].GPIO_port, &GPIO_InitStruct);
}
}
static void RF_CONTROL_AntennaSwitch_Disable(void)
{
uint32_t table_size = sizeof(rt_antenna_switch_gpio_table)/sizeof(rt_antenna_switch_gpio_table[0]);
for(unsigned int cpt = 0; cpt<table_size; cpt++)
{
HAL_GPIO_DeInit(rt_antenna_switch_gpio_table[cpt].GPIO_port, rt_antenna_switch_gpio_table[cpt].GPIO_pin);
}
}
void RF_CONTROL_AntennaSwitch(rf_antenna_switch_state_t state)
{
#if (SUPPORT_AOA_AOD == 1)
ble_stat_t status = GENERAL_FAILURE;
#endif
if(state == RF_ANTSW_ENABLE)
{
#if (SUPPORT_AOA_AOD == 1)
status = ll_intf_set_num_of_antennas(CFG_RADIO_NUM_OF_ANTENNAS);
if(status != SUCCESS)
{
/* Specified number of antennas is not supported */
assert_param(0);
return;
}
#endif /* SUPPORT_AOA_AOD */
RF_CONTROL_AntennaSwitch_Enable();
}
else
{
RF_CONTROL_AntennaSwitch_Disable();
}
}
#else /* SUPPORT_AOA_AOD || SUPPORT_ANT_DIV */
void RF_CONTROL_AntennaSwitch(rf_antenna_switch_state_t state)
{
/* AoA-AoD or antenna diversity feature is not supported with this Link Layer configuration */
assert_param(0);
}
#endif /* SUPPORT_AOA_AOD || SUPPORT_ANT_DIV */

View File

@@ -0,0 +1,56 @@
/**
******************************************************************************
* @file rf_antenna_switch.h
* @author MCD Application Team
* @brief RF related module to handle dedictated GPIOs for antenna switch
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef RF_ANTENNA_SWITCH_H
#define RF_ANTENNA_SWITCH_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32wbaxx.h"
#define RF_ANTSW0 {GPIOA, GPIO_PIN_12, GPIO_AF11_RF_ANTSW0}
#define RF_ANTSW1 {GPIOA, GPIO_PIN_11, GPIO_AF11_RF_ANTSW1}
#define RF_ANTSW2 {GPIOB, GPIO_PIN_2, GPIO_AF11_RF_ANTSW2}
typedef struct {
GPIO_TypeDef* GPIO_port;
uint16_t GPIO_pin;
uint8_t GPIO_alternate;
} st_gpio_antsw_t;
typedef enum {
RF_ANTSW_DISABLE = 0,
RF_ANTSW_ENABLE
} rf_antenna_switch_state_t;
static const st_gpio_antsw_t rt_antenna_switch_gpio_table[] =
{
RF_ANTSW0,
RF_ANTSW1,
RF_ANTSW2
};
void RF_CONTROL_AntennaSwitch(rf_antenna_switch_state_t state);
#ifdef __cplusplus
}
#endif
#endif /* RF_ANTENNA_SWITCH_H */

View File

@@ -0,0 +1,89 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file rf_external_pa.c
* @author MCD Application Team
* @brief RF related module to handle dedictated GPIOs for external PA
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
#include "rf_external_pa.h"
#include "power_table.h"
#include "ll_intf.h"
#include "app_conf.h"
static void RF_CONTROL_ExternalPA_Enable(void);
static void RF_CONTROL_ExternalPA_Disable(void);
static uint8_t RF_CONTROL_ExternalPA_Enable_cb(uint8_t epa_enable);
static void RF_CONTROL_ExternalPA_Enable(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
uint32_t table_size = sizeof(rf_external_pa_gpio_table)/sizeof(rf_external_pa_gpio_table[0]);
for(unsigned int cpt = 0; cpt<table_size; cpt++)
{
GPIO_InitStruct.Pin = rf_external_pa_gpio_table[cpt].GPIO_pin;
GPIO_InitStruct.Mode = rf_external_pa_gpio_table[cpt].GPIO_mode;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = rf_external_pa_gpio_table[cpt].GPIO_alternate;
HAL_GPIO_Init(rf_external_pa_gpio_table[cpt].GPIO_port, &GPIO_InitStruct);
}
}
static void RF_CONTROL_ExternalPA_Disable(void)
{
uint32_t table_size = sizeof(rf_external_pa_gpio_table)/sizeof(rf_external_pa_gpio_table[0]);
for(unsigned int cpt = 0; cpt<table_size; cpt++)
{
HAL_GPIO_DeInit(rf_external_pa_gpio_table[cpt].GPIO_port, rf_external_pa_gpio_table[cpt].GPIO_pin);
}
}
static uint8_t RF_CONTROL_ExternalPA_Enable_cb(uint8_t epa_enable)
{
if(epa_enable == 1)
{
HAL_GPIO_WritePin(rf_external_pa_gpio_table[RF_EPA_SIGNAL_CSD].GPIO_port, rf_external_pa_gpio_table[RF_EPA_SIGNAL_CSD].GPIO_pin, GPIO_PIN_SET);
}
else
{
HAL_GPIO_WritePin(rf_external_pa_gpio_table[RF_EPA_SIGNAL_CSD].GPIO_port, rf_external_pa_gpio_table[RF_EPA_SIGNAL_CSD].GPIO_pin, GPIO_PIN_RESET);
}
return 0;
}
void RF_CONTROL_ExternalPA(rf_external_pa_state_t state)
{
ble_stat_t status = GENERAL_FAILURE;
if(state == RF_EPA_ENABLE)
{
status = ll_tx_pwr_if_epa_init(1, RF_CONTROL_ExternalPA_Enable_cb);
if(status != SUCCESS)
{
/* EPA callback is not defined */
assert_param(0);
return;
}
RF_CONTROL_ExternalPA_Enable();
}
else
{
RF_CONTROL_ExternalPA_Disable();
}
}

View File

@@ -0,0 +1,61 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file rf_external_pa.h
* @author MCD Application Team
* @brief RF related module to handle dedictated GPIOs for external PA
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
#ifndef RF_EXTERNAL_PA_H
#define RF_EXTERNAL_PA_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32wbaxx.h"
#define RF_EPA_CSD {GPIOA, GPIO_PIN_9, GPIO_MODE_OUTPUT_PP, GPIO_AF15_EVENTOUT}
#define RF_EPA_CTX {GPIOB, GPIO_PIN_15, GPIO_MODE_AF_PP, GPIO_AF11_RF_IO1}
typedef struct {
GPIO_TypeDef* GPIO_port;
uint16_t GPIO_pin;
uint32_t GPIO_mode;
uint8_t GPIO_alternate;
} st_gpio_epa_t;
typedef enum {
RF_EPA_DISABLE = 0,
RF_EPA_ENABLE
} rf_external_pa_state_t;
typedef enum {
RF_EPA_SIGNAL_CSD = 0,
RF_EPA_SIGNAL_CTX
} rf_external_pa_signal_t;
static const st_gpio_epa_t rf_external_pa_gpio_table[] =
{
[RF_EPA_SIGNAL_CSD] = RF_EPA_CSD,
[RF_EPA_SIGNAL_CTX] = RF_EPA_CTX
};
void RF_CONTROL_ExternalPA(rf_external_pa_state_t state);
#ifdef __cplusplus
}
#endif
#endif /* RF_EXTERNAL_PA_H */

View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* @file RTDebug.c
* @author MCD Application Team
* @brief Real Time Debug module API definition
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#include "RTDebug.h"
#include "local_debug_tables.h"
#include "stm32wbaxx_hal.h"
#include <assert.h>
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
static_assert((sizeof(general_debug_table)/sizeof(st_gpio_debug_t)) == RT_DEBUG_SIGNALS_TOTAL_NUM,
"Debug signals number is different from debug signal table size."
);
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
/***********************/
/** System debug APIs **/
/***********************/
void SYSTEM_DEBUG_SIGNAL_SET(system_debug_signal_t signal)
{
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
GENERIC_DEBUG_GPIO_SET(signal, system_debug_table);
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
}
void SYSTEM_DEBUG_SIGNAL_RESET(system_debug_signal_t signal)
{
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
GENERIC_DEBUG_GPIO_RESET(signal, system_debug_table);
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
}
void SYSTEM_DEBUG_SIGNAL_TOGGLE(system_debug_signal_t signal)
{
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
GENERIC_DEBUG_GPIO_TOGGLE(signal, system_debug_table);
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
}
/***************************/
/** Link Layer debug APIs **/
/***************************/
/* Link Layer debug API definition */
void LINKLAYER_DEBUG_SIGNAL_SET(linklayer_debug_signal_t signal)
{
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
GENERIC_DEBUG_GPIO_SET(signal, linklayer_debug_table);
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
}
void LINKLAYER_DEBUG_SIGNAL_RESET(linklayer_debug_signal_t signal)
{
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
GENERIC_DEBUG_GPIO_RESET(signal, linklayer_debug_table);
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
}
void LINKLAYER_DEBUG_SIGNAL_TOGGLE(linklayer_debug_signal_t signal)
{
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
GENERIC_DEBUG_GPIO_TOGGLE(signal, linklayer_debug_table);
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
}

View File

@@ -0,0 +1,93 @@
/**
******************************************************************************
* @file RTDebug.h
* @author MCD Application Team
* @brief Real Time Debug module API declaration
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef SYSTEM_DEBUG_H
#define SYSTEM_DEBUG_H
#ifdef __cplusplus
extern "C" {
#endif
#include "debug_config.h"
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
/**************************************************************/
/** Generic macros for local signal table index recuperation **/
/** and global signal table GPIO manipulation **/
/**************************************************************/
#define GENERIC_DEBUG_GPIO_SET(signal, table) do { \
uint32_t debug_table_idx = 0; \
if(signal >= sizeof(table)) \
{ \
return; \
} \
debug_table_idx = table[signal]; \
if(debug_table_idx != RT_DEBUG_SIGNAL_UNUSED) \
{ \
LL_GPIO_SetOutputPin(general_debug_table[debug_table_idx].GPIO_port, \
general_debug_table[debug_table_idx].GPIO_pin); \
} \
} while(0)
#define GENERIC_DEBUG_GPIO_RESET(signal, table) do { \
uint32_t debug_table_idx = 0; \
if(signal >= sizeof(table)) \
{ \
return; \
} \
debug_table_idx = table[signal]; \
if(debug_table_idx != RT_DEBUG_SIGNAL_UNUSED) \
{ \
LL_GPIO_ResetOutputPin(general_debug_table[debug_table_idx].GPIO_port, \
general_debug_table[debug_table_idx].GPIO_pin); \
} \
} while(0)
#define GENERIC_DEBUG_GPIO_TOGGLE(signal, table) do { \
uint32_t debug_table_idx = 0; \
if(signal >= sizeof(table)) \
{ \
return; \
} \
debug_table_idx = table[signal]; \
if(debug_table_idx != RT_DEBUG_SIGNAL_UNUSED) \
{ \
LL_GPIO_TogglePin(general_debug_table[debug_table_idx].GPIO_port, \
general_debug_table[debug_table_idx].GPIO_pin); \
} \
} while(0)
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
/* System debug API definition */
void SYSTEM_DEBUG_SIGNAL_SET(system_debug_signal_t signal);
void SYSTEM_DEBUG_SIGNAL_RESET(system_debug_signal_t signal);
void SYSTEM_DEBUG_SIGNAL_TOGGLE(system_debug_signal_t signal);
/* Link Layer debug API definition */
void LINKLAYER_DEBUG_SIGNAL_SET(linklayer_debug_signal_t signal);
void LINKLAYER_DEBUG_SIGNAL_RESET(linklayer_debug_signal_t signal);
void LINKLAYER_DEBUG_SIGNAL_TOGGLE(linklayer_debug_signal_t signal);
#ifdef __cplusplus
}
#endif
#endif /* SYSTEM_DEBUG_H */

View File

@@ -0,0 +1,147 @@
/**
******************************************************************************
* @file RTDebug_dtb.c
* @author MCD Application Team
* @brief Real Time Debug module API definition for DTB usage
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/**
* The DEBUG DTB interface is INTENDED TO BE USED ONLY ON REQUEST FROM ST SUPPORT.
* It provides HW signals from RF PHY activity.
*/
/* Includes ------------------------------------------------------------------*/
#include "RTDebug_dtb.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#if(CFG_RT_DEBUG_DTB == 1)
/* Private function prototypes -----------------------------------------------*/
static void RT_DEBUG_SetDTBMode(uint8_t dtb, uint8_t mode);
/* Private functions ---------------------------------------------------------*/
static void RT_DEBUG_SetDTBMode(uint8_t dtb, uint8_t mode)
{
/* Set SYSCFG for DTB */
uint32_t addr = (uint32_t)(&SYSCFG->SECCFGR);
__HAL_RCC_SYSCFG_CLK_ENABLE();
addr += 0x100; /* contains SYSCFG->DBTCR address */
/* Keep others DTB in current modes */
*(uint32_t*)addr |= (0xF<<(dtb*4)); /* Selected DTB unmask mode */
*(uint32_t*)addr ^= (0xF<<(dtb*4)); /* Selected DTB unset mode */
/* Selected DTB set to mode */
*(uint32_t*)addr |= (mode<<(dtb*4));
}
void RT_DEBUG_DTBInit(void)
{
/** access_match PA7 DTB[7] on TL_10 **/
/*
LL_GPIO_SetPinSpeed(GPIOA,LL_GPIO_PIN_7,LL_GPIO_SPEED_FREQ_HIGH);
LL_GPIO_SetPinMode(GPIOA,LL_GPIO_PIN_7,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOA,LL_GPIO_PIN_7,LL_GPIO_AF_15);
LL_PWR_EnableGPIOStandbyRetention(LL_PWR_GPIO_STATE_RETENTION_ENABLE_PORTA, LL_PWR_GPIO_PIN_7);
*/
/** long_range_iq_vld PA6 DTB[6] on TL_9 **/
LL_GPIO_SetPinMode(GPIOA,LL_GPIO_PIN_6,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOA,LL_GPIO_PIN_6,LL_GPIO_AF_15);
/** tx_data PA5 DTB[5] on TL_8 **/
/*
LL_GPIO_SetPinMode(GPIOA,LL_GPIO_PIN_5,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOA,LL_GPIO_PIN_5,LL_GPIO_AF_15);
*/
/** rx_data PB9 DTB[4] on TL_31 **/
/*
LL_GPIO_SetPinMode(GPIOB,LL_GPIO_PIN_9,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOB,LL_GPIO_PIN_9,LL_GPIO_AF_15);
LL_PWR_EnableGPIOStandbyRetention(LL_PWR_GPIO_STATE_RETENTION_ENABLE_PORTB, LL_PWR_GPIO_PIN_9);
*/
/** tx_data_clk PB8 DTB[3] on TL_30 **/
/*
LL_GPIO_SetPinMode(GPIOB,LL_GPIO_PIN_8,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_8_15(GPIOB,LL_GPIO_PIN_8,LL_GPIO_AF_15);
*/
/** rx_data_clk PA2 DTB[2] on TL_3 **/
/*
LL_GPIO_SetPinMode(GPIOA,LL_GPIO_PIN_2,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOA,LL_GPIO_PIN_2,LL_GPIO_AF_15);
LL_PWR_EnableGPIOStandbyRetention(LL_PWR_GPIO_STATE_RETENTION_ENABLE_PORTA, LL_PWR_GPIO_PIN_2);
*/
/** tx_on PA1 DTB[1] on TL_2 **/
LL_GPIO_SetPinMode(GPIOA,LL_GPIO_PIN_1,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOA,LL_GPIO_PIN_1,LL_GPIO_AF_15);
LL_PWR_EnableGPIOStandbyRetention(LL_PWR_GPIO_STATE_RETENTION_ENABLE_PORTA, LL_PWR_GPIO_PIN_1);
/** rx_on PA0 DTB[0] on TL_1 **/
/*
LL_GPIO_SetPinMode(GPIOA,LL_GPIO_PIN_0,LL_GPIO_MODE_ALTERNATE);
LL_GPIO_SetAFPin_0_7(GPIOA,LL_GPIO_PIN_0,LL_GPIO_AF_15);
LL_PWR_EnableGPIOStandbyRetention(LL_PWR_GPIO_STATE_RETENTION_ENABLE_PORTA, LL_PWR_GPIO_PIN_0);
*/
/* Set SYSCFG for DTB */
uint32_t addr = (uint32_t)(&SYSCFG->SECCFGR);
__HAL_RCC_SYSCFG_CLK_ENABLE();
addr += 0x100; /* contains SYSCFG->DBTCR address */
/* Default DTB in test mode 0 */
*(uint32_t*)addr = 0x00000000;
}
/* Public functions ----------------------------------------------------------*/
void RT_DEBUG_DTBConfig(void)
{
/*
** Monitor DTB **
* A0 o PA0 AF15 DTB[0] mode 1 rx_on
* A1 o PA1 AF15 DTB[1] mode 1 tx_on
* A2 o PB9 AF15 DTB[4] mode 5 radio_bbclk
* A3 o PA7 AF15 DTB[7] mode 3 slptmr_irq
* A4 o PA2 AF15 DTB[2] mode 5 CM33_sleepdeep
* A5 o PA6 AF00 PWR_CSTOP
* A6 o PA8 as SYSclk source
* A7 o PB1 Monitor wakeup GPIO
* A8 o PB0 Debug PIN
* A9 o PC0 o_pm_sleep_sw
* A10 o PC1 o_pm_act_com_sw
**/
RT_DEBUG_SetDTBMode(6, 3) ; /* Radio IRQ */
RT_DEBUG_SetDTBMode(1, 1); /* tx_on */
//RT_DEBUG_SetDTBMode(0, 1); /* rx_on */
//RT_DEBUG_SetDTBMode(1, 3); /* sleep timer irq */
//RT_DEBUG_SetDTBMode(2, 5); /* CM33_sleepdeep */
//RT_DEBUG_SetDTBMode(4, 5); /* radio_bbclk */
//RT_DEBUG_SetDTBMode(7, 3); /* slptm_irq */
//RT_DEBUG_SetDTBMode(7, 5); /* radio_bus_clk */
//RT_DEBUG_SetDTBMode(7, 6); /* test tm 00 */
//RT_DEBUG_SetDTBMode(6, 6); /* test tm 01 */
}
#endif /* CFG_RT_DEBUG_DTB */

View File

@@ -0,0 +1,43 @@
/**
******************************************************************************
* @file RTDebug_dtb.h
* @author MCD Application Team
* @brief Real Time Debug module API declaration for DTB usage
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef RT_DEBUG_DTB_H
#define RT_DEBUG_DTB_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* The DEBUG DTB interface is INTENDED TO BE USED ONLY ON REQUEST FROM ST SUPPORT.
* It provides HW signals from RF PHY activity.
*/
#include "app_conf.h"
#if(CFG_RT_DEBUG_DTB == 1)
void RT_DEBUG_DTBConfig(void);
void RT_DEBUG_DTBInit(void);
#endif /* CFG_RT_DEBUG_DTB */
#ifdef __cplusplus
}
#endif
#endif /* RT_DEBUG_DTB_H */

View File

@@ -0,0 +1,833 @@
/**
******************************************************************************
* @file debug_signals.h
* @author MCD Application Team
* @brief Real Time Debug module System and Link Layer signal definition
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef DEBUG_SIGNALS_H
#define DEBUG_SIGNALS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "bsp.h"
/**************************************************/
/** Specific Link Layer debug signals definition **/
/**************************************************/
typedef Debug_GPIO_t linklayer_debug_signal_t;
/**********************************************/
/** Specific System debug signals definition **/
/**********************************************/
typedef enum {
ADC_ACTIVATION,
ADC_DEACTIVATION,
ADC_TEMPERATURE_ACQUISITION,
RNG_ENABLE,
RNG_DISABLE,
RNG_GEN_RAND_NUM,
LOW_POWER_STOP_MODE_ENTER,
LOW_POWER_STOP_MODE_EXIT,
LOW_POWER_STOP_MODE_ACTIVE,
LOW_POWER_STOP2_MODE_ENTER,
LOW_POWER_STOP2_MODE_EXIT,
LOW_POWER_STOP2_MODE_ACTIVE,
LOW_POWER_STANDBY_MODE_ENTER,
LOW_POWER_STANDBY_MODE_EXIT,
LOW_POWER_STANDBY_MODE_ACTIVE,
SCM_SETUP,
SCM_SYSTEM_CLOCK_CONFIG,
SCM_HSERDY_ISR,
} system_debug_signal_t;
#if(CFG_RT_DEBUG_GPIO_MODULE == 1)
/*************************************/
/** Global debug signals definition **/
/*************************************/
typedef enum {
RT_DEBUG_SIGNAL_UNUSED = 0x0,
/********************/
/** System signals **/
/********************/
#if (USE_RT_DEBUG_SCM_SETUP == 1)
RT_DEBUG_SCM_SETUP,
#endif /* USE_RT_DEBUG_SCM_SETUP */
#if (USE_RT_DEBUG_SCM_HSERDY_ISR == 1)
RT_DEBUG_SCM_HSERDY_ISR,
#endif /* USE_RT_DEBUG_SCM_HSERDY_ISR */
#if (USE_RT_DEBUG_SCM_SYSTEM_CLOCK_CONFIG == 1)
RT_DEBUG_SCM_SYSTEM_CLOCK_CONFIG,
#endif /* USE_RT_DEBUG_SCM_SYSTEM_CLOCK_CONFIG */
#if (USE_RT_DEBUG_ADC_ACTIVATION == 1)
RT_DEBUG_ADC_ACTIVATION,
#endif /* USE_RT_DEBUG_ADC_ACTIVATION */
#if (USE_RT_DEBUG_ADC_DEACTIVATION == 1)
RT_DEBUG_ADC_DEACTIVATION,
#endif /* USE_RT_DEBUG_ADC_DEACTIVATION */
#if (USE_RT_DEBUG_ADC_TEMPERATURE_ACQUISITION == 1)
RT_DEBUG_ADC_TEMPERATURE_ACQUISITION,
#endif /* USE_RT_DEBUG_ADC_TEMPERATURE_ACQUISITION */
#if (USE_RT_DEBUG_RNG_ENABLE == 1)
RT_DEBUG_RNG_ENABLE,
#endif /* USE_RT_DEBUG_RNG_ENABLE */
#if (USE_RT_DEBUG_RNG_DISABLE == 1)
RT_DEBUG_RNG_DISABLE,
#endif /* USE_RT_DEBUG_RNG_DISABLE */
#if (USE_RT_DEBUG_RNG_GEN_RAND_NUM == 1)
RT_DEBUG_RNG_GEN_RAND_NUM,
#endif /* USE_RT_DEBUG_RNG_GEN_RAND_NUM */
#if (USE_RT_DEBUG_LOW_POWER_STOP_MODE_ENTER == 1)
RT_DEBUG_LOW_POWER_STOP_MODE_ENTER,
#endif /* USE_RT_DEBUG_LOW_POWER_STOP_MODE_ENTER */
#if (USE_RT_DEBUG_LOW_POWER_STOP_MODE_EXIT == 1)
RT_DEBUG_LOW_POWER_STOP_MODE_EXIT,
#endif /* USE_RT_DEBUG_LOW_POWER_STOP_MODE_EXIT */
#if (USE_RT_DEBUG_LOW_POWER_STOP_MODE_ACTIVE == 1)
RT_DEBUG_LOW_POWER_STOP_MODE_ACTIVE,
#endif /* USE_RT_DEBUG_LOW_POWER_STOP_MODE_ACTIVE */
#if (USE_RT_DEBUG_LOW_POWER_STOP2_MODE_ENTER == 1)
RT_DEBUG_LOW_POWER_STOP2_MODE_ENTER,
#endif /* USE_RT_DEBUG_LOW_POWER_STOP2_MODE_ENTER */
#if (USE_RT_DEBUG_LOW_POWER_STOP2_MODE_EXIT == 1)
RT_DEBUG_LOW_POWER_STOP2_MODE_EXIT,
#endif /* USE_RT_DEBUG_LOW_POWER_STOP2_MODE_EXIT */
#if (USE_RT_DEBUG_LOW_POWER_STOP2_MODE_ACTIVE == 1)
RT_DEBUG_LOW_POWER_STOP2_MODE_ACTIVE,
#endif /* USE_RT_DEBUG_LOW_POWER_STOP2_MODE_ACTIVE */
#if (USE_RT_DEBUG_LOW_POWER_STANDBY_MODE_ENTER == 1)
RT_DEBUG_LOW_POWER_STANDBY_MODE_ENTER,
#endif /* USE_RT_DEBUG_LOW_POWER_STANDBY_MODE_ENTER */
#if (USE_RT_DEBUG_LOW_POWER_STANDBY_MODE_EXIT == 1)
RT_DEBUG_LOW_POWER_STANDBY_MODE_EXIT,
#endif /* USE_RT_DEBUG_LOW_POWER_STANDBY_MODE_EXIT */
#if (USE_RT_DEBUG_LOW_POWER_STANDBY_MODE_ACTIVE == 1)
RT_DEBUG_LOW_POWER_STANDBY_MODE_ACTIVE,
#endif /* USE_RT_DEBUG_LOW_POWER_STANDBY_MODE_ACTIVE */
/************************/
/** Link Layer signals **/
/************************/
#if (USE_RT_DEBUG_HCI_READ_DONE == 1)
RT_DEBUG_HCI_READ_DONE,
#endif /* USE_RT_DEBUG_HCI_READ_DONE */
#if (USE_RT_DEBUG_HCI_RCVD_CMD == 1)
RT_DEBUG_HCI_RCVD_CMD,
#endif /* USE_RT_DEBUG_HCI_RCVD_CMD */
#if (USE_RT_DEBUG_HCI_WRITE_DONE == 1)
RT_DEBUG_HCI_WRITE_DONE,
#endif /* USE_RT_DEBUG_HCI_WRITE_DONE */
#if (USE_RT_DEBUG_SCHDLR_EVNT_UPDATE == 1)
RT_DEBUG_SCHDLR_EVNT_UPDATE,
#endif /* USE_RT_DEBUG_SCHDLR_EVNT_UPDATE */
#if (USE_RT_DEBUG_SCHDLR_TIMER_SET == 1)
RT_DEBUG_SCHDLR_TIMER_SET,
#endif /* USE_RT_DEBUG_SCHDLR_TIMER_SET */
#if (USE_RT_DEBUG_SCHDLR_PHY_CLBR_TIMER == 1)
RT_DEBUG_SCHDLR_PHY_CLBR_TIMER,
#endif /* USE_RT_DEBUG_SCHDLR_PHY_CLBR_TIMER */
#if (USE_RT_DEBUG_SCHDLR_EVNT_SKIPPED == 1)
RT_DEBUG_SCHDLR_EVNT_SKIPPED,
#endif /* USE_RT_DEBUG_SCHDLR_EVNT_SKIPPED */
#if (USE_RT_DEBUG_SCHDLR_HNDL_NXT_TRACE == 1)
RT_DEBUG_SCHDLR_HNDL_NXT_TRACE,
#endif /* USE_RT_DEBUG_SCHDLR_HNDL_NXT_TRACE */
#if (USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_DETEDTED == 1)
RT_DEBUG_ACTIVE_SCHDLR_NEAR_DETEDTED,
#endif /* USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_DETEDTED */
#if (USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_GAP_CHECK == 1)
RT_DEBUG_ACTIVE_SCHDLR_NEAR_GAP_CHECK,
#endif /* USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_GAP_CHECK */
#if (USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_TIME_CHECK == 1)
RT_DEBUG_ACTIVE_SCHDLR_NEAR_TIME_CHECK,
#endif /* USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_TIME_CHECK */
#if (USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_TRACE == 1)
RT_DEBUG_ACTIVE_SCHDLR_NEAR_TRACE,
#endif /* USE_RT_DEBUG_ACTIVE_SCHDLR_NEAR_TRACE */
#if (USE_RT_DEBUG_SCHDLR_EVNT_RGSTR == 1)
RT_DEBUG_SCHDLR_EVNT_RGSTR,
#endif /* USE_RT_DEBUG_SCHDLR_EVNT_RGSTR */
#if (USE_RT_DEBUG_SCHDLR_ADD_CONFLICT_Q == 1)
RT_DEBUG_SCHDLR_ADD_CONFLICT_Q,
#endif /* USE_RT_DEBUG_SCHDLR_ADD_CONFLICT_Q */
#if (USE_RT_DEBUG_SCHDLR_HNDL_MISSED_EVNT == 1)
RT_DEBUG_SCHDLR_HNDL_MISSED_EVNT,
#endif /* USE_RT_DEBUG_SCHDLR_HNDL_MISSED_EVNT */
#if (USE_RT_DEBUG_SCHDLR_UNRGSTR_EVNT == 1)
RT_DEBUG_SCHDLR_UNRGSTR_EVNT,
#endif /* USE_RT_DEBUG_SCHDLR_UNRGSTR_EVNT */
#if (USE_RT_DEBUG_SCHDLR_EXEC_EVNT_TRACE == 1)
RT_DEBUG_SCHDLR_EXEC_EVNT_TRACE,
#endif /* USE_RT_DEBUG_SCHDLR_EXEC_EVNT_TRACE */
#if (USE_RT_DEBUG_SCHDLR_EXEC_EVNT_PROFILE == 1)
RT_DEBUG_SCHDLR_EXEC_EVNT_PROFILE,
#endif /* USE_RT_DEBUG_SCHDLR_EXEC_EVNT_PROFILE */
#if (USE_RT_DEBUG_SCHDLR_EXEC_EVNT_ERROR == 1)
RT_DEBUG_SCHDLR_EXEC_EVNT_ERROR,
#endif /* USE_RT_DEBUG_SCHDLR_EXEC_EVNT_ERROR */
#if (USE_RT_DEBUG_SCHDLR_EXEC_EVNT_WINDOW_WIDENING == 1)
RT_DEBUG_SCHDLR_EXEC_EVNT_WINDOW_WIDENING,
#endif /* USE_RT_DEBUG_SCHDLR_EXEC_EVNT_WINDOW_WIDENING */
#if (USE_RT_DEBUG_LLHWC_CMN_CLR_ISR == 1)
RT_DEBUG_LLHWC_CMN_CLR_ISR,
#endif /* USE_RT_DEBUG_LLHWC_CMN_CLR_ISR */
#if (USE_RT_DEBUG_LLWCC_CMN_HG_ISR == 1)
RT_DEBUG_LLWCC_CMN_HG_ISR,
#endif /* USE_RT_DEBUG_LLWCC_CMN_HG_ISR */
#if (USE_RT_DEBUG_LLHWC_CMN_LW_ISR == 1)
RT_DEBUG_LLHWC_CMN_LW_ISR,
#endif /* USE_RT_DEBUG_LLHWC_CMN_LW_ISR */
#if (USE_RT_DEBUG_LLHWC_CMN_CLR_TIMER_ERROR == 1)
RT_DEBUG_LLHWC_CMN_CLR_TIMER_ERROR,
#endif /* USE_RT_DEBUG_LLHWC_CMN_CLR_TIMER_ERROR */
#if (USE_RT_DEBUG_LLHWC_LL_ISR == 1)
RT_DEBUG_LLHWC_LL_ISR,
#endif /* USE_RT_DEBUG_LLHWC_LL_ISR */
#if (USE_RT_DEBUG_LLHWC_SPLTMR_SET == 1)
RT_DEBUG_LLHWC_SPLTMR_SET,
#endif /* USE_RT_DEBUG_LLHWC_SPLTMR_SET */
#if (USE_RT_DEBUG_LLHWC_SPLTMR_GET == 1)
RT_DEBUG_LLHWC_SPLTMR_GET,
#endif /* USE_RT_DEBUG_LLHWC_SPLTMR_GET */
#if (USE_RT_DEBUG_LLHWC_LOW_ISR == 1)
RT_DEBUG_LLHWC_LOW_ISR,
#endif /* USE_RT_DEBUG_LLHWC_LOW_ISR */
#if (USE_RT_DEBUG_LLHWC_STOP_SCN == 1)
RT_DEBUG_LLHWC_STOP_SCN,
#endif /* USE_RT_DEBUG_LLHWC_STOP_SCN */
#if (USE_RT_DEBUG_LLHWC_WAIT_ENVT_ON_AIR == 1)
RT_DEBUG_LLHWC_WAIT_ENVT_ON_AIR,
#endif /* USE_RT_DEBUG_LLHWC_WAIT_ENVT_ON_AIR */
#if (USE_RT_DEBUG_LLHWC_SET_CONN_EVNT_PARAM == 1)
RT_DEBUG_LLHWC_SET_CONN_EVNT_PARAM,
#endif /* USE_RT_DEBUG_LLHWC_SET_CONN_EVNT_PARAM */
#if (USE_RT_DEBUG_POST_EVNT == 1)
RT_DEBUG_POST_EVNT,
#endif /* USE_RT_DEBUG_POST_EVNT */
#if (USE_RT_DEBUG_HNDL_ALL_EVNTS == 1)
RT_DEBUG_HNDL_ALL_EVNTS,
#endif /* USE_RT_DEBUG_HNDL_ALL_EVNTS */
#if (USE_RT_DEBUG_PROCESS_EVNT == 1)
RT_DEBUG_PROCESS_EVNT,
#endif /* USE_RT_DEBUG_PROCESS_EVNT */
#if (USE_RT_DEBUG_PROCESS_ISO_DATA == 1)
RT_DEBUG_PROCESS_ISO_DATA,
#endif /* USE_RT_DEBUG_PROCESS_ISO_DATA */
#if (USE_RT_DEBUG_ALLOC_TX_ISO_EMPTY_PKT == 1)
RT_DEBUG_ALLOC_TX_ISO_EMPTY_PKT,
#endif /* USE_RT_DEBUG_ALLOC_TX_ISO_EMPTY_PKT */
#if (USE_RT_DEBUG_BIG_FREE_EMPTY_PKTS == 1)
RT_DEBUG_BIG_FREE_EMPTY_PKTS,
#endif /* USE_RT_DEBUG_BIG_FREE_EMPTY_PKTS */
#if (USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_OK == 1)
RT_DEBUG_RECOMBINE_UNFRMD_DATA_OK,
#endif /* USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_OK */
#if (USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_CRC == 1)
RT_DEBUG_RECOMBINE_UNFRMD_DATA_CRC,
#endif /* USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_CRC */
#if (USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_NoRX == 1)
RT_DEBUG_RECOMBINE_UNFRMD_DATA_NoRX,
#endif /* USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_NoRX */
#if (USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_TRACE == 1)
RT_DEBUG_RECOMBINE_UNFRMD_DATA_TRACE,
#endif /* USE_RT_DEBUG_RECOMBINE_UNFRMD_DATA_TRACE */
#if (USE_RT_DEBUG_ISO_HNDL_SDU == 1)
RT_DEBUG_ISO_HNDL_SDU,
#endif /* USE_RT_DEBUG_ISO_HNDL_SDU */
#if (USE_RT_DEBUG_LL_INTF_INIT == 1)
RT_DEBUG_LL_INTF_INIT,
#endif /* USE_RT_DEBUG_LL_INTF_INIT */
#if (USE_RT_DEBUG_DATA_TO_CNTRLR == 1)
RT_DEBUG_DATA_TO_CNTRLR,
#endif /* USE_RT_DEBUG_DATA_TO_CNTRLR */
#if (USE_RT_DEBUG_FREE_LL_PKT_HNDLR == 1)
RT_DEBUG_FREE_LL_PKT_HNDLR,
#endif /* USE_RT_DEBUG_FREE_LL_PKT_HNDLR */
#if (USE_RT_DEBUG_PHY_INIT_CLBR_TRACE == 1)
RT_DEBUG_PHY_INIT_CLBR_TRACE,
#endif /* USE_RT_DEBUG_PHY_INIT_CLBR_TRACE */
#if (USE_RT_DEBUG_PHY_RUNTIME_CLBR_TRACE == 1)
RT_DEBUG_PHY_RUNTIME_CLBR_TRACE,
#endif /* USE_RT_DEBUG_PHY_RUNTIME_CLBR_TRACE */
#if (USE_RT_DEBUG_PHY_CLBR_ISR == 1)
RT_DEBUG_PHY_CLBR_ISR,
#endif /* USE_RT_DEBUG_PHY_CLBR_ISR */
#if (USE_RT_DEBUG_PHY_INIT_CLBR_SINGLE_CH == 1)
RT_DEBUG_PHY_INIT_CLBR_SINGLE_CH,
#endif /* USE_RT_DEBUG_PHY_INIT_CLBR_SINGLE_CH */
#if (USE_RT_DEBUG_PHY_CLBR_STRTD == 1)
RT_DEBUG_PHY_CLBR_STRTD,
#endif /* USE_RT_DEBUG_PHY_CLBR_STRTD */
#if (USE_RT_DEBUG_PHY_CLBR_EXEC == 1)
RT_DEBUG_PHY_CLBR_EXEC,
#endif /* USE_RT_DEBUG_PHY_CLBR_EXEC */
#if (USE_RT_DEBUG_RCO_STRT_STOP_RUNTIME_CLBR_ACTV == 1)
RT_DEBUG_RCO_STRT_STOP_RUNTIME_CLBR_ACTV,
#endif /* USE_RT_DEBUG_RCO_STRT_STOP_RUNTIME_CLBR_ACTV */
#if (USE_RT_DEBUG_RCO_STRT_STOP_RUNTIME_RCO_CLBR == 1)
RT_DEBUG_RCO_STRT_STOP_RUNTIME_RCO_CLBR,
#endif /* USE_RT_DEBUG_RCO_STRT_STOP_RUNTIME_RCO_CLBR */
#if (USE_RT_DEBUG_STRT_STOP_RUNTIME_RCO_CLBR_SWT == 1)
RT_DEBUG_STRT_STOP_RUNTIME_RCO_CLBR_SWT,
#endif /* USE_RT_DEBUG_STRT_STOP_RUNTIME_RCO_CLBR_SWT */
#if (USE_RT_DEBUG_STRT_STOP_RUNTIME_RCO_CLBR_TRACE == 1)
RT_DEBUG_STRT_STOP_RUNTIME_RCO_CLBR_TRACE,
#endif /* USE_RT_DEBUG_STRT_STOP_RUNTIME_RCO_CLBR_TRACE */
#if (USE_RT_DEBUG_RCO_ISR_TRACE == 1)
RT_DEBUG_RCO_ISR_TRACE,
#endif /* USE_RT_DEBUG_RCO_ISR_TRACE */
#if (USE_RT_DEBUG_RCO_ISR_COMPENDATE == 1)
RT_DEBUG_RCO_ISR_COMPENDATE,
#endif /* USE_RT_DEBUG_RCO_ISR_COMPENDATE */
#if (USE_RT_DEBUG_RAL_STRT_TX == 1)
RT_DEBUG_RAL_STRT_TX,
#endif /* USE_RT_DEBUG_RAL_STRT_TX */
#if (USE_RT_DEBUG_RAL_ISR_TIMER_ERROR == 1)
RT_DEBUG_RAL_ISR_TIMER_ERROR,
#endif /* USE_RT_DEBUG_RAL_ISR_TIMER_ERROR */
#if (USE_RT_DEBUG_RAL_ISR_TRACE == 1)
RT_DEBUG_RAL_ISR_TRACE,
#endif /* USE_RT_DEBUG_RAL_ISR_TRACE */
#if (USE_RT_DEBUG_RAL_STOP_OPRTN == 1)
RT_DEBUG_RAL_STOP_OPRTN,
#endif /* USE_RT_DEBUG_RAL_STOP_OPRTN */
#if (USE_RT_DEBUG_RAL_STRT_RX == 1)
RT_DEBUG_RAL_STRT_RX,
#endif /* USE_RT_DEBUG_RAL_STRT_RX */
#if (USE_RT_DEBUG_RAL_DONE_CLBK_TX == 1)
RT_DEBUG_RAL_DONE_CLBK_TX,
#endif /* USE_RT_DEBUG_RAL_DONE_CLBK_TX */
#if (USE_RT_DEBUG_RAL_DONE_CLBK_RX == 1)
RT_DEBUG_RAL_DONE_CLBK_RX,
#endif /* USE_RT_DEBUG_RAL_DONE_CLBK_RX */
#if (USE_RT_DEBUG_RAL_DONE_CLBK_ED == 1)
RT_DEBUG_RAL_DONE_CLBK_ED,
#endif /* USE_RT_DEBUG_RAL_DONE_CLBK_ED */
#if (USE_RT_DEBUG_RAL_ED_SCAN == 1)
RT_DEBUG_RAL_ED_SCAN,
#endif /* USE_RT_DEBUG_RAL_ED_SCAN */
#if (USE_RT_DEBUG_ERROR_MEM_CAP_EXCED == 1)
RT_DEBUG_ERROR_MEM_CAP_EXCED,
#endif /* USE_RT_DEBUG_ERROR_MEM_CAP_EXCED */
#if (USE_RT_DEBUG_ERROR_COMMAND_DISALLOWED == 1)
RT_DEBUG_ERROR_COMMAND_DISALLOWED,
#endif /* USE_RT_DEBUG_ERROR_COMMAND_DISALLOWED */
#if (USE_RT_DEBUG_PTA_INIT == 1)
RT_DEBUG_PTA_INIT,
#endif /* USE_RT_DEBUG_PTA_INIT */
#if (USE_RT_DEBUG_PTA_EN == 1)
RT_DEBUG_PTA_EN,
#endif /* USE_RT_DEBUG_PTA_EN */
#if (USE_RT_DEBUG_LLHWC_PTA_SET_EN == 1)
RT_DEBUG_LLHWC_PTA_SET_EN,
#endif /* USE_RT_DEBUG_LLHWC_PTA_SET_EN */
#if (USE_RT_DEBUG_LLHWC_PTA_SET_PARAMS == 1)
RT_DEBUG_LLHWC_PTA_SET_PARAMS,
#endif /* USE_RT_DEBUG_LLHWC_PTA_SET_PARAMS */
#if (USE_RT_DEBUG_COEX_STRT_ON_IDLE == 1)
RT_DEBUG_COEX_STRT_ON_IDLE,
#endif /* USE_RT_DEBUG_COEX_STRT_ON_IDLE */
#if (USE_RT_DEBUG_COEX_ASK_FOR_AIR == 1)
RT_DEBUG_COEX_ASK_FOR_AIR,
#endif /* USE_RT_DEBUG_COEX_ASK_FOR_AIR */
#if (USE_RT_DEBUG_COEX_TIMER_EVNT_CLBK == 1)
RT_DEBUG_COEX_TIMER_EVNT_CLBK,
#endif /* USE_RT_DEBUG_COEX_TIMER_EVNT_CLBK */
#if (USE_RT_DEBUG_COEX_STRT_ONE_SHOT == 1)
RT_DEBUG_COEX_STRT_ONE_SHOT,
#endif /* USE_RT_DEBUG_COEX_STRT_ONE_SHOT */
#if (USE_RT_DEBUG_COEX_FORCE_STOP_RX == 1)
RT_DEBUG_COEX_FORCE_STOP_RX,
#endif /* USE_RT_DEBUG_COEX_FORCE_STOP_RX */
#if (USE_RT_DEBUG_LLHWC_ADV_DONE == 1)
RT_DEBUG_LLHWC_ADV_DONE,
#endif /* USE_RT_DEBUG_LLHWC_ADV_DONE */
#if (USE_RT_DEBUG_LLHWC_SCN_DONE == 1)
RT_DEBUG_LLHWC_SCN_DONE,
#endif /* USE_RT_DEBUG_LLHWC_SCN_DONE */
#if (USE_RT_DEBUG_LLHWC_INIT_DONE == 1)
RT_DEBUG_LLHWC_INIT_DONE,
#endif /* USE_RT_DEBUG_LLHWC_INIT_DONE */
#if (USE_RT_DEBUG_LLHWC_CONN_DONE == 1)
RT_DEBUG_LLHWC_CONN_DONE,
#endif /* USE_RT_DEBUG_LLHWC_CONN_DONE */
#if (USE_RT_DEBUG_LLHWC_CIG_DONE == 1)
RT_DEBUG_LLHWC_CIG_DONE,
#endif /* USE_RT_DEBUG_LLHWC_CIG_DONE */
#if (USE_RT_DEBUG_LLHWC_BIG_DONE == 1)
RT_DEBUG_LLHWC_BIG_DONE,
#endif /* USE_RT_DEBUG_LLHWC_BIG_DONE */
#if (USE_RT_DEBUG_OS_TMR_CREATE == 1)
RT_DEBUG_OS_TMR_CREATE,
#endif /* USE_RT_DEBUG_OS_TMR_CREATE */
#if (USE_RT_DEBUG_ADV_EXT_TIMEOUT_CBK == 1)
RT_DEBUG_ADV_EXT_TIMEOUT_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_TIMEOUT_CBK */
#if (USE_RT_DEBUG_ADV_EXT_SCN_DUR_CBK == 1)
RT_DEBUG_ADV_EXT_SCN_DUR_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_SCN_DUR_CBK */
#if (USE_RT_DEBUG_ADV_EXT_SCN_PERIOD_CBK == 1)
RT_DEBUG_ADV_EXT_SCN_PERIOD_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_SCN_PERIOD_CBK */
#if (USE_RT_DEBUG_ADV_EXT_PRDC_SCN_TIMEOUT_CBK == 1)
RT_DEBUG_ADV_EXT_PRDC_SCN_TIMEOUT_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_PRDC_SCN_TIMEOUT_CBK */
#if (USE_RT_DEBUG_BIS_SYNC_TIMEOUT_TMR_CBK == 1)
RT_DEBUG_BIS_SYNC_TIMEOUT_TMR_CBK,
#endif /* USE_RT_DEBUG_BIS_SYNC_TIMEOUT_TMR_CBK */
#if (USE_RT_DEBUG_BIS_TERM_TMR_CBK == 1)
RT_DEBUG_BIS_TERM_TMR_CBK,
#endif /* USE_RT_DEBUG_BIS_TERM_TMR_CBK */
#if (USE_RT_DEBUG_BIS_TST_MODE_CBK == 1)
RT_DEBUG_BIS_TST_MODE_CBK,
#endif /* USE_RT_DEBUG_BIS_TST_MODE_CBK */
#if (USE_RT_DEBUG_BIS_TST_MODE_TMR_CBK == 1)
RT_DEBUG_BIS_TST_MODE_TMR_CBK,
#endif /* USE_RT_DEBUG_BIS_TST_MODE_TMR_CBK */
#if (USE_RT_DEBUG_ISO_POST_TMR_CBK == 1)
RT_DEBUG_ISO_POST_TMR_CBK,
#endif /* USE_RT_DEBUG_ISO_POST_TMR_CBK */
#if (USE_RT_DEBUG_ISO_TST_MODE_TMR_CBK == 1)
RT_DEBUG_ISO_TST_MODE_TMR_CBK,
#endif /* USE_RT_DEBUG_ISO_TST_MODE_TMR_CBK */
#if (USE_RT_DEBUG_CONN_POST_TMR_CBK == 1)
RT_DEBUG_CONN_POST_TMR_CBK,
#endif /* USE_RT_DEBUG_CONN_POST_TMR_CBK */
#if (USE_RT_DEBUG_EVNT_SCHDLR_TMR_CBK == 1)
RT_DEBUG_EVNT_SCHDLR_TMR_CBK,
#endif /* USE_RT_DEBUG_EVNT_SCHDLR_TMR_CBK */
#if (USE_RT_DEBUG_HCI_POST_TMR_CBK == 1)
RT_DEBUG_HCI_POST_TMR_CBK,
#endif /* USE_RT_DEBUG_HCI_POST_TMR_CBK */
#if (USE_RT_DEBUG_LLCP_POST_TMR_CBK == 1)
RT_DEBUG_LLCP_POST_TMR_CBK,
#endif /* USE_RT_DEBUG_LLCP_POST_TMR_CBK */
#if (USE_RT_DEBUG_LLHWC_ENRGY_DETECT_CBK == 1)
RT_DEBUG_LLHWC_ENRGY_DETECT_CBK,
#endif /* USE_RT_DEBUG_LLHWC_ENRGY_DETECT_CBK */
#if (USE_RT_DEBUG_PRVCY_POST_TMR_CBK == 1)
RT_DEBUG_PRVCY_POST_TMR_CBK,
#endif /* USE_RT_DEBUG_PRVCY_POST_TMR_CBK */
#if (USE_RT_DEBUG_ANT_PRPR_TMR_CBK == 1)
RT_DEBUG_ANT_PRPR_TMR_CBK,
#endif /* USE_RT_DEBUG_ANT_PRPR_TMR_CBK */
#if (USE_RT_DEBUG_COEX_TMR_FRC_STOP_AIR_GRANT_CBK == 1)
RT_DEBUG_COEX_TMR_FRC_STOP_AIR_GRANT_CBK,
#endif /* USE_RT_DEBUG_COEX_TMR_FRC_STOP_AIR_GRANT_CBK */
#if (USE_RT_DEBUG_MLME_RX_EN_TMR_CBK == 1)
RT_DEBUG_MLME_RX_EN_TMR_CBK,
#endif /* USE_RT_DEBUG_MLME_RX_EN_TMR_CBK */
#if (USE_RT_DEBUG_MLME_GNRC_TMR_CBK == 1)
RT_DEBUG_MLME_GNRC_TMR_CBK,
#endif /* USE_RT_DEBUG_MLME_GNRC_TMR_CBK */
#if (USE_RT_DEBUG_MIB_JOIN_LST_TMR_CBK == 1)
RT_DEBUG_MIB_JOIN_LST_TMR_CBK,
#endif /* USE_RT_DEBUG_MIB_JOIN_LST_TMR_CBK */
#if (USE_RT_DEBUG_MLME_PWR_PRES_TMR_CBK == 1)
RT_DEBUG_MLME_PWR_PRES_TMR_CBK,
#endif /* USE_RT_DEBUG_MLME_PWR_PRES_TMR_CBK */
#if (USE_RT_DEBUG_PRESISTENCE_TMR_CBK == 1)
RT_DEBUG_PRESISTENCE_TMR_CBK,
#endif /* USE_RT_DEBUG_PRESISTENCE_TMR_CBK */
#if (USE_RT_DEBUG_RADIO_PHY_PRDC_CLBK_TMR_CBK == 1)
RT_DEBUG_RADIO_PHY_PRDC_CLBK_TMR_CBK,
#endif /* USE_RT_DEBUG_RADIO_PHY_PRDC_CLBK_TMR_CBK */
#if (USE_RT_DEBUG_RADIO_CSMA_TMR_CBK == 1)
RT_DEBUG_RADIO_CSMA_TMR_CBK,
#endif /* USE_RT_DEBUG_RADIO_CSMA_TMR_CBK */
#if (USE_RT_DEBUG_RADIO_CSL_RCV_TMR_CBK == 1)
RT_DEBUG_RADIO_CSL_RCV_TMR_CBK,
#endif /* USE_RT_DEBUG_RADIO_CSL_RCV_TMR_CBK */
#if (USE_RT_DEBUG_ED_TMR_CBK == 1)
RT_DEBUG_ED_TMR_CBK,
#endif /* USE_RT_DEBUG_ED_TMR_CBK */
#if (USE_RT_DEBUG_DIO_EXT_TMR_CBK == 1)
RT_DEBUG_DIO_EXT_TMR_CBK,
#endif /* USE_RT_DEBUG_DIO_EXT_TMR_CBK */
#if (USE_RT_DEBUG_RCO_CLBR_TMR_CBK == 1)
RT_DEBUG_RCO_CLBR_TMR_CBK,
#endif /* USE_RT_DEBUG_RCO_CLBR_TMR_CBK */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_ADV_CBK == 1)
RT_DEBUG_ADV_EXT_MNGR_ADV_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_ADV_CBK */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_SCN_CBK == 1)
RT_DEBUG_ADV_EXT_MNGR_SCN_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_SCN_CBK */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_SCN_ERR_CBK == 1)
RT_DEBUG_ADV_EXT_MNGR_SCN_ERR_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_SCN_ERR_CBK */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_CBK == 1)
RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_CBK */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_ERR_CBK == 1)
RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_ERR_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_ERR_CBK */
#if (USE_RT_DEBUG_BIG_ADV_CBK == 1)
RT_DEBUG_BIG_ADV_CBK,
#endif /* USE_RT_DEBUG_BIG_ADV_CBK */
#if (USE_RT_DEBUG_BIG_ADV_ERR_CBK == 1)
RT_DEBUG_BIG_ADV_ERR_CBK,
#endif /* USE_RT_DEBUG_BIG_ADV_ERR_CBK */
#if (USE_RT_DEBUG_BIG_SYNC_CBK == 1)
RT_DEBUG_BIG_SYNC_CBK,
#endif /* USE_RT_DEBUG_BIG_SYNC_CBK */
#if (USE_RT_DEBUG_BIG_SYNC_ERR_CBK == 1)
RT_DEBUG_BIG_SYNC_ERR_CBK,
#endif /* USE_RT_DEBUG_BIG_SYNC_ERR_CBK */
#if (USE_RT_DEBUG_ISO_CIS_PKT_TRNSM_RECEIVED_CBK == 1)
RT_DEBUG_ISO_CIS_PKT_TRNSM_RECEIVED_CBK,
#endif /* USE_RT_DEBUG_ISO_CIS_PKT_TRNSM_RECEIVED_CBK */
#if (USE_RT_DEBUG_ISO_CIG_ERR_CBK == 1)
RT_DEBUG_ISO_CIG_ERR_CBK,
#endif /* USE_RT_DEBUG_ISO_CIG_ERR_CBK */
#if (USE_RT_DEBUG_CONN_PKT_TRNSM_RECEIVED_CBK == 1)
RT_DEBUG_CONN_PKT_TRNSM_RECEIVED_CBK,
#endif /* USE_RT_DEBUG_CONN_PKT_TRNSM_RECEIVED_CBK */
#if (USE_RT_DEBUG_PRDC_CLBR_EXTRL_CBK == 1)
RT_DEBUG_PRDC_CLBR_EXTRL_CBK,
#endif /* USE_RT_DEBUG_PRDC_CLBR_EXTRL_CBK */
#if (USE_RT_DEBUG_PTR_PRDC_ADV_SYNC_CBK == 1)
RT_DEBUG_PTR_PRDC_ADV_SYNC_CBK,
#endif /* USE_RT_DEBUG_PTR_PRDC_ADV_SYNC_CBK */
#if (USE_RT_DEBUG_NCONN_SCN_CBK == 1)
RT_DEBUG_NCONN_SCN_CBK,
#endif /* USE_RT_DEBUG_NCONN_SCN_CBK */
#if (USE_RT_DEBUG_NCONN_ADV_CBK == 1)
RT_DEBUG_NCONN_ADV_CBK,
#endif /* USE_RT_DEBUG_NCONN_ADV_CBK */
#if (USE_RT_DEBUG_NCONN_INIT_CBK == 1)
RT_DEBUG_NCONN_INIT_CBK,
#endif /* USE_RT_DEBUG_NCONN_INIT_CBK */
#if (USE_RT_DEBUG_ANT_RADIO_CMPLT_EVNT_CBK == 1)
RT_DEBUG_ANT_RADIO_CMPLT_EVNT_CBK,
#endif /* USE_RT_DEBUG_ANT_RADIO_CMPLT_EVNT_CBK */
#if (USE_RT_DEBUG_ANT_STACK_EVNT_CBK == 1)
RT_DEBUG_ANT_STACK_EVNT_CBK,
#endif /* USE_RT_DEBUG_ANT_STACK_EVNT_CBK */
#if (USE_RT_DEBUG_ADV_EXT_PROCESS_TMOUT_EVNT_CBK == 1)
RT_DEBUG_ADV_EXT_PROCESS_TMOUT_EVNT_CBK,
#endif /* USE_RT_DEBUG_ADV_EXT_PROCESS_TMOUT_EVNT_CBK */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_SCN_DUR_EVNT == 1)
RT_DEBUG_ADV_EXT_MNGR_SCN_DUR_EVNT,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_SCN_DUR_EVNT */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_SCN_PERIODIC_EVNT == 1)
RT_DEBUG_ADV_EXT_MNGR_SCN_PERIODIC_EVNT,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_SCN_PERIODIC_EVNT */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_TMOUT_EVNT == 1)
RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_TMOUT_EVNT,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_TMOUT_EVNT */
#if (USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_CNCEL_EVNT == 1)
RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_CNCEL_EVNT,
#endif /* USE_RT_DEBUG_ADV_EXT_MNGR_PRDC_SCN_CNCEL_EVNT */
#if (USE_RT_DEBUG_BIS_MNGR_BIG_TERM_CBK == 1)
RT_DEBUG_BIS_MNGR_BIG_TERM_CBK,
#endif /* USE_RT_DEBUG_BIS_MNGR_BIG_TERM_CBK */
#if (USE_RT_DEBUG_BIS_MNGR_SYNC_TMOUT_CBK == 1)
RT_DEBUG_BIS_MNGR_SYNC_TMOUT_CBK,
#endif /* USE_RT_DEBUG_BIS_MNGR_SYNC_TMOUT_CBK */
#if (USE_RT_DEBUG_ISOAL_MNGR_SDU_GEN == 1)
RT_DEBUG_ISOAL_MNGR_SDU_GEN,
#endif /* USE_RT_DEBUG_ISOAL_MNGR_SDU_GEN */
#if (USE_RT_DEBUG_ISO_MNGR_CIS_PROCESS_EVNT_CBK == 1)
RT_DEBUG_ISO_MNGR_CIS_PROCESS_EVNT_CBK,
#endif /* USE_RT_DEBUG_ISO_MNGR_CIS_PROCESS_EVNT_CBK */
#if (USE_RT_DEBUG_CONN_MNGR_PROCESS_EVNT_CLBK == 1)
RT_DEBUG_CONN_MNGR_PROCESS_EVNT_CLBK,
#endif /* USE_RT_DEBUG_CONN_MNGR_PROCESS_EVNT_CLBK */
#if (USE_RT_DEBUG_CONN_MNGR_UPDT_CONN_PARAM_CBK == 1)
RT_DEBUG_CONN_MNGR_UPDT_CONN_PARAM_CBK,
#endif /* USE_RT_DEBUG_CONN_MNGR_UPDT_CONN_PARAM_CBK */
#if (USE_RT_DEBUG_EVNT_SCHDLR_HW_EVNT_CMPLT == 1)
RT_DEBUG_EVNT_SCHDLR_HW_EVNT_CMPLT,
#endif /* USE_RT_DEBUG_EVNT_SCHDLR_HW_EVNT_CMPLT */
#if (USE_RT_DEBUG_HCI_EVENT_HNDLR == 1)
RT_DEBUG_HCI_EVENT_HNDLR,
#endif /* USE_RT_DEBUG_HCI_EVENT_HNDLR */
#if (USE_RT_DEBUG_MLME_TMRS_CBK == 1)
RT_DEBUG_MLME_TMRS_CBK,
#endif /* USE_RT_DEBUG_MLME_TMRS_CBK */
#if (USE_RT_DEBUG_DIRECT_TX_EVNT_CBK == 1)
RT_DEBUG_DIRECT_TX_EVNT_CBK,
#endif /* USE_RT_DEBUG_DIRECT_TX_EVNT_CBK */
#if (USE_RT_DEBUG_INDIRECT_PKT_TOUR_CBK == 1)
RT_DEBUG_INDIRECT_PKT_TOUR_CBK,
#endif /* USE_RT_DEBUG_INDIRECT_PKT_TOUR_CBK */
#if (USE_RT_DEBUG_RADIO_CSMA_TMR == 1)
RT_DEBUG_RADIO_CSMA_TMR,
#endif /* USE_RT_DEBUG_RADIO_CSMA_TMR */
#if (USE_RT_DEBUG_RAL_SM_DONE_EVNT_CBK == 1)
RT_DEBUG_RAL_SM_DONE_EVNT_CBK,
#endif /* USE_RT_DEBUG_RAL_SM_DONE_EVNT_CBK */
#if (USE_RT_DEBUG_ED_TMR_HNDL == 1)
RT_DEBUG_ED_TMR_HNDL,
#endif /* USE_RT_DEBUG_ED_TMR_HNDL */
#if (USE_RT_DEBUG_OS_TMR_EVNT_CBK == 1)
RT_DEBUG_OS_TMR_EVNT_CBK,
#endif /* USE_RT_DEBUG_OS_TMR_EVNT_CBK */
#if (USE_RT_DEBUG_PROFILE_MARKER_PHY_WAKEUP_TIME == 1)
RT_DEBUG_PROFILE_MARKER_PHY_WAKEUP_TIME,
#endif /* USE_RT_DEBUG_PROFILE_MARKER_PHY_WAKEUP_TIME */
#if (USE_RT_DEBUG_PROFILE_END_DRIFT_TIME == 1)
RT_DEBUG_PROFILE_END_DRIFT_TIME,
#endif /* USE_RT_DEBUG_PROFILE_END_DRIFT_TIME */
#if (USE_RT_DEBUG_PROC_RADIO_RCV == 1)
RT_DEBUG_PROC_RADIO_RCV,
#endif /* USE_RT_DEBUG_PROC_RADIO_RCV */
#if (USE_RT_DEBUG_EVNT_TIME_UPDT == 1)
RT_DEBUG_EVNT_TIME_UPDT,
#endif /* USE_RT_DEBUG_EVNT_TIME_UPDT */
#if (USE_RT_DEBUG_MAC_RECEIVE_DONE == 1)
RT_DEBUG_MAC_RECEIVE_DONE,
#endif /* USE_RT_DEBUG_MAC_RECEIVE_DONE */
#if (USE_RT_DEBUG_MAC_TX_DONE == 1)
RT_DEBUG_MAC_TX_DONE,
#endif /* USE_RT_DEBUG_MAC_TX_DONE */
#if (USE_RT_DEBUG_RADIO_APPLY_CSMA == 1)
RT_DEBUG_RADIO_APPLY_CSMA,
#endif /* USE_RT_DEBUG_RADIO_APPLY_CSMA */
#if (USE_RT_DEBUG_RADIO_TRANSMIT == 1)
RT_DEBUG_RADIO_TRANSMIT,
#endif /* USE_RT_DEBUG_RADIO_TRANSMIT */
#if (USE_RT_DEBUG_PROC_RADIO_TX == 1)
RT_DEBUG_PROC_RADIO_TX,
#endif /* USE_RT_DEBUG_PROC_RADIO_TX */
#if (USE_RT_DEBUG_RAL_TX_DONE == 1)
RT_DEBUG_RAL_TX_DONE,
#endif /* USE_RT_DEBUG_RAL_TX_DONE */
#if (USE_RT_DEBUG_RAL_TX_DONE_INCREMENT_BACKOFF_COUNT == 1)
RT_DEBUG_RAL_TX_DONE_INCREMENT_BACKOFF_COUNT,
#endif /* USE_RT_DEBUG_RAL_TX_DONE_INCREMENT_BACKOFF_COUNT */
#if (USE_RT_DEBUG_RAL_TX_DONE_RST_BACKOFF_COUNT == 1)
RT_DEBUG_RAL_TX_DONE_RST_BACKOFF_COUNT,
#endif /* USE_RT_DEBUG_RAL_TX_DONE_RST_BACKOFF_COUNT */
#if (USE_RT_DEBUG_RAL_CONTINUE_RX == 1)
RT_DEBUG_RAL_CONTINUE_RX,
#endif /* USE_RT_DEBUG_RAL_CONTINUE_RX */
#if (USE_RT_DEBUG_RAL_PERFORM_CCA == 1)
RT_DEBUG_RAL_PERFORM_CCA,
#endif /* USE_RT_DEBUG_RAL_PERFORM_CCA */
#if (USE_RT_DEBUG_RAL_ENABLE_TRANSMITTER == 1)
RT_DEBUG_RAL_ENABLE_TRANSMITTER,
#endif /* USE_RT_DEBUG_RAL_ENABLE_TRANSMITTER */
#if (USE_RT_DEBUG_LLHWC_GET_CH_IDX_ALGO_2 == 1)
RT_DEBUG_LLHWC_GET_CH_IDX_ALGO_2,
#endif /* USE_RT_DEBUG_LLHWC_GET_CH_IDX_ALGO_2 */
#if (USE_RT_DEBUG_BACK_FROM_DEEP_SLEEP == 1)
RT_DEBUG_BACK_FROM_DEEP_SLEEP,
#endif /* USE_RT_DEBUG_BACK_FROM_DEEP_SLEEP */
#include "app_debug_signal_def.h"
RT_DEBUG_SIGNALS_TOTAL_NUM
} rt_debug_signal_t;
#endif /* CFG_RT_DEBUG_GPIO_MODULE */
#ifdef __cplusplus
}
#endif
#endif /* DEBUG_SIGNALS_H */

View File

@@ -0,0 +1,114 @@
/**
******************************************************************************
* @file serial_cmd_interpreter.c
* @author MCD Application Team
* @brief Source file for the serial commands interpreter module.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "log_module.h"
#include "app_conf.h"
#include "stm32_adv_trace.h"
#include "serial_cmd_interpreter.h"
/* Private includes -----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private defines -----------------------------------------------------------*/
#define RX_BUFF_SIZE (256U)
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static uint8_t RxBuffer[RX_BUFF_SIZE];
static uint16_t indexRxBuffer = 0;
/* Global variables ----------------------------------------------------------*/
/* Private functions prototypes ----------------------------------------------*/
static void UART_Rx_Callback(uint8_t *PData, uint16_t Size, uint8_t Error);
/* External variables --------------------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
void Serial_CMD_Interpreter_Init(void)
{
/* Init Communication reception. Need that Log/Traces are activated */
UTIL_ADV_TRACE_StartRxProcess(UART_Rx_Callback);
}
__weak void Serial_CMD_Interpreter_CmdExecute( uint8_t * pRxBuffer, uint16_t iRxBufferSize )
{
/* NOTE : This function should not be modified, when the callback is needed,
the enter_standby_notification could be implemented in the user file
*/
/*
This user function is in charge of interpreting the received data.
Here is an example of how to use them.
In this simple case, we'll generate a SW IT on GPIO14 if the received data is a string "TEST".
Add the following code into the user code section :
// Extended line handler on which we will generate the IT
EXTI_HandleTypeDef exti_handle;
// Check RxBuffer's content to know if we're matching our case
if( strcmp( (char const*)pRxBuffer, "TEST" ) == 0 )
{
LOG_INFO_APP("TEST has been received in Uart_Cmd_Execute.\n");
exti_handle.Line = EXTI_LINE_14;
HAL_EXTI_GenerateSWI(&exti_handle);
}
*/
}
/* Private functions definition ----------------------------------------------*/
static void UART_Rx_Callback( uint8_t * pData, uint16_t Size, uint8_t Error )
{
/* Filling buffer and wait for '\r' charactere to execute actions */
if ( indexRxBuffer < RX_BUFF_SIZE )
{
if ( *pData == '\r' )
{
Serial_CMD_Interpreter_CmdExecute( RxBuffer, indexRxBuffer );
/* Clear receive buffer and character counter*/
indexRxBuffer = 0;
memset( &RxBuffer[0], 0, RX_BUFF_SIZE );
}
else
{
if ( ( * pData == '\n' ) && ( indexRxBuffer == 0 ) )
{
/* discard this first charactere if it's a delimiter */
}
else
{
RxBuffer[indexRxBuffer++] = *pData;
}
}
}
else
{
indexRxBuffer = 0;
memset(&RxBuffer[0], 0, RX_BUFF_SIZE);
}
return;
}

View File

@@ -0,0 +1,47 @@
/**
******************************************************************************
* @file serial_cmd_interpreter.h
* @author MCD Application Team
* @brief Header file for the serial commands interpreter module.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SERIAL_CMD_INTERPRETER_H
#define SERIAL_CMD_INTERPRETER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Private includes ----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
void Serial_CMD_Interpreter_Init(void);
void Serial_CMD_Interpreter_CmdExecute( uint8_t * pRxBuffer, uint16_t iRxBufferSize );
/* Private defines -----------------------------------------------------------*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SERIAL_CMD_INTERPRETER_H */

View File

@@ -0,0 +1,892 @@
/**
******************************************************************************
* @file adc_ctrl.c
* @author MCD Application Team
* @brief Source file for ADC controller module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
/* Utilities */
#include "utilities_common.h"
/* Real time trace for debug */
#include "RTDebug.h"
/* Own header files */
#include "adc_ctrl.h"
#include "adc_ctrl_conf.h"
/* LL ADC header */
#include "stm32wbaxx_ll_adc.h"
/* Private defines -----------------------------------------------------------*/
/**
* @brief Initial value define for configuration tracking number
*/
#define ADCCTRL_NO_CONFIG (uint32_t)(0x00000000u)
/**
* @brief Init variable out of expected ADC conversion data range
*/
#define VAR_CONVERTED_DATA_INIT_VALUE_12B (__LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_12B) + 1)
#define VAR_CONVERTED_DATA_INIT_VALUE_10B (__LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_10B) + 1)
#define VAR_CONVERTED_DATA_INIT_VALUE_8B (__LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_8B) + 1)
#define VAR_CONVERTED_DATA_INIT_VALUE_6B (__LL_ADC_DIGITAL_SCALE(LL_ADC_RESOLUTION_6B) + 1)
/**
* @brief Internal temperature sensor, parameter V30 (unit: mV).
*
* @details Refer to device datasheet for min/typ/max values.
*
*/
#define TEMPSENSOR_TYP_CAL1_V (( int32_t) 760)
/**
* @brief Internal temperature sensor, parameter Avg_Slope (unit: uV/DegCelsius).
*
* @details Refer to device datasheet for min/typ/max values.
*
*/
#define TEMPSENSOR_TYP_AVGSLOPE (( int32_t) 2500)
/* Definitions of environment analog values */
/**
* @brief Value of analog reference voltage (Vref+), connected to analog voltage
*
* @details supply Vdda (unit: mV).
*
*/
#define VDDA_APPLI (3300UL)
/* Private typedef -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/**
* @brief ADC IP Client list
*/
static uint32_t ClientList;
/**
* @brief Tracker of the current applied configuration
*/
static uint32_t CurrentConfig = ADCCTRL_NO_CONFIG;
/**
* @brief Higher registered handle ID
*/
static uint32_t MaxRegisteredId = ADCCTRL_NO_CONFIG;
/**
* @brief Handle of the ADC
*/
static ADC_TypeDef * p_ADCHandle = ADCCTRL_HWADDR;
/* Global variables ----------------------------------------------------------*/
/* Error Handler */
extern void Error_Handler(void);
/* Private function prototypes -----------------------------------------------*/
/**
* @brief Activate ADC.
* Activation order is as follow:
* - Enable ADC peripharal clock
* - Enable ADC internal voltage regulator
* - Enable ADC
* @param None
* @retval None
*/
static inline void AdcActivate (void);
/**
* @brief Deactivate ADC IP.
* Deactivation order is as follow:
* - Disable ADC
* - Disable ADC internal voltage regulator
* - Disable ADC peripharal clock
* @param None
* @retval None
*/
static inline void AdcDeactivate (void);
/**
* @brief Configure ADC IP.
* @param p_Handle: Handle to work with
* @retval State of the configuration
*/
static inline ADCCTRL_Cmd_Status_t AdcConfigure (const ADCCTRL_Handle_t * const p_Handle);
/**
* @brief Read the raw value
* @param p_Handle: Handle to work with
* @return Raw value
*/
static inline uint16_t AdcReadRaw (const ADCCTRL_Handle_t * const p_Handle);
/**
* @brief Perform ADC group regular conversion start, poll for conversion
* completion.
* (ADCCTRL_HWADDR instance: ADC).
* @note This function does not perform ADC group regular conversion stop:
* intended to be used with ADC in single mode, trigger SW start
* (only 1 ADC conversion done at each trigger, no conversion stop
* needed).
* In case of continuous mode or conversion trigger set to
* external trigger, ADC group regular conversion stop must be added.
* @param None
* @retval None
*/
static inline void ConversionStartPoll_ADC_GrpRegular (void);
/* Functions Definition ------------------------------------------------------*/
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_Init (void)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_UNKNOWN;
/* Try to take the ADC mutex */
error = ADCCTRL_MutexTake ();
if (ADCCTRL_OK == error)
{
CurrentConfig = ADCCTRL_NO_CONFIG;
p_ADCHandle = ADCCTRL_HWADDR;
/* Reset ADC Client list */
ClientList = 0x00u;
/* Deactivate the ADC */
AdcDeactivate();
/* Release the mutex */
ADCCTRL_MutexRelease ();
}
return error;
}
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_RegisterHandle (ADCCTRL_Handle_t * const p_Handle)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_UNKNOWN;
if (NULL == p_Handle)
{
error = ADCCTRL_ERROR_NULL_POINTER;
}
else if (ADCCTRL_HANDLE_REG == p_Handle->State)
{
error = ADCCTRL_HANDLE_ALREADY_REGISTERED;
}
else
{
/* Try to take the ADC mutex */
error = ADCCTRL_MutexTake ();
if (ADCCTRL_OK == error)
{
/* Update the maximum registered handle */
MaxRegisteredId = MaxRegisteredId + 1u;
/* Update the handle UUID */
p_Handle->Uid = MaxRegisteredId;
/* Set handle as initialized */
p_Handle->State = ADCCTRL_HANDLE_REG;
/* Release the mutex */
ADCCTRL_MutexRelease ();
}
}
return error;
}
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_RequestIpState (const ADCCTRL_Handle_t * const p_Handle,
const ADCCTRL_Ip_State_t State)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_UNKNOWN;
UTILS_ENTER_CRITICAL_SECTION();
if (ADC_OFF == State)
{
ClientList &= (~(1U << p_Handle->Uid));
error = ADCCTRL_OK;
}
else if (ADC_ON == State)
{
ClientList |= (1U << p_Handle->Uid);
error = ADCCTRL_OK;
}
else
{
error = ADCCTRL_ERROR_STATE;
}
if (0x00u == ClientList)
{
/* Disable ADC as there is no request anymore */
AdcDeactivate();
}
else
{
/* Enable ADC as there at least one request */
AdcActivate();
}
UTILS_EXIT_CRITICAL_SECTION();
return error;
}
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_RequestRawValue (const ADCCTRL_Handle_t * const p_Handle,
uint16_t * const p_ReadValue)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_UNKNOWN;
/* Null pointer for handle or payload */
if ((NULL == p_Handle) || (NULL == p_ReadValue))
{
error = ADCCTRL_ERROR_NULL_POINTER;
}
/* Handle not init */
else if (ADCCTRL_HANDLE_NOT_REG == p_Handle->State)
{
error = ADCCTRL_HANDLE_NOT_REGISTERED;
}
/* Handle not in the range */
else if ((MaxRegisteredId < p_Handle->Uid) ||
(ADCCTRL_NO_CONFIG >= p_Handle->Uid))
{
error = ADCCTRL_HANDLE_NOT_VALID;
}
/* Check ADC state */
else if (0x00u == (ClientList & (1U << p_Handle->Uid)))
{
error = ADCCTRL_ERROR_STATE;
}
else
{
/* Try to take the ADC mutex */
error = ADCCTRL_MutexTake ();
if (ADCCTRL_OK == error)
{
/* Is the current config IS NOT the same as the one requested ? */
if (CurrentConfig != p_Handle->Uid)
{
/* Configure the ADC before use */
error = AdcConfigure (p_Handle);
/* Enable ADC */
LL_ADC_Enable(p_ADCHandle);
}
if (ADCCTRL_OK == error)
{
/* Return the read value */
*p_ReadValue = AdcReadRaw (p_Handle);
}
else
{
error = ADCCTRL_ERROR_CONFIG;
}
/* Release the mutex */
ADCCTRL_MutexRelease ();
}
}
return error;
}
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_RequestTemperature (const ADCCTRL_Handle_t * const p_Handle,
int16_t * const p_ReadValue)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_UNKNOWN;
/* Variables for ADC conversion data */
__IO uint16_t uhADCxConvertedData = 0x00;
SYSTEM_DEBUG_SIGNAL_SET(ADC_TEMPERATURE_ACQUISITION);
/* Null pointer for handle or payload */
if ((NULL == p_Handle) || (NULL == p_ReadValue))
{
error = ADCCTRL_ERROR_NULL_POINTER;
}
/* Handle not init */
else if (ADCCTRL_HANDLE_NOT_REG == p_Handle->State)
{
error = ADCCTRL_HANDLE_NOT_REGISTERED;
}
/* Handle not in the range */
else if ((MaxRegisteredId < p_Handle->Uid) ||
(ADCCTRL_NO_CONFIG >= p_Handle->Uid))
{
error = ADCCTRL_HANDLE_NOT_VALID;
}
/* Check ADC state */
else if (0x00u == (ClientList & (1U << p_Handle->Uid)))
{
error = ADCCTRL_ERROR_STATE;
}
else
{
/* Try to take the ADC mutex */
error = ADCCTRL_MutexTake ();
if (ADCCTRL_OK == error)
{
/* Is the current config IS NOT the same as the one requested ? */
if (CurrentConfig != p_Handle->Uid)
{
/* Configure the ADC before use */
error = AdcConfigure (p_Handle);
/* Enable ADC */
LL_ADC_Enable(p_ADCHandle);
}
if (ADCCTRL_OK == error)
{
/* Return the read value */
uhADCxConvertedData = AdcReadRaw (p_Handle);
/* Computation of ADC conversions raw data to physical values */
/* using LL ADC driver helper macro. */
if(*TEMPSENSOR_CAL1_ADDR == *TEMPSENSOR_CAL2_ADDR)
{
/* Case of samples not calibrated in production */
*p_ReadValue = __LL_ADC_CALC_TEMPERATURE_TYP_PARAMS (TEMPSENSOR_TYP_AVGSLOPE,
TEMPSENSOR_TYP_CAL1_V,
TEMPSENSOR_CAL1_TEMP,
VDDA_APPLI,
uhADCxConvertedData,
p_Handle->InitConf.ConvParams.Resolution);
}
else
{
/* Case of samples calibrated in production */
*p_ReadValue = __LL_ADC_CALC_TEMPERATURE (VDDA_APPLI,
uhADCxConvertedData,
p_Handle->InitConf.ConvParams.Resolution);
}
}
else
{
error = ADCCTRL_ERROR_CONFIG;
}
/* Release the mutex */
ADCCTRL_MutexRelease ();
}
}
return error;
}
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_RequestCoreVoltage (const ADCCTRL_Handle_t * const p_Handle,
uint16_t * const p_ReadValue)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_UNKNOWN;
/* Variables for ADC conversion data */
__IO uint16_t uhADCxConvertedData = 0x00;
SYSTEM_DEBUG_SIGNAL_SET(ADC_TEMPERATURE_ACQUISITION);
/* Null pointer for handle or payload */
if ((NULL == p_Handle) || (NULL == p_ReadValue))
{
error = ADCCTRL_ERROR_NULL_POINTER;
}
/* Handle not init */
else if (ADCCTRL_HANDLE_NOT_REG == p_Handle->State)
{
error = ADCCTRL_HANDLE_NOT_REGISTERED;
}
/* Handle not in the range */
else if ((MaxRegisteredId < p_Handle->Uid) ||
(ADCCTRL_NO_CONFIG >= p_Handle->Uid))
{
error = ADCCTRL_HANDLE_NOT_VALID;
}
/* Check ADC state */
else if (0x00u == (ClientList & (1U << p_Handle->Uid)))
{
error = ADCCTRL_ERROR_STATE;
}
else
{
/* Try to take the ADC mutex */
error = ADCCTRL_MutexTake ();
if (ADCCTRL_OK == error)
{
/* Is the current config IS NOT the same as the one requested ? */
if (CurrentConfig != p_Handle->Uid)
{
/* Configure the ADC before use */
error = AdcConfigure (p_Handle);
/* Enable ADC */
LL_ADC_Enable(p_ADCHandle);
}
if (ADCCTRL_OK == error)
{
/* Return the read value */
uhADCxConvertedData = AdcReadRaw (p_Handle);
/* Computation of ADC conversions raw data to physical values */
/* using LL ADC driver helper macro. */
*p_ReadValue = __LL_ADC_CALC_DATA_TO_VOLTAGE (VDDA_APPLI,
uhADCxConvertedData,
p_Handle->InitConf.ConvParams.Resolution);
}
else
{
error = ADCCTRL_ERROR_CONFIG;
}
/* Release the mutex */
ADCCTRL_MutexRelease ();
}
}
return error;
}
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_RequestRefVoltage (const ADCCTRL_Handle_t * const p_Handle,
uint16_t * const p_ReadValue)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_UNKNOWN;
/* Variables for ADC conversion data */
__IO uint16_t uhADCxConvertedData = 0x00;
SYSTEM_DEBUG_SIGNAL_SET(ADC_TEMPERATURE_ACQUISITION);
/* Null pointer for handle or payload */
if ((NULL == p_Handle) || (NULL == p_ReadValue))
{
error = ADCCTRL_ERROR_NULL_POINTER;
}
/* Handle not init */
else if (ADCCTRL_HANDLE_NOT_REG == p_Handle->State)
{
error = ADCCTRL_HANDLE_NOT_REGISTERED;
}
/* Handle not in the range */
else if ((MaxRegisteredId < p_Handle->Uid) ||
(ADCCTRL_NO_CONFIG >= p_Handle->Uid))
{
error = ADCCTRL_HANDLE_NOT_VALID;
}
/* Check ADC state */
else if (0x00u == (ClientList & (1U << p_Handle->Uid)))
{
error = ADCCTRL_ERROR_STATE;
}
else
{
/* Try to take the ADC mutex */
error = ADCCTRL_MutexTake ();
if (ADCCTRL_OK == error)
{
/* Is the current config IS NOT the same as the one requested ? */
if (CurrentConfig != p_Handle->Uid)
{
/* Configure the ADC before use */
error = AdcConfigure (p_Handle);
/* Enable ADC */
LL_ADC_Enable(p_ADCHandle);
}
if (ADCCTRL_OK == error)
{
/* Return the read value */
uhADCxConvertedData = AdcReadRaw (p_Handle);
/* Computation of ADC conversions raw data to physical values */
/* using LL ADC driver helper macro. */
*p_ReadValue = __LL_ADC_CALC_VREFANALOG_VOLTAGE (uhADCxConvertedData,
p_Handle->InitConf.ConvParams.Resolution);
}
else
{
error = ADCCTRL_ERROR_CONFIG;
}
/* Release the mutex */
ADCCTRL_MutexRelease ();
}
}
return error;
}
/* Private function Definition -----------------------------------------------*/
void AdcActivate (void)
{
__IO uint32_t backup_setting_adc_dma_transfer = 0U;
SYSTEM_DEBUG_SIGNAL_SET(ADC_ACTIVATION);
UTILS_ENTER_CRITICAL_SECTION();
/*## Operation on ADC hierarchical scope: ADC instance #####################*/
/* Note: Hardware constraint (refer to description of the functions */
/* below): */
/* On this STM32 series, setting of these features is conditioned to */
/* ADC state: */
/* ADC must be disabled. */
/* Note: In this example, all these checks are not necessary but are */
/* implemented anyway to show the best practice usages */
/* corresponding to reference manual procedure. */
/* Software can be optimized by removing some of these checks, if */
/* they are not relevant considering previous settings and actions */
/* in user application. */
if (LL_ADC_IsEnabled(p_ADCHandle) == 0)
{
/* Select clock source */
ADCTCTRL_SET_CLOCK_SOURCE ();
/* Peripheral clock enable */
ADCCTRL_ENABLE_CLOCK ();
/* Enable ADC internal voltage regulator */
LL_ADC_EnableInternalRegulator(p_ADCHandle);
/* Waiting for ADC internal voltage regulator stabilization. */
while(LL_ADC_IsInternalRegulatorEnabled(p_ADCHandle) == 0);
/* Disable ADC DMA transfer request during calibration */
/* Note: Specificity of this STM32 series: Calibration factor is */
/* available in data register and also transferred by DMA. */
/* To not insert ADC calibration factor among ADC conversion data */
/* in DMA destination address, DMA transfer must be disabled during */
/* calibration. */
backup_setting_adc_dma_transfer = LL_ADC_REG_GetDMATransfer(p_ADCHandle);
LL_ADC_REG_SetDMATransfer(p_ADCHandle, LL_ADC_REG_DMA_TRANSFER_NONE);
/* Run ADC self calibration */
LL_ADC_StartCalibration(p_ADCHandle);
/* Poll for ADC effectively calibrated */
while (LL_ADC_IsCalibrationOnGoing(p_ADCHandle) != 0);
/* Restore ADC DMA transfer request after calibration */
LL_ADC_REG_SetDMATransfer(p_ADCHandle, backup_setting_adc_dma_transfer);
/* Delay required between ADC end of calibration and ADC enable */
/* LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES --> 2 cycles */
__asm("mov r0, r0");
__asm("mov r0, r0");
/* Enable ADC */
LL_ADC_Enable(p_ADCHandle);
/* Poll for ADC ready to convert */
while (LL_ADC_IsActiveFlag_ADRDY(p_ADCHandle) == 0);
/* Note: ADC flag ADRDY is not cleared here to be able to check ADC */
/* status afterwards. */
/* This flag should be cleared at ADC Deactivation, before a new */
/* ADC activation, using function "LL_ADC_ClearFlag_ADRDY()". */
}
/*## Operation on ADC hierarchical scope: ADC group regular ################*/
/* Note: No operation on ADC group regular performed here. */
/* ADC group regular conversions to be performed after this function */
/* using function: */
/* "LL_ADC_REG_StartConversion();" */
/*## Operation on ADC hierarchical scope: ADC group injected ###############*/
/* Note: Feature not available on this STM32 series */
UTILS_EXIT_CRITICAL_SECTION();
SYSTEM_DEBUG_SIGNAL_RESET(ADC_ACTIVATION);
}
void AdcDeactivate (void)
{
SYSTEM_DEBUG_SIGNAL_SET(ADC_DEACTIVATION);
UTILS_ENTER_CRITICAL_SECTION();
if(LL_ADC_IsEnabled(p_ADCHandle))
{
/* Disable ADC */
LL_ADC_Disable(p_ADCHandle);
/* Clear flag ADC ready */
LL_ADC_ClearFlag_ADRDY(p_ADCHandle);
/* Wait until ADC_CR_ADEN bit is reset before turning off ADC internal regulator */
while(LL_ADC_IsEnabled(p_ADCHandle) == 1UL);
/* Wait until ADC_CR_ADSTP bit is reset before turning off ADC internal regulator */
while(LL_ADC_REG_IsStopConversionOngoing(p_ADCHandle) == 1U);
/* Disable ADC internal voltage regulator */
LL_ADC_DisableInternalRegulator(p_ADCHandle);
while(LL_ADC_IsInternalRegulatorEnabled(p_ADCHandle) == 1U);
/* Peripharal clock disable */
ADCCTRL_DISABLE_CLOCK ();
}
UTILS_EXIT_CRITICAL_SECTION();
SYSTEM_DEBUG_SIGNAL_RESET(ADC_DEACTIVATION);
}
ADCCTRL_Cmd_Status_t AdcConfigure (const ADCCTRL_Handle_t * const p_Handle)
{
ADCCTRL_Cmd_Status_t error = ADCCTRL_OK;
__IO uint32_t backup_setting_adc_dma_transfer = 0U;
LL_ADC_InitTypeDef ADC_InitStruct = {0};
LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
/* DeInit the ADC module */
if (SUCCESS != LL_ADC_DeInit (p_ADCHandle))
{
error = ADCCTRL_NOK;
}
else
{
/* Restart a calibration */
/* Disable ADC DMA transfer request during calibration */
/* Note: Specificity of this STM32 series: Calibration factor is */
/* available in data register and also transferred by DMA. */
/* To not insert ADC calibration factor among ADC conversion data */
/* in DMA destination address, DMA transfer must be disabled during */
/* calibration. */
backup_setting_adc_dma_transfer = LL_ADC_REG_GetDMATransfer(p_ADCHandle);
LL_ADC_REG_SetDMATransfer(p_ADCHandle, LL_ADC_REG_DMA_TRANSFER_NONE);
/* Run ADC self calibration */
LL_ADC_StartCalibration(p_ADCHandle);
/* Poll for ADC effectively calibrated */
while (LL_ADC_IsCalibrationOnGoing(p_ADCHandle) != 0);
/* Restore ADC DMA transfer request after calibration */
LL_ADC_REG_SetDMATransfer(p_ADCHandle, backup_setting_adc_dma_transfer);
/* Delay required between ADC end of calibration and ADC enable */
/* LL_ADC_DELAY_CALIB_ENABLE_ADC_CYCLES --> 2 cycles */
__asm("mov r0, r0");
__asm("mov r0, r0");
}
/* All OK ? */
if (ADCCTRL_OK == error)
{
/* Update init and configuration parameters with requested values */
ADC_InitStruct.Resolution = p_Handle->InitConf.ConvParams.Resolution;
ADC_InitStruct.DataAlignment = p_Handle->InitConf.ConvParams.DataAlign;
ADC_REG_InitStruct.TriggerSource = p_Handle->InitConf.ConvParams.TriggerStart;
ADC_REG_InitStruct.SequencerLength = p_Handle->InitConf.SeqParams.Length;
ADC_REG_InitStruct.SequencerDiscont = p_Handle->InitConf.SeqParams.DiscMode;
ADC_REG_InitStruct.ContinuousMode = p_Handle->InitConf.ConvParams.ConversionMode;
ADC_REG_InitStruct.DMATransfer = p_Handle->InitConf.ConvParams.DmaTransfer;
ADC_REG_InitStruct.Overrun = p_Handle->InitConf.ConvParams.Overrun;
/* Configure Regular Channel - Only for internal channels */
if (LL_ADC_CHANNEL_VREFINT == p_Handle->ChannelConf.Channel)
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(p_ADCHandle),
LL_ADC_PATH_INTERNAL_VREFINT);
}
else if (LL_ADC_CHANNEL_TEMPSENSOR == p_Handle->ChannelConf.Channel)
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(p_ADCHandle),
LL_ADC_PATH_INTERNAL_TEMPSENSOR);
}
else
{
LL_ADC_SetCommonPathInternalCh(__LL_ADC_COMMON_INSTANCE(p_ADCHandle),
LL_ADC_PATH_INTERNAL_NONE);
}
/* Set trigger frequency */
LL_ADC_SetTriggerFrequencyMode(p_ADCHandle,
p_Handle->InitConf.ConvParams.TriggerFrequencyMode);
/* Apply the requested ADC configuration - Init part */
if (SUCCESS != LL_ADC_Init(p_ADCHandle,
&ADC_InitStruct))
{
error = ADCCTRL_NOK;
}
else
{
/* Set Sequencer if configurable */
LL_ADC_REG_SetSequencerConfigurable(p_ADCHandle,
p_Handle->InitConf.SeqParams.Setup);
/* Apply the requested ADC configuration - Register init part */
if (SUCCESS != LL_ADC_REG_Init(p_ADCHandle,
&ADC_REG_InitStruct))
{
error = ADCCTRL_NOK;
}
else
{
/* Set Low power characteristics */
LL_ADC_SetLPModeAutoPowerOff(p_ADCHandle,
p_Handle->InitConf.LowPowerParams.AutoPowerOff);
LL_ADC_SetLPModeAutonomousDPD(p_ADCHandle,
p_Handle->InitConf.LowPowerParams.AutonomousDPD);
/* Set Sampling time for channels */
LL_ADC_SetSamplingTimeCommonChannels(p_ADCHandle,
LL_ADC_SAMPLINGTIME_COMMON_1,
p_Handle->InitConf.ConvParams.SamplingTimeCommon1);
LL_ADC_SetSamplingTimeCommonChannels(p_ADCHandle,
LL_ADC_SAMPLINGTIME_COMMON_2,
p_Handle->InitConf.ConvParams.SamplingTimeCommon2);
/* Configure the channel */
LL_ADC_REG_SetSequencerRanks(p_ADCHandle,
p_Handle->ChannelConf.Rank,
p_Handle->ChannelConf.Channel);
LL_ADC_SetChannelSamplingTime(p_ADCHandle,
p_Handle->ChannelConf.Channel,
p_Handle->ChannelConf.SamplingTime);
/* Update the current configuration */
CurrentConfig = p_Handle->Uid;
}
}
}
return error;
}
uint16_t AdcReadRaw (const ADCCTRL_Handle_t * const p_Handle)
{
/* Variables for ADC conversion data */
__IO uint16_t uhADCxConvertedData = 0x00;
/* Perform ADC group regular conversion start, poll for conversion */
/* completion. */
ConversionStartPoll_ADC_GrpRegular ();
/* Retrieve ADC conversion data */
switch (p_Handle->InitConf.ConvParams.Resolution)
{
case LL_ADC_RESOLUTION_12B:
{
uhADCxConvertedData = VAR_CONVERTED_DATA_INIT_VALUE_12B;
uhADCxConvertedData = LL_ADC_REG_ReadConversionData12(p_ADCHandle);
break;
}
case LL_ADC_RESOLUTION_10B:
{
uhADCxConvertedData = VAR_CONVERTED_DATA_INIT_VALUE_10B;
uhADCxConvertedData = LL_ADC_REG_ReadConversionData10(p_ADCHandle);
break;
}
case LL_ADC_RESOLUTION_8B:
{
uhADCxConvertedData = VAR_CONVERTED_DATA_INIT_VALUE_8B;
uhADCxConvertedData = LL_ADC_REG_ReadConversionData8(p_ADCHandle);
break;
}
case LL_ADC_RESOLUTION_6B:
{
uhADCxConvertedData = VAR_CONVERTED_DATA_INIT_VALUE_6B;
uhADCxConvertedData = LL_ADC_REG_ReadConversionData6(p_ADCHandle);
break;
}
default:
{
/* Do nothing */
break;
}
}
return uhADCxConvertedData;
}
void ConversionStartPoll_ADC_GrpRegular (void)
{
/* Start ADC group regular conversion */
/* Note: Hardware constraint (refer to description of the function */
/* below): */
/* On this STM32 series, setting of this feature is conditioned to */
/* ADC state: */
/* ADC must be enabled without conversion on going on group regular, */
/* without ADC disable command on going. */
/* Note: In this example, all these checks are not necessary but are */
/* implemented anyway to show the best practice usages */
/* corresponding to reference manual procedure. */
/* Software can be optimized by removing some of these checks, if */
/* they are not relevant considering previous settings and actions */
/* in user application. */
if ((LL_ADC_IsEnabled(p_ADCHandle) == 1) &&
(LL_ADC_IsDisableOngoing(p_ADCHandle) == 0) &&
(LL_ADC_REG_IsConversionOngoing(p_ADCHandle) == 0) )
{
LL_ADC_REG_StartConversion(p_ADCHandle);
}
else
{
/* Error: ADC conversion start could not be performed */
Error_Handler();
}
while (LL_ADC_IsActiveFlag_EOC(p_ADCHandle) == 0);
/* Clear flag ADC group regular end of unitary conversion */
/* Note: This action is not needed here, because flag ADC group regular */
/* end of unitary conversion is cleared automatically when */
/* software reads conversion data from ADC data register. */
/* Nevertheless, this action is done anyway to show how to clear */
/* this flag, needed if conversion data is not always read */
/* or if group injected end of unitary conversion is used (for */
/* devices with group injected available). */
LL_ADC_ClearFlag_EOC(p_ADCHandle);
}
/* Weak function Definition --------------------------------------------------*/
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_MutexTake (void)
{
return ADCCTRL_OK;
}
__WEAK ADCCTRL_Cmd_Status_t ADCCTRL_MutexRelease (void)
{
return ADCCTRL_OK;
}

View File

@@ -0,0 +1,276 @@
/**
******************************************************************************
* @file adc_ctrl.h
* @author MCD Application Team
* @brief Header for ADC client manager module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef ADC_CTRL_H
#define ADC_CTRL_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Utilities */
#include "utilities_common.h"
/* Exported defines ----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/**
* @brief ADC command status codes
*/
typedef enum ADCCTRL_Cmd_Status
{
ADCCTRL_OK,
ADCCTRL_NOK,
ADCCTRL_BUSY,
ADCCTRL_HANDLE_ALREADY_REGISTERED,
ADCCTRL_HANDLE_NOT_REGISTERED,
ADCCTRL_HANDLE_NOT_VALID,
ADCCTRL_ERROR_NULL_POINTER,
ADCCTRL_ERROR_CONFIG,
ADCCTRL_ERROR_STATE,
ADCCTRL_UNKNOWN,
} ADCCTRL_Cmd_Status_t;
/**
* @brief ADC IP state
*/
typedef enum ADCCTRL_Ip_State
{
ADC_OFF,
ADC_ON
} ADCCTRL_Ip_State_t;
/**
* @brief ADC handle states
*/
typedef enum ADCCTRL_HandleState
{
ADCCTRL_HANDLE_NOT_REG,
ADCCTRL_HANDLE_REG,
} ADCCTRL_HandleState_t;
/**
* @brief ADC Init configuration structure - Conversion parameters
*/
typedef struct ADCCTRL_ConvParameters
{
uint32_t TriggerFrequencyMode; /*!< Set ADC Trigger frequency mode.
This parameter can be a value of @ref ADC_LL_EC_REG_TRIGGER_FREQ */
uint32_t Resolution; /*!< Configure the ADC resolution.
This parameter can be a value of @ref ADC_LL_EC_RESOLUTION */
uint32_t DataAlign; /*!< Specify ADC data alignment in conversion data register (right or left).
This parameter can be a value of @ref ADC_LL_EC_DATA_ALIGN */
uint32_t TriggerStart; /*!< Select the source used to trigger ADC conversion
start.
This parameter can be a value of @ref ADC_LL_EC_REG_TRIGGER_SOURCE.*/
uint32_t TriggerEdge; /*!< Select the Edge used for trigger.
This parameter can be a value of @ref ADC_LL_EC_REG_TRIGGER_EDGE.*/
uint32_t ConversionMode; /*!< Configure the conversion mode of ADC.
This parameter can be a value of @ref ADC_LL_EC_REG_CONTINUOUS_MODE */
uint32_t DmaTransfer; /*!< DMA transfer of ADC conversion data.
This parameter can be a value of @ref ADC_LL_EC_REG_DMA_TRANSFER */
uint32_t Overrun; /*!< Select the behavior in case of overrun: data overwritten or preserved (default).
This parameter can be a value of @ref ADC_LL_EC_REG_OVR_DATA_BEHAVIOR. */
uint32_t SamplingTimeCommon1; /*!< Set sampling time common to a group of channels.
This parameter can be a value of @ref ADC_LL_EC_CHANNEL_SAMPLINGTIME */
uint32_t SamplingTimeCommon2; /*!< Set sampling time common to a group of channels, second common setting possible.
This parameter can be a value of @ref ADC_LL_EC_CHANNEL_SAMPLINGTIME */
}ADCCTRL_ConvParameters_t;
/**
* @brief ADC Init configuration structure - Sequencer parameters
*/
typedef struct ADCCTRL_SeqParameters
{
uint32_t Setup; /*!< Set ADC sequencer configuration flexibility.
This parameter can be a value of @ref ADC_LL_EC_REG_SEQ_MODE */
uint32_t Length; /*!< Set ADC sequencer scan length.
This parameter can be a value of @ref ADC_LL_EC_REG_SEQ_SCAN_LENGTH */
uint32_t DiscMode; /*!< Set ADC sequencer discontinuous mode.
This parameter can be a value of @ref ADC_LL_EC_REG_SEQ_DISCONT_MODE */
}ADCCTRL_SeqParameters_t;
/**
* @brief ADC Init configuration structure - Low power parameters
*/
typedef struct ADCCTRL_LowPowerParameters
{
FunctionalState AutoPowerOff; /*!< Enable or Disable ADC Auto Power OFF mode.
This parameter can be set to ENABLE or DISABLE */
uint32_t AutonomousDPD; /*!< Enable or Disable ADC Autonomous Deep Power Down Mode.
This parameter can be a value of @ref ADC_LL_EC_AUTONOMOUS_DEEP_POWER_DOWN_MODE */
}ADCCTRL_LowPowerParameters_t;
/**
* @brief ADC Init configuration structure
*/
typedef struct ADCCTRL_InitConfig
{
ADCCTRL_ConvParameters_t ConvParams;
ADCCTRL_SeqParameters_t SeqParams;
ADCCTRL_LowPowerParameters_t LowPowerParams;
} ADCCTRL_InitConfig_t;
/**
* @brief ADC Channel configuration structure
*/
typedef struct ADCCTRL_ChannelConfig
{
uint32_t Channel; /*!< Specify the channel to configure into ADC regular group.
This parameter can be a value of @ref ADC_LL_EC_CHANNEL */
uint32_t Rank; /*!< Add or remove the channel from ADC regular group sequencer and specify its
conversion rank.
This parameter can be a value of @ref ADC_LL_EC_REG_SEQ_RANKS */
uint32_t SamplingTime; /*!< Sampling time value to be set for the selected channel.
This parameter can be a value of @ref ADC_LL_EC_SAMPLINGTIME_COMMON */
} ADCCTRL_ChannelConfig_t;
/**
* @brief ADC handle typedef
*/
typedef struct ADCCTRL_Handle
{
uint32_t Uid; /* Id of the Handle instance */
ADCCTRL_HandleState_t State; /* State of the ADC Controller handle */
ADCCTRL_InitConfig_t InitConf; /* Init configuration of the ADC */
ADCCTRL_ChannelConfig_t ChannelConf; /* Channel configuration of the ADC */
} ADCCTRL_Handle_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
/**
* @brief Initialize the adc controller
*
* @retval State of the initialization
*/
ADCCTRL_Cmd_Status_t ADCCTRL_Init(void);
/**
* @brief Register a ADC handle
*
* @param p_Handle: Handle to register
*
* @return State of the handle initialization
*/
ADCCTRL_Cmd_Status_t ADCCTRL_RegisterHandle (ADCCTRL_Handle_t * const p_Handle);
/**
* @brief Request a specific state for the ADC IP - Either On or Off
*
* @param p_Handle: ADC handle
* @param State: Requested state to apply
*
* @return State of the operation
*/
ADCCTRL_Cmd_Status_t ADCCTRL_RequestIpState (const ADCCTRL_Handle_t * const p_Handle,
const ADCCTRL_Ip_State_t State);
/**
* @brief Read raw value of the ADC
*
* @param p_Handle: ADC handle
* @param p_ReadValue: Raw ADC value
*
* @retval Operation state
*/
ADCCTRL_Cmd_Status_t ADCCTRL_RequestRawValue (const ADCCTRL_Handle_t * const p_Handle,
uint16_t * const p_ReadValue);
/**
* @brief Read temperature from ADC temperature sensor
*
* @details The returned value is actual temperature sensor value
*
* @param p_Handle: ADC handle
* @param p_ReadValue: Temperature measurement
*
* @retval Operation state
*/
ADCCTRL_Cmd_Status_t ADCCTRL_RequestTemperature (const ADCCTRL_Handle_t * const p_Handle,
int16_t * const p_ReadValue);
/**
* @brief Read Voltage from ADC
*
* @details The returned value is actual Voltage value in mVolts
*
* @param p_Handle: ADC handle
* @param p_ReadValue: Core Voltage measurement
*
* @retval Operation state
*/
ADCCTRL_Cmd_Status_t ADCCTRL_RequestCoreVoltage (const ADCCTRL_Handle_t * const p_Handle,
uint16_t * const p_ReadValue);
/**
* @brief Read reference Voltage from ADC
*
* @details The returned value is actual reference Voltage value in mVolts
*
* @param p_Handle: ADC handle
* @param p_ReadValue: Reference Voltage measurement
*
* @retval Operation state
*/
ADCCTRL_Cmd_Status_t ADCCTRL_RequestRefVoltage (const ADCCTRL_Handle_t * const p_Handle,
uint16_t * const p_ReadValue);
/* Exported functions to be implemented by the user ------------------------- */
/**
* @brief Take ownership on the ADC mutex
*
* @details This function shall be implemented by the user
*
* @return Status of the command
* @retval ADCCTRL_Cmd_Status_t::ADCCTRL_OK
* @retval ADCCTRL_Cmd_Status_t::ADCCTRL_NOK
*/
extern ADCCTRL_Cmd_Status_t ADCCTRL_MutexTake (void);
/**
* @brief Release ownership on the ADC mutex
*
* @details This function shall be implemented by the user
*
* @return Status of the command
* @retval ADCCTRL_Cmd_Status_t::ADCCTRL_OK
* @retval ADCCTRL_Cmd_Status_t::ADCCTRL_NOK
*/
extern ADCCTRL_Cmd_Status_t ADCCTRL_MutexRelease (void);
#ifdef __cplusplus
}
#endif
#endif /* ADC_CTRL_H */

View File

@@ -0,0 +1,123 @@
/**
******************************************************************************
* @file app_sys.c
* @author MCD Application Team
* @brief Application system for STM32WPAN Middleware.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "app_sys.h"
#include "app_conf.h"
#include "timer_if.h"
#include "stm32_lpm.h"
#include "ll_intf.h"
#include "ll_sys.h"
#if (UTIL_LPM_LEGACY_ENABLED == 0)
#include "stm32_lpm_if.h"
#endif
#if MAC
#include "ral.h"
#endif
/* External functions --------------------------------------------------------*/
extern uint32_t llhwc_cmn_is_dp_slp_enabled(void);
/* External variables --------------------------------------------------------*/
/* Private variables --------------------------------------------------------*/
static uint32_t wakeup_offset = RADIO_DEEPSLEEP_WAKEUP_TIME_US;
/* Functions Definition ------------------------------------------------------*/
/**
*
*/
#if SUPPORT_BLE
void APP_SYS_BLE_EnterDeepSleep(void)
{
ble_stat_t cmd_status;
uint32_t radio_remaining_time = 0;
if (ll_sys_dp_slp_get_state() == LL_SYS_DP_SLP_DISABLED)
{
/* Enable radio to retrieve next radio activity */
/* Getting next radio event time if any */
cmd_status = ll_intf_le_get_remaining_time_for_next_event(&radio_remaining_time);
UNUSED(cmd_status);
assert_param(cmd_status == SUCCESS);
if (radio_remaining_time == LL_DP_SLP_NO_WAKEUP)
{
/* No next radio event scheduled */
(void)ll_sys_dp_slp_enter(LL_DP_SLP_NO_WAKEUP);
}
else if (radio_remaining_time > wakeup_offset)
{
/* No event in a "near" futur */
(void)ll_sys_dp_slp_enter(radio_remaining_time - wakeup_offset);
}
else
{
#if (UTIL_LPM_LEGACY_ENABLED == 1)
UTIL_LPM_SetOffMode(1U << CFG_LPM_LL_DEEPSLEEP, UTIL_LPM_DISABLE);
#else /* (UTIL_LPM_LEGACY_ENABLED == 1) */
#if (CFG_LPM_STOP1_SUPPORTED == 1)
UTIL_LPM_SetMaxMode(1U << CFG_LPM_LL_DEEPSLEEP, UTIL_LPM_STOP1_MODE);
#else /* (CFG_LPM_STOP1_SUPPORTED == 1) */
UTIL_LPM_SetMaxMode(1U << CFG_LPM_LL_DEEPSLEEP, UTIL_LPM_SLEEP_MODE);
#endif /* (CFG_LPM_STOP1_SUPPORTED == 1) */
#endif /* (UTIL_LPM_LEGACY_ENABLED == 1) */
}
}
}
#else /* SUPPORT_BLE */
/**
*
*/
void APP_SYS_LPM_EnterLowPowerMode(void)
{
ral_instance_t radio_instance;
uint8_t channel;
uint64_t next_radio_evt;
/* Ensure there are no radio events (implement bsp function like bsp_is_radio_idle() ) */
ral_event_state_enum_t radio_state = ral_get_current_event_state( &radio_instance, &channel );
LL_UNUSED(radio_instance);
LL_UNUSED(channel);
if (radio_state != RAL_IDLE)
{
return;
}
next_radio_evt = os_timer_get_earliest_time();
if ( llhwc_cmn_is_dp_slp_enabled() == 0 )
{
if ( next_radio_evt > wakeup_offset )
{
/* No event in a "near" futur */
ll_sys_dp_slp_enter( next_radio_evt - wakeup_offset );
}
}
}
#endif /* SUPPORT_BLE */
void APP_SYS_SetWakeupOffset(uint32_t wakeup_offset_us)
{
wakeup_offset = wakeup_offset_us;
}

View File

@@ -0,0 +1,307 @@
/**
******************************************************************************
* @file crc_ctrl.c
* @author MCD Application Team
* @brief Source for CRC client controller module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
/* Utilities */
#include "utilities_common.h"
/* Own header files */
#include "crc_ctrl.h"
#include "crc_ctrl_conf.h"
/* HAL CRC header */
#include "stm32wbaxx_hal_crc.h"
/* Private defines -----------------------------------------------------------*/
/**
* @brief Initial value define for configuration tracking number
*
*/
#define CRCCTRL_NO_CONFIG (uint32_t)(0x00000000u)
/* Private typedef -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/**
* @brief Tracker of the current applied configuration
*/
static uint32_t CurrentConfig = CRCCTRL_NO_CONFIG;
/**
* @brief Higher registered handle ID
*/
static uint32_t MaxRegisteredId = CRCCTRL_NO_CONFIG;
/**
* @brief Handle of the HAL CRC
*/
static CRC_HandleTypeDef CRCHandle =
{
.Instance = CRCCTRL_HWADDR,
};
/* Global variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/**
* @brief Configure CRC IP
* @param p_Handle: CRC handle
* @retval State of the configuration
*/
static inline HAL_StatusTypeDef CrcConfigure (CRCCTRL_Handle_t * const p_Handle);
/* Functions Definition ------------------------------------------------------*/
__WEAK CRCCTRL_Cmd_Status_t CRCCTRL_Init (void)
{
CRCCTRL_Cmd_Status_t error = CRCCTRL_UNKNOWN;
/* Try to take the CRC mutex */
error = CRCCTRL_MutexTake ();
if (CRCCTRL_OK == error)
{
CurrentConfig = CRCCTRL_NO_CONFIG;
CRCHandle.State = HAL_CRC_STATE_RESET;
CRCHandle.Instance = CRCCTRL_HWADDR;
/* Release the mutex */
CRCCTRL_MutexRelease ();
}
return error;
}
__WEAK CRCCTRL_Cmd_Status_t CRCCTRL_RegisterHandle (CRCCTRL_Handle_t * const p_Handle)
{
CRCCTRL_Cmd_Status_t error = CRCCTRL_UNKNOWN;
if (NULL == p_Handle)
{
error = CRCCTRL_ERROR_NULL_POINTER;
}
else if (HANDLE_REG == p_Handle->State)
{
error = CRCCTRL_HANDLE_ALREADY_REGISTERED;
}
else
{
/* Try to take the CRC mutex */
error = CRCCTRL_MutexTake ();
if (CRCCTRL_OK == error)
{
/* Update the maximum registered handle */
MaxRegisteredId = MaxRegisteredId + 1u;
/* Update the handle UUID */
p_Handle->Uid = MaxRegisteredId;
/* Init the previous value */
p_Handle->PreviousComputedValue = p_Handle->Configuration.InitValue;
/* Set handle as initialized */
p_Handle->State = HANDLE_REG;
/* Release the mutex */
CRCCTRL_MutexRelease ();
}
}
return error;
}
__WEAK CRCCTRL_Cmd_Status_t CRCCTRL_Calculate (CRCCTRL_Handle_t * const p_Handle,
uint32_t a_Payload[],
const uint32_t PayloadSize,
uint32_t * const p_ConmputedValue)
{
CRCCTRL_Cmd_Status_t error = CRCCTRL_UNKNOWN;
HAL_StatusTypeDef eReturn = HAL_OK;
/* Null pointer for handle or payload */
if ((NULL == p_Handle) || (NULL == a_Payload) || (NULL == p_ConmputedValue))
{
error = CRCCTRL_ERROR_NULL_POINTER;
}
/* Handle not init */
else if (HANDLE_NOT_REG == p_Handle->State)
{
error = CRCCTRL_HANDLE_NOT_REGISTERED;
}
/* Handle not in the range */
else if ((MaxRegisteredId < p_Handle->Uid) ||
(CRCCTRL_NO_CONFIG >= p_Handle->Uid))
{
error = CRCCTRL_HANDLE_NOT_VALID;
}
else
{
/* Try to take the CRC mutex */
error = CRCCTRL_MutexTake ();
if (CRCCTRL_OK == error)
{
/* Is the current config IS NOT the same as the one requested ? */
if (CurrentConfig != p_Handle->Uid)
{
/* Configure the CRC before use */
eReturn = CrcConfigure (p_Handle);
}
if (eReturn == HAL_OK)
{
*p_ConmputedValue = HAL_CRC_Calculate (&CRCHandle, a_Payload, PayloadSize);
/* Update the handle with the computed value */
p_Handle->PreviousComputedValue = *p_ConmputedValue;
}
else
{
error = CRCCTRL_ERROR_CONFIG;
}
/* Release the mutex */
CRCCTRL_MutexRelease ();
}
}
return error;
}
__WEAK CRCCTRL_Cmd_Status_t CRCCTRL_Accumulate (CRCCTRL_Handle_t * const p_Handle,
uint32_t a_Payload[],
const uint32_t PayloadSize,
uint32_t * const p_ConmputedValue)
{
CRCCTRL_Cmd_Status_t error = CRCCTRL_UNKNOWN;
/* Null pointer for handle or payload */
if ((NULL == p_Handle) || (NULL == a_Payload) || (NULL == p_ConmputedValue))
{
error = CRCCTRL_ERROR_NULL_POINTER;
}
/* Handle not init */
else if (HANDLE_NOT_REG == p_Handle->State)
{
error = CRCCTRL_HANDLE_NOT_REGISTERED;
}
/* Handle not in the range */
else if ((MaxRegisteredId < p_Handle->Uid) ||
(CRCCTRL_NO_CONFIG >= p_Handle->Uid))
{
error = CRCCTRL_HANDLE_NOT_VALID;
}
else
{
/* Try to take the CRC mutex */
error = CRCCTRL_MutexTake ();
if (CRCCTRL_OK == error)
{
/* Check if the config has to change */
if (CurrentConfig == p_Handle->Uid)
{
*p_ConmputedValue = HAL_CRC_Accumulate (&CRCHandle,
a_Payload,
PayloadSize);
/* Update the handle with the computed value */
p_Handle->PreviousComputedValue = *p_ConmputedValue;
}
/* Configure the CRC before use */
else if (HAL_OK == CrcConfigure (p_Handle))
{
/* Before starting the accumulation, the init register shall be written with the previous value */
CRCHandle.Instance->INIT = p_Handle->PreviousComputedValue;
*p_ConmputedValue = HAL_CRC_Calculate (&CRCHandle,
a_Payload,
PayloadSize);
/* Update the handle with the computed value */
p_Handle->PreviousComputedValue = *p_ConmputedValue;
}
else
{
error = CRCCTRL_ERROR_CONFIG;
}
/* Release the mutex */
CRCCTRL_MutexRelease ();
}
}
return error;
}
/* Private function Definition -----------------------------------------------*/
HAL_StatusTypeDef CrcConfigure (CRCCTRL_Handle_t * const p_Handle)
{
HAL_StatusTypeDef error = HAL_OK;
/* No need to DeInit if the CRC if it is not yet initialized */
if (HAL_CRC_STATE_RESET != CRCHandle.State)
{
/* DeInit the CRC module */
error = HAL_CRC_DeInit(&CRCHandle);
}
/* All OK ? */
if (HAL_OK == error)
{
/* Fulfill the configuration part */
CRCHandle.Init.CRCLength = p_Handle->Configuration.CRCLength;
CRCHandle.Init.DefaultInitValueUse = p_Handle->Configuration.DefaultInitValueUse;
CRCHandle.Init.DefaultPolynomialUse = p_Handle->Configuration.DefaultPolynomialUse;
CRCHandle.Init.GeneratingPolynomial = p_Handle->Configuration.GeneratingPolynomial;
CRCHandle.Init.InitValue = p_Handle->Configuration.InitValue;
CRCHandle.Init.InputDataInversionMode = p_Handle->Configuration.InputDataInversionMode;
CRCHandle.Init.OutputDataInversionMode = p_Handle->Configuration.OutputDataInversionMode;
CRCHandle.InputDataFormat = p_Handle->Configuration.InputDataFormat;
/* Apply the requested CRC configuration */
error = HAL_CRC_Init(&CRCHandle);
if (HAL_OK == error)
{
/* Update the current configuration */
CurrentConfig = p_Handle->Uid;
}
else
{
/* There must be an issue with configuration, clean the configuration */
memset ((void *)(&CRCHandle.Init),
0x00,
sizeof (CRC_InitTypeDef));
CRCHandle.InputDataFormat = 0x00u;
}
}
return error;
}
/* Weak function Definition --------------------------------------------------*/
__WEAK CRCCTRL_Cmd_Status_t CRCCTRL_MutexTake (void)
{
return CRCCTRL_OK;
}
__WEAK CRCCTRL_Cmd_Status_t CRCCTRL_MutexRelease (void)
{
return CRCCTRL_OK;
}

View File

@@ -0,0 +1,214 @@
/**
******************************************************************************
* @file crc_ctrl.h
* @author MCD Application Team
* @brief Header for CRC client manager module
******************************************************************************
* @attention
*
* Copyright (c) 2023 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef CRC_CTRL_H
#define CRC_CTRL_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Utilities */
#include "utilities_common.h"
/* HAL CRC header */
#include "stm32wbaxx_hal_crc.h"
/* Exported defines ----------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/**
* @brief CRC command status codes
*/
typedef enum CRCCTRL_Cmd_Status
{
CRCCTRL_OK,
CRCCTRL_NOK,
CRCCTRL_BUSY,
CRCCTRL_HANDLE_ALREADY_REGISTERED,
CRCCTRL_HANDLE_NOT_REGISTERED,
CRCCTRL_HANDLE_NOT_VALID,
CRCCTRL_ERROR_NULL_POINTER,
CRCCTRL_ERROR_CONFIG,
CRCCTRL_UNKNOWN,
} CRCCTRL_Cmd_Status_t;
/**
* @brief CRC command status codes
*/
typedef enum CRCCTRL_HandleState
{
HANDLE_NOT_REG,
HANDLE_REG,
} CRCCTRL_HandleState_t;
/**
* @brief CRC configuration structure
*
*/
typedef struct CRCCTRL_Config
{
uint8_t DefaultPolynomialUse; /*!< This parameter is a value of @ref CRC_Default_Polynomial and indicates if default polynomial is used.
If set to DEFAULT_POLYNOMIAL_ENABLE, resort to default
X^32 + X^26 + X^23 + X^22 + X^16 + X^12 + X^11 + X^10 +X^8 + X^7 + X^5 +
X^4 + X^2+ X +1.
In that case, there is no need to set GeneratingPolynomial field.
If otherwise set to DEFAULT_POLYNOMIAL_DISABLE, GeneratingPolynomial and
CRCLength fields must be set. */
uint8_t DefaultInitValueUse; /*!< This parameter is a value of @ref CRC_Default_InitValue_Use and indicates if default init value is used.
If set to DEFAULT_INIT_VALUE_ENABLE, resort to default
0xFFFFFFFF value. In that case, there is no need to set InitValue field. If
otherwise set to DEFAULT_INIT_VALUE_DISABLE, InitValue field must be set. */
uint32_t GeneratingPolynomial; /*!< Set CRC generating polynomial as a 7, 8, 16 or 32-bit long value for a polynomial degree
respectively equal to 7, 8, 16 or 32. This field is written in normal,
representation e.g., for a polynomial of degree 7, X^7 + X^6 + X^5 + X^2 + 1
is written 0x65. No need to specify it if DefaultPolynomialUse is set to
DEFAULT_POLYNOMIAL_ENABLE. */
uint32_t CRCLength; /*!< This parameter is a value of @ref CRC_Polynomial_Sizes and indicates CRC length.
Value can be either one of
@arg @ref CRC_POLYLENGTH_32B (32-bit CRC),
@arg @ref CRC_POLYLENGTH_16B (16-bit CRC),
@arg @ref CRC_POLYLENGTH_8B (8-bit CRC),
@arg @ref CRC_POLYLENGTH_7B (7-bit CRC). */
uint32_t InitValue; /*!< Init value to initiate CRC computation. No need to specify it if DefaultInitValueUse
is set to DEFAULT_INIT_VALUE_ENABLE. */
uint32_t InputDataInversionMode; /*!< This parameter is a value of @ref CRCEx_Input_Data_Inversion and specifies input data inversion mode.
Can be either one of the following values
@arg @ref CRC_INPUTDATA_INVERSION_NONE no input data inversion
@arg @ref CRC_INPUTDATA_INVERSION_BYTE byte-wise inversion, 0x1A2B3C4D
becomes 0x58D43CB2
@arg @ref CRC_INPUTDATA_INVERSION_HALFWORD halfword-wise inversion,
0x1A2B3C4D becomes 0xD458B23C
@arg @ref CRC_INPUTDATA_INVERSION_WORD word-wise inversion, 0x1A2B3C4D
becomes 0xB23CD458 */
uint32_t OutputDataInversionMode; /*!< This parameter is a value of @ref CRCEx_Output_Data_Inversion and specifies output data (i.e. CRC) inversion mode.
Can be either
@arg @ref CRC_OUTPUTDATA_INVERSION_DISABLE no CRC inversion,
@arg @ref CRC_OUTPUTDATA_INVERSION_ENABLE CRC 0x11223344 is converted
into 0x22CC4488 */
uint32_t InputDataFormat; /*!< This parameter is a value of @ref CRC_Input_Buffer_Format and specifies input data format.
Can be either
@arg @ref CRC_INPUTDATA_FORMAT_BYTES input data is a stream of bytes
(8-bit data)
@arg @ref CRC_INPUTDATA_FORMAT_HALFWORDS input data is a stream of
half-words (16-bit data)
@arg @ref CRC_INPUTDATA_FORMAT_WORDS input data is a stream of words
(32-bit data)
Note that constant CRC_INPUT_FORMAT_UNDEFINED is defined but an initialization
error must occur if InputBufferFormat is not one of the three values listed
above */
} CRCCTRL_Config_t;
typedef struct CRCCTRL_Handle
{
uint32_t Uid; /* Id of the Handle instance */
uint32_t PreviousComputedValue; /* Previous CRC computed value for Accumulate purposes */
CRCCTRL_HandleState_t State; /* State of the CRC Controller handle */
CRCCTRL_Config_t Configuration; /* Configuration of the CRC */
} CRCCTRL_Handle_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
/**
* @brief Init the CRC Ctrl variables
*
* @return State of the handle initialization
*/
CRCCTRL_Cmd_Status_t CRCCTRL_Init (void);
/**
* @brief Register a CRC handle
*
* @param p_Handle: Handle to register
*
* @return State of the handle registration
*/
CRCCTRL_Cmd_Status_t CRCCTRL_RegisterHandle (CRCCTRL_Handle_t * const p_Handle);
/**
* @brief Compute the CRC of the given payload
*
* @param p_Handle: CRC handle
* @param a_Payload: Address of the first payload element
* @param PayloadSize: Size of the payload to compute the CRC
* @param p_ComputedValue: Computed CRC (returned value LSBs for CRC shorter than 32 bits)
*
* @return State of the operation
*/
CRCCTRL_Cmd_Status_t CRCCTRL_Calculate (CRCCTRL_Handle_t * const p_Handle,
uint32_t a_Payload[],
const uint32_t PayloadSize,
uint32_t * const p_ConmputedValue);
/**
* @brief Keep computing the CRC of a given payload
*
* @details Computation starts with the previous computed CRC as initialization value.
*
* @details The CRCCTRL_Calculate shall be used before any call of this API.
*
* @param p_Handle: Address of the first payload element
* @param a_Payload: Address of the first payload element
* @param PayloadSize: Size of the payload to compute the CRC
* @param p_ComputedValue: Computed CRC (returned value LSBs for CRC shorter than 32 bits)
*
* @return State of the operation
*/
CRCCTRL_Cmd_Status_t CRCCTRL_Accumulate (CRCCTRL_Handle_t * const p_Handle,
uint32_t a_Payload[],
const uint32_t PayloadSize,
uint32_t * const p_ConmputedValue);
/* Exported functions to be implemented by the user ------------------------- */
/**
* @brief Take ownership on the CRC mutex
*
* @details This function shall be implemented by the user
*
* @return Status of the command
* @retval CRCCTRL_Cmd_Status_t::CRCCTRL_OK
* @retval CRCCTRL_Cmd_Status_t::CRCCTRL_NOK
*/
extern CRCCTRL_Cmd_Status_t CRCCTRL_MutexTake (void);
/**
* @brief Release ownership on the CRC mutex
*
* @details This function shall be implemented by the user
*
* @return Status of the command
* @retval CRCCTRL_Cmd_Status_t::CRCCTRL_OK
* @retval CRCCTRL_Cmd_Status_t::CRCCTRL_NOK
*/
extern CRCCTRL_Cmd_Status_t CRCCTRL_MutexRelease (void);
#ifdef __cplusplus
}
#endif
#endif /* CRC_CTRL_H */

View File

@@ -0,0 +1,101 @@
/**
******************************************************************************
* @file dbg_trace.h
* @author MCD Application Team
* @brief Header for dbg_trace.c
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef DBG_TRACE_H
#define DBG_TRACE_H
#ifdef __cplusplus
extern "C"
{
#endif
/* Exported types ------------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
#if ( ( CFG_DEBUG_TRACE_FULL != 0 ) || ( CFG_DEBUG_TRACE_LIGHT != 0 ) )
#define PRINT_LOG_BUFF_DBG(...) DbgTraceBuffer(__VA_ARGS__)
#if ( CFG_DEBUG_TRACE_FULL != 0 )
#define PRINT_MESG_DBG(...) do{printf("\r\n [%s][%s][%d] ", DbgTraceGetFileName(__FILE__),__FUNCTION__,__LINE__);printf(__VA_ARGS__);}while(0);
#else
#define PRINT_MESG_DBG printf
#endif
#else
#define PRINT_LOG_BUFF_DBG(...)
#define PRINT_MESG_DBG(...)
#endif
#define PRINT_NO_MESG(...)
/* Exported functions ------------------------------------------------------- */
/**
* @brief Request the user to initialize the peripheral to output traces
*
* @param None
* @retval None
*/
extern void DbgOutputInit( void );
/**
* @brief Request the user to sent the traces on the output peripheral
*
* @param p_data: Address of the buffer to be sent
* @param size: Size of the data to be sent
* @param cb: Function to be called when the data has been sent
* @retval None
*/
extern void DbgOutputTraces( uint8_t *p_data, uint16_t size, void (*cb)(void) );
/**
* @brief DbgTraceInit Initialize Logging feature.
*
* @param: None
* @retval: None
*/
void DbgTraceInit( void );
/**********************************************************************************************************************/
/** This function outputs into the log the buffer (in hex) and the provided format string and arguments.
***********************************************************************************************************************
*
* @param pBuffer Buffer to be output into the logs.
* @param u32Length Length of the buffer, in bytes.
* @param strFormat The format string in printf() style.
* @param ... Arguments of the format string.
*
**********************************************************************************************************************/
void DbgTraceBuffer( const void *pBuffer , uint32_t u32Length , const char *strFormat , ... );
const char *DbgTraceGetFileName( const char *fullpath );
/**
* @brief Override the standard lib function to redirect printf to USART.
* @param handle output handle (STDIO, STDERR...)
* @param buf buffer to write
* @param bufsize buffer size
* @retval Number of elements written
*/
size_t DbgTraceWrite(int handle, const unsigned char * buf, size_t bufSize);
#ifdef __cplusplus
}
#endif
#endif /* DBG_TRACE_H */

View File

@@ -0,0 +1,98 @@
/**
******************************************************************************
* @file otp.c
* @author MCD HW Board & MCD Application Team
* @brief Source file for One Time Programmable (OTP) area
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "otp.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
HAL_StatusTypeDef OTP_Read(uint8_t index, OTP_Data_s** otp_ptr)
{
*otp_ptr = (OTP_Data_s*) (FLASH_OTP_BASE + FLASH_OTP_SIZE - 16);
while ( (*otp_ptr)->index != index && (*otp_ptr) != (OTP_Data_s*) FLASH_OTP_BASE)
{
(*otp_ptr) -= 1;
}
if ((*otp_ptr)->index != index)
{
return HAL_ERROR;
}
return HAL_OK;
}
HAL_StatusTypeDef OTP_Write(uint8_t* additional_data, uint8_t* bd_address, uint8_t hsetune, uint8_t index)
{
HAL_StatusTypeDef err = HAL_ERROR;
OTP_Data_s otp_data;
int i;
/* Fill OTP_Data_s structure */
for (i = 0; i < sizeof(otp_data.additional_data); i++)
{
otp_data.additional_data[i] = additional_data[i];
}
for (i = 0; i < sizeof(otp_data.bd_address); i++)
{
otp_data.bd_address[i] = bd_address[i];
}
otp_data.hsetune = hsetune;
otp_data.index = index;
/* Find free space */
uint32_t free_address = FLASH_OTP_BASE;
while ( ( *(uint64_t*)(free_address) != 0xFFFFFFFFFFFFFFFFUL ) &&
( *(uint64_t*)(free_address + 8) != 0xFFFFFFFFFFFFFFFFUL ) &&
( (free_address + 16) != FLASH_OTP_BASE + FLASH_OTP_SIZE ) )
{
free_address += 16;
}
if ( ( *(uint64_t*)(free_address) == 0xFFFFFFFFFFFFFFFFUL ) &&
( *(uint64_t*)(free_address + 8) == 0xFFFFFFFFFFFFFFFFUL ) )
{
/* Store OTP structure in OTP area */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS); /* Clear all Flash flags before write operation*/
err = HAL_FLASH_Unlock();
err |= HAL_FLASH_Program(FLASH_NSCR1_PG, free_address, (uint32_t) &otp_data);
err |= HAL_FLASH_Lock();
}
return err;
}
/* Private functions ---------------------------------------------------------*/

View File

@@ -0,0 +1,87 @@
/**
******************************************************************************
* @file otp.h
* @author MCD HW Board & MCD Application Team
* @brief Header file for One Time Programmable (OTP) area
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef OTP_H
#define OTP_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32wbaxx_hal.h"
#include "cmsis_compiler.h"
/* Exported types ------------------------------------------------------------*/
/*
--------------------------------------------------------------------------------
|LSB MSB|
--------------------------------------------------------------------------------
| additional_data 8-bytes | bd_address 6 bytes | hsetune 1 byte | index 1 byte |
--------------------------------------------------------------------------------
*/
typedef __PACKED_STRUCT
{
uint8_t additional_data[8]; /*!< 64 bits of data to fill OTP slot Ex: MB184510 */
uint8_t bd_address[6]; /*!< Bluetooth Device Address*/
uint8_t hsetune; /*!< Load capacitance to be applied on HSE pad */
uint8_t index; /*!< Structure index */
} OTP_Data_s;
/* Exported constants --------------------------------------------------------*/
#define DEFAULT_OTP_IDX 0
/* Exported macro ------------------------------------------------------------*/
/* Exported variables ------------------------------------------------------- */
/* Exported functions ------------------------------------------------------- */
/**
* * @brief Minimal code to use the OTP_Read function:
*
OTP_Data_s* otp_ptr = NULL;
if (OTP_Read(DEFAULT_OTP_IDX, &otp_ptr) != HAL_OK) {
return HAL_ERROR;
}
uint64_t bd_addr = (uint64_t) otp_ptr->bd_address[0] |
(uint64_t) otp_ptr->bd_address[1] << 8 |
(uint64_t) otp_ptr->bd_address[2] << 16 |
(uint64_t) otp_ptr->bd_address[3] << 24 |
(uint64_t) otp_ptr->bd_address[4] << 32 |
(uint64_t) otp_ptr->bd_address[5] << 40 ;
uint8_t hsetune = otp_ptr->hsetune;
uint8_t index = otp_ptr->index;
*/
HAL_StatusTypeDef OTP_Read(uint8_t index, OTP_Data_s** data);
/**
* @brief Write OTP
*/
HAL_StatusTypeDef OTP_Write(uint8_t* additional_data, uint8_t* bd_address, uint8_t hsetune, uint8_t index);
#ifdef __cplusplus
}
#endif
#endif /* OTP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,286 @@
/**
******************************************************************************
* @file scm.h
* @author MCD Application Team
* @brief Header for scm.c module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef SCM_H
#define SCM_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#if (CFG_SCM_SUPPORTED == 1)
#include "stm32wbaxx_hal.h"
#include "stm32wbaxx_ll_pwr.h"
#include "stm32wbaxx_ll_rcc.h"
#include "stm32wbaxx_ll_tim.h"
/* Exported types ------------------------------------------------------------*/
typedef enum {
NO_CLOCK_CONFIG = 0,
HSE_16MHZ,
HSE_32MHZ,
SYS_PLL,
} scm_clockconfig_t;
typedef enum {
LP,
RUN,
HSE16,
HSE32,
PLL,
} scm_ws_lp_t;
typedef enum {
HSEPRE_DISABLE = 0,
HSEPRE_ENABLE
} scm_hse_hsepre_t;
typedef enum {
SCM_USER_APP,
SCM_USER_LL_FW,
SCM_USER_LL_HW_RCO_CLBR,
TOTAL_CLIENT_NUM, /* To be at the end of the enum */
} scm_user_id_t;
typedef enum {
NO_PLL,
PLL_INTEGER_MODE,
PLL_FRACTIONAL_MODE,
} scm_pll_mode_t;
typedef enum {
SCM_RADIO_NOT_ACTIVE = 0,
SCM_RADIO_ACTIVE,
} scm_radio_state_t;
typedef struct {
uint8_t are_pll_params_initialized;
scm_pll_mode_t pll_mode;
uint32_t PLLM;
uint32_t PLLN;
uint32_t PLLP;
uint32_t PLLQ;
uint32_t PLLR;
uint32_t PLLFractional;
uint32_t AHB5_PLL1_CLKDivider;
} scm_pll_config_t;
typedef struct{
scm_clockconfig_t targeted_clock_freq;
uint32_t flash_ws_cfg;
uint32_t sram_ws_cfg;
scm_pll_config_t pll;
} scm_system_clock_t;
/* Exported constants --------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
/**
* @brief System Clock Manager init code
* @param None
* @retval None
*/
void scm_init(void);
/**
* @brief Setup the system clock source in usable configuration for Connectivity use cases.
* Called at startup or out of low power modes.
* @param None
* @retval None
*/
void scm_setup(void);
/**
* @brief Configure the PLL mode and parameters before PLL selection as system clock.
* @param p_pll_config PLL coniguration to apply
* @retval None
* @note scm_pll_setconfig to be called before PLL activation (PLL set as system core clock)
*/
void scm_pll_setconfig(const scm_pll_config_t *p_pll_config);
/**
* @brief Restore system clock configuration when moving out of standby.
* @param None
* @retval None
*/
void scm_standbyexit(void);
/**
* @brief Return the state of the Radio.
* @param None
* @retval radio_state
*/
scm_radio_state_t isRadioActive(void);
/**
* @brief Configure the PLL for switching fractional parameters on the fly.
* @param pll_frac Up to date fractional configuration.
* @retval None
* @note A PLL update is requested only when the system clock is
* running on the PLL with a different configuration that the
* one required.
*/
void scm_pll_fractional_update(uint32_t pll_frac);
/**
* @brief Set the HSE clock to the requested frequency.
* @param user_id This parameter can be one of the following:
* @arg SCM_USER_APP
* @arg SCM_USER_LL_FW
* @param sysclockconfig This parameter can be one of the following:
* @arg HSE_16MHZ
* @arg HSE_32MHZ
* @arg SYS_PLL
* @retval None
*/
void scm_setsystemclock (scm_user_id_t user_id, scm_clockconfig_t sysclockconfig);
/**
* @brief Called each time the PLL is ready
* @param None
* @retval None
* @note This function is defined as weak in SCM module.
* Can be overridden by user.
*/
void scm_pllready(void);
/**
* @brief Configure the Flash and SRAMs wait cycle (when required for system clock source change)
* @param ws_lp_config: This parameter can be one of the following:
* @arg LP
* @arg RUN
* @arg HSE16
* @arg HSE32
* @arg PLL
* @retval None
*/
void scm_setwaitstates(const scm_ws_lp_t ws_lp_config);
/**
* @brief Notify the state of the Radio
* @param radio_state: This parameter can be one of the following:
* @arg SCM_RADIO_ACTIVE
* @arg SCM_RADIO_NOT_ACTIVE
* @retval None
*/
void scm_notifyradiostate(const scm_radio_state_t radio_state);
/**
* @brief SCM HSERDY interrupt handler.
* Switch system clock on HSE.
* @param None
* @retval None
*/
void scm_hserdy_isr(void);
/**
* @brief SCM PLLRDY interrupt handler.
* Switch system clock on PLL.
* @param None
* @retval None
*/
void scm_pllrdy_isr(void);
/* SCM HSE BEGIN */
/**
* @brief Getter for SW HSERDY flag
*/
uint8_t SCM_HSE_Get_SW_HSERDY(void);
/**
* @brief Setter for SW HSERDY flag
*/
void SCM_HSE_Set_SW_HSERDY(void);
/**
* @brief Clean of SW HSERDY flag
*/
void SCM_HSE_Clear_SW_HSERDY(void);
/**
* @brief Polling function to wait until HSE is ready
*/
void SCM_HSE_WaitUntilReady(void);
/**
* @brief Start the HSE stabilization timer
*/
void SCM_HSE_StartStabilizationTimer(void);
/**
* @brief Stop the HSE stabilization timer
*/
void SCM_HSE_StopStabilizationTimer(void);
/**
* @brief HSE stabilization timer interrupt handler
*/
void SCM_HSE_SW_HSERDY_isr(void);
/* SCM HSE END */
/* Exported functions - To be implemented by the user ------------------------- */
/**
* @brief SCM HSI clock enable
* @details A weak version is implemented in the module sources.
* @details It can be overridden by user.
* @param None
* @retval None
*/
extern void SCM_HSI_CLK_ON(void);
/**
* @brief SCM HSI clock may be disabled when this function is called
* @details A weak version is implemented in the module sources.
* @details It can be overridden by user.
* @param None
* @retval None
*/
extern void SCM_HSI_CLK_OFF(void);
/* SCM HSE BEGIN */
/**
* @brief Entry hook for HSI switch
*/
extern void SCM_HSI_SwithSystemClock_Entry(void);
/**
* @brief Exit hook for HSI switch
*/
extern void SCM_HSI_SwithSystemClock_Exit(void);
/* SCM HSE END */
#else /* CFG_SCM_SUPPORTED */
/* Unused empty functions */
void scm_hserdy_isr(void);
void scm_pllrdy_isr(void);
#endif /* CFG_SCM_SUPPORTED */
#ifdef __cplusplus
}
#endif
#endif /* SCM_H */

View File

@@ -0,0 +1,199 @@
/**
******************************************************************************
* @file stm_list.c
* @author MCD Application Team
* @brief TCircular Linked List Implementation.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/******************************************************************************
* Include Files
******************************************************************************/
#include "stm_list.h"
/******************************************************************************
* Function Definitions
******************************************************************************/
void LST_init_head (tListNode * listHead)
{
listHead->next = listHead;
listHead->prev = listHead;
}
uint8_t LST_is_empty (tListNode * listHead)
{
uint32_t primask_bit;
uint8_t return_value;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
if(listHead->next == listHead)
{
return_value = TRUE;
}
else
{
return_value = FALSE;
}
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
return return_value;
}
void LST_insert_head (tListNode * listHead, tListNode * node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = listHead->next;
node->prev = listHead;
listHead->next = node;
(node->next)->prev = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_insert_tail (tListNode * listHead, tListNode * node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = listHead;
node->prev = listHead->prev;
listHead->prev = node;
(node->prev)->next = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_remove_node (tListNode * node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
(node->prev)->next = node->next;
(node->next)->prev = node->prev;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_remove_head (tListNode * listHead, tListNode ** node )
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = listHead->next;
LST_remove_node (listHead->next);
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_remove_tail (tListNode * listHead, tListNode ** node )
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = listHead->prev;
LST_remove_node (listHead->prev);
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_insert_node_after (tListNode * node, tListNode * ref_node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = ref_node->next;
node->prev = ref_node;
ref_node->next = node;
(node->next)->prev = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_insert_node_before (tListNode * node, tListNode * ref_node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
node->next = ref_node;
node->prev = ref_node->prev;
ref_node->prev = node;
(node->prev)->next = node;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
int LST_get_size (tListNode * listHead)
{
int size = 0;
tListNode * temp;
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
temp = listHead->next;
while (temp != listHead)
{
size++;
temp = temp->next;
}
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
return (size);
}
void LST_get_next_node (tListNode * ref_node, tListNode ** node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = ref_node->next;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}
void LST_get_prev_node (tListNode * ref_node, tListNode ** node)
{
uint32_t primask_bit;
primask_bit = __get_PRIMASK(); /**< backup PRIMASK bit */
__disable_irq(); /**< Disable all interrupts by setting PRIMASK bit on Cortex*/
*node = ref_node->prev;
__set_PRIMASK(primask_bit); /**< Restore PRIMASK bit*/
}

View File

@@ -0,0 +1,62 @@
/**
******************************************************************************
* @file stm_list.h
* @author MCD Application Team
* @brief Header file for linked list library.
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
#ifndef STM_LIST_H
#define STM_LIST_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32_wpan_common.h"
typedef __PACKED_STRUCT _tListNode {
struct _tListNode * next;
struct _tListNode * prev;
} tListNode;
void LST_init_head (tListNode * listHead);
uint8_t LST_is_empty (tListNode * listHead);
void LST_insert_head (tListNode * listHead, tListNode * node);
void LST_insert_tail (tListNode * listHead, tListNode * node);
void LST_remove_node (tListNode * node);
void LST_remove_head (tListNode * listHead, tListNode ** node );
void LST_remove_tail (tListNode * listHead, tListNode ** node );
void LST_insert_node_after (tListNode * node, tListNode * ref_node);
void LST_insert_node_before (tListNode * node, tListNode * ref_node);
int LST_get_size (tListNode * listHead);
void LST_get_next_node (tListNode * ref_node, tListNode ** node);
void LST_get_prev_node (tListNode * ref_node, tListNode ** node);
#ifdef __cplusplus
}
#endif
#endif /* STM_LIST_H */

View File

@@ -0,0 +1,384 @@
/**
******************************************************************************
* @file stm_queue.c
* @author MCD Application Team
* @brief Queue management
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
#include "stm_queue.h"
/* Private define ------------------------------------------------------------*/
/* Private typedef -------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#define MOD(X,Y) (((X) >= (Y)) ? ((X)-(Y)) : (X))
/* Private variables ---------------------------------------------------------*/
/* Global variables ----------------------------------------------------------*/
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
/**
* @brief Initilialze queue structure .
* @note This function is used to initialize the global queue structure.
* @param q: pointer on queue structure to be initialised
* @param queueBuffer: pointer on Queue Buffer
* @param queueSize: Size of Queue Buffer
* @param elementSize: Size of an element in the queue. if =0, the queue will manage variable sizze elements
* @retval always 0
*/
int CircularQueue_Init(queue_t *q, uint8_t* queueBuffer, uint32_t queueSize, uint16_t elementSize, uint8_t optionFlags)
{
q->qBuff = queueBuffer;
q->first = 0;
q->last = 0; /* queueSize-1; */
q->byteCount = 0;
q->elementCount = 0;
q->queueMaxSize = queueSize;
q->elementSize = elementSize;
q->optionFlags = optionFlags;
if ((optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG) && q-> elementSize)
{
/* can not deal with splitting at the end of buffer with fixed size element */
return -1;
}
return 0;
}
/**
* @brief Add element to the queue .
* @note This function is used to add one or more element(s) to the Circular Queue .
* @param q: pointer on queue structure to be handled
* @param X; pointer on element(s) to be added
* @param elementSize: Size of element to be added to the queue. Only used if the queue manage variable size elements
* @param nbElements: number of elements in the in buffer pointed by x
* @retval pointer on last element just added to the queue, NULL if the element to be added do not fit in the queue (too big)
*/
uint8_t* CircularQueue_Add(queue_t *q, uint8_t* x, uint16_t elementSize, uint32_t nbElements)
{
uint8_t* ptr = NULL; /* fct return ptr to the element freshly added, if no room fct return NULL */
uint16_t curElementSize = 0; /* the size of the element currently stored at q->last position */
uint8_t elemSizeStorageRoom = 0 ; /* Indicate the header (which contain only size) of element in case of varaibale size element (q->elementsize == 0) */
uint32_t curBuffPosition; /* the current position in the queue buffer */
uint32_t i; /* loop counter */
uint32_t NbBytesToCopy = 0, NbCopiedBytes = 0 ; /* Indicators for copying bytes in queue */
uint32_t eob_free_size; /* Eof End of Quque Buffer Free Size */
uint8_t wrap_will_occur = 0; /* indicate if a wrap around will occurs */
uint8_t wrapped_element_eob_size; /* In case of Wrap around, indicate size of parta of element that fit at thened of the queuue buffer */
uint16_t overhead = 0; /* In case of CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG or CIRCULAR_QUEUE_NO_WRAP_FLAG options,
indcate the size overhead that will be generated by adding the element with wrap management (split or no wrap ) */
elemSizeStorageRoom = (q->elementSize == 0) ? 2 : 0;
/* retrieve the size of last element sored: the value stored at the beginning of the queue element if element size is variable otherwise take it from fixed element Size member */
if (q->byteCount)
{
curElementSize = (q->elementSize == 0) ? q->qBuff[q->last] + ((q->qBuff[MOD((q->last+1), q->queueMaxSize)])<<8) + 2 : q->elementSize;
}
/* if queue element have fixed size , reset the elementSize arg with fixed element size value */
if (q->elementSize > 0)
{
elementSize = q->elementSize;
}
eob_free_size = (q->last >= q->first) ? q->queueMaxSize - (q->last + curElementSize) : 0;
/* check how many bytes of wrapped element (if anay) are at end of buffer */
wrapped_element_eob_size = (((elementSize + elemSizeStorageRoom )*nbElements) < eob_free_size) ? 0 : (eob_free_size % (elementSize + elemSizeStorageRoom));
wrap_will_occur = wrapped_element_eob_size > elemSizeStorageRoom;
overhead = (wrap_will_occur && (q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG)) ? wrapped_element_eob_size : overhead;
overhead = (wrap_will_occur && (q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG)) ? elemSizeStorageRoom : overhead;
/* Store now the elements if ennough room for all elements */
if (elementSize && ((q->byteCount + ((elementSize + elemSizeStorageRoom )*nbElements) + overhead) <= q->queueMaxSize))
{
/* loop to add all elements */
for (i=0; i < nbElements; i++)
{
q->last = MOD ((q->last + curElementSize),q->queueMaxSize);
curBuffPosition = q->last;
/* store the element */
/* store first the element size if element size is variable */
if (q->elementSize == 0)
{
q->qBuff[curBuffPosition++]= elementSize & 0xFF;
curBuffPosition = MOD(curBuffPosition, q->queueMaxSize);
q->qBuff[curBuffPosition++]= (elementSize & 0xFF00) >> 8 ;
curBuffPosition = MOD(curBuffPosition, q->queueMaxSize);
q->byteCount += 2;
}
/* Identify number of bytes of copy takeing account possible wrap, in this case NbBytesToCopy will contains size that fit at end of the queue buffer */
NbBytesToCopy = MIN((q->queueMaxSize-curBuffPosition),elementSize);
/* check if no wrap (NbBytesToCopy == elementSize) or if Wrap and no spsicf option;
In this case part of data will copied at the end of the buffer and the rest a the beginning */
if ((NbBytesToCopy == elementSize) || ((NbBytesToCopy < elementSize) && (q->optionFlags == CIRCULAR_QUEUE_NO_FLAG)))
{
/* Copy First part (or emtire buffer ) from current position up to the end of the buffer queue (or before if enough room) */
memcpy(&q->qBuff[curBuffPosition],&x[i*elementSize],NbBytesToCopy);
/* Adjust bytes count */
q->byteCount += NbBytesToCopy;
/* Wrap */
curBuffPosition = 0;
/* set NbCopiedBytes bytes with ampount copied */
NbCopiedBytes = NbBytesToCopy;
/* set the rest to copy if wrao , if no wrap will be 0 */
NbBytesToCopy = elementSize - NbBytesToCopy;
/* set the current element Size, will be used to calaculate next last position at beginning of loop */
curElementSize = (elementSize) + elemSizeStorageRoom ;
}
else if (NbBytesToCopy) /* We have a wrap to manage */
{
/* case of CIRCULAR_QUEUE_NO_WRAP_FLAG option */
if (q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG)
{
/* if element size are variable and NO_WRAP option, Invalidate end of buffer setting 0xFFFF size*/
if (q->elementSize == 0)
{
q->qBuff[curBuffPosition-2] = 0xFF;
q->qBuff[curBuffPosition-1] = 0xFF;
}
q->byteCount += NbBytesToCopy; /* invalid data at the end of buffer are take into account in byteCount */
/* No bytes coped a the end of buffer */
NbCopiedBytes = 0;
/* all element to be copied at the begnning of buffer */
NbBytesToCopy = elementSize;
/* Wrap */
curBuffPosition = 0;
/* if variable size element, invalidate end of buffer setting OxFFFF in element header (size) */
if (q->elementSize == 0)
{
q->qBuff[curBuffPosition++] = NbBytesToCopy & 0xFF;
q->qBuff[curBuffPosition++] = (NbBytesToCopy & 0xFF00) >> 8 ;
q->byteCount += 2;
}
}
/* case of CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG option */
else if (q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG)
{
if (q->elementSize == 0)
{
/* reset the size of current element to the nb bytes fitting at the end of buffer */
q->qBuff[curBuffPosition-2] = NbBytesToCopy & 0xFF;
q->qBuff[curBuffPosition-1] = (NbBytesToCopy & 0xFF00) >> 8 ;
/* copy the bytes */
memcpy(&q->qBuff[curBuffPosition],&x[i*elementSize],NbBytesToCopy);
q->byteCount += NbBytesToCopy;
/* set the number of copied bytes */
NbCopiedBytes = NbBytesToCopy;
/* set rest of data to be copied to begnning of buffer */
NbBytesToCopy = elementSize - NbBytesToCopy;
/* one element more dur to split in 2 elements */
q->elementCount++;
/* Wrap */
curBuffPosition = 0;
/* Set new size for rest of data */
q->qBuff[curBuffPosition++] = NbBytesToCopy & 0xFF;
q->qBuff[curBuffPosition++] = (NbBytesToCopy & 0xFF00) >> 8 ;
q->byteCount += 2;
}
else
{
/* Should not occur */
/* can not manage split Flag on Fixed size element */
/* Buffer is corrupted */
return NULL;
}
}
curElementSize = (NbBytesToCopy) + elemSizeStorageRoom ;
q->last = 0;
}
/* some remaining byte to copy */
if (NbBytesToCopy)
{
memcpy(&q->qBuff[curBuffPosition],&x[(i*elementSize)+NbCopiedBytes],NbBytesToCopy);
q->byteCount += NbBytesToCopy;
}
/* One more element */
q->elementCount++;
}
ptr = q->qBuff + (MOD((q->last+elemSizeStorageRoom ),q->queueMaxSize));
}
/* for Breakpoint only...to remove */
else
{
return NULL;
}
return ptr;
}
/**
* @brief Remove element from the queue and copy it in provided buffer
* @note This function is used to remove and element from the Circular Queue .
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed
* @param buffer: destination buffer where to copy element
* @retval Pointer on removed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Remove_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer)
{
return NULL;
}
/**
* @brief Remove element from the queue.
* @note This function is used to remove and element from the Circular Queue .
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed (ignored if NULL)
* @retval Pointer on removed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Remove(queue_t *q, uint16_t* elementSize)
{
uint8_t elemSizeStorageRoom = 0;
uint8_t* ptr= NULL;
elemSizeStorageRoom = (q->elementSize == 0) ? 2 : 0;
uint16_t eltSize = 0;
if (q->byteCount > 0)
{
/* retrieve element Size */
eltSize = (q->elementSize == 0) ? q->qBuff[q->first] + ((q->qBuff[MOD((q->first+1), q->queueMaxSize)])<<8) : q->elementSize;
if ((q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG) && !(q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG))
{
if (((eltSize == 0xFFFF) && q->elementSize == 0 ) ||
((q->first > q->last) && q->elementSize && ((q->queueMaxSize - q->first) < q->elementSize)))
{
/* all data from current position up to the end of buffer are invalid */
q->byteCount -= (q->queueMaxSize - q->first);
/* Adjust first element pos */
q->first = 0;
/* retrieve the right size after the wrap [if variable size element] */
eltSize = (q->elementSize == 0) ? q->qBuff[q->first] + ((q->qBuff[MOD((q->first+1), q->queueMaxSize)])<<8) : q->elementSize;
}
}
/* retrieve element */
ptr = q->qBuff + (MOD((q->first + elemSizeStorageRoom), q->queueMaxSize));
/* adjust byte count */
q->byteCount -= (eltSize + elemSizeStorageRoom) ;
/* Adjust q->first */
if (q->byteCount > 0)
{
q->first = MOD((q->first+ eltSize + elemSizeStorageRoom ), q->queueMaxSize);
}
/* adjust element count */
--q->elementCount;
}
if (elementSize != NULL)
{
*elementSize = eltSize;
}
return ptr;
}
/**
* @brief "Sense" first element of the queue, without removing it and copy it in provided buffer
* @note This function is used to return a pointer on the first element of the queue without removing it.
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed
* @param buffer: destination buffer where to copy element
* @retval Pointer on sensed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Sense_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer)
{
return NULL;
}
/**
* @brief "Sense" first element of the queue, without removing it.
* @note This function is used to return a pointer on the first element of the queue without removing it.
* @param q: pointer on queue structure to be handled
* @param elementSize: Pointer to return Size of element to be removed (ignored if NULL)
* @retval Pointer on sensed element. NULL if queue was empty
*/
uint8_t* CircularQueue_Sense(queue_t *q, uint16_t* elementSize)
{
uint8_t elemSizeStorageRoom = 0;
uint8_t* x= NULL;
elemSizeStorageRoom = (q->elementSize == 0) ? 2 : 0;
uint16_t eltSize = 0;
uint32_t FirstElemetPos = 0;
if (q->byteCount > 0)
{
FirstElemetPos = q->first;
eltSize = (q->elementSize == 0) ? q->qBuff[q->first] + ((q->qBuff[MOD((q->first+1), q->queueMaxSize)])<<8) : q->elementSize;
if ((q->optionFlags & CIRCULAR_QUEUE_NO_WRAP_FLAG) && !(q->optionFlags & CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG))
{
if (((eltSize == 0xFFFF) && q->elementSize == 0 ) ||
((q->first > q->last) && q->elementSize && ((q->queueMaxSize - q->first) < q->elementSize)))
{
/* all data from current position up to the end of buffer are invalid */
FirstElemetPos = 0; /* wrap to the begiining of buffer */
/* retrieve the right size after the wrap [if variable size element] */
eltSize = (q->elementSize == 0) ? q->qBuff[FirstElemetPos]+ ((q->qBuff[MOD((FirstElemetPos+1), q->queueMaxSize)])<<8) : q->elementSize;
}
}
/* retrieve element */
x = q->qBuff + (MOD((FirstElemetPos + elemSizeStorageRoom), q->queueMaxSize));
}
if (elementSize != NULL)
{
*elementSize = eltSize;
}
return x;
}
/**
* @brief Check if queue is empty.
* @note This function is used to to check if the queue is empty.
* @param q: pointer on queue structure to be handled
* @retval TRUE (!0) if the queue is empyu otherwise FALSE (0)
*/
int CircularQueue_Empty(queue_t *q)
{
int ret=FALSE;
if (q->byteCount <= 0)
{
ret=TRUE;
}
return ret;
}
int CircularQueue_NbElement(queue_t *q)
{
return q->elementCount;
}

View File

@@ -0,0 +1,69 @@
/**
******************************************************************************
* @file stm_queue.h
* @author MCD Application Team
* @brief Header for stm_queue.c
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM_QUEUE_H
#define __STM_QUEUE_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* Exported define -----------------------------------------------------------*/
/* Options flags */
#define CIRCULAR_QUEUE_NO_FLAG 0
#define CIRCULAR_QUEUE_NO_WRAP_FLAG 1
#define CIRCULAR_QUEUE_SPLIT_IF_WRAPPING_FLAG 2
/* Exported types ------------------------------------------------------------*/
typedef struct {
uint8_t* qBuff; /* queue buffer, , provided by init fct */
uint32_t queueMaxSize; /* size of the queue, provided by init fct (in bytes)*/
uint16_t elementSize; /* -1 variable. If variable element size the size is stored in the 4 first of the queue element */
uint32_t first; /* position of first element */
uint32_t last; /* position of last element */
uint32_t byteCount; /* number of bytes in the queue */
uint32_t elementCount; /* number of element in the queue */
uint8_t optionFlags; /* option to enable specific features */
} queue_t;
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
int CircularQueue_Init(queue_t *q, uint8_t* queueBuffer, uint32_t queueSize, uint16_t elementSize, uint8_t optionlags);
uint8_t* CircularQueue_Add(queue_t *q, uint8_t* x, uint16_t elementSize, uint32_t nbElements);
uint8_t* CircularQueue_Remove(queue_t *q, uint16_t* elementSize);
uint8_t* CircularQueue_Sense(queue_t *q, uint16_t* elementSize);
int CircularQueue_Empty(queue_t *q);
int CircularQueue_NbElement(queue_t *q);
uint8_t* CircularQueue_Remove_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer);
uint8_t* CircularQueue_Sense_Copy(queue_t *q, uint16_t* elementSize, uint8_t* buffer);
/******************* (C) COPYRIGHT 2010 STMicroelectronics *****END OF FILE****/
#ifdef __cplusplus
}
#endif
#endif /* __STM_QUEUE_H */

View File

@@ -0,0 +1,92 @@
/**
******************************************************************************
* @file temp_measurement.c
* @author MCD Application Team
* @brief Temp measurement module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
/* Common utilites */
#include "utilities_common.h"
#if (USE_TEMPERATURE_BASED_RADIO_CALIBRATION == 1)
/* Own header file */
#include "temp_measurement.h"
/* ADC Controller module */
#include "adc_ctrl.h"
#include "adc_ctrl_conf.h"
/* Link layer interfaces */
#include "ll_intf.h"
#include "ll_intf_cmn.h"
/* Private defines -----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Global variables ----------------------------------------------------------*/
/* Error Handler */
extern void Error_Handler(void);
/* Private function prototypes -----------------------------------------------*/
/* Functions Definition ------------------------------------------------------*/
TEMPMEAS_Cmd_Status_t TEMPMEAS_Init (void)
{
TEMPMEAS_Cmd_Status_t error = TEMPMEAS_UNKNOWN;
ADCCTRL_Cmd_Status_t eReturn = ADCCTRL_UNKNOWN;
eReturn = ADCCTRL_RegisterHandle (&LLTempRequest_Handle);
if ((ADCCTRL_HANDLE_ALREADY_REGISTERED == eReturn) ||
(ADCCTRL_OK == eReturn))
{
error = TEMPMEAS_OK;
}
else
{
error = TEMPMEAS_ADC_INIT;
}
return error;
}
void TEMPMEAS_RequestTemperatureMeasurement (void)
{
int16_t temperature_value = 0;
/* Enter limited critical section : disable all the interrupts with priority higher than RCC one
* Concerns link layer interrupts (high and SW low) or any other high priority user system interrupt
*/
UTILS_ENTER_LIMITED_CRITICAL_SECTION(RCC_INTR_PRIO<<4);
/* Request ADC IP activation */
ADCCTRL_RequestIpState(&LLTempRequest_Handle, ADC_ON);
/* Get temperature from ADC dedicated channel */
ADCCTRL_RequestTemperature (&LLTempRequest_Handle,
&temperature_value);
/* Request ADC IP deactivation */
ADCCTRL_RequestIpState(&LLTempRequest_Handle, ADC_OFF);
/* Give shifted value of the temperature to the link layer */
ll_intf_cmn_set_temperature_value((uint32_t)(temperature_value + TEMPMEAS_MIN_TEMP_LIMIT));
/* Exit limited critical section */
UTILS_EXIT_LIMITED_CRITICAL_SECTION();
}
#endif /* USE_TEMPERATURE_BASED_RADIO_CALIBRATION */
/* Private Functions Definition ------------------------------------------------------*/

View File

@@ -0,0 +1,74 @@
/**
******************************************************************************
* @file temp_measurement.h
* @author MCD Application Team
* @brief Header for temp_measurement.c module
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef TEMP_MEASUREMENT_H
#define TEMP_MEASUREMENT_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "utilities_common.h"
/* Exported defines ----------------------------------------------------------*/
/**
* @brief Minimum operating temperature limit absolute value
*
* @details I.e.: Operating temperature is between -40C and 105degC,
* Minimum value expected is 40u.
*/
#define TEMPMEAS_MIN_TEMP_LIMIT ((uint32_t)40u)
/* Exported types ------------------------------------------------------------*/
/**
* @brief Temperature Measurement command status codes
*/
typedef enum TEMPMEAS_Cmd_Status
{
TEMPMEAS_OK,
TEMPMEAS_NOK,
TEMPMEAS_ADC_INIT,
TEMPMEAS_UNKNOWN,
} TEMPMEAS_Cmd_Status_t;
/* Exported constants --------------------------------------------------------*/
/* External variables --------------------------------------------------------*/
/* Exported macros -----------------------------------------------------------*/
/* Exported functions prototypes ---------------------------------------------*/
/**
* @brief Initialize the temperature measurement
*
* @retval Operation state
*/
TEMPMEAS_Cmd_Status_t TEMPMEAS_Init (void);
/**
* @brief Request temperature measurement
* @param None
* @retval None
*/
void TEMPMEAS_RequestTemperatureMeasurement (void);
#ifdef __cplusplus
}
#endif
#endif /* TEMP_MEASUREMENT_H */

View File

@@ -0,0 +1,163 @@
/**
******************************************************************************
* @file utilities_common.h
* @author MCD Application Team
* @brief Common file to utilities
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef UTILITIES_COMMON_H
#define UTILITIES_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "app_conf.h"
/* -------------------------------- *
* Basic definitions *
* -------------------------------- */
#undef NULL
#define NULL 0
#undef FALSE
#define FALSE 0
#undef TRUE
#define TRUE (!0)
/* -------------------------------- *
* Critical Section definition *
* -------------------------------- */
#undef BACKUP_PRIMASK
#define BACKUP_PRIMASK() uint32_t primask_bit= __get_PRIMASK()
#undef DISABLE_IRQ
#define DISABLE_IRQ() __disable_irq()
#undef RESTORE_PRIMASK
#define RESTORE_PRIMASK() __set_PRIMASK(primask_bit)
/* -------------------------------- *
* Macro delimiters *
* -------------------------------- */
#undef M_BEGIN
#define M_BEGIN do {
#undef M_END
#define M_END } while(0)
/* -------------------------------- *
* Some useful macro definitions *
* -------------------------------- */
#undef MAX
#define MAX( x, y ) (((x)>(y))?(x):(y))
#undef MIN
#define MIN( x, y ) (((x)<(y))?(x):(y))
#undef MODINC
#define MODINC( a, m ) M_BEGIN (a)++; if ((a)>=(m)) (a)=0; M_END
#undef MODDEC
#define MODDEC( a, m ) M_BEGIN if ((a)==0) (a)=(m); (a)--; M_END
#undef MODADD
#define MODADD( a, b, m ) M_BEGIN (a)+=(b); if ((a)>=(m)) (a)-=(m); M_END
#undef MODSUB
#define MODSUB( a, b, m ) MODADD( a, (m)-(b), m )
#undef ALIGN
#ifdef WIN32
#define ALIGN(n)
#else
#define ALIGN(n) __attribute__((aligned(n)))
#endif
#undef PAUSE
#define PAUSE( t ) M_BEGIN \
volatile int _i; \
for ( _i = t; _i > 0; _i -- ); \
M_END
#undef DIVF
#define DIVF( x, y ) ((x)/(y))
#undef DIVC
#define DIVC( x, y ) (((x)+(y)-1)/(y))
#undef DIVR
#define DIVR( x, y ) (((x)+((y)/2))/(y))
#undef SHRR
#define SHRR( x, n ) ((((x)>>((n)-1))+1)>>1)
#undef BITN
#define BITN( w, n ) (((w)[(n)/32] >> ((n)%32)) & 1)
#undef BITNSET
#define BITNSET( w, n, b ) M_BEGIN (w)[(n)/32] |= ((U32)(b))<<((n)%32); M_END
/* -------------------------------- *
* Section attribute *
* -------------------------------- */
#define PLACE_IN_SECTION( __x__ ) __attribute__((section (__x__)))
#ifdef __cplusplus
}
#endif
#define SYS_WAITING_CYCLES_25() do {\
__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");\
__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");\
__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");\
__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");\
__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");__asm("mov r0, r0");\
} while(0)
#define SYS_WAITING_RNGCLK_DEACTIVATION() do {\
for(volatile unsigned int cpt = 178 ; cpt!=0 ; --cpt);\
} while(0)
#define STM32WBA5x_DEFAULT_SCA_RANGE (0)
#define STM32WBA5x_REV_ID_A_SCA_RANGE (0)
#define STM32WBA5x_REV_ID_B_SCA_RANGE (0)
#ifdef STM32WBA65xx
#define STM32WBA6x_SCA_RANGE (0)
#endif
/* Macro helper for optimizing by speed specific functions.
* For IAR only: The functions with this definition will be optimized
* by speed only if the project uses a High optimisation level.
*/
#if defined(__IAR_SYSTEMS_ICC__)
#define OPTIMIZED _Pragma("optimize=speed")
#elif defined(__clang__)
#define OPTIMIZED _Pragma("pragma Ofast")
#elif defined(__GNUC__)
#define OPTIMIZED __attribute__((optimize("Ofast")))
#endif
#define UTIL_UNUSED(X) (void)X /* To avoid gcc/g++ warnings */
#endif /* UTILITIES_COMMON_H */

View File

@@ -0,0 +1,131 @@
;********************************************************************************
;* File Name : stm32wbaxx_ResetHandler.s
;* Author : MCD Application Team
;* Description : STM32WBA5xx Ultra Low Power Devices specific
; Reset handler for connectivity applications.
; EWARM toolchain.
;********************************************************************************
;* @attention
;*
;* Copyright (c) 2022 STMicroelectronics.
;* All rights reserved.
;*
;* This software is licensed under terms that can be found in the LICENSE file
;* in the root directory of this software component.
;* If no LICENSE file comes with this software, it is provided AS-IS.
;*
;*******************************************************************************
;
; Cortex-M version
;
EXTERN __iar_program_start
EXTERN SystemInit
EXTERN is_boot_from_standby
EXTERN SYS_WAITING_CYCLES_25
IMPORT backup_MSP
IMPORT register_backup_table
IMPORT register_backup_table_size
EXPORT CPUcontextSave
EXPORT backup_system_register
EXPORT restore_system_register
PUBLIC Reset_Handler
SECTION .text:CODE:NOROOT:REORDER(2)
Reset_Handler
/* If we exit from standby mode, restore CPU context and jump to asleep point. */
BL is_boot_from_standby
CMP R0, #1
BEQ CPUcontextRestore
/* buffer for local variables (up to 10)from is_boot_from_standby*/
SUB SP, SP, #0x28
/* end of specific code section for standby */
LDR R0, =SystemInit
BLX R0
LDR R0, =__iar_program_start
BX R0
/* These 2 functions are designed to save and then restore CPU context. */
CPUcontextSave
PUSH { R4 - R12, LR } /* store R4 to R12 and LR (10 words) onto C stack */
LDR R4, =backup_MSP /* load address of backup_MSP into R4 */
MOV R3, SP /* load the stack pointer into R3 */
STR R3, [R4] /* store the MSP into backup_MSP */
DSB
WFI /* all saved, trigger deep sleep */
CPUcontextRestore
/* Even if we fall through the WFI instruction, we will immediately
* execute a context restore and end up where we left off with no
* ill effects. Normally at this point the core will either be
* powered off or reset (depending on the deep sleep level). */
LDR R4, =backup_MSP /* load address of backup_MSP into R4 */
LDR R4, [R4] /* load the SP from backup_MSP */
MOV SP, R4 /* restore the SP from R4 */
POP { R4 - R12, PC } /* load R4 to R12 and PC (10 words) from C stack */
backup_system_register
/* R0 -> register_backup_table array current item address */
/* R1 -> loop counter (from register_backup_table_size to 0) */
/* R2 -> register_backup_table array current item value */
backup_loop_init:
LDR R0, =register_backup_table /* R0 points to the first array item */
LDR R1, =register_backup_table_size
LDR R1, [R1] /* R1 contains the number of registers in the array */
backup_loop_iter:
/* Offset processing */
LDR R2, [R0], #4 /* R2 contains the register_backup_table current item (register address) */
/* R0 points to the next register_backup_table item (uint32_t items -> 4 bytes added to previous address) */
/* Register value backup */
LDR R2, [R2] /* R2 contains now the register value to backup */
PUSH {R2} /* Push register value into the stack */
/* Loop iteration control */
SUBS R1, #1 /* Decrement loop counter by 1 and update APSR (Application Processor Status Register) */
BNE backup_loop_iter /* Loop continues until Z flag is set (still array item to handle) */
backup_loop_end:
BX LR /* Return to caller */
restore_system_register
/* R0 -> register_backup_table array current item address */
/* R1 -> loop counter (from register_backup_table_size to 0) */
/* R2 -> register_backup_table array current item value */
restore_loop_init:
LDR R0, =register_backup_table /* R0 points to the first array item */
/* Reverse loop: counter initial value processing */
LDR R1, =register_backup_table_size
LDR R1, [R1] /* R1 contains the number of registers in the array */
SUB R1, #1 /* R1 now contains last array item index (register_backup_table_size - 1) */
/* Reverse loop: apply offset to current array index (point to last array element) */
ADD R0, R1, LSL #2 /* R0 now points to last array item (register_backup_table + (register_backup_table_size - 1) * 4) */
ADD R1, #1 /* Re-add 1 to R1 (array length) */
/* Reverse loop */
restore_loop_iter:
/* Offset processing */
LDR R2, [R0], #-4 /* R2 contains the register_backup_table current item (register address) */
/* R0 now points to the previous register_backup_table item (uint32_t items -> 4 bytes subtracted to previous address) */
/* Register value restoration */
POP {R3} /* Head of stack popped into R3. R3 contains register value to restore */
STR R3, [R2] /* Write backuped value into the register */
/* Loop iteration control */
SUBS R1, #1 /* Decrement loop counter by 1 and update APSR (Application Processor Status Register) */
BNE restore_loop_iter /* Loop continues until Z flag is set (still array item to handle) */
restore_loop_end:
BX LR /* Return to caller */
/* end of specific code section for standby */
END

View File

@@ -0,0 +1,189 @@
/**
******************************************************************************
* File Name : stm32wbaxx_ResetHandler.s
* Author : MCD Application Team
* Description : STM32WBA5xx Ultra Low Power Devices specific
* Reset handler for connectivity applications.
GCC toolchain.
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*
* Cortex-M version
*
******************************************************************************
*/
.syntax unified
.cpu cortex-m33
.fpu softvfp
.thumb
.extern SystemInit
.extern is_boot_from_standby
.extern SYS_WAITING_CYCLES_25
.global backup_system_register
.global restore_system_register
/* INIT_BSS macro is used to fill the specified region [start : end] with zeros */
.macro INIT_BSS start, end
ldr r0, =\start
ldr r1, =\end
movs r3, #0
bl LoopFillZerobss
.endm
/* INIT_DATA macro is used to copy data in the region [start : end] starting from 'src' */
.macro INIT_DATA start, end, src
ldr r0, =\start
ldr r1, =\end
ldr r2, =\src
movs r3, #0
bl LoopCopyDataInit
.endm
.section .text.data_initializers
CopyDataInit:
ldr r4, [r2, r3]
str r4, [r0, r3]
adds r3, r3, #4
LoopCopyDataInit:
adds r4, r0, r3
cmp r4, r1
bcc CopyDataInit
bx lr
FillZerobss:
str r3, [r0]
adds r0, r0, #4
LoopFillZerobss:
cmp r0, r1
bcc FillZerobss
bx lr
.section .text.Reset_Handler
.global Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr r0, =_estack
mov sp, r0 /* set stack pointer */
/* If we exit from standby mode, restore CPU context and jump to asleep point. */
BL is_boot_from_standby
CMP R0, #1
BEQ CPUcontextRestore
/* buffer for local variables (up to 10)from is_boot_from_standby*/
SUB SP, SP, #0x28
/* end of specific code section for standby */
/* Call the clock system initialization function.*/
bl SystemInit
/* Copy the data segment initializers from flash to SRAM */
INIT_DATA _sdata, _edata, _sidata
/* Zero fill the bss segments. */
INIT_BSS _sbss, _ebss
/* Call static constructors */
bl __libc_init_array
/* Call the application s entry point.*/
bl main
LoopForever:
b LoopForever
/* These 2 functions are designed to save and then restore CPU context. */
.global CPUcontextSave
.type CPUcontextSave, %function
CPUcontextSave:
PUSH { R4 - R12, LR } /* store R4 to R12 and LR (10 words) onto C stack */
LDR R4, =backup_MSP /* load address of backup_MSP into R4 */
MOV R3, SP /* load the stack pointer into R3 */
STR R3, [R4] /* store the MSP into backup_MSP */
DSB
WFI /* all saved, trigger deep sleep */
CPUcontextRestore:
/* Even if we fall through the WFI instruction, we will immediately
* execute a context restore and end up where we left off with no
* ill effects. Normally at this point the core will either be
* powered off or reset (depending on the deep sleep level). */
LDR R4, =backup_MSP /* load address of backup_MSP into R4 */
LDR R4, [R4] /* load the SP from backup_MSP */
MOV SP, R4 /* restore the SP from R4 */
POP { R4 - R12, PC } /* load R4 to R12 and PC (10 words) from C stack */
backup_system_register:
/* R0 -> register_backup_table array current item address */
/* R1 -> loop counter (from register_backup_table_size to 0) */
/* R2 -> register_backup_table array current item value */
backup_loop_init:
LDR R0, =register_backup_table /* R0 points to the first array item */
LDR R1, =register_backup_table_size
LDR R1, [R1] /* R1 contains the number of registers in the array */
backup_loop_iter:
/* Offset processing */
LDR R2, [R0], #4 /* R2 contains the register_backup_table current item (register address) */
/* R0 points to the next register_backup_table item (uint32_t items -> 4 bytes added to previous address) */
/* Register value backup */
LDR R2, [R2] /* R2 contains now the register value to backup */
PUSH {R2} /* Push register value into the stack */
/* Loop iteration control */
SUBS R1, #1 /* Decrement loop counter by 1 and update APSR (Application Processor Status Register) */
BNE backup_loop_iter /* Loop continues until Z flag is set (still array item to handle) */
backup_loop_end:
BX LR /* Return to caller */
restore_system_register:
/* R0 -> register_backup_table array current item address */
/* R1 -> loop counter (from register_backup_table_size to 0) */
/* R2 -> register_backup_table array current item value */
restore_loop_init:
LDR R0, =register_backup_table /* R0 points to the first array item */
/* Reverse loop: counter initial value processing */
LDR R1, =register_backup_table_size
LDR R1, [R1] /* R1 contains the number of registers in the array */
SUB R1, #1 /* R1 now contains last array item index (register_backup_table_size - 1) */
/* Reverse loop: apply offset to current array index (point to last array element) */
LSL R1, #2 /* Left shift R1 by 2 */
ADD R0, R1 /* R0 now points to last array item (register_backup_table + (register_backup_table_size - 1) * 4) */
LSR R1, #2 /* Reverse left shift operation on R1 */
ADD R1, #1 /* Re-add 1 to R1 (array length) */
/* Reverse loop */
restore_loop_iter:
/* Offset processing */
LDR R2, [R0], #-4 /* R2 contains the register_backup_table current item (register address) */
/* R0 now points to the previous register_backup_table item (uint32_t items -> 4 bytes subtracted to previous address) */
/* Register value restoration */
POP {R3} /* Head of stack popped into R3. R3 contains register value to restore */
STR R3, [R2] /* Write backuped value into the register */
/* Loop iteration control */
SUBS R1, #1 /* Decrement loop counter by 1 and update APSR (Application Processor Status Register) */
BNE restore_loop_iter /* Loop continues until Z flag is set (still array item to handle) */
restore_loop_end:
BX LR /* Return to caller */
/* end of specific code section for standby */
.end

View File

@@ -0,0 +1,134 @@
;********************************************************************************
;* File Name : stm32wbaxx_ResetHandler.s
;* Author : MCD Application Team
;* Description : STM32WBA5xx Ultra Low Power Devices specific
; Reset handler for connectivity applications.
; MDK-ARM toolchain.
;********************************************************************************
;* @attention
;*
;* Copyright (c) 2022 STMicroelectronics.
;* All rights reserved.
;*
;* This software is licensed under terms that can be found in the LICENSE file
;* in the root directory of this software component.
;* If no LICENSE file comes with this software, it is provided AS-IS.
;*
;*******************************************************************************
;
; Cortex-M version
;
PRESERVE8
THUMB
AREA |.text|, CODE, READONLY
; Reset_Handler
Reset_Handler PROC
EXPORT Reset_Handler
IMPORT SystemInit
IMPORT __main
IMPORT is_boot_from_standby
IMPORT backup_MSP
IMPORT register_backup_table
IMPORT register_backup_table_size
EXPORT CPUcontextSave
EXPORT backup_system_register
EXPORT restore_system_register
; If we exit from standby mode, restore CPU context and jump to asleep point.
BL is_boot_from_standby
CMP R0, #1
BEQ CPUcontextRestore
; buffer for local variables (up to 10)from is_boot_from_standby.
SUB SP, SP, #0x28
; end of specific code section for standby
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
; These 2 functions are designed to save and then restore CPU context.
CPUcontextSave
PUSH { R4 - R12, lr } ; store R4 to R12 and LR (10 words) onto C stack
LDR R4, =backup_MSP ; load address of backup_MSP into R4
MOV R3, SP ; load the stack pointer into R3
STR R3, [R4] ; store the MSP into backup_MSP
DSB
WFI ; all saved, trigger deep sleep
CPUcontextRestore
; Even if we fall through the WFI instruction, we will immediately
; execute a context restore and end up where we left off with no
; ill effects. Normally at this point the core will either be
; powered off or reset (depending on the deep sleep level).
LDR R4, =backup_MSP ; load address of backup_MSP into R4.
LDR R4, [R4] ; load the SP from backup_MSP.
MOV SP, R4 ; restore the SP from R4.
POP { R4 - R12, PC } ; load R4-R12 and PC (10 words) from C stack
; end of specific code section for standby.
backup_system_register
; R0 -> register_backup_table array current item address
; R1 -> loop counter (from register_backup_table_size to 0)
; R2 -> register_backup_table array current item value
backup_loop_init
LDR R0, =register_backup_table ; R0 points to the first array item
LDR R1, =register_backup_table_size
LDR R1, [R1] ; R1 contains the number of registers in the array
backup_loop_iter
; Offset processing
LDR R2, [R0], #4 ; R2 contains the register_backup_table current item (register address)
; R0 points to the next register_backup_table item (uint32_t items -> 4 bytes added to previous address)
; Register value backup
LDR R2, [R2] ; R2 contains now the register value to backup
PUSH {R2} ; Push register value into the stack
; Loop iteration control
SUBS R1, #1 ; Decrement loop counter by 1 and update APSR (Application Processor Status Register)
BNE backup_loop_iter ; Loop continues until Z flag is set (still array item to handle)
backup_loop_end
BX LR ; Return to caller
restore_system_register
; R0 -> register_backup_table array current item address
; R1 -> loop counter (from register_backup_table_size to 0)
; R2 -> register_backup_table array current item value
restore_loop_init
LDR R0, =register_backup_table ; R0 points to the first array item
; Reverse loop: counter initial value processing
LDR R1, =register_backup_table_size
LDR R1, [R1] ; R1 contains the number of registers in the array
SUB R1, #1 ; R1 now contains last array item index (register_backup_table_size - 1)
; Reverse loop: apply offset to current array index (point to last array element)
ADD R0, R1, LSL #2 ; R0 now points to last array item (register_backup_table + (register_backup_table_size - 1) * 4)
ADD R1, #1 ; Re-add 1 to R1 (array length)
; Reverse loop
restore_loop_iter
; Offset processing
LDR R2, [R0], #-4 ; R2 contains the register_backup_table current item (register address)
; R0 now points to the previous register_backup_table item (uint32_t items -> 4 bytes subtracted to previous address)
; Register value restoration
POP {R3} ; Head of stack popped into R3. R3 contains register value to restore
STR R3, [R2] ; Write backuped value into the register
; Loop iteration control
SUBS R1, #1 ; Decrement loop counter by 1 and update APSR (Application Processor Status Register)
BNE restore_loop_iter ; Loop continues until Z flag is set (still array item to handle)
restore_loop_end
BX LR ; Return to caller
END