Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 
 
 
 
 

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