Trinity Devboard PCB V1.0 Firmware. FreeRTOS is setup and the MCU reads IMU data over SPI fand Magnetometer data over I2C, each with a seperate task. Sensordata is then run though MadgwickAHRS and send over USB as serial packet data to use in trinity visualizer. Bare minimum functionality works and is replicated from the first prototype.

This commit is contained in:
2026-09-13 19:51:03 +02:00
commit 7ee381de58
1630 changed files with 632404 additions and 0 deletions
+626
View File
@@ -0,0 +1,626 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file app_entry.c
* @author MCD Application Team
* @brief Entry point of the application
******************************************************************************
* @attention
*
* Copyright (c) 2026 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 "app_common.h"
#include "main.h"
#include "app_entry.h"
#include "ble.h"
#include "tl.h"
#include "cmsis_os.h"
#include "shci_tl.h"
#include "stm32_lpm.h"
#include "app_debug.h"
#include "dbg_trace.h"
#include "shci.h"
#include "otp.h"
/* Private includes -----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
extern RTC_HandleTypeDef hrtc;
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private defines -----------------------------------------------------------*/
#define POOL_SIZE (CFG_TLBLE_EVT_QUEUE_LENGTH*4U*DIVC((sizeof(TL_PacketHeader_t) + TL_BLE_EVENT_FRAME_SIZE), 4U))
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macros ------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t EvtPool[POOL_SIZE];
PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static TL_CmdPacket_t SystemCmdBuffer;
PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t SystemSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255U];
PLACE_IN_SECTION("MB_MEM2") ALIGN(4) static uint8_t BleSpareEvtBuffer[sizeof(TL_PacketHeader_t) + TL_EVT_HDR_SIZE + 255];
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Global variables ----------------------------------------------------------*/
osMutexId_t MtxShciId;
osSemaphoreId_t SemShciId;
osThreadId_t ShciUserEvtProcessId;
const osThreadAttr_t ShciUserEvtProcess_attr = {
.name = CFG_SHCI_USER_EVT_PROCESS_NAME,
.attr_bits = CFG_SHCI_USER_EVT_PROCESS_ATTR_BITS,
.cb_mem = CFG_SHCI_USER_EVT_PROCESS_CB_MEM,
.cb_size = CFG_SHCI_USER_EVT_PROCESS_CB_SIZE,
.stack_mem = CFG_SHCI_USER_EVT_PROCESS_STACK_MEM,
.priority = CFG_SHCI_USER_EVT_PROCESS_PRIORITY,
.stack_size = CFG_SHCI_USER_EVT_PROCESS_STACK_SIZE
};
/* Private functions prototypes-----------------------------------------------*/
static void ShciUserEvtProcess(void *argument);
static void Config_HSE(void);
static void Reset_Device(void);
#if (CFG_HW_RESET_BY_FW == 1)
static void Reset_IPCC(void);
static void Reset_BackupDomain(void);
#endif /* CFG_HW_RESET_BY_FW == 1*/
static void System_Init(void);
static void SystemPower_Config(void);
static void appe_Tl_Init(void);
static void APPE_SysStatusNot(SHCI_TL_CmdStatus_t status);
static void APPE_SysUserEvtRx(void * pPayload);
static void APPE_SysEvtReadyProcessing(void * pPayload);
static void APPE_SysEvtError(void * pPayload);
static void Init_Rtc(void);
__WEAK void APP_BLE_Init(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Functions Definition ------------------------------------------------------*/
void MX_APPE_Config(void)
{
/**
* The OPTVERR flag is wrongly set at power on
* It shall be cleared before using any HAL_FLASH_xxx() api
*/
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
/**
* Reset some configurations so that the system behave in the same way
* when either out of nReset or Power On
*/
Reset_Device();
/* Configure HSE Tuning */
Config_HSE();
return;
}
void MX_APPE_Init(void)
{
System_Init(); /**< System initialization */
SystemPower_Config(); /**< Configure the system Power Mode */
HW_TS_Init(hw_ts_InitMode_Full, &hrtc); /**< Initialize the TimerServer */
/* USER CODE BEGIN APPE_Init_1 */
/* USER CODE END APPE_Init_1 */
appe_Tl_Init(); /* Initialize all transport layers */
/**
* From now, the application is waiting for the ready event (VS_HCI_C2_Ready)
* received on the system channel before starting the Stack
* This system event is received with APPE_SysUserEvtRx()
*/
/* USER CODE BEGIN APPE_Init_2 */
/* USER CODE END APPE_Init_2 */
return;
}
void Init_Smps(void)
{
#if (CFG_USE_SMPS != 0)
/**
* Configure and enable SMPS
*
* The SMPS configuration is not yet supported by CubeMx
* when SMPS output voltage is set to 1.4V, the RF output power is limited to 3.7dBm
* the SMPS output voltage shall be increased for higher RF output power
*/
LL_PWR_SMPS_SetStartupCurrent(LL_PWR_SMPS_STARTUP_CURRENT_80MA);
LL_PWR_SMPS_SetOutputVoltageLevel(LL_PWR_SMPS_OUTPUT_VOLTAGE_1V40);
LL_PWR_SMPS_Enable();
#endif /* CFG_USE_SMPS != 0 */
return;
}
void Init_Exti(void)
{
/* Enable IPCC(36), HSEM(38) wakeup interrupts on CPU1 */
LL_EXTI_EnableIT_32_63(LL_EXTI_LINE_36 | LL_EXTI_LINE_38);
return;
}
/* USER CODE BEGIN FD */
/* USER CODE END FD */
/*************************************************************
*
* LOCAL FUNCTIONS
*
*************************************************************/
static void Reset_Device(void)
{
#if (CFG_HW_RESET_BY_FW == 1)
Reset_BackupDomain();
Reset_IPCC();
#endif /* CFG_HW_RESET_BY_FW == 1 */
return;
}
#if (CFG_HW_RESET_BY_FW == 1)
static void Reset_BackupDomain(void)
{
if ((LL_RCC_IsActiveFlag_PINRST() != FALSE) && (LL_RCC_IsActiveFlag_SFTRST() == FALSE))
{
HAL_PWR_EnableBkUpAccess(); /**< Enable access to the RTC registers */
/**
* Write twice the value to flush the APB-AHB bridge
* This bit shall be written in the register before writing the next one
*/
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_BACKUPRESET_FORCE();
__HAL_RCC_BACKUPRESET_RELEASE();
}
return;
}
static void Reset_IPCC(void)
{
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_IPCC);
LL_C1_IPCC_ClearFlag_CHx(
IPCC,
LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | LL_IPCC_CHANNEL_4
| LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6);
LL_C2_IPCC_ClearFlag_CHx(
IPCC,
LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | LL_IPCC_CHANNEL_4
| LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6);
LL_C1_IPCC_DisableTransmitChannel(
IPCC,
LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | LL_IPCC_CHANNEL_4
| LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6);
LL_C2_IPCC_DisableTransmitChannel(
IPCC,
LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | LL_IPCC_CHANNEL_4
| LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6);
LL_C1_IPCC_DisableReceiveChannel(
IPCC,
LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | LL_IPCC_CHANNEL_4
| LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6);
LL_C2_IPCC_DisableReceiveChannel(
IPCC,
LL_IPCC_CHANNEL_1 | LL_IPCC_CHANNEL_2 | LL_IPCC_CHANNEL_3 | LL_IPCC_CHANNEL_4
| LL_IPCC_CHANNEL_5 | LL_IPCC_CHANNEL_6);
return;
}
#endif /* CFG_HW_RESET_BY_FW == 1 */
static void Config_HSE(void)
{
OTP_ID0_t * p_otp;
/**
* Read HSE_Tuning from OTP
*/
p_otp = (OTP_ID0_t *) OTP_Read(0);
if (p_otp)
{
LL_RCC_HSE_SetCapacitorTuning(p_otp->hse_tuning);
}
return;
}
static void System_Init(void)
{
Init_Smps();
Init_Exti();
Init_Rtc();
return;
}
static void Init_Rtc(void)
{
/* Disable RTC registers write protection */
LL_RTC_DisableWriteProtection(RTC);
LL_RTC_WAKEUP_SetClock(RTC, CFG_RTC_WUCKSEL_DIVIDER);
/* Enable RTC registers write protection */
LL_RTC_EnableWriteProtection(RTC);
return;
}
/**
* @brief Configure the system for power optimization
*
* @note This API configures the system to be ready for low power mode
*
* @param None
* @retval None
*/
static void SystemPower_Config(void)
{
/**
* Select HSI as system clock source after Wake Up from Stop mode
*/
LL_RCC_SetClkAfterWakeFromStop(LL_RCC_STOP_WAKEUPCLOCK_HSI);
/* Initialize low power manager */
UTIL_LPM_Init();
/* Initialize the CPU2 reset value before starting CPU2 with C2BOOT */
LL_C2_PWR_SetPowerMode(LL_PWR_MODE_SHUTDOWN);
#if (CFG_USB_INTERFACE_ENABLE != 0)
/**
* Enable USB power
*/
HAL_PWREx_EnableVddUSB();
#endif /* CFG_USB_INTERFACE_ENABLE != 0 */
return;
}
static void appe_Tl_Init(void)
{
TL_MM_Config_t tl_mm_config;
SHCI_TL_HciInitConf_t SHci_Tl_Init_Conf;
/**< Reference table initialization */
TL_Init();
MtxShciId = osMutexNew(NULL);
SemShciId = osSemaphoreNew(1, 0, NULL); /*< Create the semaphore and make it busy at initialization */
/** FreeRTOS system task creation */
ShciUserEvtProcessId = osThreadNew(ShciUserEvtProcess, NULL, &ShciUserEvtProcess_attr);
/**< System channel initialization */
SHci_Tl_Init_Conf.p_cmdbuffer = (uint8_t*)&SystemCmdBuffer;
SHci_Tl_Init_Conf.StatusNotCallBack = APPE_SysStatusNot;
shci_init(APPE_SysUserEvtRx, (void*) &SHci_Tl_Init_Conf);
/**< Memory Manager channel initialization */
tl_mm_config.p_BleSpareEvtBuffer = BleSpareEvtBuffer;
tl_mm_config.p_SystemSpareEvtBuffer = SystemSpareEvtBuffer;
tl_mm_config.p_AsynchEvtPool = EvtPool;
tl_mm_config.AsynchEvtPoolSize = POOL_SIZE;
TL_MM_Init(&tl_mm_config);
TL_Enable();
return;
}
__WEAK void APP_BLE_Init(void)
{
}
static void APPE_SysStatusNot(SHCI_TL_CmdStatus_t status)
{
switch (status)
{
case SHCI_TL_CmdBusy:
osMutexAcquire(MtxShciId, osWaitForever);
break;
case SHCI_TL_CmdAvailable:
osMutexRelease(MtxShciId);
break;
default:
break;
}
return;
}
/**
* The type of the payload for a system user event is tSHCI_UserEvtRxParam
* When the system event is both :
* - a ready event (subevtcode = SHCI_SUB_EVT_CODE_READY)
* - reported by the FUS (sysevt_ready_rsp == FUS_FW_RUNNING)
* The buffer shall not be released
* (eg ((tSHCI_UserEvtRxParam*)pPayload)->status shall be set to SHCI_TL_UserEventFlow_Disable)
* When the status is not filled, the buffer is released by default
*/
static void APPE_SysUserEvtRx(void * pPayload)
{
TL_AsynchEvt_t *p_sys_event;
WirelessFwInfo_t WirelessInfo;
p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload);
switch(p_sys_event->subevtcode)
{
case SHCI_SUB_EVT_CODE_READY:
/* Read the firmware version of both the wireless firmware and the FUS */
SHCI_GetWirelessFwInfo(&WirelessInfo);
APP_DBG_MSG("Wireless Firmware version %d.%d.%d\n", WirelessInfo.VersionMajor, WirelessInfo.VersionMinor, WirelessInfo.VersionSub);
APP_DBG_MSG("Wireless Firmware build %d\n", WirelessInfo.VersionReleaseType);
APP_DBG_MSG("FUS version %d.%d.%d\n", WirelessInfo.FusVersionMajor, WirelessInfo.FusVersionMinor, WirelessInfo.FusVersionSub);
APP_DBG_MSG(">>== SHCI_SUB_EVT_CODE_READY\n\r");
APPE_SysEvtReadyProcessing(pPayload);
break;
case SHCI_SUB_EVT_ERROR_NOTIF:
APP_DBG_MSG(">>== SHCI_SUB_EVT_ERROR_NOTIF \n\r");
APPE_SysEvtError(pPayload);
break;
case SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE:
APP_DBG_MSG(">>== SHCI_SUB_EVT_BLE_NVM_RAM_UPDATE -- BLE NVM RAM HAS BEEN UPDATED BY CPU2 \n");
APP_DBG_MSG(" - StartAddress = %lx , Size = %ld\n",
((SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload)->StartAddress,
((SHCI_C2_BleNvmRamUpdate_Evt_t*)p_sys_event->payload)->Size);
break;
case SHCI_SUB_EVT_NVM_START_WRITE:
APP_DBG_MSG("==>> SHCI_SUB_EVT_NVM_START_WRITE : NumberOfWords = %ld\n",
((SHCI_C2_NvmStartWrite_Evt_t*)p_sys_event->payload)->NumberOfWords);
break;
case SHCI_SUB_EVT_NVM_END_WRITE:
APP_DBG_MSG(">>== SHCI_SUB_EVT_NVM_END_WRITE\n\r");
break;
case SHCI_SUB_EVT_NVM_START_ERASE:
APP_DBG_MSG("==>>SHCI_SUB_EVT_NVM_START_ERASE : NumberOfSectors = %ld\n",
((SHCI_C2_NvmStartErase_Evt_t*)p_sys_event->payload)->NumberOfSectors);
break;
case SHCI_SUB_EVT_NVM_END_ERASE:
APP_DBG_MSG(">>== SHCI_SUB_EVT_NVM_END_ERASE\n\r");
break;
default:
break;
}
return;
}
/**
* @brief Notify a system error coming from the M0 firmware
* @param ErrorCode : errorCode detected by the M0 firmware
*
* @retval None
*/
static void APPE_SysEvtError(void * pPayload)
{
TL_AsynchEvt_t *p_sys_event;
SCHI_SystemErrCode_t *p_sys_error_code;
p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload);
p_sys_error_code = (SCHI_SystemErrCode_t*) p_sys_event->payload;
APP_DBG_MSG(">>== SHCI_SUB_EVT_ERROR_NOTIF WITH REASON %x \n\r",(*p_sys_error_code));
if ((*p_sys_error_code) == ERR_BLE_INIT)
{
/* Error during BLE stack initialization */
APP_DBG_MSG(">>== SHCI_SUB_EVT_ERROR_NOTIF WITH REASON - ERR_BLE_INIT \n");
}
else
{
APP_DBG_MSG(">>== SHCI_SUB_EVT_ERROR_NOTIF WITH REASON - BLE ERROR \n");
}
return;
}
static void APPE_SysEvtReadyProcessing(void * pPayload)
{
TL_AsynchEvt_t *p_sys_event;
SHCI_C2_Ready_Evt_t *p_sys_ready_event;
SHCI_C2_CONFIG_Cmd_Param_t config_param = {0};
uint32_t RevisionID=0;
uint32_t DeviceID=0;
p_sys_event = (TL_AsynchEvt_t*)(((tSHCI_UserEvtRxParam*)pPayload)->pckt->evtserial.evt.payload);
p_sys_ready_event = (SHCI_C2_Ready_Evt_t*) p_sys_event->payload;
if (p_sys_ready_event->sysevt_ready_rsp == WIRELESS_FW_RUNNING)
{
/**
* The wireless firmware is running on the CPU2
*/
APP_DBG_MSG(">>== WIRELESS_FW_RUNNING \n");
/* Traces channel initialization */
APPD_EnableCPU2();
/* Enable all events Notification */
config_param.PayloadCmdSize = SHCI_C2_CONFIG_PAYLOAD_CMD_SIZE;
config_param.EvtMask1 = SHCI_C2_CONFIG_EVTMASK1_BIT0_ERROR_NOTIF_ENABLE
+ SHCI_C2_CONFIG_EVTMASK1_BIT1_BLE_NVM_RAM_UPDATE_ENABLE
+ SHCI_C2_CONFIG_EVTMASK1_BIT2_THREAD_NVM_RAM_UPDATE_ENABLE
+ SHCI_C2_CONFIG_EVTMASK1_BIT3_NVM_START_WRITE_ENABLE
+ SHCI_C2_CONFIG_EVTMASK1_BIT4_NVM_END_WRITE_ENABLE
+ SHCI_C2_CONFIG_EVTMASK1_BIT5_NVM_START_ERASE_ENABLE
+ SHCI_C2_CONFIG_EVTMASK1_BIT6_NVM_END_ERASE_ENABLE;
/* Read revision identifier */
/**
* @brief Return the device revision identifier
* @note This field indicates the revision of the device.
* @rmtoll DBGMCU_IDCODE REV_ID LL_DBGMCU_GetRevisionID
* @retval Values between Min_Data=0x00 and Max_Data=0xFFFF
*/
RevisionID = LL_DBGMCU_GetRevisionID();
APP_DBG_MSG(">>== DBGMCU_GetRevisionID= %lx \n\r", RevisionID);
config_param.RevisionID = (uint16_t)RevisionID;
DeviceID = LL_DBGMCU_GetDeviceID();
APP_DBG_MSG(">>== DBGMCU_GetDeviceID= %lx \n\r", DeviceID);
config_param.DeviceID = (uint16_t)DeviceID;
(void)SHCI_C2_Config(&config_param);
APP_BLE_Init();
UTIL_LPM_SetOffMode(1U << CFG_LPM_APP, UTIL_LPM_ENABLE);
}
else if (p_sys_ready_event->sysevt_ready_rsp == FUS_FW_RUNNING)
{
/**
* The FUS firmware is running on the CPU2
* In the scope of this application, there should be no case when we get here
*/
APP_DBG_MSG(">>== SHCI_SUB_EVT_CODE_READY - FUS_FW_RUNNING \n\r");
/* The packet shall not be released as this is not supported by the FUS */
((tSHCI_UserEvtRxParam*)pPayload)->status = SHCI_TL_UserEventFlow_Disable;
}
else
{
APP_DBG_MSG(">>== SHCI_SUB_EVT_CODE_READY - UNEXPECTED CASE \n\r");
}
return;
}
/*************************************************************
*
* FREERTOS WRAPPER FUNCTIONS
*
*************************************************************/
static void ShciUserEvtProcess(void *argument)
{
UNUSED(argument);
for(;;)
{
/* USER CODE BEGIN SHCI_USER_EVT_PROCESS_1 */
/* USER CODE END SHCI_USER_EVT_PROCESS_1 */
osThreadFlagsWait(1, osFlagsWaitAny, osWaitForever);
shci_user_evt_proc();
/* USER CODE BEGIN SHCI_USER_EVT_PROCESS_2 */
/* USER CODE END SHCI_USER_EVT_PROCESS_2 */
}
}
/* USER CODE BEGIN FD_LOCAL_FUNCTIONS */
/* USER CODE END FD_LOCAL_FUNCTIONS */
/*************************************************************
*
* WRAP FUNCTIONS
*
*************************************************************/
void HAL_Delay(uint32_t Delay)
{
uint32_t tickstart = HAL_GetTick();
uint32_t wait = Delay;
/* Add a freq to guarantee minimum wait */
if (wait < HAL_MAX_DELAY)
{
wait += HAL_GetTickFreq();
}
while ((HAL_GetTick() - tickstart) < wait)
{
/************************************************************************************
* ENTER SLEEP MODE
***********************************************************************************/
LL_LPM_EnableSleep(); /**< Clear SLEEPDEEP bit of Cortex System Control Register */
/**
* This option is used to ensure that store operations are completed
*/
#if defined (__CC_ARM) || defined (__ARMCC_VERSION)
__force_stores();
#endif /* __ARMCC_VERSION */
__WFI();
}
}
void shci_notify_asynch_evt(void* pdata)
{
UNUSED(pdata);
osThreadFlagsSet(ShciUserEvtProcessId, 1);
return;
}
void shci_cmd_resp_release(uint32_t flag)
{
UNUSED(flag);
osSemaphoreRelease(SemShciId);
return;
}
void shci_cmd_resp_wait(uint32_t timeout)
{
UNUSED(timeout);
osSemaphoreAcquire(SemShciId, osWaitForever);
return;
}
/* USER CODE BEGIN FD_WRAP_FUNCTIONS */
/* USER CODE END FD_WRAP_FUNCTIONS */