Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

736 rader
24 KiB

  1. #include "plsr_planner.h"
  2. #include <stddef.h>
  3. #include <string.h>
  4. #define PLSR_PLANNER_Q32_ONE (4294967296ULL)
  5. static const uint32_t PlsrPlannerSmoothIntegralQ24[65] =
  6. {
  7. 0UL, 64UL, 504UL, 1688UL, 3968UL, 7688UL, 13176UL, 20752UL,
  8. 30720UL, 43376UL, 59000UL, 77864UL, 100224UL, 126328UL, 156408UL,
  9. 190688UL, 229376UL, 272672UL, 320760UL, 373816UL, 432000UL,
  10. 495464UL, 564344UL, 638768UL, 718848UL, 804688UL, 896376UL,
  11. 993992UL, 1097600UL, 1207256UL, 1323000UL, 1444864UL, 1572864UL,
  12. 1707008UL, 1847288UL, 1993688UL, 2146176UL, 2304712UL, 2469240UL,
  13. 2639696UL, 2816000UL, 2998064UL, 3185784UL, 3379048UL, 3577728UL,
  14. 3781688UL, 3990776UL, 4204832UL, 4423680UL, 4647136UL, 4875000UL,
  15. 5107064UL, 5343104UL, 5582888UL, 5826168UL, 6072688UL, 6322176UL,
  16. 6574352UL, 6828920UL, 7085576UL, 7344000UL, 7603864UL, 7864824UL,
  17. 8126528UL, 8388608UL
  18. };
  19. static const uint32_t PlsrPlannerSineIntegralQ24[65] =
  20. {
  21. 0UL, 53UL, 421UL, 1420UL, 3362UL, 6560UL, 11321UL, 17949UL,
  22. 26744UL, 38000UL, 52007UL, 69047UL, 89393UL, 113314UL, 141066UL,
  23. 172899UL, 209052UL, 249753UL, 295221UL, 345662UL, 401269UL,
  24. 462225UL, 528698UL, 600845UL, 678806UL, 762711UL, 852672UL,
  25. 948789UL, 1051146UL, 1159812UL, 1274841UL, 1396271UL, 1524127UL,
  26. 1658415UL, 1799129UL, 1946244UL, 2099722UL, 2259509UL, 2425536UL,
  27. 2597719UL, 2775958UL, 2960141UL, 3150138UL, 3345809UL, 3546997UL,
  28. 3753534UL, 3965237UL, 4181913UL, 4403356UL, 4629347UL, 4859658UL,
  29. 5094050UL, 5332273UL, 5574071UL, 5819175UL, 6067312UL, 6318200UL,
  30. 6571549UL, 6827065UL, 7084448UL, 7343394UL, 7603596UL, 7864741UL,
  31. 8126517UL, 8388608UL
  32. };
  33. static uint32_t PlsrPlannerAbsDifference(uint32_t first, uint32_t second)
  34. {
  35. return (first > second) ? (first - second) : (second - first);
  36. }
  37. static uint32_t PlsrPlannerRampTime(const PLSR_MOTION_BLOCK *block,
  38. uint32_t fromHz,
  39. uint32_t toHz)
  40. {
  41. uint32_t baseTimeMs;
  42. uint64_t durationMs;
  43. if (fromHz == toHz)
  44. {
  45. return 0UL;
  46. }
  47. baseTimeMs = (toHz > fromHz) ? block->accelerationTimeMs
  48. : block->decelerationTimeMs;
  49. if (baseTimeMs == 0UL)
  50. {
  51. return 0UL;
  52. }
  53. durationMs = ((uint64_t)PlsrPlannerAbsDifference(fromHz, toHz)
  54. * baseTimeMs + block->referenceSpeedHz - 1UL)
  55. / block->referenceSpeedHz;
  56. return (durationMs > 0xFFFFFFFFULL) ? 0xFFFFFFFFUL
  57. : (uint32_t)durationMs;
  58. }
  59. static uint16_t PlsrPlannerBaseRampTime(const PLSR_MOTION_BLOCK *block,
  60. uint32_t fromHz,
  61. uint32_t toHz)
  62. {
  63. if (toHz > fromHz)
  64. {
  65. return block->accelerationTimeMs;
  66. }
  67. if (toHz < fromHz)
  68. {
  69. return block->decelerationTimeMs;
  70. }
  71. return 0U;
  72. }
  73. static uint64_t PlsrPlannerRampWeight(uint32_t fromHz,
  74. uint32_t toHz,
  75. uint16_t baseTimeMs)
  76. {
  77. uint64_t fromSquared = (uint64_t)fromHz * fromHz;
  78. uint64_t toSquared = (uint64_t)toHz * toHz;
  79. uint64_t difference = (fromSquared > toSquared)
  80. ? (fromSquared - toSquared)
  81. : (toSquared - fromSquared);
  82. return difference * baseTimeMs;
  83. }
  84. static uint64_t PlsrPlannerRequiredPulses(const PLSR_MOTION_BLOCK *block,
  85. uint64_t rampWeight)
  86. {
  87. uint64_t denominator = (uint64_t)2U * block->referenceSpeedHz * 1000UL;
  88. return (rampWeight == 0ULL) ? 0ULL
  89. : (rampWeight + denominator - 1ULL)
  90. / denominator;
  91. }
  92. static uint32_t PlsrPlannerIntegerSquareRoot(uint64_t value)
  93. {
  94. uint64_t bit = (uint64_t)1U << 62U;
  95. uint64_t root = 0ULL;
  96. while (bit > value)
  97. {
  98. bit >>= 2U;
  99. }
  100. while (bit != 0ULL)
  101. {
  102. if (value >= root + bit)
  103. {
  104. value -= root + bit;
  105. root = (root >> 1U) + bit;
  106. }
  107. else
  108. {
  109. root >>= 1U;
  110. }
  111. bit >>= 2U;
  112. }
  113. return (uint32_t)root;
  114. }
  115. static uint32_t PlsrPlannerReachableFrequency(
  116. const PLSR_MOTION_BLOCK *block,
  117. uint32_t fromHz,
  118. uint32_t towardHz,
  119. uint32_t pulseCount)
  120. {
  121. uint16_t baseTimeMs = PlsrPlannerBaseRampTime(block, fromHz, towardHz);
  122. uint64_t frequencySquared = (uint64_t)fromHz * fromHz;
  123. uint64_t changeSquared;
  124. uint32_t reachableHz;
  125. if ((baseTimeMs == 0U) || (fromHz == towardHz))
  126. {
  127. return towardHz;
  128. }
  129. changeSquared = (uint64_t)2U * pulseCount * block->referenceSpeedHz
  130. * 1000UL / baseTimeMs;
  131. if (towardHz > fromHz)
  132. {
  133. reachableHz = PlsrPlannerIntegerSquareRoot(
  134. frequencySquared + changeSquared);
  135. return (reachableHz > towardHz) ? towardHz : reachableHz;
  136. }
  137. frequencySquared = (changeSquared >= frequencySquared)
  138. ? 0ULL : (frequencySquared - changeSquared);
  139. reachableHz = PlsrPlannerIntegerSquareRoot(frequencySquared);
  140. if ((uint64_t)reachableHz * reachableHz < frequencySquared)
  141. {
  142. reachableHz++;
  143. }
  144. return (reachableHz < towardHz) ? towardHz : reachableHz;
  145. }
  146. static uint32_t PlsrPlannerPeak(const PLSR_MOTION_BLOCK *block,
  147. uint32_t startHz,
  148. uint32_t endHz)
  149. {
  150. uint32_t targetHz = block->cruiseHz;
  151. uint32_t upperEndpoint = (startHz > endHz) ? startHz : endHz;
  152. uint32_t lowerEndpoint = (startHz < endHz) ? startHz : endHz;
  153. uint16_t entryTimeMs;
  154. uint16_t exitTimeMs;
  155. uint32_t timeSumMs;
  156. uint64_t weightedEndpoints;
  157. uint64_t availableArea;
  158. uint64_t peakSquared;
  159. uint32_t peakHz;
  160. if ((targetHz <= upperEndpoint) && (targetHz >= lowerEndpoint))
  161. {
  162. return targetHz;
  163. }
  164. entryTimeMs = PlsrPlannerBaseRampTime(block, startHz, targetHz);
  165. exitTimeMs = PlsrPlannerBaseRampTime(block, targetHz, endHz);
  166. timeSumMs = (uint32_t)entryTimeMs + exitTimeMs;
  167. if (timeSumMs == 0UL)
  168. {
  169. return targetHz;
  170. }
  171. weightedEndpoints = (uint64_t)startHz * startHz * entryTimeMs
  172. + (uint64_t)endHz * endHz * exitTimeMs;
  173. availableArea = (uint64_t)2U * block->pulseBudget
  174. * block->referenceSpeedHz * 1000UL;
  175. if (targetHz > upperEndpoint)
  176. {
  177. peakSquared = (availableArea + weightedEndpoints) / timeSumMs;
  178. peakHz = PlsrPlannerIntegerSquareRoot(peakSquared);
  179. if (peakHz < upperEndpoint)
  180. {
  181. peakHz = upperEndpoint;
  182. }
  183. return (peakHz > targetHz) ? targetHz : peakHz;
  184. }
  185. if (availableArea >= weightedEndpoints)
  186. {
  187. return targetHz;
  188. }
  189. peakSquared = (weightedEndpoints - availableArea) / timeSumMs;
  190. peakHz = PlsrPlannerIntegerSquareRoot(peakSquared);
  191. if (peakHz < targetHz)
  192. {
  193. peakHz = targetHz;
  194. }
  195. return (peakHz > lowerEndpoint) ? lowerEndpoint : peakHz;
  196. }
  197. static uint64_t PlsrPlannerCurveIntegralQ32(uint64_t progressQ32,
  198. uint16_t curveMode)
  199. {
  200. const uint32_t *table;
  201. uint64_t scaled;
  202. uint32_t index;
  203. uint32_t fraction;
  204. uint64_t first;
  205. uint64_t second;
  206. if (progressQ32 >= PLSR_PLANNER_Q32_ONE)
  207. {
  208. return PLSR_PLANNER_Q32_ONE / 2ULL;
  209. }
  210. if (curveMode == 0U)
  211. {
  212. return (progressQ32 * progressQ32) >> 33U;
  213. }
  214. table = (curveMode == 1U) ? PlsrPlannerSmoothIntegralQ24
  215. : PlsrPlannerSineIntegralQ24;
  216. scaled = progressQ32 * 64ULL;
  217. index = (uint32_t)(scaled >> 32U);
  218. fraction = (uint32_t)scaled;
  219. first = (uint64_t)table[index] << 8U;
  220. second = (uint64_t)table[index + 1UL] << 8U;
  221. return first + (((second - first) * fraction) >> 32U);
  222. }
  223. static uint64_t PlsrPlannerRampAreaQ32(const PLSR_PLANNER_CONTEXT *context,
  224. uint32_t fromHz,
  225. uint32_t toHz,
  226. uint64_t progressQ32)
  227. {
  228. int64_t delta = (int64_t)toHz - (int64_t)fromHz;
  229. int64_t area = (int64_t)((uint64_t)fromHz * progressQ32)
  230. + delta * (int64_t)PlsrPlannerCurveIntegralQ32(
  231. progressQ32, context->block.curveMode);
  232. return (uint64_t)area;
  233. }
  234. static uint64_t PlsrPlannerExactBoundaryQ32(
  235. const PLSR_PLANNER_CONTEXT *context,
  236. uint64_t previousBoundaryQ32,
  237. uint64_t targetAreaQ32)
  238. {
  239. uint64_t lowerQ32 = previousBoundaryQ32;
  240. uint64_t upperQ32 = PLSR_PLANNER_Q32_ONE;
  241. uint64_t middleQ32;
  242. uint32_t iteration;
  243. for (iteration = 0UL; iteration < 32UL; iteration++)
  244. {
  245. middleQ32 = lowerQ32 + ((upperQ32 - lowerQ32) >> 1U);
  246. if (PlsrPlannerRampAreaQ32(context, context->rampFromHz,
  247. context->rampToHz, middleQ32)
  248. < targetAreaQ32)
  249. {
  250. lowerQ32 = middleQ32;
  251. }
  252. else
  253. {
  254. upperQ32 = middleQ32;
  255. }
  256. }
  257. return upperQ32;
  258. }
  259. static uint32_t PlsrPlannerInstantFrequency(
  260. const PLSR_PLANNER_CONTEXT *context,
  261. uint64_t progressQ32)
  262. {
  263. const uint32_t *table;
  264. uint64_t scaled;
  265. uint64_t curveProgressQ32;
  266. uint32_t index;
  267. uint32_t gap;
  268. if (progressQ32 >= PLSR_PLANNER_Q32_ONE)
  269. {
  270. return context->rampToHz;
  271. }
  272. if (context->block.curveMode == 0U)
  273. {
  274. curveProgressQ32 = progressQ32;
  275. }
  276. else
  277. {
  278. table = (context->block.curveMode == 1U)
  279. ? PlsrPlannerSmoothIntegralQ24
  280. : PlsrPlannerSineIntegralQ24;
  281. scaled = progressQ32 * 64ULL;
  282. index = (uint32_t)(scaled >> 32U);
  283. curveProgressQ32 =
  284. (uint64_t)(table[index + 1UL] - table[index]) << 14U;
  285. }
  286. if (context->rampToHz >= context->rampFromHz)
  287. {
  288. gap = context->rampToHz - context->rampFromHz;
  289. return context->rampFromHz
  290. + (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
  291. }
  292. gap = context->rampFromHz - context->rampToHz;
  293. return context->rampFromHz
  294. - (uint32_t)(((uint64_t)gap * curveProgressQ32) >> 32U);
  295. }
  296. static uint64_t PlsrPlannerPredictedBoundaryQ32(
  297. const PLSR_PLANNER_CONTEXT *context,
  298. uint64_t targetAreaQ32)
  299. {
  300. uint64_t previousQ32 = context->rampBoundaryQ32;
  301. uint64_t currentAreaQ32 = (previousQ32 == 0ULL)
  302. ? 0ULL
  303. : PlsrPlannerRampAreaQ32(
  304. context, context->rampFromHz,
  305. context->rampToHz, previousQ32);
  306. uint64_t candidateQ32;
  307. uint64_t candidateAreaQ32;
  308. uint64_t differenceQ32;
  309. uint64_t correctionQ32;
  310. uint32_t derivativeHz;
  311. if (context->rampLastPhaseStepQ32
  312. >= PLSR_PLANNER_Q32_ONE - previousQ32)
  313. {
  314. candidateQ32 = PLSR_PLANNER_Q32_ONE;
  315. }
  316. else if (context->rampLastPhaseStepQ32 != 0ULL)
  317. {
  318. candidateQ32 = previousQ32 + context->rampLastPhaseStepQ32;
  319. }
  320. else
  321. {
  322. derivativeHz = PlsrPlannerInstantFrequency(context, previousQ32);
  323. if (derivativeHz == 0UL)
  324. {
  325. derivativeHz = 1UL;
  326. }
  327. differenceQ32 = targetAreaQ32 - currentAreaQ32;
  328. correctionQ32 = (differenceQ32 + derivativeHz - 1UL)
  329. / derivativeHz;
  330. candidateQ32 = (correctionQ32
  331. >= PLSR_PLANNER_Q32_ONE - previousQ32)
  332. ? PLSR_PLANNER_Q32_ONE
  333. : previousQ32 + correctionQ32;
  334. }
  335. candidateAreaQ32 = PlsrPlannerRampAreaQ32(
  336. context, context->rampFromHz, context->rampToHz, candidateQ32);
  337. derivativeHz = PlsrPlannerInstantFrequency(context, candidateQ32);
  338. if (derivativeHz == 0UL)
  339. {
  340. derivativeHz = 1UL;
  341. }
  342. if (candidateAreaQ32 < targetAreaQ32)
  343. {
  344. differenceQ32 = targetAreaQ32 - candidateAreaQ32;
  345. correctionQ32 = (differenceQ32 + derivativeHz - 1UL)
  346. / derivativeHz;
  347. candidateQ32 = (correctionQ32
  348. >= PLSR_PLANNER_Q32_ONE - candidateQ32)
  349. ? PLSR_PLANNER_Q32_ONE
  350. : candidateQ32 + correctionQ32;
  351. }
  352. else if (candidateAreaQ32 > targetAreaQ32)
  353. {
  354. differenceQ32 = candidateAreaQ32 - targetAreaQ32;
  355. correctionQ32 = differenceQ32 / derivativeHz;
  356. if (correctionQ32 == 0ULL)
  357. {
  358. correctionQ32 = 1ULL;
  359. }
  360. candidateQ32 = (correctionQ32 >= candidateQ32 - previousQ32)
  361. ? previousQ32 + 1ULL
  362. : candidateQ32 - correctionQ32;
  363. }
  364. return candidateQ32;
  365. }
  366. static void PlsrPlannerStartRamp(PLSR_PLANNER_CONTEXT *context,
  367. uint8_t rampKind,
  368. uint32_t fromHz,
  369. uint32_t toHz,
  370. uint32_t pulseCount)
  371. {
  372. context->rampKind = rampKind;
  373. context->rampRelativePulse = 0UL;
  374. context->rampPulseCount = pulseCount;
  375. context->rampFromHz = fromHz;
  376. context->rampToHz = toHz;
  377. context->rampDurationMs = PlsrPlannerRampTime(&context->block,
  378. fromHz, toHz);
  379. context->rampTotalAreaQ32 = PlsrPlannerRampAreaQ32(
  380. context, fromHz, toHz, PLSR_PLANNER_Q32_ONE);
  381. context->rampAreaStepQ32 = context->rampTotalAreaQ32 / pulseCount;
  382. context->rampAreaRemainder =
  383. (uint32_t)(context->rampTotalAreaQ32 % pulseCount);
  384. context->rampRemainderAccumulator = 0UL;
  385. context->rampTargetAreaQ32 = 0ULL;
  386. context->rampBoundaryQ32 = 0ULL;
  387. context->rampActualTimeQ32 = 0ULL;
  388. context->rampLastPhaseStepQ32 = 0ULL;
  389. context->lastRampHz = 0UL;
  390. context->rampFirstBoundaryQ32 = PlsrPlannerExactBoundaryQ32(
  391. context, 0ULL, context->rampAreaStepQ32);
  392. if (pulseCount > 1UL)
  393. {
  394. uint64_t secondTargetAreaQ32 = context->rampAreaStepQ32 * 2ULL
  395. + ((uint64_t)context->rampAreaRemainder * 2ULL) / pulseCount;
  396. context->rampSecondBoundaryQ32 = PlsrPlannerExactBoundaryQ32(
  397. context, context->rampFirstBoundaryQ32,
  398. secondTargetAreaQ32);
  399. }
  400. else
  401. {
  402. context->rampSecondBoundaryQ32 = PLSR_PLANNER_Q32_ONE;
  403. }
  404. }
  405. static uint8_t PlsrPlannerSameSetting(
  406. const PLSR_PLATFORM_TIMER_SETTING *first,
  407. const PLSR_PLATFORM_TIMER_SETTING *second)
  408. {
  409. return ((first->actualFrequencyHz == second->actualFrequencyHz)
  410. && (first->prescaler == second->prescaler)
  411. && (first->pairPrescaler == second->pairPrescaler)
  412. && (first->period == second->period)
  413. && (first->compare == second->compare)) ? 1U : 0U;
  414. }
  415. static uint8_t PlsrPlannerBuildStep(PLSR_PLANNER_CONTEXT *context,
  416. uint32_t requestedHz,
  417. PLSR_PLATFORM_TIMER_SETTING *setting)
  418. {
  419. if (requestedHz == 0UL)
  420. {
  421. requestedHz = 1UL;
  422. }
  423. if (requestedHz > PLSR_FREQUENCY_MAX_HZ)
  424. {
  425. requestedHz = PLSR_FREQUENCY_MAX_HZ;
  426. }
  427. return PlsrPlatformBuildTimerSetting(context->block.pulseOutput,
  428. PLSR_OUTPUT_PULSE_DIR,
  429. requestedHz, setting);
  430. }
  431. static uint8_t PlsrPlannerTakeRampStep(
  432. PLSR_PLANNER_CONTEXT *context,
  433. PLSR_PLATFORM_TIMER_SETTING *setting)
  434. {
  435. uint64_t nextBoundaryQ32;
  436. uint64_t desiredDeltaQ32;
  437. uint64_t denominator;
  438. uint64_t requestedHz;
  439. uint64_t actualDeltaQ32;
  440. context->rampTargetAreaQ32 += context->rampAreaStepQ32;
  441. context->rampRemainderAccumulator += context->rampAreaRemainder;
  442. if (context->rampRemainderAccumulator >= context->rampPulseCount)
  443. {
  444. context->rampTargetAreaQ32++;
  445. context->rampRemainderAccumulator -= context->rampPulseCount;
  446. }
  447. if (context->rampRelativePulse + 1UL >= context->rampPulseCount)
  448. {
  449. context->rampTargetAreaQ32 = context->rampTotalAreaQ32;
  450. nextBoundaryQ32 = PLSR_PLANNER_Q32_ONE;
  451. }
  452. else if (context->rampRelativePulse == 0UL)
  453. {
  454. nextBoundaryQ32 = context->rampFirstBoundaryQ32;
  455. }
  456. else if (context->rampRelativePulse == 1UL)
  457. {
  458. nextBoundaryQ32 = context->rampSecondBoundaryQ32;
  459. }
  460. else
  461. {
  462. nextBoundaryQ32 = PlsrPlannerPredictedBoundaryQ32(
  463. context, context->rampTargetAreaQ32);
  464. }
  465. desiredDeltaQ32 = (nextBoundaryQ32 > context->rampActualTimeQ32)
  466. ? (nextBoundaryQ32 - context->rampActualTimeQ32)
  467. : 1ULL;
  468. /* The allocated pulse count closes the ramp area exactly. Derive the
  469. physical duration from N/averageHz instead of rounding it to whole
  470. milliseconds; short clipped ramps can be well below 1 ms. */
  471. denominator = (uint64_t)context->rampPulseCount * desiredDeltaQ32;
  472. requestedHz = (denominator == 0ULL)
  473. ? context->rampToHz
  474. : (context->rampTotalAreaQ32
  475. + denominator / 2ULL) / denominator;
  476. if (requestedHz == 0ULL)
  477. {
  478. requestedHz = 1ULL;
  479. }
  480. if (requestedHz > PLSR_FREQUENCY_MAX_HZ)
  481. {
  482. requestedHz = PLSR_FREQUENCY_MAX_HZ;
  483. }
  484. if ((context->lastRampHz != 0UL)
  485. && (((context->rampToHz > context->rampFromHz)
  486. && (requestedHz < context->lastRampHz))
  487. || ((context->rampToHz < context->rampFromHz)
  488. && (requestedHz > context->lastRampHz))))
  489. {
  490. requestedHz = context->lastRampHz;
  491. }
  492. if (PlsrPlannerBuildStep(context, (uint32_t)requestedHz, setting) == 0U)
  493. {
  494. return 0U;
  495. }
  496. denominator = (uint64_t)context->rampPulseCount
  497. * setting->actualFrequencyHz;
  498. actualDeltaQ32 = (denominator == 0ULL)
  499. ? desiredDeltaQ32
  500. : (context->rampTotalAreaQ32
  501. + denominator / 2ULL) / denominator;
  502. context->rampActualTimeQ32 += actualDeltaQ32;
  503. context->rampLastPhaseStepQ32 =
  504. nextBoundaryQ32 - context->rampBoundaryQ32;
  505. context->rampBoundaryQ32 = nextBoundaryQ32;
  506. context->lastRampHz = setting->actualFrequencyHz;
  507. context->rampRelativePulse++;
  508. return 1U;
  509. }
  510. static uint8_t PlsrPlannerTakeStep(PLSR_PLANNER_CONTEXT *context,
  511. PLSR_PLATFORM_TIMER_SETTING *setting,
  512. uint32_t *repeatCount)
  513. {
  514. uint32_t entryEnd = context->entryPulses;
  515. uint32_t steadyEnd = entryEnd + context->steadyPulses;
  516. *repeatCount = 1UL;
  517. if (context->generatedPulses >= context->block.pulseBudget)
  518. {
  519. return 0U;
  520. }
  521. if (context->generatedPulses < entryEnd)
  522. {
  523. if (context->rampKind != 1U)
  524. {
  525. PlsrPlannerStartRamp(context, 1U, context->startHz,
  526. context->peakHz, context->entryPulses);
  527. }
  528. return PlsrPlannerTakeRampStep(context, setting);
  529. }
  530. if (context->generatedPulses < steadyEnd)
  531. {
  532. *repeatCount = steadyEnd - context->generatedPulses;
  533. context->rampKind = 0U;
  534. return PlsrPlannerBuildStep(context, context->peakHz, setting);
  535. }
  536. if (context->rampKind != 2U)
  537. {
  538. PlsrPlannerStartRamp(context, 2U, context->peakHz,
  539. context->endHz, context->exitPulses);
  540. }
  541. return PlsrPlannerTakeRampStep(context, setting);
  542. }
  543. PLSR_PLANNER_STATUS PlsrPlannerBegin(PLSR_PLANNER_CONTEXT *context,
  544. const PLSR_MOTION_BLOCK *block,
  545. uint32_t appliedHz,
  546. uint64_t phasePulses)
  547. {
  548. uint64_t directRequired;
  549. uint64_t entryRequired;
  550. uint64_t exitRequired;
  551. uint64_t entryWeight;
  552. uint64_t exitWeight;
  553. uint64_t totalWeight;
  554. uint64_t scaledEntry;
  555. if ((context == NULL) || (block == NULL)
  556. || (block->pulseBudget == 0UL)
  557. || (block->referenceSpeedHz == 0UL)
  558. || (block->referenceSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  559. || (block->entryHz > PLSR_FREQUENCY_MAX_HZ)
  560. || (block->cruiseHz == 0UL)
  561. || (block->cruiseHz > PLSR_FREQUENCY_MAX_HZ)
  562. || (block->exitHz > PLSR_FREQUENCY_MAX_HZ)
  563. || (appliedHz > PLSR_FREQUENCY_MAX_HZ)
  564. || (block->curveMode > 2U) || (block->pulseOutput > 3U))
  565. {
  566. return PLSR_PLANNER_INVALID;
  567. }
  568. (void)memset(context, 0, sizeof(*context));
  569. context->block = *block;
  570. context->phasePulses = phasePulses;
  571. context->startHz = (appliedHz != 0UL) ? appliedHz : block->entryHz;
  572. if (context->startHz == 0UL)
  573. {
  574. context->startHz = 1UL;
  575. }
  576. context->endHz = (block->exitHz == 0UL) ? 1UL : block->exitHz;
  577. directRequired = PlsrPlannerRequiredPulses(
  578. block, PlsrPlannerRampWeight(
  579. context->startHz, context->endHz,
  580. PlsrPlannerBaseRampTime(block, context->startHz,
  581. context->endHz)));
  582. if (directRequired > block->pulseBudget)
  583. {
  584. context->peakHz = PlsrPlannerReachableFrequency(
  585. block, context->startHz, context->endHz, block->pulseBudget);
  586. context->endHz = context->peakHz;
  587. context->entryPulses = block->pulseBudget;
  588. context->clipped = 1U;
  589. context->active = 1U;
  590. return PLSR_PLANNER_CLIPPED;
  591. }
  592. context->peakHz = PlsrPlannerPeak(block, context->startHz,
  593. context->endHz);
  594. entryWeight = PlsrPlannerRampWeight(
  595. context->startHz, context->peakHz,
  596. PlsrPlannerBaseRampTime(block, context->startHz, context->peakHz));
  597. exitWeight = PlsrPlannerRampWeight(
  598. context->peakHz, context->endHz,
  599. PlsrPlannerBaseRampTime(block, context->peakHz, context->endHz));
  600. entryRequired = PlsrPlannerRequiredPulses(block, entryWeight);
  601. exitRequired = PlsrPlannerRequiredPulses(block, exitWeight);
  602. if ((entryRequired + exitRequired) <= block->pulseBudget)
  603. {
  604. context->entryPulses = (uint32_t)entryRequired;
  605. context->exitPulses = (uint32_t)exitRequired;
  606. context->steadyPulses = block->pulseBudget
  607. - context->entryPulses
  608. - context->exitPulses;
  609. }
  610. else if (entryRequired == 0ULL)
  611. {
  612. context->exitPulses = block->pulseBudget;
  613. context->clipped = 1U;
  614. }
  615. else if (exitRequired == 0ULL)
  616. {
  617. context->entryPulses = block->pulseBudget;
  618. context->clipped = 1U;
  619. }
  620. else
  621. {
  622. totalWeight = entryWeight + exitWeight;
  623. scaledEntry = ((uint64_t)block->pulseBudget * entryWeight
  624. + totalWeight / 2ULL) / totalWeight;
  625. if (scaledEntry == 0ULL)
  626. {
  627. scaledEntry = 1ULL;
  628. }
  629. if (scaledEntry >= block->pulseBudget)
  630. {
  631. scaledEntry = block->pulseBudget - 1UL;
  632. }
  633. context->entryPulses = (uint32_t)scaledEntry;
  634. context->exitPulses = block->pulseBudget
  635. - context->entryPulses;
  636. context->clipped = 1U;
  637. }
  638. if (context->peakHz != block->cruiseHz)
  639. {
  640. context->clipped = 1U;
  641. }
  642. context->active = 1U;
  643. return (context->clipped != 0U) ? PLSR_PLANNER_CLIPPED
  644. : PLSR_PLANNER_OK;
  645. }
  646. uint16_t PlsrPlannerGenerate(PLSR_PLANNER_CONTEXT *context,
  647. PLSR_STREAM_ITEM *output,
  648. uint16_t capacity)
  649. {
  650. PLSR_PLATFORM_TIMER_SETTING setting;
  651. uint32_t repeatCount;
  652. uint16_t produced = 0U;
  653. if ((context == NULL) || (output == NULL) || (capacity == 0U)
  654. || (context->active == 0U))
  655. {
  656. return 0U;
  657. }
  658. while ((produced < capacity)
  659. && (context->generatedPulses < context->block.pulseBudget))
  660. {
  661. if (PlsrPlannerTakeStep(context, &setting, &repeatCount) == 0U)
  662. {
  663. context->active = 0U;
  664. break;
  665. }
  666. if ((produced != 0U)
  667. && (PlsrPlannerSameSetting(&output[produced - 1U].setting,
  668. &setting) != 0U)
  669. && (output[produced - 1U].repeatCount
  670. <= 0xFFFFFFFFUL - repeatCount))
  671. {
  672. output[produced - 1U].repeatCount += repeatCount;
  673. }
  674. else
  675. {
  676. output[produced].setting = setting;
  677. output[produced].repeatCount = repeatCount;
  678. produced++;
  679. }
  680. context->generatedPulses += repeatCount;
  681. }
  682. if (context->generatedPulses >= context->block.pulseBudget)
  683. {
  684. context->active = 0U;
  685. }
  686. return produced;
  687. }