Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

1110 rindas
44 KiB

  1. #include "plsr_self_test.h"
  2. #include "plsr_build_config.h"
  3. #include "plc_device.h"
  4. #include "modbus_data_store.h"
  5. #include "plsr_core.h"
  6. #include "plsr_job.h"
  7. #include "plsr_modbus_data.h"
  8. #include <string.h>
  9. #if PLSR_ENABLE_BOARD_SELF_TEST != 0U
  10. /* 上电自测(验证后可删除):
  11. * - AB 模式使用 Q0(A)/Q1(B),其余用出厂默认参数(K1)
  12. * - 任务:3 段完整 AB 周期(H00 完成,顺序衔接):
  13. * 段1:2000Hz / +1000 周期(A 超前 B)
  14. * 段2:5000Hz / +6000 周期(A 超前 B)
  15. * 段3:1000Hz / -500 周期(B 超前 A,验证反向)
  16. * 数据源为静态数组,仅自测使用(正式 D 设备适配器见 Modbus 阶段)。 */
  17. #define SELF_TEST_WORD_CAPACITY (192U)
  18. #define SELF_TEST_S0_BASE (10U)
  19. #define SELF_TEST_S1_BASE (60U)
  20. #define SELF_TEST_DIR_POINT (4U)
  21. #define SELF_TEST_SFD_AXIS_STRIDE (130U)
  22. #define SELF_TEST_SFD_SET_OFFSET (50U)
  23. #define SELF_TEST_MODBUS_S0_BASE (1000UL)
  24. #define SELF_TEST_MODBUS_S1_BASE (1100UL)
  25. static uint16_t SelfTestWords[3][SELF_TEST_WORD_CAPACITY];
  26. volatile int32_t PlsrSelfTestLiveFrequencyHz;
  27. volatile uint32_t PlsrSelfTestDynamicTick100us;
  28. volatile uint8_t PlsrSelfTestDynamicPhase;
  29. static volatile uint8_t PlsrSelfTestDynamicEnabled;
  30. void PlsrSelfTestControlTick100us(void)
  31. {
  32. if (PlsrSelfTestDynamicEnabled == 0U)
  33. {
  34. return;
  35. }
  36. if (PlsrSelfTestDynamicTick100us != UINT32_MAX)
  37. {
  38. PlsrSelfTestDynamicTick100us++;
  39. }
  40. switch (PlsrSelfTestDynamicTick100us)
  41. {
  42. case 10000UL: /* 1.0s: 1000 -> 4000Hz. */
  43. PlsrSelfTestLiveFrequencyHz = 4000;
  44. PlsrSelfTestDynamicPhase = 1U;
  45. break;
  46. case 15000UL: /* 1.5s: 4000 -> 500Hz. */
  47. PlsrSelfTestLiveFrequencyHz = 500;
  48. PlsrSelfTestDynamicPhase = 2U;
  49. break;
  50. case 20000UL: /* 2.0s: zero selects the 1000Hz S2 default. */
  51. PlsrSelfTestLiveFrequencyHz = 0;
  52. PlsrSelfTestDynamicPhase = 3U;
  53. break;
  54. case 22000UL: /* 2.2s: 8000 is clamped to the 5000Hz maximum. */
  55. PlsrSelfTestLiveFrequencyHz = 8000;
  56. PlsrSelfTestDynamicPhase = 4U;
  57. break;
  58. case 27000UL: /* 2.7s: invalid value must retain the safe target. */
  59. PlsrSelfTestLiveFrequencyHz = -1;
  60. PlsrSelfTestDynamicPhase = 5U;
  61. break;
  62. case 29000UL: /* 2.9s: recover and hold 2000Hz. */
  63. PlsrSelfTestLiveFrequencyHz = 2000;
  64. PlsrSelfTestDynamicPhase = 6U;
  65. PlsrSelfTestDynamicEnabled = 0U;
  66. break;
  67. default:
  68. break;
  69. }
  70. }
  71. static uint8_t SelfTestValidateWords(void *context,
  72. PLSR_DEVICE_TYPE device,
  73. uint32_t firstAddress,
  74. uint32_t wordCount)
  75. {
  76. (void)context;
  77. if ((device > PLSR_DEVICE_FD) || (wordCount == 0UL))
  78. {
  79. return 0U;
  80. }
  81. return (((uint64_t)firstAddress + wordCount)
  82. <= SELF_TEST_WORD_CAPACITY)
  83. ? 1U
  84. : 0U;
  85. }
  86. static uint8_t SelfTestReadWord(void *context,
  87. PLSR_DEVICE_TYPE device,
  88. uint32_t address,
  89. uint16_t *value)
  90. {
  91. (void)context;
  92. if ((device > PLSR_DEVICE_FD) || (value == NULL)
  93. || (address >= SELF_TEST_WORD_CAPACITY))
  94. {
  95. return 0U;
  96. }
  97. *value = SelfTestWords[device][address];
  98. return 1U;
  99. }
  100. static uint8_t SelfTestReadDwordLive(void *context,
  101. PLSR_DEVICE_TYPE device,
  102. uint32_t address,
  103. int32_t *value)
  104. {
  105. uint16_t lowWord;
  106. uint16_t highWord;
  107. if (value == NULL)
  108. {
  109. return 0U;
  110. }
  111. if ((device == PLSR_DEVICE_D)
  112. && (address == SELF_TEST_S0_BASE + 10UL))
  113. {
  114. /* Aligned Cortex-M4 dword load: atomic source for the TIM6 ISR. */
  115. *value = PlsrSelfTestLiveFrequencyHz;
  116. return 1U;
  117. }
  118. if ((SelfTestReadWord(context, device, address, &lowWord) == 0U)
  119. || (SelfTestReadWord(context,
  120. device,
  121. address + 1UL,
  122. &highWord) == 0U))
  123. {
  124. return 0U;
  125. }
  126. *value = (int32_t)(((uint32_t)highWord << 16U) | lowWord);
  127. return 1U;
  128. }
  129. static uint8_t SelfTestReadBit(void *context,
  130. PLSR_DEVICE_TYPE device,
  131. uint32_t address,
  132. uint8_t *value)
  133. {
  134. (void)context;
  135. (void)device;
  136. (void)address;
  137. *value = 0U;
  138. return 1U;
  139. }
  140. static void SelfTestWriteDword(PLSR_DEVICE_TYPE device,
  141. uint32_t address,
  142. uint32_t value)
  143. {
  144. SelfTestWords[device][address] = (uint16_t)(value & 0xFFFFUL);
  145. SelfTestWords[device][address + 1UL] = (uint16_t)(value >> 16U);
  146. }
  147. static void SelfTestWriteSfdDword(uint16_t address, uint32_t value)
  148. {
  149. (void)PlcDeviceWriteSfd(address, (uint16_t)(value & 0xFFFFUL));
  150. (void)PlcDeviceWriteSfd((uint16_t)(address + 1U),
  151. (uint16_t)(value >> 16U));
  152. }
  153. PLSR_RESULT PlsrSelfTestQueue(void)
  154. {
  155. PLSR_CALL call;
  156. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  157. /* 方向端子 Y4(PULSE/DIR 模式必需,接线参数)。 */
  158. (void)PlcDeviceWriteSfd(906U, SELF_TEST_DIR_POINT);
  159. (void)PlcDeviceWriteSfd(912U, 0U);
  160. (void)PlcDeviceWriteSfd(915U, 0xFFFFU);
  161. /* S0:3 段,H00 完成,顺序跳转。 */
  162. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 3U);
  163. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 10U, 2000UL);
  164. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 12U, 1000UL);
  165. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 20U, 5000UL);
  166. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 22U, 6000UL);
  167. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 30U, 1000UL);
  168. SelfTestWriteDword(PLSR_DEVICE_D,
  169. SELF_TEST_S0_BASE + 32U,
  170. (uint32_t)(int32_t)-500);
  171. /* S1:相对模式,起始段 0(=段1)。 */
  172. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U);
  173. (void)memset(&call, 0, sizeof(call));
  174. call.sequence = 0xA5A5UL;
  175. call.source.context = NULL;
  176. call.source.validateWords = SelfTestValidateWords;
  177. call.source.readWord = SelfTestReadWord;
  178. call.source.readBit = SelfTestReadBit;
  179. call.s0.device = PLSR_DEVICE_D;
  180. call.s0.address = SELF_TEST_S0_BASE;
  181. call.s1.device = PLSR_DEVICE_D;
  182. call.s1.address = SELF_TEST_S1_BASE;
  183. call.s2.type = PLSR_OPERAND_CONSTANT;
  184. call.s2.constant = 1;
  185. call.dAxis = 0U;
  186. call.outputModeOverride = PLSR_OUTPUT_AB;
  187. return PlsrPostCall(&call);
  188. }
  189. PLSR_RESULT PlsrEquivalentSelfTestQueue(void)
  190. {
  191. PLSR_CALL call;
  192. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  193. /* SFD900 Bit10~8=001(1um当量);3脉冲/2单位。 */
  194. (void)PlcDeviceWriteSfd(900U, (1U << 8U));
  195. SelfTestWriteSfdDword(902U, 3UL);
  196. SelfTestWriteSfdDword(904U, 2UL);
  197. (void)PlcDeviceWriteSfd(906U, SELF_TEST_DIR_POINT);
  198. (void)PlcDeviceWriteSfd(907U, 10U);
  199. (void)PlcDeviceWriteSfd(912U, 0U);
  200. (void)PlcDeviceWriteSfd(915U, 0xFFFFU);
  201. /* 当量换算后物理最高速度=90000Hz,不超过硬件100kHz。 */
  202. SelfTestWriteSfdDword(956U, 60000UL);
  203. /* 板端可观察版本:两段各1001工程单位。
  204. * 3脉冲/2单位带余数换算后分别输出1501、1502脉冲,累计3003脉冲;
  205. * 1500Hz附近持续约2s,避免原3脉冲自检在逻辑分析仪启动前已经结束。 */
  206. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 2U);
  207. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 10U, 1000UL);
  208. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 12U, 1001UL);
  209. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 20U, 1000UL);
  210. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE + 22U, 1001UL);
  211. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U);
  212. (void)memset(&call, 0, sizeof(call));
  213. call.sequence = 0xA5A6UL;
  214. call.source.context = NULL;
  215. call.source.validateWords = SelfTestValidateWords;
  216. call.source.readWord = SelfTestReadWord;
  217. call.source.readBit = SelfTestReadBit;
  218. call.s0.device = PLSR_DEVICE_D;
  219. call.s0.address = SELF_TEST_S0_BASE;
  220. call.s1.device = PLSR_DEVICE_D;
  221. call.s1.address = SELF_TEST_S1_BASE;
  222. call.s2.type = PLSR_OPERAND_CONSTANT;
  223. call.s2.constant = 1;
  224. call.dAxis = 0U;
  225. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  226. return PlsrPostCall(&call);
  227. }
  228. PLSR_RESULT PlsrProtectionSelfTestQueue(void)
  229. {
  230. PLSR_CALL call;
  231. PLSR_COMMAND command;
  232. PLSR_RESULT result;
  233. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  234. /* Pulse unit, soft limits enabled, 1 pulse per position unit. */
  235. (void)PlcDeviceWriteSfd(900U, (1U << 2U));
  236. SelfTestWriteSfdDword(902U, 1UL);
  237. SelfTestWriteSfdDword(904U, 1UL);
  238. (void)PlcDeviceWriteSfd(906U, SELF_TEST_DIR_POINT);
  239. (void)PlcDeviceWriteSfd(907U, 10U);
  240. (void)PlcDeviceWriteSfd(912U, 0U);
  241. (void)PlcDeviceWriteSfd(915U, 0xFFFFU);
  242. SelfTestWriteSfdDword(930U, 500UL);
  243. SelfTestWriteSfdDword(932U, (uint32_t)(int32_t)-500);
  244. /* K1: 1000Hz, 100ms acceleration/deceleration, 1ms refresh. */
  245. SelfTestWriteSfdDword(950U, 1000UL);
  246. (void)PlcDeviceWriteSfd(952U, 100U);
  247. (void)PlcDeviceWriteSfd(953U, 100U);
  248. (void)PlcDeviceWriteSfd(954U, 0U);
  249. (void)PlcDeviceWriteSfd(955U, 0U);
  250. SelfTestWriteSfdDword(956U, 100000UL);
  251. SelfTestWriteSfdDword(958U, 1000UL);
  252. SelfTestWriteSfdDword(960U, 0UL);
  253. (void)PlcDeviceWriteSfd(962U, 50U);
  254. (void)PlcDeviceWriteSfd(963U, 0U);
  255. (void)PlcDeviceWriteSfd(964U, 0U);
  256. SelfTestWriteSfdDword(966U, 2000UL);
  257. SelfTestWriteSfdDword(968U, 200UL);
  258. /* One relative segment requests +10000 pulses; +500 must stop it. */
  259. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 1U);
  260. SelfTestWriteDword(PLSR_DEVICE_D,
  261. SELF_TEST_S0_BASE + 10U,
  262. 1000UL);
  263. SelfTestWriteDword(PLSR_DEVICE_D,
  264. SELF_TEST_S0_BASE + 12U,
  265. 10000UL);
  266. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U);
  267. (void)memset(&command, 0, sizeof(command));
  268. command.sequence = 0xA5A7UL;
  269. command.axis = 0U;
  270. command.opcode = PLSR_CMD_SET_POSITION;
  271. command.argument = 0;
  272. result = PlsrPostCommand(&command);
  273. if (result != PLSR_RESULT_QUEUED)
  274. {
  275. return result;
  276. }
  277. (void)memset(&call, 0, sizeof(call));
  278. call.sequence = 0xA5A8UL;
  279. call.source.context = NULL;
  280. call.source.validateWords = SelfTestValidateWords;
  281. call.source.readWord = SelfTestReadWord;
  282. call.source.readBit = SelfTestReadBit;
  283. call.s0.device = PLSR_DEVICE_D;
  284. call.s0.address = SELF_TEST_S0_BASE;
  285. call.s1.device = PLSR_DEVICE_D;
  286. call.s1.address = SELF_TEST_S1_BASE;
  287. call.s2.type = PLSR_OPERAND_CONSTANT;
  288. call.s2.constant = 1;
  289. call.dAxis = 0U;
  290. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  291. return PlsrPostCall(&call);
  292. }
  293. PLSR_RESULT PlsrFourAxisSelfTestQueue(void)
  294. {
  295. static const uint16_t s0Base[PLSR_AXIS_COUNT] =
  296. {
  297. 10U, 40U, 70U, 100U
  298. };
  299. static const uint16_t s1Base[PLSR_AXIS_COUNT] =
  300. {
  301. 160U, 164U, 168U, 172U
  302. };
  303. static const uint32_t frequencyHz[PLSR_AXIS_COUNT] =
  304. {
  305. 1000UL, 2000UL, 3000UL, 4000UL
  306. };
  307. static const int32_t pulseCount[PLSR_AXIS_COUNT] =
  308. {
  309. 1000, 2000, 3000, 4000
  310. };
  311. PLSR_CALL call;
  312. PLSR_COMMAND command;
  313. PLSR_RESULT result;
  314. uint16_t commonBase;
  315. uint16_t setBase;
  316. uint8_t axis;
  317. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  318. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  319. {
  320. commonBase = (uint16_t)(900U
  321. + (uint16_t)axis
  322. * SELF_TEST_SFD_AXIS_STRIDE);
  323. setBase = (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  324. /* Pulse unit, PULSE/DIR, no limit input, Q4..Q7 as DIR. */
  325. (void)PlcDeviceWriteSfd(commonBase, 0U);
  326. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  327. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  328. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U),
  329. (uint16_t)(SELF_TEST_DIR_POINT + axis));
  330. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U);
  331. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  332. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  333. /* K1 has no ramp so all four channels keep an exact fixed rate. */
  334. SelfTestWriteSfdDword(setBase, frequencyHz[axis]);
  335. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 0U);
  336. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 0U);
  337. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  338. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  339. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 100000UL);
  340. SelfTestWriteSfdDword((uint16_t)(setBase + 8U),
  341. frequencyHz[axis]);
  342. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL);
  343. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  344. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  345. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 0U);
  346. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  347. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  348. SelfTestWriteDword(PLSR_DEVICE_D, s0Base[axis], 1U);
  349. SelfTestWriteDword(PLSR_DEVICE_D,
  350. (uint32_t)s0Base[axis] + 10UL,
  351. frequencyHz[axis]);
  352. SelfTestWriteDword(PLSR_DEVICE_D,
  353. (uint32_t)s0Base[axis] + 12UL,
  354. (uint32_t)pulseCount[axis]);
  355. SelfTestWriteDword(PLSR_DEVICE_D, s1Base[axis], 0U);
  356. /* Make the board-test result independent of a previously restored
  357. * Backup SRAM position. */
  358. (void)memset(&command, 0, sizeof(command));
  359. command.sequence = 0xA500UL + axis;
  360. command.axis = axis;
  361. command.opcode = PLSR_CMD_SET_POSITION;
  362. command.argument = 0;
  363. result = PlsrPostCommand(&command);
  364. if (result != PLSR_RESULT_QUEUED)
  365. {
  366. return result;
  367. }
  368. (void)memset(&call, 0, sizeof(call));
  369. call.sequence = 0xA600UL + axis;
  370. call.source.context = NULL;
  371. call.source.validateWords = SelfTestValidateWords;
  372. call.source.readWord = SelfTestReadWord;
  373. call.source.readBit = SelfTestReadBit;
  374. call.s0.device = PLSR_DEVICE_D;
  375. call.s0.address = s0Base[axis];
  376. call.s1.device = PLSR_DEVICE_D;
  377. call.s1.address = s1Base[axis];
  378. call.s2.type = PLSR_OPERAND_CONSTANT;
  379. call.s2.constant = 1;
  380. call.dAxis = axis;
  381. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  382. result = PlsrPostCall(&call);
  383. if (result != PLSR_RESULT_QUEUED)
  384. {
  385. return result;
  386. }
  387. }
  388. return PLSR_RESULT_QUEUED;
  389. }
  390. PLSR_RESULT PlsrBacklashSelfTestQueue(void)
  391. {
  392. PLSR_CALL call;
  393. PLSR_COMMAND command;
  394. PLSR_RESULT result;
  395. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  396. /* Pulse unit, Q4 direction, +10/-20 pulse backlash. */
  397. (void)PlcDeviceWriteSfd(900U, 0U);
  398. SelfTestWriteSfdDword(902U, 1UL);
  399. SelfTestWriteSfdDword(904U, 1UL);
  400. (void)PlcDeviceWriteSfd(906U, SELF_TEST_DIR_POINT);
  401. (void)PlcDeviceWriteSfd(907U, 10U);
  402. (void)PlcDeviceWriteSfd(908U, 10U);
  403. (void)PlcDeviceWriteSfd(909U, 20U);
  404. (void)PlcDeviceWriteSfd(912U, 0U);
  405. (void)PlcDeviceWriteSfd(915U, 0xFFFFU);
  406. /* K1 user segments are fixed 1kHz. Backlash blocks use a 20ms
  407. * acceleration/deceleration parameter. */
  408. SelfTestWriteSfdDword(950U, 1000UL);
  409. (void)PlcDeviceWriteSfd(952U, 0U);
  410. (void)PlcDeviceWriteSfd(953U, 0U);
  411. (void)PlcDeviceWriteSfd(954U, 20U);
  412. (void)PlcDeviceWriteSfd(955U, 0U);
  413. SelfTestWriteSfdDword(956U, 100000UL);
  414. SelfTestWriteSfdDword(958U, 1000UL);
  415. SelfTestWriteSfdDword(960U, 0UL);
  416. (void)PlcDeviceWriteSfd(962U, 50U);
  417. (void)PlcDeviceWriteSfd(963U, 0U);
  418. (void)PlcDeviceWriteSfd(964U, 0U);
  419. SelfTestWriteSfdDword(966U, 2000UL);
  420. SelfTestWriteSfdDword(968U, 200UL);
  421. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 3U);
  422. SelfTestWriteDword(PLSR_DEVICE_D,
  423. SELF_TEST_S0_BASE + 10U,
  424. 1000UL);
  425. SelfTestWriteDword(PLSR_DEVICE_D,
  426. SELF_TEST_S0_BASE + 12U,
  427. 200UL);
  428. SelfTestWriteDword(PLSR_DEVICE_D,
  429. SELF_TEST_S0_BASE + 20U,
  430. 1000UL);
  431. SelfTestWriteDword(PLSR_DEVICE_D,
  432. SELF_TEST_S0_BASE + 22U,
  433. (uint32_t)(int32_t)-200);
  434. SelfTestWriteDword(PLSR_DEVICE_D,
  435. SELF_TEST_S0_BASE + 30U,
  436. 1000UL);
  437. SelfTestWriteDword(PLSR_DEVICE_D,
  438. SELF_TEST_S0_BASE + 32U,
  439. 100UL);
  440. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U);
  441. (void)memset(&command, 0, sizeof(command));
  442. command.sequence = 0xA700UL;
  443. command.axis = 0U;
  444. command.opcode = PLSR_CMD_SET_POSITION;
  445. command.argument = 0;
  446. result = PlsrPostCommand(&command);
  447. if (result != PLSR_RESULT_QUEUED)
  448. {
  449. return result;
  450. }
  451. (void)memset(&call, 0, sizeof(call));
  452. call.sequence = 0xA701UL;
  453. call.source.context = NULL;
  454. call.source.validateWords = SelfTestValidateWords;
  455. call.source.readWord = SelfTestReadWord;
  456. call.source.readBit = SelfTestReadBit;
  457. call.s0.device = PLSR_DEVICE_D;
  458. call.s0.address = SELF_TEST_S0_BASE;
  459. call.s1.device = PLSR_DEVICE_D;
  460. call.s1.address = SELF_TEST_S1_BASE;
  461. call.s2.type = PLSR_OPERAND_CONSTANT;
  462. call.s2.constant = 1;
  463. call.dAxis = 0U;
  464. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  465. return PlsrPostCall(&call);
  466. }
  467. PLSR_RESULT PlsrDirectionLogicSelfTestQueue(void)
  468. {
  469. static const uint16_t s0Base[2] = {10U, 40U};
  470. static const uint16_t s1Base[2] = {160U, 164U};
  471. static const uint8_t directionPoint[2] = {4U, 3U};
  472. PLSR_CALL call;
  473. PLSR_COMMAND command;
  474. PLSR_RESULT result;
  475. uint16_t commonBase;
  476. uint16_t setBase;
  477. uint8_t axis;
  478. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  479. for (axis = 0U; axis < 2U; axis++)
  480. {
  481. commonBase = (uint16_t)(900U
  482. + (uint16_t)axis
  483. * SELF_TEST_SFD_AXIS_STRIDE);
  484. setBase = (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  485. /* Axis 0 uses positive logic; axis 1 uses negative logic. */
  486. (void)PlcDeviceWriteSfd(commonBase,
  487. (axis == 0U) ? 0U : (1U << 1U));
  488. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  489. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  490. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U),
  491. directionPoint[axis]);
  492. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U);
  493. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  494. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  495. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  496. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  497. SelfTestWriteSfdDword(setBase, 1000UL);
  498. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 0U);
  499. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 0U);
  500. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  501. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  502. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 100000UL);
  503. SelfTestWriteSfdDword((uint16_t)(setBase + 8U), 1000UL);
  504. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL);
  505. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  506. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  507. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 0U);
  508. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  509. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  510. SelfTestWriteDword(PLSR_DEVICE_D, s0Base[axis], 2U);
  511. SelfTestWriteDword(PLSR_DEVICE_D,
  512. (uint32_t)s0Base[axis] + 10UL,
  513. 1000UL);
  514. SelfTestWriteDword(PLSR_DEVICE_D,
  515. (uint32_t)s0Base[axis] + 12UL,
  516. 200UL);
  517. SelfTestWriteDword(PLSR_DEVICE_D,
  518. (uint32_t)s0Base[axis] + 20UL,
  519. 1000UL);
  520. SelfTestWriteDword(PLSR_DEVICE_D,
  521. (uint32_t)s0Base[axis] + 22UL,
  522. (uint32_t)(int32_t)-200);
  523. SelfTestWriteDword(PLSR_DEVICE_D, s1Base[axis], 0U);
  524. (void)memset(&command, 0, sizeof(command));
  525. command.sequence = 0xA800UL + axis;
  526. command.axis = axis;
  527. command.opcode = PLSR_CMD_SET_POSITION;
  528. command.argument = 0;
  529. result = PlsrPostCommand(&command);
  530. if (result != PLSR_RESULT_QUEUED)
  531. {
  532. return result;
  533. }
  534. (void)memset(&call, 0, sizeof(call));
  535. call.sequence = 0xA810UL + axis;
  536. call.source.context = NULL;
  537. call.source.validateWords = SelfTestValidateWords;
  538. call.source.readWord = SelfTestReadWord;
  539. call.source.readBit = SelfTestReadBit;
  540. call.s0.device = PLSR_DEVICE_D;
  541. call.s0.address = s0Base[axis];
  542. call.s1.device = PLSR_DEVICE_D;
  543. call.s1.address = s1Base[axis];
  544. call.s2.type = PLSR_OPERAND_CONSTANT;
  545. call.s2.constant = 1;
  546. call.dAxis = axis;
  547. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  548. result = PlsrPostCall(&call);
  549. if (result != PLSR_RESULT_QUEUED)
  550. {
  551. return result;
  552. }
  553. }
  554. return PLSR_RESULT_QUEUED;
  555. }
  556. PLSR_RESULT PlsrCwCcwSelfTestQueue(void)
  557. {
  558. const uint16_t commonBase = 900U;
  559. const uint16_t setBase =
  560. (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  561. PLSR_CALL call;
  562. PLSR_COMMAND command;
  563. PLSR_RESULT result;
  564. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  565. (void)PlcDeviceWriteSfd(commonBase, 0U);
  566. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  567. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  568. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U),
  569. SELF_TEST_DIR_POINT);
  570. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U);
  571. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  572. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  573. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  574. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  575. SelfTestWriteSfdDword(setBase, 2000UL);
  576. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 0U);
  577. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 0U);
  578. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  579. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  580. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 100000UL);
  581. SelfTestWriteSfdDword((uint16_t)(setBase + 8U), 1000UL);
  582. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL);
  583. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  584. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  585. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 0U);
  586. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  587. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  588. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 2U);
  589. SelfTestWriteDword(PLSR_DEVICE_D,
  590. SELF_TEST_S0_BASE + 10UL,
  591. 2000UL);
  592. SelfTestWriteDword(PLSR_DEVICE_D,
  593. SELF_TEST_S0_BASE + 12UL,
  594. 300UL);
  595. SelfTestWriteDword(PLSR_DEVICE_D,
  596. SELF_TEST_S0_BASE + 20UL,
  597. 1000UL);
  598. SelfTestWriteDword(PLSR_DEVICE_D,
  599. SELF_TEST_S0_BASE + 22UL,
  600. (uint32_t)(int32_t)-200);
  601. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U);
  602. (void)memset(&command, 0, sizeof(command));
  603. command.sequence = 0xA900UL;
  604. command.axis = 0U;
  605. command.opcode = PLSR_CMD_SET_POSITION;
  606. result = PlsrPostCommand(&command);
  607. if (result != PLSR_RESULT_QUEUED)
  608. {
  609. return result;
  610. }
  611. (void)memset(&call, 0, sizeof(call));
  612. call.sequence = 0xA901UL;
  613. call.source.context = NULL;
  614. call.source.validateWords = SelfTestValidateWords;
  615. call.source.readWord = SelfTestReadWord;
  616. call.source.readBit = SelfTestReadBit;
  617. call.s0.device = PLSR_DEVICE_D;
  618. call.s0.address = SELF_TEST_S0_BASE;
  619. call.s1.device = PLSR_DEVICE_D;
  620. call.s1.address = SELF_TEST_S1_BASE;
  621. call.s2.type = PLSR_OPERAND_CONSTANT;
  622. call.s2.constant = 1;
  623. call.dAxis = 0U;
  624. call.outputModeOverride = PLSR_OUTPUT_CW_CCW;
  625. return PlsrPostCall(&call);
  626. }
  627. PLSR_RESULT PlsrFastRefreshSelfTestQueue(void)
  628. {
  629. static const uint16_t s0Base[2] = {10U, 40U};
  630. static const uint16_t s1Base[2] = {160U, 164U};
  631. static const uint8_t directionPoint[2] = {4U, 3U};
  632. PLSR_CALL call;
  633. PLSR_COMMAND command;
  634. PLSR_RESULT result;
  635. uint16_t commonBase;
  636. uint16_t setBase;
  637. uint8_t axis;
  638. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  639. for (axis = 0U; axis < 2U; axis++)
  640. {
  641. commonBase = (uint16_t)(900U
  642. + (uint16_t)axis
  643. * SELF_TEST_SFD_AXIS_STRIDE);
  644. setBase = (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  645. (void)PlcDeviceWriteSfd(commonBase, 0U);
  646. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  647. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  648. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U),
  649. directionPoint[axis]);
  650. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U);
  651. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  652. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  653. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  654. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  655. SelfTestWriteSfdDword(setBase, 5000UL);
  656. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 100U);
  657. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 100U);
  658. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  659. /* Linear curve keeps the 1ms/0.1ms update granularity visible. */
  660. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  661. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 100000UL);
  662. SelfTestWriteSfdDword((uint16_t)(setBase + 8U), 100UL);
  663. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 100UL);
  664. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  665. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  666. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U),
  667. (axis == 0U) ? 0U : 2U);
  668. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  669. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  670. SelfTestWriteDword(PLSR_DEVICE_D, s0Base[axis], 1U);
  671. SelfTestWriteDword(PLSR_DEVICE_D,
  672. (uint32_t)s0Base[axis] + 10UL,
  673. 5000UL);
  674. SelfTestWriteDword(PLSR_DEVICE_D,
  675. (uint32_t)s0Base[axis] + 12UL,
  676. 2000UL);
  677. SelfTestWriteDword(PLSR_DEVICE_D, s1Base[axis], 0U);
  678. (void)memset(&command, 0, sizeof(command));
  679. command.sequence = 0xAA00UL + axis;
  680. command.axis = axis;
  681. command.opcode = PLSR_CMD_SET_POSITION;
  682. result = PlsrPostCommand(&command);
  683. if (result != PLSR_RESULT_QUEUED)
  684. {
  685. return result;
  686. }
  687. (void)memset(&call, 0, sizeof(call));
  688. call.sequence = 0xAA10UL + axis;
  689. call.source.context = NULL;
  690. call.source.validateWords = SelfTestValidateWords;
  691. call.source.readWord = SelfTestReadWord;
  692. call.source.readBit = SelfTestReadBit;
  693. call.s0.device = PLSR_DEVICE_D;
  694. call.s0.address = s0Base[axis];
  695. call.s1.device = PLSR_DEVICE_D;
  696. call.s1.address = s1Base[axis];
  697. call.s2.type = PLSR_OPERAND_CONSTANT;
  698. call.s2.constant = 1;
  699. call.dAxis = axis;
  700. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  701. result = PlsrPostCall(&call);
  702. if (result != PLSR_RESULT_QUEUED)
  703. {
  704. return result;
  705. }
  706. }
  707. return PLSR_RESULT_QUEUED;
  708. }
  709. PLSR_RESULT PlsrDynamicFrequencySelfTestQueue(void)
  710. {
  711. const uint16_t commonBase = 900U;
  712. const uint16_t setBase =
  713. (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  714. PLSR_CALL call;
  715. PLSR_COMMAND command;
  716. PLSR_RESULT result;
  717. (void)memset(SelfTestWords, 0, sizeof(SelfTestWords));
  718. PlsrSelfTestLiveFrequencyHz = 1000;
  719. PlsrSelfTestDynamicTick100us = 0UL;
  720. PlsrSelfTestDynamicPhase = 0U;
  721. PlsrSelfTestDynamicEnabled = 1U;
  722. PlsrSetControlTickHook(PlsrSelfTestControlTick100us);
  723. (void)PlcDeviceWriteSfd(commonBase, 0U);
  724. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  725. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  726. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U), 4U);
  727. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U);
  728. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  729. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  730. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  731. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  732. /* 1000Hz default, 5000Hz maximum, 10Hz/ms slope, 0.1ms refresh. */
  733. SelfTestWriteSfdDword(setBase, 1000UL);
  734. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 100U);
  735. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 100U);
  736. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  737. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  738. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 5000UL);
  739. SelfTestWriteSfdDword((uint16_t)(setBase + 8U), 1000UL);
  740. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL);
  741. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  742. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  743. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 2U);
  744. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  745. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  746. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S0_BASE, 1U);
  747. SelfTestWriteDword(PLSR_DEVICE_D,
  748. SELF_TEST_S0_BASE + 10UL,
  749. 1000UL);
  750. SelfTestWriteDword(PLSR_DEVICE_D,
  751. SELF_TEST_S0_BASE + 12UL,
  752. 100000UL);
  753. SelfTestWriteDword(PLSR_DEVICE_D, SELF_TEST_S1_BASE, 0U);
  754. (void)memset(&command, 0, sizeof(command));
  755. command.sequence = 0xAB00UL;
  756. command.axis = 0U;
  757. command.opcode = PLSR_CMD_SET_POSITION;
  758. result = PlsrPostCommand(&command);
  759. if (result != PLSR_RESULT_QUEUED)
  760. {
  761. return result;
  762. }
  763. (void)memset(&call, 0, sizeof(call));
  764. call.sequence = 0xAB01UL;
  765. call.source.context = NULL;
  766. call.source.validateWords = SelfTestValidateWords;
  767. call.source.readWord = SelfTestReadWord;
  768. call.source.readDword = SelfTestReadDwordLive;
  769. call.source.readBit = SelfTestReadBit;
  770. call.s0.device = PLSR_DEVICE_D;
  771. call.s0.address = SELF_TEST_S0_BASE;
  772. call.s1.device = PLSR_DEVICE_D;
  773. call.s1.address = SELF_TEST_S1_BASE;
  774. call.s2.type = PLSR_OPERAND_CONSTANT;
  775. call.s2.constant = 1;
  776. call.dAxis = 0U;
  777. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  778. return PlsrPostCall(&call);
  779. }
  780. PLSR_RESULT PlsrModbusDataSelfTestQueue(void)
  781. {
  782. const uint16_t commonBase = 900U;
  783. const uint16_t setBase =
  784. (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  785. uint16_t s0Words[20] = {0U};
  786. uint16_t s1Words[4] = {0U};
  787. PLSR_CALL call;
  788. PLSR_COMMAND command;
  789. PLSR_RESULT result;
  790. /* P12 uses D1000 as S0 and D1100 as S1. D1010/D1011 is the live
  791. * current-segment frequency written atomically by Modbus function 0x10. */
  792. s0Words[0] = 1U;
  793. s0Words[10] = 1000U;
  794. s0Words[11] = 0U;
  795. s0Words[12] = (uint16_t)(100000UL & 0xFFFFUL);
  796. s0Words[13] = (uint16_t)(100000UL >> 16U);
  797. if ((ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
  798. SELF_TEST_MODBUS_S0_BASE,
  799. s0Words,
  800. 20UL) == 0U)
  801. || (ModbusDataWriteWords(MODBUS_DATA_DEVICE_D,
  802. SELF_TEST_MODBUS_S1_BASE,
  803. s1Words,
  804. 4UL) == 0U))
  805. {
  806. return PLSR_RESULT_DATA_ACCESS;
  807. }
  808. (void)PlcDeviceWriteSfd(commonBase, 0U);
  809. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  810. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  811. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U), 4U);
  812. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U);
  813. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  814. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  815. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  816. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  817. /* Same limits as P11: 1000Hz default, 5000Hz maximum, 10Hz/ms ramp,
  818. * and a 0.1ms live-frequency refresh. */
  819. SelfTestWriteSfdDword(setBase, 1000UL);
  820. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 100U);
  821. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 100U);
  822. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  823. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  824. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 5000UL);
  825. SelfTestWriteSfdDword((uint16_t)(setBase + 8U), 1000UL);
  826. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL);
  827. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  828. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  829. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 2U);
  830. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  831. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  832. (void)memset(&command, 0, sizeof(command));
  833. command.sequence = 0xAC00UL;
  834. command.axis = 0U;
  835. command.opcode = PLSR_CMD_SET_POSITION;
  836. result = PlsrPostCommand(&command);
  837. if (result != PLSR_RESULT_QUEUED)
  838. {
  839. return result;
  840. }
  841. (void)memset(&call, 0, sizeof(call));
  842. call.sequence = 0xAC01UL;
  843. PlsrModbusDataSourceInit(&call.source);
  844. call.s0.device = PLSR_DEVICE_D;
  845. call.s0.address = SELF_TEST_MODBUS_S0_BASE;
  846. call.s1.device = PLSR_DEVICE_D;
  847. call.s1.address = SELF_TEST_MODBUS_S1_BASE;
  848. call.s2.type = PLSR_OPERAND_CONSTANT;
  849. call.s2.constant = 1;
  850. call.dAxis = 0U;
  851. call.outputModeOverride = PLSR_OUTPUT_PULSE_DIR;
  852. return PlsrPostCall(&call);
  853. }
  854. PLSR_RESULT PlsrModbusControlSelfTestPrepare(void)
  855. {
  856. const uint16_t commonBase = 900U;
  857. const uint16_t setBase =
  858. (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  859. (void)PlcDeviceWriteSfd(commonBase, 0U);
  860. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  861. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  862. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U), 4U);
  863. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 10U);
  864. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  865. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  866. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  867. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  868. /* K1: 1000Hz default/start, 5000Hz maximum, 100ms ramps, 1ms refresh. */
  869. SelfTestWriteSfdDword(setBase, 1000UL);
  870. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 100U);
  871. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 100U);
  872. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  873. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  874. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 5000UL);
  875. SelfTestWriteSfdDword((uint16_t)(setBase + 8U), 1000UL);
  876. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL);
  877. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  878. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  879. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 0U);
  880. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  881. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  882. return PLSR_RESULT_OK;
  883. }
  884. PLSR_RESULT PlsrHardwareCounterSelfTestPrepare(void)
  885. {
  886. uint16_t commonBase;
  887. uint16_t setBase;
  888. uint16_t limitSetBase;
  889. uint16_t abSetBase;
  890. uint32_t limitFrequencyHz;
  891. uint8_t axis;
  892. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  893. {
  894. commonBase = (uint16_t)(900U
  895. + (uint16_t)axis
  896. * SELF_TEST_SFD_AXIS_STRIDE);
  897. setBase = (uint16_t)(commonBase + SELF_TEST_SFD_SET_OFFSET);
  898. limitSetBase = (uint16_t)(setBase + 20U);
  899. abSetBase = (uint16_t)(setBase + 40U);
  900. /* PULSE/DIR, pulse-unit soft limits, one direction point per axis. */
  901. (void)PlcDeviceWriteSfd(commonBase, (1U << 2U));
  902. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  903. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  904. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U),
  905. (uint16_t)(SELF_TEST_DIR_POINT + axis));
  906. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 0U);
  907. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  908. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  909. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  910. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  911. SelfTestWriteSfdDword((uint16_t)(commonBase + 30U), 1000000UL);
  912. SelfTestWriteSfdDword((uint16_t)(commonBase + 32U),
  913. (uint32_t)(int32_t)-1000000);
  914. /* Exact 100kHz plateau. 200000-pulse S0 jobs cross the 16-bit
  915. * counter boundary three times while avoiding profile ramp effects. */
  916. SelfTestWriteSfdDword(setBase, 100000UL);
  917. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 2U), 0U);
  918. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 3U), 0U);
  919. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 4U), 0U);
  920. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 5U), 0U);
  921. SelfTestWriteSfdDword((uint16_t)(setBase + 6U), 100000UL);
  922. SelfTestWriteSfdDword((uint16_t)(setBase + 8U), 100000UL);
  923. SelfTestWriteSfdDword((uint16_t)(setBase + 10U), 0UL);
  924. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 12U), 50U);
  925. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 13U), 0U);
  926. (void)PlcDeviceWriteSfd((uint16_t)(setBase + 14U), 0U);
  927. SelfTestWriteSfdDword((uint16_t)(setBase + 16U), 2000UL);
  928. SelfTestWriteSfdDword((uint16_t)(setBase + 18U), 200UL);
  929. /* K2: P15 limit matrix. Even axes use 500Hz, odd axes 2000Hz;
  930. * start at target speed and decelerate for 100ms at a soft limit. */
  931. limitFrequencyHz = ((axis & 1U) == 0U) ? 500UL : 2000UL;
  932. SelfTestWriteSfdDword(limitSetBase, limitFrequencyHz);
  933. (void)PlcDeviceWriteSfd((uint16_t)(limitSetBase + 2U), 0U);
  934. (void)PlcDeviceWriteSfd((uint16_t)(limitSetBase + 3U), 100U);
  935. (void)PlcDeviceWriteSfd((uint16_t)(limitSetBase + 4U), 0U);
  936. (void)PlcDeviceWriteSfd((uint16_t)(limitSetBase + 5U), 0U);
  937. SelfTestWriteSfdDword((uint16_t)(limitSetBase + 6U),
  938. limitFrequencyHz);
  939. SelfTestWriteSfdDword((uint16_t)(limitSetBase + 8U),
  940. limitFrequencyHz);
  941. SelfTestWriteSfdDword((uint16_t)(limitSetBase + 10U), 0UL);
  942. (void)PlcDeviceWriteSfd((uint16_t)(limitSetBase + 12U), 50U);
  943. (void)PlcDeviceWriteSfd((uint16_t)(limitSetBase + 13U), 0U);
  944. (void)PlcDeviceWriteSfd((uint16_t)(limitSetBase + 14U), 0U);
  945. SelfTestWriteSfdDword((uint16_t)(limitSetBase + 16U), 2000UL);
  946. SelfTestWriteSfdDword((uint16_t)(limitSetBase + 18U), 200UL);
  947. /* K3: dual-AB 100kHz plateau. TIM9/TIM12 count complete-cycle
  948. * source events so the output timers only interrupt for rephase and
  949. * the guarded final 00 boundary. */
  950. SelfTestWriteSfdDword(abSetBase, 100000UL);
  951. (void)PlcDeviceWriteSfd((uint16_t)(abSetBase + 2U), 0U);
  952. (void)PlcDeviceWriteSfd((uint16_t)(abSetBase + 3U), 0U);
  953. (void)PlcDeviceWriteSfd((uint16_t)(abSetBase + 4U), 0U);
  954. (void)PlcDeviceWriteSfd((uint16_t)(abSetBase + 5U), 0U);
  955. SelfTestWriteSfdDword((uint16_t)(abSetBase + 6U), 100000UL);
  956. SelfTestWriteSfdDword((uint16_t)(abSetBase + 8U), 100000UL);
  957. SelfTestWriteSfdDword((uint16_t)(abSetBase + 10U), 0UL);
  958. (void)PlcDeviceWriteSfd((uint16_t)(abSetBase + 12U), 50U);
  959. (void)PlcDeviceWriteSfd((uint16_t)(abSetBase + 13U), 0U);
  960. (void)PlcDeviceWriteSfd((uint16_t)(abSetBase + 14U), 0U);
  961. SelfTestWriteSfdDword((uint16_t)(abSetBase + 16U), 2000UL);
  962. SelfTestWriteSfdDword((uint16_t)(abSetBase + 18U), 200UL);
  963. }
  964. return PLSR_RESULT_OK;
  965. }
  966. PLSR_RESULT PlsrLongStressSelfTestPrepare(void)
  967. {
  968. uint16_t commonBase;
  969. uint16_t longSetBase;
  970. uint8_t axis;
  971. for (axis = 0U; axis < PLSR_AXIS_COUNT; axis++)
  972. {
  973. commonBase = (uint16_t)(900U
  974. + (uint16_t)axis
  975. * SELF_TEST_SFD_AXIS_STRIDE);
  976. longSetBase = (uint16_t)(commonBase
  977. + SELF_TEST_SFD_SET_OFFSET
  978. + 60U); /* K4 occupies the final 20 words. */
  979. /* P18 is a bench-only PULSE/DIR endurance fixture. Keep the proven
  980. * Q4..Q7 direction mapping and disable both hard-input assignments and
  981. * soft limits so the deliberately long positive jobs cannot stop at
  982. * the P14/P15 +/-1000000-pulse validation boundary. */
  983. (void)PlcDeviceWriteSfd(commonBase, 0U);
  984. SelfTestWriteSfdDword((uint16_t)(commonBase + 2U), 1UL);
  985. SelfTestWriteSfdDword((uint16_t)(commonBase + 4U), 1UL);
  986. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 6U),
  987. (uint16_t)(SELF_TEST_DIR_POINT + axis));
  988. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 7U), 0U);
  989. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 8U), 0U);
  990. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 9U), 0U);
  991. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 12U), 0U);
  992. (void)PlcDeviceWriteSfd((uint16_t)(commonBase + 15U), 0xFFFFU);
  993. SelfTestWriteSfdDword((uint16_t)(commonBase + 30U), 0UL);
  994. SelfTestWriteSfdDword((uint16_t)(commonBase + 32U), 0UL);
  995. /* K4: exact 100kHz plateau, no acceleration/deceleration ramp. */
  996. SelfTestWriteSfdDword(longSetBase, 100000UL);
  997. (void)PlcDeviceWriteSfd((uint16_t)(longSetBase + 2U), 0U);
  998. (void)PlcDeviceWriteSfd((uint16_t)(longSetBase + 3U), 0U);
  999. (void)PlcDeviceWriteSfd((uint16_t)(longSetBase + 4U), 0U);
  1000. (void)PlcDeviceWriteSfd((uint16_t)(longSetBase + 5U), 0U);
  1001. SelfTestWriteSfdDword((uint16_t)(longSetBase + 6U), 100000UL);
  1002. SelfTestWriteSfdDword((uint16_t)(longSetBase + 8U), 100000UL);
  1003. SelfTestWriteSfdDword((uint16_t)(longSetBase + 10U), 0UL);
  1004. (void)PlcDeviceWriteSfd((uint16_t)(longSetBase + 12U), 50U);
  1005. (void)PlcDeviceWriteSfd((uint16_t)(longSetBase + 13U), 0U);
  1006. (void)PlcDeviceWriteSfd((uint16_t)(longSetBase + 14U), 0U);
  1007. SelfTestWriteSfdDword((uint16_t)(longSetBase + 16U), 2000UL);
  1008. SelfTestWriteSfdDword((uint16_t)(longSetBase + 18U), 200UL);
  1009. }
  1010. return PLSR_RESULT_OK;
  1011. }
  1012. #endif