ソースを参照

故障安全:NMI_Handler() 和 Error_Handler() 现在都会先强制关闭 PLSR 定时器、计数器并将输出置为安全电平。[stm32f4xx_it.c (line 73)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/Core/Src/stm32f4xx_it.c:73) [main.c (line 310)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/Core/Src/main.c:310)

增量规划:不再单次填满 1024 项队列。启动预填 400 项,运行期补到 800 项,每轮最多生成 200 项;按 100 kHz 极限分别提供约 4 ms、8 ms 缓冲,并限制单轮计算量。[plsr.c (line 50)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/PLSR/Src/plsr.c:50) [plsr.c (line 1918)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/PLSR/Src/plsr.c:1918)

USB CDC:移除了主程序中的 USB 头文件和 MX_USB_DEVICE_Init(),未使用的 USB 不再启动,也不会启用 OTG 最高优先级中断。[main.c (line 118)](F:/Xinje_Modbus_IAR/TrainCamp_yuwenhao_modbus/Core/Src/main.c:118)
codex/plsr-2026-minimal
ywh 1ヶ月前
コミット
295a259215
3個のファイルの変更38行の追加12行の削除
  1. +2
    -2
      Core/Src/main.c
  2. +2
    -1
      Core/Src/stm32f4xx_it.c
  3. +34
    -9
      PLSR/Src/plsr.c

+ 2
- 2
Core/Src/main.c ファイルの表示

@@ -18,7 +18,6 @@
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
@@ -58,6 +57,7 @@ static void MX_DMA_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
static void AppTaskStart(void *pArg);
extern void PlsrPlatformForceSafeOutputsFromFault(void);

/* USER CODE END PFP */

@@ -118,7 +118,6 @@ int main(void)
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USB_DEVICE_Init();
MX_USART1_UART_Init();
if (PlsrInit() == 0U)
{
@@ -313,6 +312,7 @@ void Error_Handler(void)
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state
*/
PlsrPlatformForceSafeOutputsFromFault();
__disable_irq();
while (1)
{


+ 2
- 1
Core/Src/stm32f4xx_it.c ファイルの表示

@@ -73,7 +73,8 @@ extern UART_HandleTypeDef huart1;
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */

/* CSS clock failures can leave autonomous pulse timers running. */
PlsrPlatformForceSafeOutputsFromFault();
/* USER CODE END NonMaskableInt_IRQn 0 */
HAL_RCC_NMI_IRQHandler();
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */


+ 34
- 9
PLSR/Src/plsr.c ファイルの表示

@@ -49,6 +49,13 @@
#define PLSR_POSITION_CHECKPOINT_MS (10U)
#define PLSR_PROFILE_QUEUE_CAPACITY (1024U)
#define PLSR_PROFILE_QUEUE_MASK (PLSR_PROFILE_QUEUE_CAPACITY - 1U)
/* A profile item can represent only one pulse. At the 100 kHz limit these
thresholds provide 4 ms of startup data, refill toward 8 ms, and cap each
1 ms producer pass at 2 ms worth of newly planned items. */
#define PLSR_PROFILE_STARTUP_TARGET (400U)
#define PLSR_PROFILE_STARTUP_BUDGET (400U)
#define PLSR_PROFILE_REFILL_TARGET (800U)
#define PLSR_PROFILE_REFILL_BUDGET (200U)
#define PLSR_HANDOFF_WARMUP_ITEMS (8U)
#define PLSR_REPLAN_WARMUP_ITEMS (8U)
#define PLSR_RAMP_POLL_RESERVE_AREA_DIVISOR (20ULL)
@@ -320,7 +327,8 @@ static uint8_t PlsrProfileQueueBegin(
uint32_t producerEpoch,
uint8_t producerSegment,
uint8_t preparedHandoffBank);
static uint8_t PlsrProfileQueueFill(uint16_t targetCount);
static uint8_t PlsrProfileQueueFill(uint16_t targetCount,
uint16_t *itemBudget);
static uint8_t PlsrStageCountedHandoff(void);
static PLSR_PLATFORM_QUEUE_RESULT PlsrProfileQueueCommitNext(
uint8_t pulseOutput);
@@ -1764,6 +1772,7 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
uint32_t epoch;
uint8_t segmentNumber;
uint8_t handoffBank;
uint16_t fillBudget = PLSR_REPLAN_WARMUP_ITEMS;

PlsrRamp.active = 0U;
PlsrShortProfile.active = 0U;
@@ -1794,7 +1803,8 @@ static uint8_t PlsrReplanPulseDir(uint32_t targetHz,
handoffBank = PlsrPreparedHandoffBank;
(void)PlsrProfileQueueBegin(&PlsrShortProfile, epoch,
segmentNumber, handoffBank);
if (PlsrProfileQueueFill(PLSR_REPLAN_WARMUP_ITEMS) == 0U)
if (PlsrProfileQueueFill(PLSR_REPLAN_WARMUP_ITEMS,
&fillBudget) == 0U)
{
PlsrProfileQueueReset();
PlsrShortProfile.active = 0U;
@@ -1905,7 +1915,8 @@ static void PlsrProfileRecordProducerCycles(uint32_t startCycles)
}
#endif

static uint8_t PlsrProfileQueueFill(uint16_t targetCount)
static uint8_t PlsrProfileQueueFill(uint16_t targetCount,
uint16_t *itemBudget)
{
PLSR_SHORT_PROFILE candidate;
PLSR_PROFILE_ENTRY entry;
@@ -1918,6 +1929,10 @@ static uint8_t PlsrProfileQueueFill(uint16_t targetCount)
uint32_t startCycles;
#endif

if (itemBudget == NULL)
{
return 0U;
}
if ((targetCount == 0U)
|| (targetCount > PLSR_PROFILE_QUEUE_CAPACITY))
{
@@ -1928,11 +1943,13 @@ static uint8_t PlsrProfileQueueFill(uint16_t targetCount)
criticalState = PlsrPlatformEnterCritical();
if ((PlsrProfileQueue.active == 0U)
|| (PlsrProfileQueue.generatorComplete != 0U)
|| (PlsrProfileQueueCount() >= targetCount))
|| (PlsrProfileQueueCount() >= targetCount)
|| (*itemBudget == 0U))
{
PlsrPlatformExitCritical(criticalState);
return 1U;
}
(*itemBudget)--;
generation = PlsrProfileQueue.generation;
producerEpoch = PlsrProfileQueue.producerEpoch;
PlsrCopyShortProfile(&candidate,
@@ -2196,6 +2213,7 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
uint32_t profileEpoch;
uint8_t profileSegment;
uint8_t profileHandoffBank;
uint16_t fillBudget = PLSR_PROFILE_STARTUP_BUDGET;
PLSR_PROFILE_ENTRY firstRun;

PlsrSegmentClockStarted = 1U;
@@ -2220,7 +2238,8 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
profileEpoch,
profileSegment,
profileHandoffBank);
if (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)
if (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET,
&fillBudget) == 0U)
{
PlsrProfileQueueReset();
PlsrShortProfile.active = 0U;
@@ -2228,7 +2247,8 @@ static uint8_t PlsrBeginSegmentOutput(uint32_t startFrequencyHz)
}
PlsrCountedHandoffStaged = 0U;
if ((PlsrStageCountedHandoff() == 0U)
|| (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U))
|| (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET,
&fillBudget) == 0U))
{
PlsrProfileQueueReset();
PlsrShortProfile.active = 0U;
@@ -3156,6 +3176,7 @@ static uint8_t PlsrPrepareFutureHandoffQueue(void)
const PLSR_HANDOFF_PLAN *prepared;
uint8_t currentSegment = PlsrCurrentSegment;
uint8_t preparedBank = PlsrPreparedHandoffBank;
uint16_t fillBudget = PLSR_PROFILE_STARTUP_BUDGET;

PlsrProfileQueueReset();
if ((currentSegment == 0U)
@@ -3173,7 +3194,8 @@ static uint8_t PlsrPrepareFutureHandoffQueue(void)
PlsrSegmentEpoch + 1UL,
prepared->nextSegment,
preparedBank);
if (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)
if (PlsrProfileQueueFill(PLSR_PROFILE_STARTUP_TARGET,
&fillBudget) == 0U)
{
PlsrProfileQueueReset();
return 0U;
@@ -4015,6 +4037,7 @@ void PlsrPoll1ms(void)
uint32_t criticalState;
uint32_t newTargetHz;
uint32_t pollEpoch;
uint16_t fillBudget = PLSR_PROFILE_REFILL_BUDGET;

if (PlsrInitialized == 0U)
{
@@ -4046,7 +4069,8 @@ void PlsrPoll1ms(void)
|| (PlsrExecutor.mode == PLSR_EXEC_STREAM))
&& (PlsrProfileQueue.active != 0U)
&& (PlsrProfileQueue.generatorComplete == 0U)
&& (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U))
&& (PlsrProfileQueueFill(PLSR_PROFILE_REFILL_TARGET,
&fillBudget) == 0U))
{
PlsrEnterError(PLSR_ERROR_TIMER);
return;
@@ -4054,7 +4078,8 @@ void PlsrPoll1ms(void)
if (((PlsrExecutor.mode == PLSR_EXEC_STEP_TABLE)
|| (PlsrExecutor.mode == PLSR_EXEC_STREAM))
&& ((PlsrStageCountedHandoff() == 0U)
|| (PlsrProfileQueueFill(PLSR_PROFILE_QUEUE_CAPACITY) == 0U)))
|| (PlsrProfileQueueFill(PLSR_PROFILE_REFILL_TARGET,
&fillBudget) == 0U)))
{
PlsrEnterError(PLSR_ERROR_TIMER);
return;


読み込み中…
キャンセル
保存