Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

749 righe
25 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. uint32_t *normalizedRequestedHz)
  419. {
  420. if (requestedHz == 0UL)
  421. {
  422. requestedHz = 1UL;
  423. }
  424. if (requestedHz > PLSR_FREQUENCY_MAX_HZ)
  425. {
  426. requestedHz = PLSR_FREQUENCY_MAX_HZ;
  427. }
  428. *normalizedRequestedHz = requestedHz;
  429. return PlsrPlatformBuildTimerSetting(context->block.pulseOutput,
  430. PLSR_OUTPUT_PULSE_DIR,
  431. requestedHz, setting);
  432. }
  433. static uint8_t PlsrPlannerTakeRampStep(
  434. PLSR_PLANNER_CONTEXT *context,
  435. PLSR_PLATFORM_TIMER_SETTING *setting,
  436. uint32_t *requestedFrequencyHz)
  437. {
  438. uint64_t nextBoundaryQ32;
  439. uint64_t desiredDeltaQ32;
  440. uint64_t denominator;
  441. uint64_t requestedHz;
  442. uint64_t actualDeltaQ32;
  443. context->rampTargetAreaQ32 += context->rampAreaStepQ32;
  444. context->rampRemainderAccumulator += context->rampAreaRemainder;
  445. if (context->rampRemainderAccumulator >= context->rampPulseCount)
  446. {
  447. context->rampTargetAreaQ32++;
  448. context->rampRemainderAccumulator -= context->rampPulseCount;
  449. }
  450. if (context->rampRelativePulse + 1UL >= context->rampPulseCount)
  451. {
  452. context->rampTargetAreaQ32 = context->rampTotalAreaQ32;
  453. nextBoundaryQ32 = PLSR_PLANNER_Q32_ONE;
  454. }
  455. else if (context->rampRelativePulse == 0UL)
  456. {
  457. nextBoundaryQ32 = context->rampFirstBoundaryQ32;
  458. }
  459. else if (context->rampRelativePulse == 1UL)
  460. {
  461. nextBoundaryQ32 = context->rampSecondBoundaryQ32;
  462. }
  463. else
  464. {
  465. nextBoundaryQ32 = PlsrPlannerPredictedBoundaryQ32(
  466. context, context->rampTargetAreaQ32);
  467. }
  468. desiredDeltaQ32 = (nextBoundaryQ32 > context->rampActualTimeQ32)
  469. ? (nextBoundaryQ32 - context->rampActualTimeQ32)
  470. : 1ULL;
  471. /* The allocated pulse count closes the ramp area exactly. Derive the
  472. physical duration from N/averageHz instead of rounding it to whole
  473. milliseconds; short clipped ramps can be well below 1 ms. */
  474. denominator = (uint64_t)context->rampPulseCount * desiredDeltaQ32;
  475. requestedHz = (denominator == 0ULL)
  476. ? context->rampToHz
  477. : (context->rampTotalAreaQ32
  478. + denominator / 2ULL) / denominator;
  479. if (requestedHz == 0ULL)
  480. {
  481. requestedHz = 1ULL;
  482. }
  483. if (requestedHz > PLSR_FREQUENCY_MAX_HZ)
  484. {
  485. requestedHz = PLSR_FREQUENCY_MAX_HZ;
  486. }
  487. if ((context->lastRampHz != 0UL)
  488. && (((context->rampToHz > context->rampFromHz)
  489. && (requestedHz < context->lastRampHz))
  490. || ((context->rampToHz < context->rampFromHz)
  491. && (requestedHz > context->lastRampHz))))
  492. {
  493. requestedHz = context->lastRampHz;
  494. }
  495. if (PlsrPlannerBuildStep(context, (uint32_t)requestedHz, setting,
  496. requestedFrequencyHz) == 0U)
  497. {
  498. return 0U;
  499. }
  500. denominator = (uint64_t)context->rampPulseCount
  501. * setting->actualFrequencyHz;
  502. actualDeltaQ32 = (denominator == 0ULL)
  503. ? desiredDeltaQ32
  504. : (context->rampTotalAreaQ32
  505. + denominator / 2ULL) / denominator;
  506. context->rampActualTimeQ32 += actualDeltaQ32;
  507. context->rampLastPhaseStepQ32 =
  508. nextBoundaryQ32 - context->rampBoundaryQ32;
  509. context->rampBoundaryQ32 = nextBoundaryQ32;
  510. context->lastRampHz = setting->actualFrequencyHz;
  511. context->rampRelativePulse++;
  512. return 1U;
  513. }
  514. static uint8_t PlsrPlannerTakeStep(PLSR_PLANNER_CONTEXT *context,
  515. PLSR_PLATFORM_TIMER_SETTING *setting,
  516. uint32_t *requestedFrequencyHz,
  517. uint32_t *repeatCount)
  518. {
  519. uint32_t entryEnd = context->entryPulses;
  520. uint32_t steadyEnd = entryEnd + context->steadyPulses;
  521. *repeatCount = 1UL;
  522. if (context->generatedPulses >= context->block.pulseBudget)
  523. {
  524. return 0U;
  525. }
  526. if (context->generatedPulses < entryEnd)
  527. {
  528. if (context->rampKind != 1U)
  529. {
  530. PlsrPlannerStartRamp(context, 1U, context->startHz,
  531. context->peakHz, context->entryPulses);
  532. }
  533. return PlsrPlannerTakeRampStep(context, setting,
  534. requestedFrequencyHz);
  535. }
  536. if (context->generatedPulses < steadyEnd)
  537. {
  538. *repeatCount = steadyEnd - context->generatedPulses;
  539. context->rampKind = 0U;
  540. return PlsrPlannerBuildStep(context, context->peakHz, setting,
  541. requestedFrequencyHz);
  542. }
  543. if (context->rampKind != 2U)
  544. {
  545. PlsrPlannerStartRamp(context, 2U, context->peakHz,
  546. context->endHz, context->exitPulses);
  547. }
  548. return PlsrPlannerTakeRampStep(context, setting,
  549. requestedFrequencyHz);
  550. }
  551. PLSR_PLANNER_STATUS PlsrPlannerBegin(PLSR_PLANNER_CONTEXT *context,
  552. const PLSR_MOTION_BLOCK *block,
  553. uint32_t appliedHz,
  554. uint64_t phasePulses)
  555. {
  556. uint64_t directRequired;
  557. uint64_t entryRequired;
  558. uint64_t exitRequired;
  559. uint64_t entryWeight;
  560. uint64_t exitWeight;
  561. uint64_t totalWeight;
  562. uint64_t scaledEntry;
  563. if ((context == NULL) || (block == NULL)
  564. || (block->pulseBudget == 0UL)
  565. || (block->referenceSpeedHz == 0UL)
  566. || (block->referenceSpeedHz > PLSR_FREQUENCY_MAX_HZ)
  567. || (block->entryHz > PLSR_FREQUENCY_MAX_HZ)
  568. || (block->cruiseHz == 0UL)
  569. || (block->cruiseHz > PLSR_FREQUENCY_MAX_HZ)
  570. || (block->exitHz > PLSR_FREQUENCY_MAX_HZ)
  571. || (appliedHz > PLSR_FREQUENCY_MAX_HZ)
  572. || (block->curveMode > 2U) || (block->pulseOutput > 3U))
  573. {
  574. return PLSR_PLANNER_INVALID;
  575. }
  576. (void)memset(context, 0, sizeof(*context));
  577. context->block = *block;
  578. context->phasePulses = phasePulses;
  579. context->startHz = (appliedHz != 0UL) ? appliedHz : block->entryHz;
  580. if (context->startHz == 0UL)
  581. {
  582. context->startHz = 1UL;
  583. }
  584. context->endHz = (block->exitHz == 0UL) ? 1UL : block->exitHz;
  585. directRequired = PlsrPlannerRequiredPulses(
  586. block, PlsrPlannerRampWeight(
  587. context->startHz, context->endHz,
  588. PlsrPlannerBaseRampTime(block, context->startHz,
  589. context->endHz)));
  590. if (directRequired > block->pulseBudget)
  591. {
  592. context->peakHz = PlsrPlannerReachableFrequency(
  593. block, context->startHz, context->endHz, block->pulseBudget);
  594. context->endHz = context->peakHz;
  595. context->entryPulses = block->pulseBudget;
  596. context->clipped = 1U;
  597. context->active = 1U;
  598. return PLSR_PLANNER_CLIPPED;
  599. }
  600. context->peakHz = PlsrPlannerPeak(block, context->startHz,
  601. context->endHz);
  602. entryWeight = PlsrPlannerRampWeight(
  603. context->startHz, context->peakHz,
  604. PlsrPlannerBaseRampTime(block, context->startHz, context->peakHz));
  605. exitWeight = PlsrPlannerRampWeight(
  606. context->peakHz, context->endHz,
  607. PlsrPlannerBaseRampTime(block, context->peakHz, context->endHz));
  608. entryRequired = PlsrPlannerRequiredPulses(block, entryWeight);
  609. exitRequired = PlsrPlannerRequiredPulses(block, exitWeight);
  610. if ((entryRequired + exitRequired) <= block->pulseBudget)
  611. {
  612. context->entryPulses = (uint32_t)entryRequired;
  613. context->exitPulses = (uint32_t)exitRequired;
  614. context->steadyPulses = block->pulseBudget
  615. - context->entryPulses
  616. - context->exitPulses;
  617. }
  618. else if (entryRequired == 0ULL)
  619. {
  620. context->exitPulses = block->pulseBudget;
  621. context->clipped = 1U;
  622. }
  623. else if (exitRequired == 0ULL)
  624. {
  625. context->entryPulses = block->pulseBudget;
  626. context->clipped = 1U;
  627. }
  628. else
  629. {
  630. totalWeight = entryWeight + exitWeight;
  631. scaledEntry = ((uint64_t)block->pulseBudget * entryWeight
  632. + totalWeight / 2ULL) / totalWeight;
  633. if (scaledEntry == 0ULL)
  634. {
  635. scaledEntry = 1ULL;
  636. }
  637. if (scaledEntry >= block->pulseBudget)
  638. {
  639. scaledEntry = block->pulseBudget - 1UL;
  640. }
  641. context->entryPulses = (uint32_t)scaledEntry;
  642. context->exitPulses = block->pulseBudget
  643. - context->entryPulses;
  644. context->clipped = 1U;
  645. }
  646. if (context->peakHz != block->cruiseHz)
  647. {
  648. context->clipped = 1U;
  649. }
  650. context->active = 1U;
  651. return (context->clipped != 0U) ? PLSR_PLANNER_CLIPPED
  652. : PLSR_PLANNER_OK;
  653. }
  654. uint16_t PlsrPlannerGenerate(PLSR_PLANNER_CONTEXT *context,
  655. PLSR_STREAM_ITEM *output,
  656. uint16_t capacity)
  657. {
  658. PLSR_PLATFORM_TIMER_SETTING setting;
  659. uint32_t requestedFrequencyHz;
  660. uint32_t repeatCount;
  661. uint16_t produced = 0U;
  662. if ((context == NULL) || (output == NULL) || (capacity == 0U)
  663. || (context->active == 0U))
  664. {
  665. return 0U;
  666. }
  667. while ((produced < capacity)
  668. && (context->generatedPulses < context->block.pulseBudget))
  669. {
  670. if (PlsrPlannerTakeStep(context, &setting, &requestedFrequencyHz,
  671. &repeatCount) == 0U)
  672. {
  673. context->active = 0U;
  674. break;
  675. }
  676. if ((produced != 0U)
  677. && (PlsrPlannerSameSetting(&output[produced - 1U].setting,
  678. &setting) != 0U)
  679. && (output[produced - 1U].requestedFrequencyHz
  680. == requestedFrequencyHz)
  681. && (output[produced - 1U].repeatCount
  682. <= 0xFFFFFFFFUL - repeatCount))
  683. {
  684. output[produced - 1U].repeatCount += repeatCount;
  685. }
  686. else
  687. {
  688. output[produced].setting = setting;
  689. output[produced].requestedFrequencyHz = requestedFrequencyHz;
  690. output[produced].repeatCount = repeatCount;
  691. produced++;
  692. }
  693. context->generatedPulses += repeatCount;
  694. }
  695. if (context->generatedPulses >= context->block.pulseBudget)
  696. {
  697. context->active = 0U;
  698. }
  699. return produced;
  700. }