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.
 
 
 
 
 
 

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