You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1399 lines
48 KiB

  1. #include "plsr_planner.h"
  2. #include <stddef.h>
  3. #include <string.h>
  4. #define PLSR_PLANNER_Q32_ONE (4294967296ULL)
  5. #if !defined(PLSR_HOST_TEST)
  6. #define PLSR_PLANNER_BENCHMARK_DEMCR_ADDRESS (0xE000EDFCUL)
  7. #define PLSR_PLANNER_BENCHMARK_DWT_CTRL (0xE0001000UL)
  8. #define PLSR_PLANNER_BENCHMARK_DWT_CYCCNT (0xE0001004UL)
  9. #define PLSR_PLANNER_BENCHMARK_TRCENA (1UL << 24U)
  10. #define PLSR_PLANNER_BENCHMARK_CYCCNTENA (1UL << 0U)
  11. #define PLSR_PLANNER_BENCHMARK_PULSES (100000UL)
  12. #define PLSR_PLANNER_BENCHMARK_BATCH_CALLS (128UL)
  13. #define PLSR_PLANNER_BENCHMARK_TARGET_HZ (100000UL)
  14. volatile uint32_t PlsrPlannerBenchmarkRequest;
  15. volatile uint32_t PlsrPlannerBenchmarkRunning;
  16. volatile uint32_t PlsrPlannerBenchmarkRunCount;
  17. volatile uint32_t PlsrPlannerBenchmarkCoreClockHz = 168000000UL;
  18. volatile PLSR_PLANNER_BENCHMARK_RESULT PlsrPlannerBenchmarkResults[3];
  19. #endif
  20. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  21. && !defined(PLSR_HOST_TEST)
  22. #define PLSR_PLANNER_CYCCNT_ADDRESS (0xE0001004UL)
  23. volatile PLSR_PLANNER_TIMING PlsrPlannerTiming;
  24. static uint32_t PlsrPlannerTimingNow(void)
  25. {
  26. return *((volatile uint32_t *)PLSR_PLANNER_CYCCNT_ADDRESS);
  27. }
  28. static void PlsrPlannerTimingRecord(
  29. volatile PLSR_PLANNER_TIMING_SAMPLE *sample,
  30. uint32_t startedAt)
  31. {
  32. uint32_t elapsed = PlsrPlannerTimingNow() - startedAt;
  33. uint32_t total = sample->totalCycles;
  34. sample->lastCycles = elapsed;
  35. if ((sample->callCount == 0UL) || (elapsed < sample->minCycles))
  36. {
  37. sample->minCycles = elapsed;
  38. }
  39. if (sample->callCount != 0xFFFFFFFFUL)
  40. {
  41. sample->callCount++;
  42. }
  43. sample->totalCycles = (elapsed > (0xFFFFFFFFUL - total))
  44. ? 0xFFFFFFFFUL : total + elapsed;
  45. if (elapsed > sample->maxCycles)
  46. {
  47. sample->maxCycles = elapsed;
  48. }
  49. }
  50. void PlsrPlannerTimingReset(void)
  51. {
  52. (void)memset((void *)&PlsrPlannerTiming, 0, sizeof(PlsrPlannerTiming));
  53. }
  54. #endif
  55. static const uint32_t PlsrPlannerSmoothIntegralQ24[65] =
  56. {
  57. 0UL, 64UL, 504UL, 1688UL, 3968UL, 7688UL, 13176UL, 20752UL,
  58. 30720UL, 43376UL, 59000UL, 77864UL, 100224UL, 126328UL, 156408UL,
  59. 190688UL, 229376UL, 272672UL, 320760UL, 373816UL, 432000UL,
  60. 495464UL, 564344UL, 638768UL, 718848UL, 804688UL, 896376UL,
  61. 993992UL, 1097600UL, 1207256UL, 1323000UL, 1444864UL, 1572864UL,
  62. 1707008UL, 1847288UL, 1993688UL, 2146176UL, 2304712UL, 2469240UL,
  63. 2639696UL, 2816000UL, 2998064UL, 3185784UL, 3379048UL, 3577728UL,
  64. 3781688UL, 3990776UL, 4204832UL, 4423680UL, 4647136UL, 4875000UL,
  65. 5107064UL, 5343104UL, 5582888UL, 5826168UL, 6072688UL, 6322176UL,
  66. 6574352UL, 6828920UL, 7085576UL, 7344000UL, 7603864UL, 7864824UL,
  67. 8126528UL, 8388608UL
  68. };
  69. static const uint32_t PlsrPlannerSineIntegralQ24[65] =
  70. {
  71. 0UL, 53UL, 421UL, 1420UL, 3362UL, 6560UL, 11321UL, 17949UL,
  72. 26744UL, 38000UL, 52007UL, 69047UL, 89393UL, 113314UL, 141066UL,
  73. 172899UL, 209052UL, 249753UL, 295221UL, 345662UL, 401269UL,
  74. 462225UL, 528698UL, 600845UL, 678806UL, 762711UL, 852672UL,
  75. 948789UL, 1051146UL, 1159812UL, 1274841UL, 1396271UL, 1524127UL,
  76. 1658415UL, 1799129UL, 1946244UL, 2099722UL, 2259509UL, 2425536UL,
  77. 2597719UL, 2775958UL, 2960141UL, 3150138UL, 3345809UL, 3546997UL,
  78. 3753534UL, 3965237UL, 4181913UL, 4403356UL, 4629347UL, 4859658UL,
  79. 5094050UL, 5332273UL, 5574071UL, 5819175UL, 6067312UL, 6318200UL,
  80. 6571549UL, 6827065UL, 7084448UL, 7343394UL, 7603596UL, 7864741UL,
  81. 8126517UL, 8388608UL
  82. };
  83. static uint32_t PlsrPlannerAbsDifference(uint32_t first, uint32_t second)
  84. {
  85. return (first > second) ? (first - second) : (second - first);
  86. }
  87. static uint32_t PlsrPlannerRampTime(const PLSR_MOTION_BLOCK *block,uint32_t fromHz, uint32_t toHz)
  88. {
  89. uint32_t baseTimeMs;
  90. uint64_t durationMs;
  91. if (fromHz == toHz)
  92. {
  93. return 0UL;
  94. }
  95. baseTimeMs = (toHz > fromHz) ? block->accelerationTimeMs
  96. : block->decelerationTimeMs;
  97. if (baseTimeMs == 0UL)
  98. {
  99. return 0UL;
  100. }
  101. durationMs = ((uint64_t)PlsrPlannerAbsDifference(fromHz, toHz)
  102. * baseTimeMs + block->referenceSpeedHz - 1UL)
  103. / block->referenceSpeedHz;
  104. return (durationMs > 0xFFFFFFFFULL) ? 0xFFFFFFFFUL
  105. : (uint32_t)durationMs;
  106. }
  107. static uint16_t PlsrPlannerBaseRampTime(const PLSR_MOTION_BLOCK *block,
  108. uint32_t fromHz,
  109. uint32_t toHz)
  110. {
  111. if (toHz > fromHz)
  112. {
  113. return block->accelerationTimeMs;
  114. }
  115. if (toHz < fromHz)
  116. {
  117. return block->decelerationTimeMs;
  118. }
  119. return 0U;
  120. }
  121. static uint64_t PlsrPlannerRampWeight(uint32_t fromHz,
  122. uint32_t toHz,
  123. uint16_t baseTimeMs)
  124. {
  125. uint64_t fromSquared = (uint64_t)fromHz * fromHz;
  126. uint64_t toSquared = (uint64_t)toHz * toHz;
  127. uint64_t difference = (fromSquared > toSquared)
  128. ? (fromSquared - toSquared)
  129. : (toSquared - fromSquared);
  130. return difference * baseTimeMs;
  131. }
  132. static uint64_t PlsrPlannerRequiredPulses(const PLSR_MOTION_BLOCK *block,
  133. uint64_t rampWeight)
  134. {
  135. uint64_t denominator = (uint64_t)2U * block->referenceSpeedHz * 1000UL;
  136. return (rampWeight == 0ULL) ? 0ULL
  137. : (rampWeight + denominator - 1ULL)
  138. / denominator;
  139. }
  140. static uint32_t PlsrPlannerIntegerSquareRoot(uint64_t value)
  141. {
  142. uint64_t bit = (uint64_t)1U << 62U;
  143. uint64_t root = 0ULL;
  144. while (bit > value)
  145. {
  146. bit >>= 2U;
  147. }
  148. while (bit != 0ULL)
  149. {
  150. if (value >= root + bit)
  151. {
  152. value -= root + bit;
  153. root = (root >> 1U) + bit;
  154. }
  155. else
  156. {
  157. root >>= 1U;
  158. }
  159. bit >>= 2U;
  160. }
  161. return (uint32_t)root;
  162. }
  163. static uint32_t PlsrPlannerReachableFrequency(
  164. const PLSR_MOTION_BLOCK *block,
  165. uint32_t fromHz,
  166. uint32_t towardHz,
  167. uint32_t pulseCount)
  168. {
  169. uint16_t baseTimeMs = PlsrPlannerBaseRampTime(block, fromHz, towardHz);
  170. uint64_t frequencySquared = (uint64_t)fromHz * fromHz;
  171. uint64_t changeSquared;
  172. uint32_t reachableHz;
  173. if ((baseTimeMs == 0U) || (fromHz == towardHz))
  174. {
  175. return towardHz;
  176. }
  177. changeSquared = (uint64_t)2U * pulseCount * block->referenceSpeedHz
  178. * 1000UL / baseTimeMs;
  179. if (towardHz > fromHz)
  180. {
  181. reachableHz = PlsrPlannerIntegerSquareRoot(
  182. frequencySquared + changeSquared);
  183. return (reachableHz > towardHz) ? towardHz : reachableHz;
  184. }
  185. frequencySquared = (changeSquared >= frequencySquared)
  186. ? 0ULL : (frequencySquared - changeSquared);
  187. reachableHz = PlsrPlannerIntegerSquareRoot(frequencySquared);
  188. if ((uint64_t)reachableHz * reachableHz < frequencySquared)
  189. {
  190. reachableHz++;
  191. }
  192. return (reachableHz < towardHz) ? towardHz : reachableHz;
  193. }
  194. static uint32_t PlsrPlannerPeak(const PLSR_MOTION_BLOCK *block,
  195. uint32_t startHz,
  196. uint32_t endHz)
  197. {
  198. uint32_t targetHz = block->cruiseHz;
  199. uint32_t upperEndpoint = (startHz > endHz) ? startHz : endHz;
  200. uint32_t lowerEndpoint = (startHz < endHz) ? startHz : endHz;
  201. uint16_t entryTimeMs;
  202. uint16_t exitTimeMs;
  203. uint32_t timeSumMs;
  204. uint64_t weightedEndpoints;
  205. uint64_t availableArea;
  206. uint64_t peakSquared;
  207. uint32_t peakHz;
  208. if ((targetHz <= upperEndpoint) && (targetHz >= lowerEndpoint))
  209. {
  210. return targetHz;
  211. }
  212. entryTimeMs = PlsrPlannerBaseRampTime(block, startHz, targetHz);
  213. exitTimeMs = PlsrPlannerBaseRampTime(block, targetHz, endHz);
  214. timeSumMs = (uint32_t)entryTimeMs + exitTimeMs;
  215. if (timeSumMs == 0UL)
  216. {
  217. return targetHz;
  218. }
  219. weightedEndpoints = (uint64_t)startHz * startHz * entryTimeMs
  220. + (uint64_t)endHz * endHz * exitTimeMs;
  221. availableArea = (uint64_t)2U * block->pulseBudget
  222. * block->referenceSpeedHz * 1000UL;
  223. if (targetHz > upperEndpoint)
  224. {
  225. peakSquared = (availableArea + weightedEndpoints) / timeSumMs;
  226. peakHz = PlsrPlannerIntegerSquareRoot(peakSquared);
  227. if (peakHz < upperEndpoint)
  228. {
  229. peakHz = upperEndpoint;
  230. }
  231. return (peakHz > targetHz) ? targetHz : peakHz;
  232. }
  233. if (availableArea >= weightedEndpoints)
  234. {
  235. return targetHz;
  236. }
  237. peakSquared = (weightedEndpoints - availableArea) / timeSumMs;
  238. peakHz = PlsrPlannerIntegerSquareRoot(peakSquared);
  239. if (peakHz < targetHz)
  240. {
  241. peakHz = targetHz;
  242. }
  243. return (peakHz > lowerEndpoint) ? lowerEndpoint : peakHz;
  244. }
  245. //C(x)函数
  246. //瞬时速度=delta*C(x)
  247. static uint64_t PlsrPlannerCurveIntegralQ32(uint64_t progressQ32,
  248. uint16_t curveMode)
  249. {
  250. const uint32_t *table;
  251. uint64_t scaled;
  252. uint32_t index;
  253. uint32_t fraction;
  254. uint64_t first;
  255. uint64_t second;
  256. if (progressQ32 >= PLSR_PLANNER_Q32_ONE)
  257. {
  258. return PLSR_PLANNER_Q32_ONE / 2ULL;
  259. }
  260. if (curveMode == 0U)
  261. {
  262. return (progressQ32 * progressQ32) >> 33U;
  263. }
  264. table = (curveMode == 1U) ? PlsrPlannerSmoothIntegralQ24
  265. : PlsrPlannerSineIntegralQ24;
  266. scaled = progressQ32 * 64ULL;
  267. index = (uint32_t)(scaled >> 32U);
  268. fraction = (uint32_t)scaled;
  269. first = (uint64_t)table[index] << 8U;
  270. second = (uint64_t)table[index + 1UL] << 8U;
  271. return first + (((second - first) * fraction) >> 32U);
  272. }
  273. static uint64_t PlsrPlannerRampAreaQ32(const PLSR_PLANNER_CONTEXT *context,
  274. uint32_t fromHz,
  275. uint32_t toHz,
  276. uint64_t progressQ32)
  277. {
  278. int64_t delta = (int64_t)toHz - (int64_t)fromHz;
  279. int64_t area = (int64_t)((uint64_t)fromHz * progressQ32)
  280. + delta * (int64_t)PlsrPlannerCurveIntegralQ32(
  281. progressQ32, context->block.curveMode);
  282. return (uint64_t)area;
  283. }
  284. static uint64_t PlsrPlannerExactBoundaryQ32(
  285. const PLSR_PLANNER_CONTEXT *context,
  286. uint64_t previousBoundaryQ32,
  287. uint64_t targetAreaQ32)
  288. {
  289. uint64_t lowerQ32 = previousBoundaryQ32;
  290. uint64_t upperQ32 = PLSR_PLANNER_Q32_ONE;
  291. uint64_t middleQ32;
  292. uint32_t iteration;
  293. for (iteration = 0UL; iteration < 32UL; iteration++)
  294. {
  295. middleQ32 = lowerQ32 + ((upperQ32 - lowerQ32) >> 1U);
  296. if (PlsrPlannerRampAreaQ32(context, context->rampFromHz,
  297. context->rampToHz, middleQ32)
  298. < targetAreaQ32)
  299. {
  300. lowerQ32 = middleQ32;
  301. }
  302. else
  303. {
  304. upperQ32 = middleQ32;
  305. }
  306. }
  307. return upperQ32;
  308. }
  309. static uint32_t PlsrPlannerInstantFrequency(
  310. const PLSR_PLANNER_CONTEXT *context,
  311. uint64_t progressQ32)
  312. {
  313. const uint32_t *table;
  314. uint64_t scaled;
  315. uint64_t curveProgressQ32;
  316. uint32_t index;
  317. uint32_t gap;
  318. if (progressQ32 >= PLSR_PLANNER_Q32_ONE)
  319. {
  320. return context->rampToHz;
  321. }
  322. if (context->block.curveMode == 0U)
  323. {
  324. curveProgressQ32 = progressQ32;
  325. }
  326. else
  327. {
  328. table = (context->block.curveMode == 1U)
  329. ? PlsrPlannerSmoothIntegralQ24
  330. : PlsrPlannerSineIntegralQ24;
  331. scaled = progressQ32 * 64ULL;
  332. index = (uint32_t)(scaled >> 32U);
  333. curveProgressQ32 =
  334. (uint64_t)(table[index + 1UL] - table[index]) << 14U;
  335. }
  336. if (context->rampToHz >= context->rampFromHz)
  337. {
  338. gap = context->rampToHz - context->rampFromHz;
  339. return context->rampFromHz
  340. + (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
  341. }
  342. gap = context->rampFromHz - context->rampToHz;
  343. return context->rampFromHz
  344. - (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
  345. }
  346. static uint64_t PlsrPlannerPredictedBoundaryQ32(
  347. const PLSR_PLANNER_CONTEXT *context,
  348. uint64_t targetAreaQ32)
  349. {
  350. uint64_t previousQ32 = context->rampBoundaryQ32;
  351. uint64_t currentAreaQ32 = (previousQ32 == 0ULL)
  352. ? 0ULL
  353. : PlsrPlannerRampAreaQ32(
  354. context, context->rampFromHz,
  355. context->rampToHz, previousQ32);
  356. uint64_t candidateQ32;
  357. uint64_t candidateAreaQ32;
  358. uint64_t differenceQ32;
  359. uint64_t correctionQ32;
  360. uint32_t derivativeHz;
  361. if (context->rampLastPhaseStepQ32
  362. >= PLSR_PLANNER_Q32_ONE - previousQ32)
  363. {
  364. candidateQ32 = PLSR_PLANNER_Q32_ONE;
  365. }
  366. else if (context->rampLastPhaseStepQ32 != 0ULL)
  367. {
  368. candidateQ32 = previousQ32 + context->rampLastPhaseStepQ32;
  369. }
  370. else
  371. {
  372. derivativeHz = PlsrPlannerInstantFrequency(context, previousQ32);
  373. if (derivativeHz == 0UL)
  374. {
  375. derivativeHz = 1UL;
  376. }
  377. differenceQ32 = targetAreaQ32 - currentAreaQ32;
  378. correctionQ32 = (differenceQ32 + derivativeHz - 1UL)
  379. / derivativeHz;
  380. candidateQ32 = (correctionQ32
  381. >= PLSR_PLANNER_Q32_ONE - previousQ32)
  382. ? PLSR_PLANNER_Q32_ONE
  383. : previousQ32 + correctionQ32;
  384. }
  385. candidateAreaQ32 = PlsrPlannerRampAreaQ32(
  386. context, context->rampFromHz, context->rampToHz, candidateQ32);
  387. derivativeHz = PlsrPlannerInstantFrequency(context, candidateQ32);
  388. if (derivativeHz == 0UL)
  389. {
  390. derivativeHz = 1UL;
  391. }
  392. if (candidateAreaQ32 < targetAreaQ32)
  393. {
  394. differenceQ32 = targetAreaQ32 - candidateAreaQ32;
  395. correctionQ32 = (differenceQ32 + derivativeHz - 1UL)
  396. / derivativeHz;
  397. candidateQ32 = (correctionQ32
  398. >= PLSR_PLANNER_Q32_ONE - candidateQ32)
  399. ? PLSR_PLANNER_Q32_ONE
  400. : candidateQ32 + correctionQ32;
  401. }
  402. else if (candidateAreaQ32 > targetAreaQ32)
  403. {
  404. differenceQ32 = candidateAreaQ32 - targetAreaQ32;
  405. correctionQ32 = differenceQ32 / derivativeHz;
  406. if (correctionQ32 == 0ULL)
  407. {
  408. correctionQ32 = 1ULL;
  409. }
  410. candidateQ32 = (correctionQ32 >= candidateQ32 - previousQ32)
  411. ? previousQ32 + 1ULL
  412. : candidateQ32 - correctionQ32;
  413. }
  414. return candidateQ32;
  415. }
  416. static void PlsrPlannerStartRamp(PLSR_PLANNER_CONTEXT *context,
  417. uint8_t rampKind,
  418. uint32_t fromHz,
  419. uint32_t toHz,
  420. uint32_t pulseCount)
  421. {
  422. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  423. && !defined(PLSR_HOST_TEST)
  424. uint32_t totalStartedAt = PlsrPlannerTimingNow();
  425. uint32_t phaseStartedAt;
  426. #endif
  427. context->rampKind = rampKind;
  428. context->rampRelativePulse = 0UL;
  429. context->rampPulseCount = pulseCount;
  430. context->rampFromHz = fromHz;
  431. context->rampToHz = toHz;
  432. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  433. && !defined(PLSR_HOST_TEST)
  434. phaseStartedAt = PlsrPlannerTimingNow();
  435. #endif
  436. context->rampDurationMs = PlsrPlannerRampTime(&context->block, fromHz, toHz);
  437. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  438. && !defined(PLSR_HOST_TEST)
  439. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampTime, phaseStartedAt);
  440. phaseStartedAt = PlsrPlannerTimingNow();
  441. #endif
  442. context->rampTotalAreaQ32 = PlsrPlannerRampAreaQ32(
  443. context, fromHz, toHz, PLSR_PLANNER_Q32_ONE);
  444. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  445. && !defined(PLSR_HOST_TEST)
  446. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampTotalArea,
  447. phaseStartedAt);
  448. phaseStartedAt = PlsrPlannerTimingNow();
  449. #endif
  450. context->rampAreaStepQ32 = context->rampTotalAreaQ32 / pulseCount;
  451. context->rampAreaRemainder =
  452. (uint32_t)(context->rampTotalAreaQ32 % pulseCount);
  453. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  454. && !defined(PLSR_HOST_TEST)
  455. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampAreaSplit,
  456. phaseStartedAt);
  457. #endif
  458. context->rampRemainderAccumulator = 0UL;
  459. context->rampTargetAreaQ32 = 0ULL;
  460. context->rampBoundaryQ32 = 0ULL;
  461. context->rampActualTimeQ32 = 0ULL;
  462. context->rampLastPhaseStepQ32 = 0ULL;
  463. context->lastRampHz = 0UL;
  464. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  465. && !defined(PLSR_HOST_TEST)
  466. phaseStartedAt = PlsrPlannerTimingNow();
  467. #endif
  468. context->rampFirstBoundaryQ32 = PlsrPlannerExactBoundaryQ32(
  469. context, 0ULL, context->rampAreaStepQ32);
  470. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  471. && !defined(PLSR_HOST_TEST)
  472. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampFirstBoundary,
  473. phaseStartedAt);
  474. #endif
  475. if (pulseCount > 1UL)
  476. {
  477. uint64_t secondTargetAreaQ32;
  478. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  479. && !defined(PLSR_HOST_TEST)
  480. phaseStartedAt = PlsrPlannerTimingNow();
  481. #endif
  482. secondTargetAreaQ32 = context->rampAreaStepQ32 * 2ULL
  483. + ((uint64_t)context->rampAreaRemainder * 2ULL) / pulseCount;
  484. context->rampSecondBoundaryQ32 = PlsrPlannerExactBoundaryQ32(
  485. context, context->rampFirstBoundaryQ32,
  486. secondTargetAreaQ32);
  487. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  488. && !defined(PLSR_HOST_TEST)
  489. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampSecondBoundary,
  490. phaseStartedAt);
  491. #endif
  492. }
  493. else
  494. {
  495. context->rampSecondBoundaryQ32 = PLSR_PLANNER_Q32_ONE;
  496. }
  497. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  498. && !defined(PLSR_HOST_TEST)
  499. PlsrPlannerTimingRecord(&PlsrPlannerTiming.startRamp, totalStartedAt);
  500. #endif
  501. }
  502. static uint8_t PlsrPlannerSameSetting(
  503. const PLSR_PLATFORM_TIMER_SETTING *first,
  504. const PLSR_PLATFORM_TIMER_SETTING *second)
  505. {
  506. return ((first->actualFrequencyHz == second->actualFrequencyHz)
  507. && (first->prescaler == second->prescaler)
  508. && (first->pairPrescaler == second->pairPrescaler)
  509. && (first->period == second->period)
  510. && (first->compare == second->compare)) ? 1U : 0U;
  511. }
  512. static uint8_t PlsrPlannerBuildStep(PLSR_PLANNER_CONTEXT *context,
  513. uint32_t requestedHz,
  514. PLSR_PLATFORM_TIMER_SETTING *setting,
  515. uint32_t *normalizedRequestedHz)
  516. {
  517. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  518. && !defined(PLSR_HOST_TEST)
  519. uint32_t startedAt;
  520. uint8_t result;
  521. #endif
  522. if (requestedHz == 0UL)
  523. {
  524. requestedHz = 1UL;
  525. }
  526. if (requestedHz > PLSR_FREQUENCY_MAX_HZ)
  527. {
  528. requestedHz = PLSR_FREQUENCY_MAX_HZ;
  529. }
  530. *normalizedRequestedHz = requestedHz;
  531. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  532. && !defined(PLSR_HOST_TEST)
  533. startedAt = PlsrPlannerTimingNow();
  534. result = PlsrPlatformBuildTimerSetting(context->block.pulseOutput,
  535. PLSR_OUTPUT_PULSE_DIR,
  536. requestedHz, setting);
  537. PlsrPlannerTimingRecord(&PlsrPlannerTiming.timerSetting, startedAt);
  538. return result;
  539. #else
  540. return PlsrPlatformBuildTimerSetting(context->block.pulseOutput,
  541. PLSR_OUTPUT_PULSE_DIR,
  542. requestedHz, setting);
  543. #endif
  544. }
  545. static uint8_t PlsrPlannerTakeRampStep(
  546. PLSR_PLANNER_CONTEXT *context,
  547. PLSR_PLATFORM_TIMER_SETTING *setting,
  548. uint32_t *requestedFrequencyHz)
  549. {
  550. uint64_t nextBoundaryQ32;
  551. uint64_t desiredDeltaQ32;
  552. uint64_t denominator;
  553. uint64_t requestedHz;
  554. uint64_t actualDeltaQ32;
  555. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  556. && !defined(PLSR_HOST_TEST)
  557. uint32_t totalStartedAt = PlsrPlannerTimingNow();
  558. uint32_t phaseStartedAt;
  559. #endif
  560. context->rampTargetAreaQ32 += context->rampAreaStepQ32;
  561. context->rampRemainderAccumulator += context->rampAreaRemainder;
  562. if (context->rampRemainderAccumulator >= context->rampPulseCount)
  563. {
  564. context->rampTargetAreaQ32++;
  565. context->rampRemainderAccumulator -= context->rampPulseCount;
  566. }
  567. if (context->rampRelativePulse + 1UL >= context->rampPulseCount)
  568. {
  569. context->rampTargetAreaQ32 = context->rampTotalAreaQ32;
  570. nextBoundaryQ32 = PLSR_PLANNER_Q32_ONE;
  571. }
  572. else if (context->rampRelativePulse == 0UL)
  573. {
  574. nextBoundaryQ32 = context->rampFirstBoundaryQ32;
  575. }
  576. else if (context->rampRelativePulse == 1UL)
  577. {
  578. nextBoundaryQ32 = context->rampSecondBoundaryQ32;
  579. }
  580. else
  581. {
  582. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  583. && !defined(PLSR_HOST_TEST)
  584. phaseStartedAt = PlsrPlannerTimingNow();
  585. #endif
  586. nextBoundaryQ32 = PlsrPlannerPredictedBoundaryQ32(
  587. context, context->rampTargetAreaQ32);
  588. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  589. && !defined(PLSR_HOST_TEST)
  590. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampPredictedBoundary,
  591. phaseStartedAt);
  592. #endif
  593. }
  594. desiredDeltaQ32 = (nextBoundaryQ32 > context->rampActualTimeQ32)
  595. ? (nextBoundaryQ32 - context->rampActualTimeQ32)
  596. : 1ULL;
  597. /* The allocated pulse count closes the ramp area exactly. Derive the
  598. physical duration from N/averageHz instead of rounding it to whole
  599. milliseconds; short clipped ramps can be well below 1 ms. */
  600. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  601. && !defined(PLSR_HOST_TEST)
  602. phaseStartedAt = PlsrPlannerTimingNow();
  603. #endif
  604. denominator = (uint64_t)context->rampPulseCount * desiredDeltaQ32;
  605. requestedHz = (denominator == 0ULL)
  606. ? context->rampToHz
  607. : (context->rampTotalAreaQ32
  608. + denominator / 2ULL) / denominator;
  609. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  610. && !defined(PLSR_HOST_TEST)
  611. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampRequestedDivide,
  612. phaseStartedAt);
  613. #endif
  614. if (requestedHz == 0ULL)
  615. {
  616. requestedHz = 1ULL;
  617. }
  618. if (requestedHz > PLSR_FREQUENCY_MAX_HZ)
  619. {
  620. requestedHz = PLSR_FREQUENCY_MAX_HZ;
  621. }
  622. if ((context->lastRampHz != 0UL)
  623. && (((context->rampToHz > context->rampFromHz)
  624. && (requestedHz < context->lastRampHz))
  625. || ((context->rampToHz < context->rampFromHz)
  626. && (requestedHz > context->lastRampHz))))
  627. {
  628. requestedHz = context->lastRampHz;
  629. }
  630. if (PlsrPlannerBuildStep(context, (uint32_t)requestedHz, setting,
  631. requestedFrequencyHz) == 0U)
  632. {
  633. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  634. && !defined(PLSR_HOST_TEST)
  635. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampStep,
  636. totalStartedAt);
  637. #endif
  638. return 0U;
  639. }
  640. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  641. && !defined(PLSR_HOST_TEST)
  642. phaseStartedAt = PlsrPlannerTimingNow();
  643. #endif
  644. denominator = (uint64_t)context->rampPulseCount
  645. * setting->actualFrequencyHz;
  646. actualDeltaQ32 = (denominator == 0ULL)
  647. ? desiredDeltaQ32
  648. : (context->rampTotalAreaQ32
  649. + denominator / 2ULL) / denominator;
  650. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  651. && !defined(PLSR_HOST_TEST)
  652. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampActualDivide,
  653. phaseStartedAt);
  654. #endif
  655. context->rampActualTimeQ32 += actualDeltaQ32;
  656. context->rampLastPhaseStepQ32 =
  657. nextBoundaryQ32 - context->rampBoundaryQ32;
  658. context->rampBoundaryQ32 = nextBoundaryQ32;
  659. context->lastRampHz = setting->actualFrequencyHz;
  660. context->rampRelativePulse++;
  661. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  662. && !defined(PLSR_HOST_TEST)
  663. PlsrPlannerTimingRecord(&PlsrPlannerTiming.rampStep, totalStartedAt);
  664. #endif
  665. return 1U;
  666. }
  667. static uint8_t PlsrPlannerTakeStep(PLSR_PLANNER_CONTEXT *context,
  668. PLSR_PLATFORM_TIMER_SETTING *setting,
  669. uint32_t *requestedFrequencyHz,
  670. uint32_t *repeatCount)
  671. {
  672. uint32_t entryEnd = context->entryPulses;
  673. //加速段结束门槛。已经吐出的脉冲 < entryEnd 还在加速。例如加速 1000,这里就是 1000
  674. uint32_t steadyEnd = entryEnd + context->steadyPulses;
  675. //匀速段结束门槛。< steadyEnd 且 ≥ entryEnd 就是匀速。例如再加 5000 匀速,这里就是 6000。再往后是减速
  676. *repeatCount = 1UL;
  677. if (context->generatedPulses >= context->block.pulseBudget)
  678. {
  679. return 0U;
  680. }
  681. if (context->generatedPulses < entryEnd)
  682. { //加速段
  683. if (context->rampKind != 1U)
  684. { // 第一次走进加速
  685. PlsrPlannerStartRamp(context, 1U, context->startHz,context->peakHz, context->entryPulses);
  686. }
  687. return PlsrPlannerTakeRampStep(context, setting,requestedFrequencyHz);
  688. }
  689. if (context->generatedPulses < steadyEnd)
  690. {
  691. *repeatCount = steadyEnd - context->generatedPulses;
  692. context->rampKind = 0U;
  693. return PlsrPlannerBuildStep(context, context->peakHz, setting,
  694. requestedFrequencyHz);
  695. }
  696. if (context->rampKind != 2U)
  697. { // 第一次走进减速
  698. PlsrPlannerStartRamp(context, 2U, context->peakHz,
  699. context->endHz, context->exitPulses);
  700. }
  701. return PlsrPlannerTakeRampStep(context, setting,
  702. requestedFrequencyHz);
  703. }
  704. PLSR_PLANNER_STATUS PlsrPlannerBegin(PLSR_PLANNER_CONTEXT *context,
  705. const PLSR_MOTION_BLOCK *block,
  706. uint32_t appliedHz,
  707. uint64_t phasePulses)
  708. {
  709. uint64_t directRequired;
  710. uint64_t entryRequired;
  711. uint64_t exitRequired;
  712. uint64_t entryWeight;
  713. uint64_t exitWeight;
  714. uint64_t totalWeight;
  715. uint64_t scaledEntry;
  716. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  717. && !defined(PLSR_HOST_TEST)
  718. uint32_t startedAt = PlsrPlannerTimingNow();
  719. #endif
  720. if ((context == NULL) || (block == NULL)
  721. || (block->pulseBudget == 0UL)
  722. || (block->referenceSpeedHz == 0UL)
  723. || (block->referenceSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  724. || (block->entryHz > PLSR_FREQUENCY_MAX_HZ)
  725. || (block->cruiseHz == 0UL)
  726. || (block->cruiseHz > PLSR_FREQUENCY_MAX_HZ)
  727. || (block->exitHz > PLSR_FREQUENCY_MAX_HZ)
  728. || (appliedHz > PLSR_FREQUENCY_MAX_HZ)
  729. || (block->curveMode > 2U) || (block->pulseOutput > 3U))
  730. {
  731. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  732. && !defined(PLSR_HOST_TEST)
  733. PlsrPlannerTimingRecord(&PlsrPlannerTiming.begin, startedAt);
  734. #endif
  735. return PLSR_PLANNER_INVALID;
  736. }
  737. (void)memset(context, 0, sizeof(*context));
  738. context->block = *block;
  739. context->phasePulses = phasePulses;
  740. context->startHz = (appliedHz != 0UL) ? appliedHz : block->entryHz;
  741. if (context->startHz == 0UL)
  742. {
  743. context->startHz = 1UL;
  744. }
  745. context->endHz = (block->exitHz == 0UL) ? 1UL : block->exitHz;
  746. directRequired = PlsrPlannerRequiredPulses(
  747. block, PlsrPlannerRampWeight(
  748. context->startHz, context->endHz,
  749. PlsrPlannerBaseRampTime(block, context->startHz,
  750. context->endHz)));
  751. if (directRequired > block->pulseBudget)
  752. {
  753. context->peakHz = PlsrPlannerReachableFrequency(
  754. block, context->startHz, context->endHz, block->pulseBudget);
  755. context->endHz = context->peakHz;
  756. context->entryPulses = block->pulseBudget;
  757. context->clipped = 1U;
  758. context->active = 1U;
  759. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  760. && !defined(PLSR_HOST_TEST)
  761. PlsrPlannerTimingRecord(&PlsrPlannerTiming.begin, startedAt);
  762. #endif
  763. return PLSR_PLANNER_CLIPPED;
  764. }
  765. context->peakHz = PlsrPlannerPeak(block, context->startHz,
  766. context->endHz);
  767. entryWeight = PlsrPlannerRampWeight(
  768. context->startHz, context->peakHz,
  769. PlsrPlannerBaseRampTime(block, context->startHz, context->peakHz));
  770. exitWeight = PlsrPlannerRampWeight(
  771. context->peakHz, context->endHz,
  772. PlsrPlannerBaseRampTime(block, context->peakHz, context->endHz));
  773. entryRequired = PlsrPlannerRequiredPulses(block, entryWeight);
  774. exitRequired = PlsrPlannerRequiredPulses(block, exitWeight);
  775. if ((entryRequired + exitRequired) <= block->pulseBudget)
  776. {
  777. context->entryPulses = (uint32_t)entryRequired;
  778. context->exitPulses = (uint32_t)exitRequired;
  779. context->steadyPulses = block->pulseBudget
  780. - context->entryPulses
  781. - context->exitPulses;
  782. }
  783. else if (entryRequired == 0ULL)
  784. {
  785. context->exitPulses = block->pulseBudget;
  786. context->clipped = 1U;
  787. }
  788. else if (exitRequired == 0ULL)
  789. {
  790. context->entryPulses = block->pulseBudget;
  791. context->clipped = 1U;
  792. }
  793. else
  794. {
  795. totalWeight = entryWeight + exitWeight;
  796. scaledEntry = ((uint64_t)block->pulseBudget * entryWeight
  797. + totalWeight / 2ULL) / totalWeight;
  798. if (scaledEntry == 0ULL)
  799. {
  800. scaledEntry = 1ULL;
  801. }
  802. if (scaledEntry >= block->pulseBudget)
  803. {
  804. scaledEntry = block->pulseBudget - 1UL;
  805. }
  806. context->entryPulses = (uint32_t)scaledEntry;
  807. context->exitPulses = block->pulseBudget
  808. - context->entryPulses;
  809. context->clipped = 1U;
  810. }
  811. if (context->peakHz != block->cruiseHz)
  812. {
  813. context->clipped = 1U;
  814. }
  815. context->active = 1U;
  816. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  817. && !defined(PLSR_HOST_TEST)
  818. PlsrPlannerTimingRecord(&PlsrPlannerTiming.begin, startedAt);
  819. #endif
  820. return (context->clipped != 0U) ? PLSR_PLANNER_CLIPPED
  821. : PLSR_PLANNER_OK;
  822. }
  823. //返回值:实际写了几项(合并后的项数,不是脉冲数)。0 = 没吐出任何东西
  824. uint16_t PlsrPlannerGenerate(PLSR_PLANNER_CONTEXT *context,//规划账本:三段脉冲、已经吐了多少、斜坡面积指针
  825. PLSR_STREAM_ITEM *output,//输出数组,调用方准备好的格子
  826. uint16_t capacity)//这一次最多往 output 里写几项
  827. {
  828. PLSR_PLATFORM_TIMER_SETTING setting;
  829. uint32_t requestedFrequencyHz;
  830. uint32_t repeatCount;
  831. uint16_t produced = 0U;
  832. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  833. && !defined(PLSR_HOST_TEST)
  834. uint32_t startedAt = PlsrPlannerTimingNow();
  835. #endif
  836. if ((context == NULL) || (output == NULL) || (capacity == 0U)
  837. || (context->active == 0U))
  838. {
  839. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  840. && !defined(PLSR_HOST_TEST)
  841. PlsrPlannerTimingRecord(&PlsrPlannerTiming.generate, startedAt);
  842. #endif
  843. return 0U;
  844. }
  845. while ((produced < capacity)&& (context->generatedPulses < context->block.pulseBudget))
  846. { //输出数组还没写满&&本段预算还没全部交给外面。generatedPulses 按脉冲个数计
  847. if (PlsrPlannerTakeStep(context, &setting, &requestedFrequencyHz, &repeatCount) == 0U)
  848. //本圈 TakeStep 算出的量化后 PSC/ARR/actualHz,先放栈上
  849. {
  850. context->active = 0U;//规划器关掉
  851. break;
  852. }
  853. if ((produced != 0U)
  854. && (PlsrPlannerSameSetting(&output[produced - 1U].setting,&setting) != 0U)
  855. && (output[produced - 1U].requestedFrequencyHz
  856. == requestedFrequencyHz)
  857. && (output[produced - 1U].repeatCount
  858. <= 0xFFFFFFFFUL - repeatCount))
  859. {
  860. output[produced - 1U].repeatCount += repeatCount;
  861. //不用开新格
  862. }
  863. else
  864. {
  865. output[produced].setting = setting;
  866. output[produced].requestedFrequencyHz = requestedFrequencyHz;
  867. output[produced].repeatCount = repeatCount;
  868. produced++;
  869. }
  870. context->generatedPulses += repeatCount;
  871. }
  872. if (context->generatedPulses >= context->block.pulseBudget)
  873. {
  874. context->active = 0U;
  875. }
  876. #if defined(PLSR_DEBUG_TIMING) && (PLSR_DEBUG_TIMING != 0) \
  877. && !defined(PLSR_HOST_TEST)
  878. PlsrPlannerTimingRecord(&PlsrPlannerTiming.generate, startedAt);
  879. #endif
  880. return produced;
  881. }
  882. #if !defined(PLSR_HOST_TEST)
  883. static uint32_t PlsrPlannerBenchmarkCyclesNow(void)
  884. {
  885. return *((volatile uint32_t *)PLSR_PLANNER_BENCHMARK_DWT_CYCCNT);
  886. }
  887. static void PlsrPlannerBenchmarkEnableCounter(void)
  888. {
  889. *((volatile uint32_t *)PLSR_PLANNER_BENCHMARK_DEMCR_ADDRESS) |=
  890. PLSR_PLANNER_BENCHMARK_TRCENA;
  891. *((volatile uint32_t *)PLSR_PLANNER_BENCHMARK_DWT_CYCCNT) = 0UL;
  892. *((volatile uint32_t *)PLSR_PLANNER_BENCHMARK_DWT_CTRL) |=
  893. PLSR_PLANNER_BENCHMARK_CYCCNTENA;
  894. }
  895. static uint32_t PlsrPlannerBenchmarkCyclesQ16(uint32_t cycles,
  896. uint32_t pulses)
  897. {
  898. if (pulses == 0UL)
  899. {
  900. return 0UL;
  901. }
  902. return (uint32_t)((((uint64_t)cycles << 16U) + pulses / 2UL)
  903. / pulses);
  904. }
  905. static void PlsrPlannerBenchmarkMode(uint16_t curveMode)
  906. {
  907. PLSR_MOTION_BLOCK block;
  908. PLSR_PLANNER_CONTEXT context;
  909. PLSR_STREAM_ITEM item;
  910. PLSR_PLANNER_BENCHMARK_RESULT result;
  911. PLSR_PLANNER_STATUS status;
  912. uint64_t totalCycles = 0ULL;
  913. uint32_t minimumBlockQ16 = 0xFFFFFFFFUL;
  914. uint32_t maximumBlockQ16 = 0UL;
  915. uint32_t generateCalls = 0UL;
  916. uint8_t failed = 0U;
  917. (void)memset(&block, 0, sizeof(block));
  918. (void)memset(&context, 0, sizeof(context));
  919. (void)memset(&item, 0, sizeof(item));
  920. (void)memset(&result, 0, sizeof(result));
  921. block.entryHz = 1UL;
  922. block.cruiseHz = PLSR_PLANNER_BENCHMARK_TARGET_HZ;
  923. block.exitHz = 1UL;
  924. block.pulseBudget = PLSR_PLANNER_BENCHMARK_PULSES;
  925. block.referenceSpeedHz = PLSR_PLANNER_BENCHMARK_TARGET_HZ;
  926. block.accelerationTimeMs = 1000U;
  927. block.decelerationTimeMs = 1000U;
  928. block.curveMode = curveMode;
  929. block.pulseOutput = 0U;
  930. block.boundary = PLSR_BOUNDARY_STOP;
  931. status = PlsrPlannerBegin(&context, &block, 0UL, 0ULL);
  932. result.curveMode = curveMode;
  933. result.beginStatus = (uint32_t)status;
  934. if (status == PLSR_PLANNER_OK)
  935. {
  936. while (context.active != 0U)
  937. {
  938. uint32_t batchCalls = 0UL;
  939. uint32_t startedAt = PlsrPlannerBenchmarkCyclesNow();
  940. uint32_t elapsed;
  941. uint32_t blockQ16;
  942. while ((batchCalls < PLSR_PLANNER_BENCHMARK_BATCH_CALLS)
  943. && (context.active != 0U))
  944. {
  945. if (PlsrPlannerGenerate(&context, &item, 1U) == 0U)
  946. {
  947. failed = 1U;
  948. break;
  949. }
  950. batchCalls++;
  951. }
  952. elapsed = PlsrPlannerBenchmarkCyclesNow() - startedAt;
  953. if (batchCalls != 0UL)
  954. {
  955. blockQ16 = PlsrPlannerBenchmarkCyclesQ16(elapsed,
  956. batchCalls);
  957. totalCycles += elapsed;
  958. generateCalls += batchCalls;
  959. if (blockQ16 < minimumBlockQ16)
  960. {
  961. minimumBlockQ16 = blockQ16;
  962. }
  963. if (blockQ16 > maximumBlockQ16)
  964. {
  965. maximumBlockQ16 = blockQ16;
  966. }
  967. }
  968. if (failed != 0U)
  969. {
  970. break;
  971. }
  972. }
  973. }
  974. result.plannedPulses = context.generatedPulses;
  975. result.generateCalls = generateCalls;
  976. result.totalCycles = totalCycles;
  977. result.minimumBlockCyclesPerPulseQ16 =
  978. (minimumBlockQ16 == 0xFFFFFFFFUL) ? 0UL : minimumBlockQ16;
  979. result.maximumBlockCyclesPerPulseQ16 = maximumBlockQ16;
  980. if ((context.generatedPulses != 0UL) && (totalCycles != 0ULL))
  981. {
  982. uint64_t averageQ16 = ((totalCycles << 16U)
  983. + context.generatedPulses / 2UL)
  984. / context.generatedPulses;
  985. uint64_t estimatedHz =
  986. ((uint64_t)PlsrPlannerBenchmarkCoreClockHz
  987. * context.generatedPulses + totalCycles / 2ULL)
  988. / totalCycles;
  989. uint64_t targetCyclesQ16 =
  990. ((uint64_t)PlsrPlannerBenchmarkCoreClockHz << 16U)
  991. / PLSR_PLANNER_BENCHMARK_TARGET_HZ;
  992. result.averageCyclesPerPulseQ16 =
  993. (averageQ16 > 0xFFFFFFFFULL) ? 0xFFFFFFFFUL
  994. : (uint32_t)averageQ16;
  995. result.estimatedPulsesPerSecond =
  996. (estimatedHz > 0xFFFFFFFFULL) ? 0xFFFFFFFFUL
  997. : (uint32_t)estimatedHz;
  998. result.passes100k = (averageQ16 <= targetCyclesQ16) ? 1UL : 0UL;
  999. }
  1000. result.completed = ((failed == 0U)
  1001. && (context.generatedPulses
  1002. == PLSR_PLANNER_BENCHMARK_PULSES)
  1003. && (context.active == 0U)) ? 1UL : 0UL;
  1004. PlsrPlannerBenchmarkResults[curveMode] = result;
  1005. }
  1006. void PlsrPlannerBenchmarkService(void)
  1007. {
  1008. uint16_t curveMode;
  1009. if ((PlsrPlannerBenchmarkRequest == 0UL)
  1010. || (PlsrPlannerBenchmarkRunning != 0UL))
  1011. {
  1012. return;
  1013. }
  1014. PlsrPlannerBenchmarkRequest = 0UL;
  1015. PlsrPlannerBenchmarkRunning = 1UL;
  1016. (void)memset((void *)PlsrPlannerBenchmarkResults, 0,
  1017. sizeof(PlsrPlannerBenchmarkResults));
  1018. PlsrPlannerBenchmarkEnableCounter();
  1019. for (curveMode = 0U; curveMode < 3U; curveMode++)
  1020. {
  1021. PlsrPlannerBenchmarkMode(curveMode);
  1022. }
  1023. if (PlsrPlannerBenchmarkRunCount != 0xFFFFFFFFUL)
  1024. {
  1025. PlsrPlannerBenchmarkRunCount++;
  1026. }
  1027. PlsrPlannerBenchmarkRunning = 0UL;
  1028. }
  1029. #endif
  1030. static uint64_t PlsrPlannerRampDurationUs(uint32_t pulseCount,
  1031. uint32_t fromHz,
  1032. uint32_t toHz)
  1033. {
  1034. uint64_t frequencySum = (uint64_t)fromHz + toHz;
  1035. if ((pulseCount == 0UL) || (frequencySum == 0ULL))
  1036. {
  1037. return 0ULL;
  1038. }
  1039. return ((uint64_t)2U * pulseCount * 1000000ULL
  1040. + frequencySum - 1ULL) / frequencySum;
  1041. }
  1042. /* Return floor(numerator / denominator * 2^32) without requiring a
  1043. 128-bit intermediate. Both operands are bounded by the planner's
  1044. 100 kHz Q32 ramp area, so the normalized remainder can be doubled safely. */
  1045. static uint32_t PlsrPlannerRatioQ32(uint64_t numerator,
  1046. uint64_t denominator)
  1047. {
  1048. uint64_t remainder;
  1049. uint32_t ratio = 0UL;
  1050. uint8_t bit;
  1051. if ((numerator == 0ULL) || (denominator == 0ULL))
  1052. {
  1053. return 0UL;
  1054. }
  1055. if (numerator >= denominator)
  1056. {
  1057. return 0xFFFFFFFFUL;
  1058. }
  1059. remainder = numerator;
  1060. for (bit = 0U; bit < 32U; bit++)
  1061. {
  1062. ratio <<= 1U;
  1063. remainder <<= 1U;
  1064. if (remainder >= denominator)
  1065. {
  1066. remainder -= denominator;
  1067. ratio |= 1UL;
  1068. }
  1069. }
  1070. return ratio;
  1071. }
  1072. static uint32_t PlsrPlannerRampPulsesAtTime(
  1073. const PLSR_PLANNER_CONTEXT *context,
  1074. uint32_t pulseCount,
  1075. uint32_t fromHz,
  1076. uint32_t toHz,
  1077. uint64_t elapsedUs,
  1078. uint64_t durationUs,
  1079. uint64_t *progressQ32)
  1080. {
  1081. PLSR_PLANNER_CONTEXT ramp = *context;
  1082. uint64_t partialAreaQ32;
  1083. uint64_t totalAreaQ32;
  1084. uint64_t product;
  1085. uint32_t areaRatioQ32;
  1086. uint32_t result;
  1087. if ((pulseCount == 0UL) || (elapsedUs == 0ULL)
  1088. || (durationUs == 0ULL))
  1089. {
  1090. *progressQ32 = 0ULL;
  1091. return 0UL;
  1092. }
  1093. if (elapsedUs >= durationUs)
  1094. {
  1095. *progressQ32 = PLSR_PLANNER_Q32_ONE;
  1096. return pulseCount;
  1097. }
  1098. *progressQ32 = (elapsedUs * PLSR_PLANNER_Q32_ONE) / durationUs;
  1099. ramp.rampFromHz = fromHz;
  1100. ramp.rampToHz = toHz;
  1101. partialAreaQ32 = PlsrPlannerRampAreaQ32(
  1102. &ramp, fromHz, toHz, *progressQ32);
  1103. totalAreaQ32 = PlsrPlannerRampAreaQ32(
  1104. &ramp, fromHz, toHz, PLSR_PLANNER_Q32_ONE);
  1105. areaRatioQ32 = PlsrPlannerRatioQ32(partialAreaQ32,
  1106. totalAreaQ32);
  1107. product = (uint64_t)pulseCount * areaRatioQ32;
  1108. result = (uint32_t)(product >> 32U);
  1109. if ((uint32_t)product != 0UL)
  1110. {
  1111. result++;
  1112. }
  1113. return (result > pulseCount) ? pulseCount : result;
  1114. }
  1115. static uint8_t PlsrPlannerSetPredictedFrequency(
  1116. const PLSR_PLANNER_CONTEXT *context,
  1117. uint32_t fromHz,
  1118. uint32_t toHz,
  1119. uint64_t progressQ32,
  1120. PLSR_PLANNER_TIME_PREDICTION *prediction)
  1121. {
  1122. PLSR_PLANNER_CONTEXT ramp = *context;
  1123. PLSR_PLATFORM_TIMER_SETTING setting;
  1124. uint32_t requestedHz;
  1125. ramp.rampFromHz = fromHz;
  1126. ramp.rampToHz = toHz;
  1127. requestedHz = PlsrPlannerInstantFrequency(&ramp, progressQ32);
  1128. if (PlsrPlatformBuildTimerSetting(context->block.pulseOutput,
  1129. PLSR_OUTPUT_PULSE_DIR,
  1130. requestedHz, &setting) == 0U)
  1131. {
  1132. return 0U;
  1133. }
  1134. prediction->actualFrequencyHz = setting.actualFrequencyHz;
  1135. return 1U;
  1136. }
  1137. static uint64_t PlsrPlannerRampTargetAreaQ32(uint64_t totalAreaQ32,
  1138. uint32_t pulseCount,
  1139. uint32_t pulseIndex)
  1140. {
  1141. uint64_t step = totalAreaQ32 / pulseCount;
  1142. uint64_t remainder = totalAreaQ32 % pulseCount;
  1143. return step * pulseIndex
  1144. + (remainder * pulseIndex) / pulseCount;
  1145. }
  1146. /* Predict the timer setting of the last complete ramp pulse at the deadline.
  1147. A ramp pulse represents the average frequency between two equal-area curve
  1148. boundaries; carrying that run setting is closer to the hardware state than
  1149. carrying the mathematical instantaneous frequency at the boundary. */
  1150. static uint8_t PlsrPlannerSetPredictedRampRunFrequency(
  1151. const PLSR_PLANNER_CONTEXT *context,
  1152. uint32_t pulseCount,
  1153. uint32_t fromHz,
  1154. uint32_t toHz,
  1155. uint32_t pulseIndex,
  1156. PLSR_PLANNER_TIME_PREDICTION *prediction)
  1157. {
  1158. PLSR_PLANNER_CONTEXT ramp = *context;
  1159. PLSR_PLATFORM_TIMER_SETTING setting;
  1160. uint64_t totalAreaQ32;
  1161. uint64_t previousTargetAreaQ32;
  1162. uint64_t targetAreaQ32;
  1163. uint64_t previousBoundaryQ32;
  1164. uint64_t boundaryQ32;
  1165. uint64_t denominator;
  1166. uint64_t requestedHz;
  1167. if ((pulseCount == 0UL) || (pulseIndex == 0UL))
  1168. {
  1169. return PlsrPlannerSetPredictedFrequency(
  1170. context, fromHz, toHz, 0ULL, prediction);
  1171. }
  1172. if (pulseIndex > pulseCount)
  1173. {
  1174. pulseIndex = pulseCount;
  1175. }
  1176. ramp.rampFromHz = fromHz;
  1177. ramp.rampToHz = toHz;
  1178. totalAreaQ32 = PlsrPlannerRampAreaQ32(
  1179. &ramp, fromHz, toHz, PLSR_PLANNER_Q32_ONE);
  1180. previousTargetAreaQ32 = PlsrPlannerRampTargetAreaQ32(
  1181. totalAreaQ32, pulseCount, pulseIndex - 1UL);
  1182. targetAreaQ32 = PlsrPlannerRampTargetAreaQ32(
  1183. totalAreaQ32, pulseCount, pulseIndex);
  1184. previousBoundaryQ32 = (pulseIndex == 1UL)
  1185. ? 0ULL
  1186. : PlsrPlannerExactBoundaryQ32(
  1187. &ramp, 0ULL,
  1188. previousTargetAreaQ32);
  1189. boundaryQ32 = (pulseIndex == pulseCount)
  1190. ? PLSR_PLANNER_Q32_ONE
  1191. : PlsrPlannerExactBoundaryQ32(
  1192. &ramp, previousBoundaryQ32,
  1193. targetAreaQ32);
  1194. if (boundaryQ32 <= previousBoundaryQ32)
  1195. {
  1196. return 0U;
  1197. }
  1198. denominator = (uint64_t)pulseCount
  1199. * (boundaryQ32 - previousBoundaryQ32);
  1200. requestedHz = (denominator == 0ULL)
  1201. ? toHz
  1202. : (totalAreaQ32 + denominator / 2ULL)
  1203. / denominator;
  1204. if (requestedHz == 0ULL)
  1205. {
  1206. requestedHz = 1ULL;
  1207. }
  1208. if (requestedHz > PLSR_FREQUENCY_MAX_HZ)
  1209. {
  1210. requestedHz = PLSR_FREQUENCY_MAX_HZ;
  1211. }
  1212. if (PlsrPlatformBuildTimerSetting(context->block.pulseOutput,
  1213. PLSR_OUTPUT_PULSE_DIR,
  1214. (uint32_t)requestedHz,
  1215. &setting) == 0U)
  1216. {
  1217. return 0U;
  1218. }
  1219. prediction->actualFrequencyHz = setting.actualFrequencyHz;
  1220. return 1U;
  1221. }
  1222. uint8_t PlsrPlannerPredictTime(
  1223. const PLSR_PLANNER_CONTEXT *context,
  1224. uint32_t elapsedUs,
  1225. PLSR_PLANNER_TIME_PREDICTION *prediction)
  1226. {
  1227. PLSR_PLATFORM_TIMER_SETTING steadySetting;
  1228. uint64_t remainingUs = elapsedUs;
  1229. uint64_t durationUs;
  1230. uint64_t progressQ32;
  1231. uint64_t partialPulses;
  1232. if ((context == NULL) || (prediction == NULL)
  1233. || (context->block.pulseBudget == 0UL))
  1234. {
  1235. return 0U;
  1236. }
  1237. (void)memset(prediction, 0, sizeof(*prediction));
  1238. durationUs = PlsrPlannerRampDurationUs(
  1239. context->entryPulses, context->startHz, context->peakHz);
  1240. if ((context->entryPulses != 0UL) && (remainingUs <= durationUs))
  1241. {
  1242. prediction->pulseCount = PlsrPlannerRampPulsesAtTime(
  1243. context, context->entryPulses, context->startHz,
  1244. context->peakHz, remainingUs, durationUs, &progressQ32);
  1245. prediction->phase = PLSR_PLANNER_PHASE_ENTRY;
  1246. prediction->deadlineInProfile = 1U;
  1247. return PlsrPlannerSetPredictedRampRunFrequency(
  1248. context, context->entryPulses, context->startHz,
  1249. context->peakHz, prediction->pulseCount, prediction);
  1250. }
  1251. if (context->entryPulses != 0UL)
  1252. {
  1253. remainingUs -= durationUs;
  1254. }
  1255. if (PlsrPlatformBuildTimerSetting(context->block.pulseOutput,
  1256. PLSR_OUTPUT_PULSE_DIR,
  1257. context->peakHz,
  1258. &steadySetting) == 0U)
  1259. {
  1260. return 0U;
  1261. }
  1262. durationUs = (context->steadyPulses == 0UL)
  1263. ? 0ULL
  1264. : ((uint64_t)context->steadyPulses * 1000000ULL
  1265. + steadySetting.actualFrequencyHz - 1UL)
  1266. / steadySetting.actualFrequencyHz;
  1267. if ((context->steadyPulses != 0UL) && (remainingUs <= durationUs))
  1268. {
  1269. partialPulses = (remainingUs * steadySetting.actualFrequencyHz
  1270. + 999999ULL) / 1000000ULL;
  1271. if (partialPulses > context->steadyPulses)
  1272. {
  1273. partialPulses = context->steadyPulses;
  1274. }
  1275. prediction->pulseCount = context->entryPulses
  1276. + (uint32_t)partialPulses;
  1277. prediction->actualFrequencyHz = steadySetting.actualFrequencyHz;
  1278. prediction->phase = PLSR_PLANNER_PHASE_STEADY;
  1279. prediction->deadlineInProfile = 1U;
  1280. return 1U;
  1281. }
  1282. if (context->steadyPulses != 0UL)
  1283. {
  1284. remainingUs -= durationUs;
  1285. }
  1286. durationUs = PlsrPlannerRampDurationUs(
  1287. context->exitPulses, context->peakHz, context->endHz);
  1288. if ((context->exitPulses != 0UL) && (remainingUs <= durationUs))
  1289. {
  1290. partialPulses = PlsrPlannerRampPulsesAtTime(
  1291. context, context->exitPulses, context->peakHz,
  1292. context->endHz, remainingUs, durationUs, &progressQ32);
  1293. prediction->pulseCount = context->entryPulses
  1294. + context->steadyPulses
  1295. + (uint32_t)partialPulses;
  1296. prediction->phase = PLSR_PLANNER_PHASE_EXIT;
  1297. prediction->deadlineInProfile = 1U;
  1298. return PlsrPlannerSetPredictedRampRunFrequency(
  1299. context, context->exitPulses, context->peakHz,
  1300. context->endHz, (uint32_t)partialPulses, prediction);
  1301. }
  1302. prediction->pulseCount = context->block.pulseBudget;
  1303. prediction->phase = PLSR_PLANNER_PHASE_COMPLETE;
  1304. prediction->deadlineInProfile = 0U;
  1305. return PlsrPlannerSetPredictedFrequency(
  1306. context, context->endHz, context->endHz,
  1307. PLSR_PLANNER_Q32_ONE, prediction);
  1308. }