rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
link_pages.h
Go to the documentation of this file.
1
16#ifndef RCBENCH_LINK_PAGES_H
17#define RCBENCH_LINK_PAGES_H
18
19#include <stdbool.h>
20
21#include "link_crc.h"
22#include "link_msg.h"
23
24#ifdef __cplusplus
25extern "C" {
26#endif
27
31typedef enum {
39 /*
40 * 0x21 is reserved and not assigned. A page number is part of the
41 * contract between two firmwares flashed separately; a number that
42 * changes meaning lets an old panel write into a page the IOmcu
43 * interprets differently, and be acknowledged.
44 */
70 /* Frozen: the same numbers, layout and meaning under every major. */
74
150#define LINK_PROTOCOL_MAJOR 4u
152#define LINK_PROTOCOL_MINOR 29u
153
155#define LINK_MINOR_BIND 10u
160#define LINK_MINOR_SERVO_WIN 11u
162#define LINK_MINOR_KST 12u
168#define LINK_MINOR_PROG 13u
177#define LINK_MINOR_KST_PLAN 14u
186#define LINK_MINOR_KST_LEAVE 15u
196#define LINK_MINOR_PULSE_FRAME 16u
205#define LINK_MINOR_TONE_BUSY 17u
213#define LINK_MINOR_ARM_ROLE 18u
222#define LINK_MINOR_SERVO_TARGET_RATE 19u
231#define LINK_MINOR_DRAWING 20u
239#define LINK_MINOR_REFUSED 21u
246#define LINK_MINOR_UPDATE 22u
253#define LINK_MINOR_HITEC 23u
260#define LINK_MINOR_HITEC_RX 24u
268#define LINK_MINOR_SENSE_MAP 25u
274#define LINK_MINOR_SENSE_LIMIT 27u
275
283#define LINK_MINOR_PROG_FUNC 26u
284
292#define LINK_MINOR_PROG_DSHOT 28u
293
302#define LINK_MINOR_HITEC_HOLD 29u
303
304/* ----------------------------------------------------------------- outputs */
305
306/*
307 * The three output pages. Every output protocol has a proportion of travel
308 * and a driver that renders it, so that is what the wire carries:
309 *
310 * CHANNELS what each output is asked for, and nothing else. Hot: written
311 * many times a second, and the only page in the group that is.
312 * CHAN_CFG what a channel is (throttle or surface), how fast it may move,
313 * and the pulse widths its ends correspond to.
314 * OUTPUTS which driver renders which channels, on which pin, how often.
315 *
316 * Eight of each. At four registers per slot, eight slots fit a page of
317 * LINK_MAX_REGS registers; eight is also the number of servo outputs the
318 * bench has and the number of channels PPM (pulse-position modulation)
319 * carries. A ninth slot needs a minor version and a second page.
320 */
321
322#define LINK_OUT_SLOTS 8u
323#define LINK_OUT_CHANNELS 8u
324
326#define LINK_CH_SPAN 1000u
327
328/* --- what each output is asked for */
329#define LINK_CH_COUNT LINK_OUT_CHANNELS
330
331/* --- what a channel is. Four registers each, and a channel must be written
332 * whole: min and max are a pair, and a range half-applied is a range
333 * nothing is clamped against. */
334enum {
339 LINK_CC_STRIDE = 4,
340};
341#define LINK_CC_COUNT (LINK_OUT_CHANNELS * LINK_CC_STRIDE)
342
349#define LINK_CC_SLEW_MAX 3000u
350
351#define LINK_CC_ROLE_THROTTLE 0u
352#define LINK_CC_ROLE_SURFACE 1u
353
370#define LINK_CC_DEFAULT_MIN 1000u
371#define LINK_CC_DEFAULT_MAX 2000u
372#define LINK_CC_FLOOR_US 400u
373#define LINK_CC_CEILING_US 2500u
374
384#define LINK_CC_THROTTLE_GAP_US 100u
385
386/* --- which driver drives what. Four registers a slot, written whole for the
387 * same reason: a driver claimed on a pin the rest of the write has not
388 * arrived to name yet is a driver on the wrong pin. */
389enum {
392 /*
393 * First channel and count in one register: the run of channels this slot
394 * renders. PPM is eight channels on one pin, so a slot cannot be assumed
395 * to be one channel.
396 */
399 LINK_OS_STRIDE = 4,
400};
401#define LINK_OS_COUNT (LINK_OUT_SLOTS * LINK_OS_STRIDE)
402
403/* --- the SERVO screen's page: the target's frame rate (protocol 4.1) and
404 * the sweep that drives it through a curve (4.2).
405 *
406 * FRAME_HZ is the frame rate, in Hz, of the tester's target (PROG's
407 * LINK_PG_TARGET), or 0 for its own rate. With the standard servo
408 * ports as target it is every PWM output whose first channel is a
409 * surface, 0 meaning each slot's own rate from the OUTPUTS page. One
410 * register for all of them, so a write is whole: a servo screen that
411 * moved some surfaces to 560Hz and not their slice-mates would leave a
412 * slice asked for two rates. A rate that would do that against the
413 * binding in force -- a surface and a throttle on one slice -- is
414 * refused with BAD_VALUE and nothing changes. With a programming port
415 * as target (since 4.19) it is that port's pin alone, 0 meaning 50Hz;
416 * the slots run at their own rates. A port pin that shares its PWM
417 * slice with another port's pin takes only 0 or 50 (BAD_VALUE). Every
418 * port that is not the target runs at 50Hz, and a TARGET change sets
419 * FRAME_HZ to 0. An IOmcu before 4.19 runs every surface and
420 * every port at FRAME_HZ, whatever the target.
421 *
422 * SWEEP to SWEEP_DWELL_MS are a sweep (servo_sweep.h), four registers so
423 * a start fits one frame. SWEEP is the curve, 0 stopped, 1 square,
424 * 2 sine, 3 triangle; MHZ thousandths of a cycle a second, 50 to 5000;
425 * SPAN command units either side of the centre, 0 to 500; DWELL_MS the
426 * hold at each end, 0 to 5000. A sweep needs the bench armed
427 * (NOT_ARMED) and stops after 500ms unwritten, on a disarm, or after
428 * SWEEP_MOVES ends (0 for no end), read back in SWEEP_DONE.
429 *
430 * SWEEP = 4 (LINK_SV_HOLD), one register, holds every surface where
431 * its output is -- a sweep stopped part way, exactly where it got to,
432 * slew and all -- for as long as it is written, on the same 500ms and
433 * disarm rules. A sweep that was running when the hold began keeps its
434 * phase: how far into the curve it was, so its point, its dwell and its
435 * movements reached. One that had made its movements is held at the
436 * centre it ended on. A write is judged against the page as a pass at
437 * the same moment leaves it: a sweep past its last movement, unwritten
438 * for 500ms or disarmed has ended, even before the pass that ends it.
439 *
440 * SWEEP = 5 (LINK_SV_RESUME, since 4.6), one register, carries that
441 * sweep on from the kept phase. The surfaces are commanded along the
442 * curve again at once and slew there from where they were held, at
443 * their own rate. Refused with BAD_VALUE when no phase is kept -- no
444 * sweep was running when the hold began, or the hold has ended by a
445 * write of 0, a curve written over it, a disarm, 500ms unwritten or
446 * a restart -- and when
447 * SWEEP_MHZ, SPAN, DWELL_MS or MOVES no longer read what the paused
448 * sweep runs; NOT_ARMED on a disarmed bench. A 4.5 IOmcu refuses
449 * 5 with BAD_VALUE, as any curve not written whole.
450 *
451 * Not kept: an IOmcu restart drives every slot at its own rate
452 * again, which is the binding's 50Hz for a servo, and runs no sweep. */
453enum {
454 LINK_SV_FRAME_HZ = 0,
455 LINK_SV_SWEEP = 1,
456 LINK_SV_SWEEP_MHZ = 2,
457 LINK_SV_SWEEP_SPAN = 3,
458 LINK_SV_SWEEP_DWELL_MS = 4,
459 LINK_SV_SWEEP_MOVES = 5,
461 LINK_SV_COUNT = 7,
462};
464#define LINK_SV_HOLD 4u
466#define LINK_SV_RESUME 5u
467
468/* --- the SUPPLY page (protocol 4.3): a WeAct PD Power Mini V1 Buck on a
469 * PIO UART the IOmcu runs on two of its pins (shared/bench/
470 * pdmini.h).
471 *
472 * ENABLE to BAUD are its wiring, one frame: 1 to drive it, the GPIO the
473 * UART transmits on (to the module's DM) and receives on (its DP), and
474 * the module's UART Baudrate setting, 0 to 6 for 9600 to 460800 baud,
475 * or 7 (protocol 4.4) to find it: the UART steps to the next rate
476 * after every WHO_AM_I without a valid answer, until a module has
477 * answered once, and BAUD_FOUND says which rate is in use.
478 *
479 * RESET, written alone as 1 with OUTPUT 0, restarts the module
480 * (SYSTEM_RESET) once it has answered and its output reads off; it
481 * reads 0.
482 * Refused with BAD_VALUE: a pin that is reserved, bound to an output or
483 * the other pin, a baud out of range, or any change while the output is
484 * asked on or may be on (FLAGS bit 6). The pins it takes are no
485 * output's while it holds them.
486 *
487 * Protocol 4.5: a change while a module has answered is acknowledged
488 * and waits, ENABLE to BAUD reading the wiring in force and FLAGS bit 8
489 * set, for a state read of the module sent after it -- at most about
490 * 1.2s. That read showing the output off takes it; on, or failed,
491 * refuses it: bit 8 clears and bit 9 sets until the next wiring write.
492 * Such a change comes alone, without OUTPUT to SET_MA, and an ON is
493 * refused with BAD_VALUE while one waits.
494 *
495 * OUTPUT to SET_MA are what it is to do, one frame: 1 for the output
496 * on, the set points in mV and mA, clamped to the module's 1 to 20V
497 * and 0.05 to 3A. An ON is refused with NOT_ARMED without a live
498 * heartbeat, and the output goes off when the heartbeat stops.
499 *
500 * FLAGS onwards are read only, what the module last said: bit 0
501 * online, bit 1 output on, bits 3..2 the mode (0 normal, 1 constant
502 * current, 2 overcurrent), bit 4 an output that would not switch,
503 * bit 5 set points that would not take, bit 6 an output that is on or
504 * may be -- read on, an ON not yet confirmed, or an OFF owed to a
505 * module that stopped answering, bit 7 an output the module switched
506 * off by itself, held off until OUTPUT is written 0, bit 8 a wiring
507 * change waiting for its state read and bit 9 one refused by it
508 * (4.5), bit 10 an output switched off because its input read under
509 * the set point and 500mV on 2 input reads in a row, held off until
510 * OUTPUT is written 0 (4.5);
511 * the output's voltage and current, the set points read back from it,
512 * the input's state and voltage, and the counts of readings taken and
513 * of transactions that failed, modulo 65536.
514 *
515 * The wiring is kept in the IOmcu's flash and driven at boot with
516 * the output off, so a module left on is switched off after a restart;
517 * the command is not kept. */
518enum {
519 LINK_SP_ENABLE = 0,
520 LINK_SP_TX_PIN = 1,
521 LINK_SP_RX_PIN = 2,
522 LINK_SP_BAUD = 3,
523 LINK_SP_OUTPUT = 4,
524 LINK_SP_SET_MV = 5,
525 LINK_SP_SET_MA = 6,
527 LINK_SP_V_MV = 8,
528 LINK_SP_I_MA = 9,
529 LINK_SP_SET_MV_RB = 10,
530 LINK_SP_SET_MA_RB = 11,
531 LINK_SP_IN_STATE = 12,
532 LINK_SP_VIN_MV = 13,
533 LINK_SP_SAMPLES = 14,
534 LINK_SP_ERRORS = 15,
537 LINK_SP_COUNT = 18,
538};
539#define LINK_SP_ONLINE 0x01u
540#define LINK_SP_ON 0x02u
541#define LINK_SP_MODE(f) (((f) >> 2) & 3u)
542#define LINK_SP_STUCK 0x10u
543#define LINK_SP_SET_STUCK 0x20u
544#define LINK_SP_LIVE 0x40u
545#define LINK_SP_TRIPPED 0x80u
546#define LINK_SP_WIRE_WAIT 0x100u
547#define LINK_SP_WIRE_REFUSED 0x200u
548#define LINK_SP_SAGGED 0x400u
554#define LINK_SP_PORT 0x800u
555
556/* --- the SENSE page (protocol 4.7): two I2C (Inter-Integrated Circuit)
557 * current monitors on one bus the IOmcu runs on two of its pins,
558 * a TI INA228 in the ESC's power path and a TI INA3221 on the servo
559 * rail.
560 *
561 * ENABLE to KHZ are the bus, one frame: ENABLE bit 0 the INA228, bit 1
562 * the INA3221, bit 2 the AS5600 output encoder (protocol 4.9); the GPIO for SDA and the one for SCL; the clock, 400kHz
563 * and nothing else (LINK_SN_KHZ_BUS): the schedule's 1ms tick does not
564 * fit a slower bus. The RP2350 has its I2C function at pin mod 4 -- 0 I2C0 SDA,
565 * 1 I2C0 SCL, 2 I2C1 SDA, 3 I2C1 SCL -- so SDA is a GPIO whose number
566 * mod 4 is 0 or 2 and SCL is the one after it: one I2C block's pair.
567 *
568 * I228_ADDR to register 7 are the INA228, one frame: its address, 0x40
569 * to 0x4F; its shunt in micro-ohms, 50 to 20000; the current its range
570 * is set for, in 0.1A, 1.0 to 300.0A, the bench's design maximum.
571 * That current chooses ADCRANGE only: 1
572 * while the shunt's voltage at it is at most 40.96mV, 0 up to
573 * 163.84mV, and past that the write is refused. CURRENT_LSB is the
574 * shunt ADC's step divided by the shunt at that range, so CURRENT and
575 * VSHUNT clip together, and SHUNT_CAL is 4096 at either range. A
576 * shunt whose full scale at the chosen range passes 2000A is refused
577 * too: below 81.92 micro-ohms only ADCRANGE 1 is taken. The rule is
578 * the driver's, ina228_calibrate() in shared/sense.
579 *
580 * I3221_ADDR to register 11 are the INA3221, one frame: its address,
581 * 0x40 to 0x43; its shunt in 0.1 milliohm, 50 to 10000 (5mOhm to
582 * 1Ohm); the channels read, bits 0..2 for CH1 to CH3, at least one
583 * while the part is enabled. The part's full scale is 163.8mV across
584 * the shunt: 1.638A at the DAOKAI module's 0.1Ohm, 32.76A at 5mOhm,
585 * which is the most SERVO_SENSE's signed mA carry.
586 *
587 * Registers 7 and 11 are reserved: they read 0, and a write of anything
588 * else is refused with BAD_VALUE. They keep each part's frame four
589 * registers long for a later minor to give them a meaning.
590 *
591 * Refused with BAD_VALUE: a value out of its range, SDA and SCL not one
592 * I2C block's pair (link_sn_pins_pair()) whatever ENABLE holds, and
593 * while a part is enabled a pin past the bank, reserved, bound to an
594 * output or held by the SUPPLY page, the two parts on one address while
595 * both are enabled, and any change while the bank is armed -- the bus
596 * opened again stops the readings for some milliseconds mid-run. One
597 * frame that is not a pair is taken: ENABLE 0 with SDA or SCL 0, which
598 * is how a panel writes pins that are not set. The pins are no
599 * output's while a part is enabled.
600 *
601 * FLAGS onwards are read only: FLAGS (link_sense_flag_t); PRESENT, bit
602 * n for address 0x40 + n answering the last scan; the ID the INA228
603 * gave (DEVICE_ID) and the one the INA3221 gave (die ID); transactions
604 * failed, modulo 65536; the INA228's die temperature in 0.1C, signed,
605 * and its DIAG_ALRT as read; its CHARGE in 0.01mAh, signed 32 bit, and
606 * its ENERGY in 0.01Wh, 32 bit, each low register first and counted
607 * since the run's arm; and the ESC's own telemetry voltage (10mV) and
608 * current (10mA), ESC_FLAGS bit 0 and bit 1 saying each is valid --
609 * here because BENCH carries the INA228's while it answers.
610 *
611 * The output encoder (protocol 4.9) is an ams OSRAM AS5600 magnetic
612 * angle sensor on the same bus, at its fixed address 0x36, on the horn
613 * shaft of the servo under test. ENABLE bit 2 turns it on and has no
614 * parameter of its own: the bus pins are the INA parts', and the angle
615 * comes back as the 12-bit count, 0 to 4095 for one turn (0.0879 degrees
616 * a count), with no centre applied -- the panel keeps that. The
617 * IOmcu reads it at 500Hz. A bit 2 written to a 4.8 or older
618 * IOmcu is not sent: the panel gates it on minor >= 9.
619 *
620 * AS5600_FLAGS (link_sense_enc_flag_t) say whether it answers and what
621 * its magnet is doing. AS5600_ANGLE is RAW ANGLE as last read, 0 until
622 * the first read of a set-up. It is a position only while ENC_ONLINE,
623 * ENC_VALID and ENC_MD are all set: with MD clear the part sees no
624 * magnet and the count means nothing. With ML or MH set beside MD the
625 * count is a position whose noise the datasheet does not specify. AS5600_MAGNITUDE is the part's CORDIC
626 * (coordinate rotation digital computer) magnitude, read at 20Hz, 0
627 * until read; it is a measure of the field. AS5600_SAMPLES counts the
628 * angle reads, modulo 65536: two reads of the page with the same count
629 * are one sample. AS5600_STILL_MS is how long the angle has stayed
630 * within 12 counts (1.05 degrees) of an anchor -- the angle at the last
631 * time it left that band -- in milliseconds, saturating at 65535, 0 with
632 * no sample and 0 while MD is clear: without a magnet the count is not
633 * a position, and the anchor starts afresh when MD returns. A move that ends at time t_end, read at time t_read, shows
634 * STILL_MS = t_read - t_end to within the 2ms sample interval, so the
635 * panel times the end of a move to the IOmcu's resolution
636 * whatever its own polling interval.
637 *
638 * RESETS (register 31, protocol 4.11) counts the times a current
639 * monitor was found running on its power-on set-up and not the one
640 * written to it: the INA228 in the low byte, the INA3221 in the high
641 * byte, each modulo 256, since the set-up in force was taken. The
642 * IOmcu reads the INA228's ADC_CONFIG and the INA3221's
643 * Configuration back every 40ms; a part found reset loses ONLINE and
644 * is set up again 1000ms on. The count shows a reset that was found
645 * and repaired between two reads of FLAGS. Before 4.11 the register
646 * is reserved and reads 0.
647 *
648 * ENABLE to register 11 are kept in the IOmcu's flash beside the
649 * bindings and the supply's wiring, and the bus is opened at boot. */
650enum {
651 LINK_SN_ENABLE = 0,
652 LINK_SN_SDA_PIN = 1,
653 LINK_SN_SCL_PIN = 2,
654 LINK_SN_KHZ = 3,
655 LINK_SN_I228_ADDR = 4,
656 LINK_SN_I228_SHUNT_UOHM = 5,
657 LINK_SN_I228_MAX_DA = 6,
659 LINK_SN_I3221_ADDR = 8,
660 LINK_SN_I3221_SHUNT_DMOHM = 9,
661 LINK_SN_I3221_CHANNELS = 10,
664 LINK_SN_PRESENT = 13,
665 LINK_SN_I228_ID = 14,
666 LINK_SN_I3221_ID = 15,
667 LINK_SN_ERRORS = 16,
669 LINK_SN_I228_DIAG = 18,
671 LINK_SN_I228_CHARGE_HI = 20,
673 LINK_SN_I228_ENERGY_HI = 22,
676 LINK_SN_ESC_FLAGS = 25,
683 LINK_SN_COUNT = 32,
684};
686#define LINK_SN_COUNT_V48 26u
691#define LINK_SN_CONFIG_COUNT 12u
692
694#define LINK_SN_EN_I228 0x01u
695#define LINK_SN_EN_I3221 0x02u
696#define LINK_SN_EN_AS5600 0x04u
698#define LINK_SN_EN_ALL (LINK_SN_EN_I228 | LINK_SN_EN_I3221 | LINK_SN_EN_AS5600)
699
700/* The ranges a write is held to. */
702#define LINK_SN_KHZ_BUS 400u
703#define LINK_SN_I228_ADDR_MIN 0x40u
704#define LINK_SN_I228_ADDR_MAX 0x4Fu
705#define LINK_SN_I228_UOHM_MIN 50u
706#define LINK_SN_I228_UOHM_MAX 20000u
707#define LINK_SN_I228_DA_MIN 10u
708#define LINK_SN_I228_DA_MAX 3000u
709#define LINK_SN_I3221_ADDR_MIN 0x40u
710#define LINK_SN_I3221_ADDR_MAX 0x43u
711#define LINK_SN_I3221_DMOHM_MIN 50u
712#define LINK_SN_I3221_DMOHM_MAX 10000u
713#define LINK_SN_I3221_CH_ALL 0x07u
714
726static inline bool link_sn_pins_pair(unsigned sda, unsigned scl)
727{
728 return (sda % 2u) == 0u && scl == sda + 1u;
729}
730
732typedef enum {
751 LINK_SN_I3221_ONLINE = 1u << 4,
752 LINK_SN_I3221_ID_OK = 1u << 5,
753 LINK_SN_I3221_ID_WRONG = 1u << 6,
757
759#define LINK_SN_RESETS_I228(r) ((uint8_t)((r) & 0xFFu))
760#define LINK_SN_RESETS_I3221(r) ((uint8_t)(((r) >> 8) & 0xFFu))
761
784
786#define LINK_SN_ESC_VOLTAGE_OK 0x01u
787#define LINK_SN_ESC_CURRENT_OK 0x02u
788
789/* --- the SERVO_SENSE page (protocol 4.7): the INA3221's three channels,
790 * and a move timed on the IOmcu's clock.
791 *
792 * Registers 0 to 11, four a channel from CH1: the mean and the highest
793 * current in mA, signed, and the mean and the lowest bus voltage in mV,
794 * at the load side of the shunt, over the last 50ms window. WINDOW
795 * numbers the windows, modulo 65536; a read does not end one, so a
796 * reply lost on the link loses nothing. CH_FLAGS bits 0..2 say a
797 * channel's window holds readings; bits 4..6 that one of them read the
798 * top of the range, 163.8mV across the shunt, which makes that
799 * channel's mean and highest current lower bounds and not values; bit 7
800 * the same of the capture's move.
801 *
802 * CAP_ARM to CAP_BAND_MA are a capture, one frame: CAP_ARM with bit 7
803 * set, the INA3221 channel in bits 0..1 (1: CH2 and CH3 are refused,
804 * LINK_SS_CAP_CH) and in bits 8..10 the
805 * output channel (0 to 7) whose next changed command starts the timing;
806 * the holding level the move ends at in mA, signed, -32768 to 32767
807 * (protocol 4.11; before it 0 to 32767, and 32768 to 65535 refused):
808 * a holding level near 0A reads below zero by the part's offset; the
809 * distance from
810 * the level before the command that counts as movement, and the band
811 * around the holding level that counts as arrival, each 1 to 32767mA.
812 * An arm is the whole frame from CAP_ARM; an arm restarts a capture
813 * already running. CAP_ARM written 0 disarms and is never refused,
814 * alone or at the head of the frame, whose other registers are then not
815 * stored. Refused with BAD_VALUE: any other write that is not the
816 * whole frame, CAP_ARM bits outside the three fields, a value out of
817 * range, an INA3221 channel other than CH1 or one SENSE does not read,
818 * and an output channel
819 * that is not a surface rendered by a PWM slot; with NOT_ARMED on a
820 * disarmed bank. A bank that stops driving ends a capture that has not
821 * finished: CAP_ARM reads 0 and CAP_STATE idle.
822 *
823 * CAP_STATE onwards are read only: the state (link_cap_state_t);
824 * captures finished, modulo 65536; the time from the PWM frame that
825 * carries the new pulse to the movement and to the arrival, in 0.1ms,
826 * 6553.5ms at most, resolved to CH1's 1ms sample interval; the
827 * highest and the mean filtered current of the move in mA, signed,
828 * over CAP_SAMPLES samples. A capture ends arrived, at a stop, late
829 * (movement and no arrival within 3000ms plus the meter's lag),
830 * unseen (no movement in that time) or lost (the INA3221 stopped
831 * answering, or no PWM edge came within 3000ms of the arm).
832 *
833 * Not kept: an IOmcu restart reads 0 throughout. */
834enum {
836 LINK_SS_CH_MAX_MA = 1,
837 LINK_SS_CH_MEAN_MV = 2,
838 LINK_SS_CH_MIN_MV = 3,
839 LINK_SS_CH_STRIDE = 4,
840};
841#define LINK_SS_CHANNELS 3u
846enum {
847 LINK_SS_WINDOW = 12,
848 LINK_SS_CH_FLAGS = 13,
849 LINK_SS_CAP_ARM = 14,
850 LINK_SS_CAP_HOLD_MA = 15,
851 LINK_SS_CAP_MOVE_MA = 16,
852 LINK_SS_CAP_BAND_MA = 17,
854 LINK_SS_CAP_SEQ = 19,
857 LINK_SS_CAP_PEAK_MA = 22,
858 LINK_SS_CAP_MEAN_MA = 23,
859 LINK_SS_CAP_SAMPLES = 24,
860 LINK_SS_COUNT = 25,
861};
863#define LINK_SS_CAP_FRAME 4u
864
866#define LINK_SS_CH_VALID(ch) ((uint16_t)(1u << ((unsigned)(ch) - 1u)))
867#define LINK_SS_CH_CLIPPED(ch) ((uint16_t)(1u << ((unsigned)(ch) + 3u)))
868#define LINK_SS_CAP_CLIPPED 0x80u
869
877#define LINK_SS_ARM 0x80u
878#define LINK_SS_ARM_OF(ch, out) \
879 ((uint16_t)(LINK_SS_ARM | ((unsigned)(ch) & 0x03u) \
880 | (((unsigned)(out) & 0x07u) << 8)))
881#define LINK_SS_ARM_CH(r) ((uint8_t)((r) & 0x03u))
882#define LINK_SS_ARM_OUT(r) ((uint8_t)(((r) >> 8) & 0x07u))
884#define LINK_SS_ARM_BITS 0x0F83u
886#define LINK_SS_ARM_PORT 0x0800u
891#define LINK_SS_CAP_CH 1u
892
896typedef enum {
897 LINK_CAP_IDLE = 0,
900 LINK_CAP_MOVING = 3,
910
911/* --- the SERVO_WIN page (protocol 4.11): the INA3221's CH1, the servo
912 * under test, as its last four 50ms windows. Read only: every write
913 * is refused with READ_ONLY.
914 *
915 * SERVO_SENSE shows the last window alone, so a host whose reads lie
916 * further apart than 50ms misses windows. Here a host takes each
917 * window number once, and misses none while two of its reads lie at
918 * most 200ms apart.
919 *
920 * WINDOW is the number of the newest complete window, modulo 65536,
921 * the number SERVO_SENSE's WINDOW shows. FLAGS bit 0 (LINK_SW_HAVE)
922 * says a window has closed under the set-up in force, so WINDOW is a
923 * number; bit 7 (LINK_SW_CAP_CLIPPED) is SERVO_SENSE's capture bit.
924 * CAP_STATE and CAP_SEQ read as SERVO_SENSE's registers 18 and 19, so
925 * one read shows the windows and whether a capture has ended.
926 *
927 * Then four entries of six registers, newest first: entry k, from
928 * register 4 + 6 k, is window number WINDOW - k. Mean, highest and
929 * lowest current in mA, signed; mean and lowest bus voltage in mV, at
930 * the load side of the shunt; and the entry's flags. The schedule
931 * reads CH1's current every 1ms and its bus voltage every 24ms: a
932 * window holds up to 50 current samples and 2 or 3 voltage samples.
933 *
934 * An entry's flags: bit 15 (LINK_SW_E_CLOSED) a window closed with
935 * this number -- clear for a number the IOmcu skipped because
936 * its tick ran late by more than a window, and for a number before
937 * the first window, and the entry then reads 0 throughout; bit 8
938 * (LINK_SW_E_CURRENT) the window holds current samples; bit 9
939 * (LINK_SW_E_VOLTAGE) it holds voltage samples; bit 10
940 * (LINK_SW_E_CLIP_HI) a current sample read the top of the range,
941 * 163.8mV across the shunt; bit 11 (LINK_SW_E_CLIP_LO) one read the
942 * bottom; bits 0..7 the number of samples that did, held at 255.
943 *
944 * A clipped sample counts in an entry as the reading it is: the end
945 * of the range, 1.638A or -1.6384A on the 0.1Ohm shunt, in the
946 * mean, the highest and the lowest. SERVO_SENSE's registers 0 to 11
947 * leave a clipped sample out of their figures, so the two pages
948 * differ for a window with a clipped sample, and only for such a
949 * window.
950 *
951 * A window being filled when the INA3221 is found reset (SENSE's
952 * RESETS) is emptied: its entry is closed and holds no samples.
953 *
954 * Not kept, and cleared by a SENSE set-up taken. */
955enum {
956 LINK_SW_WINDOW = 0,
957 LINK_SW_FLAGS = 1,
959 LINK_SW_CAP_SEQ = 3,
961 LINK_SW_COUNT = 28,
962};
964#define LINK_SW_RING 4u
966enum {
970 LINK_SW_E_MEAN_MV = 3,
971 LINK_SW_E_MIN_MV = 4,
972 LINK_SW_E_FLAGS = 5,
973 LINK_SW_E_STRIDE = 6,
974};
976#define LINK_SW_ENTRY(k, r) \
977 ((unsigned)LINK_SW_ENTRIES + (unsigned)(k) * LINK_SW_E_STRIDE + (unsigned)(r))
978
980#define LINK_SW_HAVE 0x01u
981#define LINK_SW_CAP_CLIPPED 0x80u
982
984#define LINK_SW_E_CLIPPED(f) ((uint8_t)((f) & 0xFFu))
985#define LINK_SW_E_CLIPPED_MAX 255u
986#define LINK_SW_E_CURRENT 0x0100u
987#define LINK_SW_E_VOLTAGE 0x0200u
988#define LINK_SW_E_CLIP_HI 0x0400u
989#define LINK_SW_E_CLIP_LO 0x0800u
990#define LINK_SW_E_CLOSED 0x8000u
991
992/* --- the SENSE_MAP page (protocol 4.25): up to four INA3221 parts on the
993 * sensor bus, at 0x40 to 0x43, three channels each. Channel c is
994 * part a's channel ch for c = 3 a + ch - 1, so 0 to 11.
995 *
996 * ENABLE bit a: the part at 0x40 + a is fitted. FAST: the channel
997 * read every 1ms, whose last four windows SERVO_WIN carries and
998 * on which SERVO_SENSE times a move; 0xFF (LINK_SM_FAST_NONE) none.
999 * SHUNT[c]: channel c's shunt in 0.1mOhm, 50 to 10000, 0 = the
1000 * channel is off and never read. WATCH[c]: what channel c measures,
1001 * for the panel's screens and logs; the IOmcu keeps it and acts on
1002 * nothing in it.
1003 *
1004 * Registers 0 to 25 are kept in the IOmcu's flash. A write lies
1005 * within them: one that reaches register 26 is refused with
1006 * READ_ONLY. The registers written are merged into the map and the
1007 * whole map judged; a map refused leaves every register as it was.
1008 * Refused with BAD_VALUE: ENABLE above 15; FAST not 0xFF and past 11,
1009 * on a part not fitted or on a channel whose SHUNT is 0; a SHUNT not 0
1010 * outside 50 to 10000; a WATCH value outside the list below; a fitted
1011 * part with all three SHUNT 0; a fitted part on the address of the
1012 * INA228 while SENSE enables it; any change while the bank drives.
1013 * A part not fitted keeps the values written for it, judged by range
1014 * alone.
1015 *
1016 * ID[a] (read only): the die ID part a answered at its last probe, 0
1017 * before one. FLAGS (read only): bit a part a online; bit 4 + a part
1018 * a answered with another identity; bit 8 (LINK_SM_IN_FORCE) the map
1019 * has been written and is kept; bit 9 (LINK_SM_DERIVED) it has never
1020 * been written and is SENSE's one part (below).
1021 *
1022 * SENSE and the map. Until the map is first written it is derived
1023 * from SENSE: ENABLE bit 1 fits the part at SENSE's I3221_ADDR, each
1024 * channel in I3221_CHANNELS has SENSE's shunt, FAST is that part's
1025 * CH1 when it is read, and nothing is watched. Once written, SENSE's
1026 * ENABLE bit 1 and registers 8 to 10 mirror the map: bit 1 set while
1027 * a part is fitted; I3221_ADDR the mirror part -- FAST's part, or
1028 * the lowest fitted part while FAST is 0xFF; I3221_SHUNT_DMOHM that
1029 * part's CH1 shunt, or its first one not 0; I3221_CHANNELS its
1030 * channels with a shunt. A SENSE write that would change bit 1 or
1031 * registers 8 to 10 is then refused with BAD_VALUE. SERVO_SENSE's
1032 * registers 0 to 11 are the mirror part's three channels, and a
1033 * capture's channel 1 (LINK_SS_CAP_CH) is FAST. */
1034enum {
1035 LINK_SM_ENABLE = 0,
1036 LINK_SM_FAST = 1,
1042 LINK_SM_FLAGS = 30,
1043 LINK_SM_RESERVED_31 = 31,
1044 LINK_SM_COUNT = 32,
1045};
1046#define LINK_SM_PARTS 4u
1047#define LINK_SM_CHANNELS 12u
1048#define LINK_SM_SHUNT(c) ((unsigned)LINK_SM_SHUNT_0 + (unsigned)(c))
1049#define LINK_SM_WATCH(c) ((unsigned)LINK_SM_WATCH_0 + (unsigned)(c))
1050#define LINK_SM_ID(a) ((unsigned)LINK_SM_ID_0 + (unsigned)(a))
1051#define LINK_SM_FIT_ALL 0x000Fu
1052#define LINK_SM_FAST_NONE 0x00FFu
1053#define LINK_SM_DMOHM_MIN 50u
1054#define LINK_SM_DMOHM_MAX 10000u
1056#define LINK_SM_WATCH_NONE 0x00u
1057#define LINK_SM_WATCH_OUT(n) (0x01u + (unsigned)(n))
1058#define LINK_SM_WATCH_PORT(n) (0x10u + (unsigned)(n))
1059#define LINK_SM_WATCH_SUPPLY 0x20u
1061#define LINK_SM_ONLINE(a) (1u << (unsigned)(a))
1062#define LINK_SM_ID_WRONG(a) (1u << (4u + (unsigned)(a)))
1063#define LINK_SM_IN_FORCE 0x0100u
1064#define LINK_SM_DERIVED 0x0200u
1065
1066/* --- the SENSE_WIN_A and SENSE_WIN_B pages (protocol 4.25): every
1067 * channel's last complete 50ms window, channels 0 to 5 on A and 6 to
1068 * 11 on B. Read only: every write is refused with READ_ONLY.
1069 *
1070 * WINDOW is the window's number, SERVO_SENSE's WINDOW. FLAGS: bit a
1071 * part a online, on both pages; bit 8 (LINK_SX_HAVE) a window has
1072 * closed under the set-up in force. Then six entries of five
1073 * registers, entry k from register 2 + 5 k the page's channel k: mean
1074 * and highest current in mA, signed; mean and lowest bus voltage in
1075 * mV; the entry's flags -- bit 0 current samples, bit 1 voltage
1076 * samples, bit 2 a current sample at the top of the range, bit 3 one
1077 * at the bottom. A clipped sample is left out of the figures, as on
1078 * SERVO_SENSE. A channel off, or of a part not online, reads 0
1079 * throughout. Rates: FAST every 1ms; every other channel with a
1080 * shunt in turn, one a 1ms tick (1000 / n Hz for n of them, 90.9Hz
1081 * with 11); each bus voltage every 24ms. Not kept. */
1082enum {
1083 LINK_SX_WINDOW = 0,
1084 LINK_SX_FLAGS = 1,
1085 LINK_SX_ENTRIES = 2,
1086 LINK_SX_COUNT = 32,
1087};
1088#define LINK_SX_PER_PAGE 6u
1093enum {
1096 LINK_SX_E_MEAN_MV = 2,
1097 LINK_SX_E_MIN_MV = 3,
1098 LINK_SX_E_FLAGS = 4,
1099 LINK_SX_E_STRIDE = 5,
1100};
1102#define LINK_SX_E(k, r) \
1103 ((unsigned)LINK_SX_ENTRIES + (unsigned)(k) * LINK_SX_E_STRIDE + (unsigned)(r))
1104#define LINK_SX_HAVE 0x0100u
1105#define LINK_SX_E_CURRENT 0x0001u
1106#define LINK_SX_E_VOLTAGE 0x0002u
1107#define LINK_SX_E_CLIP_HI 0x0004u
1108#define LINK_SX_E_CLIP_LO 0x0008u
1109
1110/* --- the SENSE_LIMIT page (protocol 4.27): a current limit for each of
1111 * SENSE_MAP's 12 channels, and the windows that passed them. An
1112 * alert only: a limit passed stops nothing and drives nothing.
1113 *
1114 * LIMIT_MA[c] (registers 0 to 11): channel c's limit in mA, 1 to
1115 * 32767; 0 = none. Kept in the IOmcu's flash. A write lies within
1116 * them: one that reaches register 12 is refused with READ_ONLY, a
1117 * value above 32767 with BAD_VALUE, and a refused write stores none
1118 * of its registers. Taken in any bank state.
1119 *
1120 * Core 1 judges each channel's window once, as it closes
1121 * (sense_window_over()): over when its highest current, in mA as
1122 * SENSE_WIN shows it, is above the limit, or when a sample read the
1123 * top of the range and that top, unrounded, is above the limit. A
1124 * negative current is never over, nor a channel off or of a part not
1125 * online at the close. Core 0 adds what core 1 counted at each
1126 * snapshot, so no window is missed however late it takes one.
1127 *
1128 * OVER (register 12, read only): bit c set when a window of channel c
1129 * was over since the last read of this register. A read that covers
1130 * register 12 clears it after the reply is filled; a reply lost on
1131 * the link loses those bits, which OVER_COUNT still counts.
1132 * OVER_COUNT (register 13, read only): channel windows over, modulo
1133 * 65536, since the IOmcu started. Registers 14 and 15 are reserved:
1134 * they read 0. */
1135enum {
1138 LINK_SL_OVER = 12,
1139 LINK_SL_OVER_COUNT = 13,
1140 LINK_SL_COUNT = 16,
1141};
1142#define LINK_SL_MA_MAX 32767u
1143
1144/* --- the TONE page (protocol 4.8): the beeps of an ESC (electronic speed
1145 * controller), heard on one motor phase. One GPIO reads the phase
1146 * through a series resistor and a zener clamp; a PIO (programmable
1147 * input/output) state machine stamps its edges at 26.7ns, and
1148 * protocols/phase_tap/tone.c turns them into beeps and their pitch.
1149 *
1150 * ENABLE to F_MAX_HZ are one frame and SPLIT_PCT to register 7 the
1151 * next. ENABLE bit 0 runs the tap. PIN is the GPIO. F_MIN_HZ and
1152 * F_MAX_HZ bound the tones heard: 50 to 2000Hz, and F_MIN_HZ + 1 to
1153 * 6900Hz (EVT_FREQ_DHZ holds 0.1Hz in 16 bits, to 6553.5Hz).
1154 * SPLIT_PCT is how far a pitch moves, in percent, to start a new beep
1155 * without a silence: 0 splits on silence only, 50 at most. GAP_MS is
1156 * the silence that ends a beep, 1 to 100ms and at least the period of
1157 * F_MIN_HZ. MIN_PERIODS is how many tone periods make a beep, 1 to
1158 * 64. Register 7 reads 0 and takes only 0.
1159 *
1160 * Refused with BAD_VALUE: a value out of its range, a combination the
1161 * detector refuses (tone_init()), and, while the tap is enabled, a pin
1162 * past the bank, one the board reserves, or an ADC (analog to digital
1163 * converter) pin: GP26 to GP29 on the RP2350A and GP40 to GP47 on the
1164 * RP2354B, rated IOVDD + 0.5V and not fault tolerant, and any pin on
1165 * an IOmcu whose core 1 did not start at boot: no capture runs
1166 * before a restart. Refused with
1167 * BUSY (since 4.17, BAD_VALUE before): while the tap is enabled, a pin
1168 * bound to an output or held by the SENSE, SUPPLY or PROG page, and a
1169 * capture the wiring cannot start for now -- core 1 in a pass, or no
1170 * PIO state machine or DMA channel left. Freed, the same write is
1171 * taken. The pin is no output's while the tap
1172 * is enabled, and an OUTPUTS write that binds it is refused, as are a
1173 * SENSE or SUPPLY write that takes it. A change is taken armed or
1174 * not: the tap is an input and drives nothing.
1175 *
1176 * FLAGS onwards are read only: FLAGS (link_tone_flag_t); WINDOW, the
1177 * detector's 8ms windows counted modulo 65536; WIN_FREQ_DHZ, the last
1178 * window's tone in 0.1Hz, 0 with no tone; WIN_PERIODS, the periods in
1179 * it.
1180 *
1181 * The IOmcu keeps the last LINK_TN_RING beeps and numbers them
1182 * from 1 to 65535, then from 1 again. BEEP_HEAD is the newest number,
1183 * 0 before the first beep. EVT_SEL names the beep that EVT_SEQ to
1184 * EVT_FLAGS show. It is the one writable register after register 7,
1185 * it is not kept, and a read does not consume a beep, so a reply lost
1186 * on the link loses nothing. EVT_SEQ equals EVT_SEL while that beep is
1187 * in the ring; when it has left the ring, or has not happened yet,
1188 * EVT_SEQ and registers 15 to 21 read 0. EVT_START_MS is the beep's
1189 * first rise in ms since the capture started (ENABLE written 1, or PIN
1190 * changed while enabled), 32 bit, low register first (49.7 days);
1191 * EVT_LEN_DMS its length to its last edge in 0.1ms, to 6553.5ms;
1192 * EVT_FREQ_DHZ its mean pitch in 0.1Hz; EVT_BURSTS its bursts, to
1193 * 65535; EVT_CARRIER_HHZ the carrier it was chopped at in 100Hz
1194 * steps, 0 unchopped. A length, pitch, burst count or carrier past its
1195 * register reads as the largest it holds. EVT_FLAGS bit 0: the beep
1196 * began at a pitch change with no silence before it; bit 1: it ended
1197 * at one.
1198 * LOST counts beeps dropped, modulo 65536: the detector's queue full,
1199 * or the hand-over between the cores full. GLITCHES counts lows the
1200 * detector ignored as shorter than 500ns, modulo 65536. The
1201 * capture's 8us hold-off removes every low shorter than 8us before
1202 * the detector sees it, so the register reads 0 on the tap.
1203 *
1204 * The capture starts when the tap is enabled or its pin changes, and
1205 * then empties the ring; the numbers go on. Registers 0 to 6 are kept
1206 * in the IOmcu's flash beside the SENSE set-up, and the tap starts
1207 * at boot. Nothing else is kept.
1208 *
1209 * While the tap is disabled the pin is an input with its pull-down on,
1210 * so a wire connected to nothing reads low. The panel's read at
1211 * 20Hz is registers 8 to 23: a request and 4 data frames. */
1212enum {
1213 LINK_TN_ENABLE = 0,
1214 LINK_TN_PIN = 1,
1215 LINK_TN_F_MIN_HZ = 2,
1216 LINK_TN_F_MAX_HZ = 3,
1217 LINK_TN_SPLIT_PCT = 4,
1218 LINK_TN_GAP_MS = 5,
1219 LINK_TN_MIN_PERIODS = 6,
1222 LINK_TN_WINDOW = 9,
1223 LINK_TN_WIN_FREQ_DHZ = 10,
1224 LINK_TN_WIN_PERIODS = 11,
1225 LINK_TN_BEEP_HEAD = 12,
1227 LINK_TN_EVT_SEQ = 14,
1229 LINK_TN_EVT_START_HI = 16,
1232 LINK_TN_EVT_BURSTS = 19,
1234 LINK_TN_EVT_FLAGS = 21,
1235 LINK_TN_LOST = 22,
1236 LINK_TN_GLITCHES = 23,
1237 LINK_TN_COUNT = 24,
1238};
1243#define LINK_TN_CONFIG_COUNT 7u
1244
1246#define LINK_TN_EN_TAP 0x01u
1247
1249#define LINK_TN_F_MIN_LO 50u
1250#define LINK_TN_F_MIN_HI 2000u
1251#define LINK_TN_F_MAX_HI 6900u
1252#define LINK_TN_SPLIT_MAX 50u
1253#define LINK_TN_GAP_MS_MIN 1u
1254#define LINK_TN_GAP_MS_MAX 100u
1255#define LINK_TN_PERIODS_MIN 1u
1256#define LINK_TN_PERIODS_MAX 64u
1258#define LINK_TN_RING 64u
1259
1264#define LINK_TN_DEFAULT_PIN 22u
1265#define LINK_TN_DEFAULT_F_MIN 400u
1266#define LINK_TN_DEFAULT_F_MAX 6500u
1267#define LINK_TN_DEFAULT_SPLIT 8u
1268#define LINK_TN_DEFAULT_GAP_MS 3u
1269#define LINK_TN_DEFAULT_PERIODS 3u
1270
1272typedef enum {
1289 LINK_TN_BEEP = 1u << 3,
1291 LINK_TN_TONE = 1u << 4,
1293
1295#define LINK_TN_EVT_AFTER_CHANGE 0x01u
1296#define LINK_TN_EVT_BEFORE_CHANGE 0x02u
1297
1298#define LINK_OS_RANGE_OF(first, count) \
1299 ((uint16_t)((((unsigned)(first) & 0xFFu) << 8) | ((unsigned)(count) & 0xFFu)))
1300#define LINK_OS_FIRST(range) ((uint8_t)((range) >> 8))
1301#define LINK_OS_CHANNELS(range) ((uint8_t)((range) & 0xFFu))
1302
1309typedef enum {
1310 LINK_DRIVER_NONE = 0,
1311 LINK_DRIVER_PWM = 1,
1312 LINK_DRIVER_PPM = 2,
1313 LINK_DRIVER_DSHOT = 3,
1314 /*
1315 * Bidirectional DShot is its own driver rather than a flag on the one
1316 * above. It inverts the line and the checksum, so an ESC (electronic
1317 * speed controller) set up for one protocol ignores the other entirely;
1318 * a slot that could be switched between them by a flag would look like
1319 * one output with a setting instead of two incompatible wires.
1320 */
1321 LINK_DRIVER_DSHOT_BIDIR = 4,
1323
1324/* -------------------------------------------------------------------- bind */
1325
1347enum {
1349 LINK_BD_COUNT = 1,
1350};
1351
1352/* ---------------------------------------------------------------- identity */
1354enum {
1355 LINK_ID_PROTOCOL_MAJOR = 0,
1356 LINK_ID_PROTOCOL_MINOR = 1,
1357 LINK_ID_FIRMWARE_MAJOR = 2,
1358 LINK_ID_FIRMWARE_MINOR = 3,
1359 LINK_ID_FIRMWARE_PATCH = 4,
1362 LINK_ID_COUNT = 7,
1363};
1364
1386
1387/* ------------------------------------------------------------------ status */
1389enum {
1392 LINK_ST_UPTIME_MS_LO = 2,
1393 LINK_ST_UPTIME_MS_HI = 3,
1396 LINK_ST_CRC_ERRORS = 6,
1397 LINK_ST_RESYNCS = 7,
1410 LINK_ST_REFUSED_HI = 9,
1411 LINK_ST_COUNT = 10,
1412};
1414#define LINK_ST_COUNT_V420 8u
1415
1422typedef enum {
1423 LINK_FAULT_NONE = 0,
1424 LINK_FAULT_LINK_SILENT = 1u << 0,
1425 LINK_FAULT_OVERCURRENT = 1u << 1,
1426 LINK_FAULT_OVERTEMP = 1u << 2,
1427 LINK_FAULT_STALL = 1u << 3,
1439} link_fault_t;
1440
1449
1450/* ------------------------------------------------------------------- bench */
1460enum {
1464 LINK_BN_RPM = 3,
1470 LINK_BN_CURR_MAX_CA = 9,
1471 LINK_BN_POWER_MAX_W = 10,
1472 LINK_BN_RPM_MAX = 11,
1474 LINK_BN_COUNT = 13,
1475};
1476
1478typedef enum {
1480 LINK_BN_CURRENT_OK = 1u << 1,
1481 LINK_BN_RPM_OK = 1u << 2,
1522
1523/* --------------------------------------------------------------- catalogue */
1524
1545#define LINK_CAT_PINS 32u
1546#define LINK_CAT_COUNT LINK_CAT_PINS
1547
1549#define LINK_CAT_OF(gpio, pad, hold) \
1550 ((uint16_t)((((unsigned)(gpio) & 0x3Fu) << 10) \
1551 | (((unsigned)(pad) & 0x3Fu) << 4) \
1552 | ((unsigned)(hold) & 0x0Fu)))
1553#define LINK_CAT_GPIO(r) ((uint8_t)(((r) >> 10) & 0x3Fu))
1554#define LINK_CAT_PAD(r) ((uint8_t)(((r) >> 4) & 0x3Fu))
1555#define LINK_CAT_HOLD(r) ((uint8_t)((r) & 0x0Fu))
1556
1565typedef enum {
1569 LINK_PIN_FLASH = 3,
1570 LINK_PIN_DEBUG = 4,
1571 LINK_PIN_SENSOR = 5,
1574
1575/* ------------------------------------------------------------------- shape */
1576
1598enum {
1609 LINK_SH_COUNT = 5,
1610};
1611
1612#define LINK_SH_LAYOUT_OF(corner, per_side) \
1613 ((uint16_t)((((unsigned)(corner) & 0xFFu) << 8) \
1614 | ((unsigned)(per_side) & 0xFFu)))
1615#define LINK_SH_CORNER(r) ((uint8_t)(((r) >> 8) & 0xFFu))
1616#define LINK_SH_PER_SIDE(r) ((uint8_t)((r) & 0xFFu))
1617
1622typedef enum {
1623 LINK_SH_BOTTOM_LEFT = 0,
1624 LINK_SH_BOTTOM_RIGHT = 1,
1625 LINK_SH_TOP_LEFT = 2,
1626 LINK_SH_TOP_RIGHT = 3,
1628
1629/* ----------------------------------------------------------------- artwork */
1630
1653enum {
1659 LINK_AW_BYTES_HI = 5,
1674 LINK_AW_HASH_HI = 8,
1675 LINK_AW_COUNT = 9,
1676};
1677
1681typedef enum {
1682 LINK_ART_NONE = 0,
1692
1733#define LINK_DRAW_VERSION 1u
1734#define LINK_DRAW_HEAD_BYTES 16u
1735#define LINK_DRAW_PAD_BYTES 8u
1736#define LINK_DRAW_SHAPE_BYTES 12u
1737#define LINK_DRAW_MAX_PADS 64u
1738#define LINK_DRAW_MAX_SHAPES 400u
1739#define LINK_DRAW_MAX_BYTES (LINK_DRAW_HEAD_BYTES \
1740 + LINK_DRAW_MAX_PADS * LINK_DRAW_PAD_BYTES \
1741 + LINK_DRAW_MAX_SHAPES * LINK_DRAW_SHAPE_BYTES)
1745#define LINK_DRAW_PAD_GPIO 4u
1747#define LINK_DRAW_PAD_SQUARE 0x01u
1748
1752typedef enum {
1753 LINK_DRAW_RECT = 1,
1754 LINK_DRAW_RRECT = 2,
1755 LINK_DRAW_DISC = 3,
1756 LINK_DRAW_LINE = 4,
1758
1770enum {
1773 LINK_AD_COUNT = LINK_MAX_REGS,
1774};
1775#define LINK_AD_WORDS ((unsigned)(LINK_AD_COUNT - LINK_AD_DATA))
1776#define LINK_AD_BYTES (LINK_AD_WORDS * 2u)
1777
1778/* -------------------------------------------------------------------- pads */
1779
1797#define LINK_PAD_SLOTS 32u
1798#define LINK_PAD_COUNT LINK_PAD_SLOTS
1799
1803#define LINK_PAD_OF(pad, kind, dv) \
1804 ((uint16_t)((((unsigned)(pad) & 0x3Fu) << 10) \
1805 | (((unsigned)(kind) & 0x03u) << 8) \
1806 | ((unsigned)(dv) & 0xFFu)))
1807#define LINK_PAD_NUM(r) ((uint8_t)(((r) >> 10) & 0x3Fu))
1808#define LINK_PAD_KIND(r) ((uint8_t)(((r) >> 8) & 0x03u))
1809#define LINK_PAD_DV(r) ((uint8_t)((r) & 0xFFu))
1810
1825
1826/* --------------------------------------------------------------------- KST */
1844enum {
1863 LINK_KS_BAD_HI = 8,
1867 LINK_KS_FP_REGS_HI = 11,
1871 LINK_KS_HALF_MAX_NS = 13,
1874 LINK_KS_DELAY_MAX_US = 15,
1879 LINK_KS_COUNT = 32,
1880};
1881
1883enum {
1916 LINK_KS_W_COUNT = 29,
1917};
1918
1920#define LINK_KS_W_CMD_FRAME 4u
1922#define LINK_KS_W_STAGED 21u
1924#define LINK_KS_IMAGE_REGS 16u
1925
1931#define LINK_KST_WRITE_KEY 0x57A5u
1932
1933#define LINK_KS_STATE_OF(r) ((uint8_t)((r) & 0x7u))
1934#define LINK_KS_PORT_OF(r) ((uint8_t)(((r) >> 12) & 0xFu))
1935#define LINK_KS_OP_OF(r) ((uint8_t)(((r) >> 12) & 0xFu))
1936#define LINK_KS_FRAMES_OF(r) ((uint16_t)((r) & 0xFFFu))
1937#define LINK_KS_W_CMD_CONFIRM 0x0080u
1944#define LINK_KS_W_CMD_PORT 0x0040u
1945#define LINK_KS_W_CMD_OF(op, port) \
1946 ((uint16_t)((unsigned)(op) | LINK_KS_W_CMD_PORT \
1947 | (((unsigned)(port) & 0xFu) << 8)))
1953#define LINK_KST_RESULT_SUPPLY 32u
1960#define LINK_KST_RESULT_NO_PATH 33u
1967#define LINK_KST_RESULT_TOO_COMPLEX 34u
1975#define LINK_KST_RESULT_PLANNING 35u
1976
1980#define LINK_KST_LEAVE_MS_MAX 10000u
1987#define LINK_KST_LEAVE_MS_DEFAULT 100u
1988
1995static inline uint16_t link_kst_crc(const uint16_t *regs, unsigned n)
1996{
1997 uint16_t crc = 0xFFFFu;
1998
1999 for (unsigned i = 0; i < n; ++i) {
2000 const uint8_t b[2] = { (uint8_t)(regs[i] & 0xFFu),
2001 (uint8_t)(regs[i] >> 8) };
2002 crc = link_crc(crc, b, sizeof(b));
2003 }
2004 return crc;
2005}
2006
2020
2024enum {
2025 LINK_KS_F_BUSY = 0x0008u,
2036 LINK_KS_F_RAIL = 0x0400u,
2040};
2041
2065
2113
2114/* -------------------------------------------------------------------- PROG */
2131enum {
2142 LINK_PG_PORT0 = 4,
2146 LINK_PG_REGS = 28,
2147};
2152enum {
2159 LINK_PG_STRIDE = 5,
2160};
2178
2179#define LINK_PG_FN_COUNT_V426 2u
2181#define LINK_PG_FN_IS_DSHOT(fn) \
2182 ((unsigned)(fn) - (unsigned)LINK_PG_FN_DSHOT150 \
2183 <= (unsigned)LINK_PG_FN_DSHOT600 - (unsigned)LINK_PG_FN_DSHOT150)
2184
2185#define LINK_PG_FN_KBIT(fn) \
2186 ((unsigned)(fn) == (unsigned)LINK_PG_FN_DSHOT150 ? 150u \
2187 : (unsigned)(fn) == (unsigned)LINK_PG_FN_DSHOT300 ? 300u \
2188 : (unsigned)(fn) == (unsigned)LINK_PG_FN_DSHOT600 ? 600u : 0u)
2189
2190#define LINK_PG_PORTS_MAX 4u
2191#define LINK_PG_PIN_NONE 0xFFFFu
2192#define LINK_PG_REG(port, r) \
2193 ((uint8_t)(LINK_PG_PORT0 + (unsigned)(port) * LINK_PG_STRIDE + (r)))
2194#define LINK_PG_FUNC(port) ((uint8_t)(LINK_PG_FUNC0 + (unsigned)(port)))
2195#define LINK_PG_F_BOUND(port) ((uint16_t)(1u << (unsigned)(port)))
2196#define LINK_PG_F_PARKED(port) ((uint16_t)(0x10u << (unsigned)(port)))
2197#define LINK_PG_F_REFUSED(port) ((uint16_t)(0x100u << (unsigned)(port)))
2199#define LINK_PG_F_DSHOT(port) ((uint16_t)(0x1000u << (unsigned)(port)))
2200
2201/* ------------------------------------------------------------------- HITEC */
2221enum {
2245 LINK_HT_COUNT = 32,
2246};
2247
2261
2263enum {
2265 LINK_HT_I_DELAY_HI = 17,
2267 LINK_HT_I_LEAD_HI = 19,
2269 LINK_HT_I_T_HI = 21,
2271 LINK_HT_I_SPAN_HI = 23,
2278 LINK_HT_I_WINDOW_HI = 28,
2281};
2282
2284enum {
2301 LINK_HT_W_LEAD_HI = 11,
2303 LINK_HT_W_WINDOW_HI = 13,
2309 LINK_HT_W_LEVEL_HI = 17,
2329 LINK_HT_W_COUNT = 24,
2330};
2331
2333typedef enum {
2343 LINK_HITEC_RX_COUNT
2345
2347#define LINK_HT_LINE_PRECHARGE 0x0100u
2348
2350#define LINK_HT_W_CMD_FRAME 4u
2352#define LINK_HT_W_STAGED 18u
2353
2358#define LINK_HITEC_WRITE_KEY 0x48A5u
2363#define LINK_HITEC_SUPPLY_MIN_MV 4800u
2364#define LINK_HITEC_SUPPLY_MAX_MV 6000u
2366#define LINK_HITEC_OFF_MS_MAX 10000u
2367
2368#define LINK_HT_STATE_OF(r) ((uint8_t)((r) & 0x7u))
2369#define LINK_HT_PORT_OF(r) ((uint8_t)(((r) >> 12) & 0xFu))
2370#define LINK_HT_OP_OF(r) ((uint8_t)(((r) >> 12) & 0xFu))
2371#define LINK_HT_W_CMD_OF(op, port) \
2372 ((uint16_t)((unsigned)(op) | (((unsigned)(port) & 0xFu) << 8)))
2373#define LINK_HT_LINE_OF(family, drive) \
2374 ((uint16_t)(((unsigned)(family) & 1u) | (((unsigned)(drive) & 1u) << 4)))
2375
2386
2390enum {
2393 LINK_HT_F_RAIL = 0x0010u,
2395 LINK_HT_F_KEY = 0x0040u,
2399};
2400
2402enum {
2403 LINK_HT_CAP_FULL = 0x0100u,
2404 LINK_HT_CAP_ANSWERED = 0x0200u,
2405 LINK_HT_CAP_OVERFLOW = 0x0400u,
2406 LINK_HT_CAP_ABORTED = 0x0800u,
2407};
2408
2410typedef enum {
2411 LINK_HITEC_DEC_NONE = 0,
2416
2433
2452
2454#define LINK_HITEC_SUPPLY_MS 3000u
2455
2481
2482/* ----------------------------------------------------------------- control */
2494enum {
2497 /*
2498 * The magnet count of the motor under test, so an electrical speed can
2499 * be turned into a mechanical one. It is the one number bidirectional
2500 * DShot cannot carry: an ESC (electronic speed controller) reports
2501 * electrical periods and has no idea what it is bolted to. Zero means
2502 * nobody has said, and rpm (revolutions per minute) is then not reported
2503 * rather than reported wrong.
2504 */
2505 LINK_CT_MOTOR_POLES = 2,
2507 LINK_CT_COUNT = 4,
2508};
2509
2511#define LINK_CT_ARM_FRAME 3u
2512
2517#define LINK_POLES_MIN 2u
2518#define LINK_POLES_MAX 42u
2519
2525#define LINK_CLEAR_MAGIC 0x5AFEu
2526
2540#define LINK_ARM_ALL 0x0001u
2541#define LINK_ARM_THROTTLE 0x0002u
2542#define LINK_ARM_SURFACE 0x0004u
2544#define LINK_ARM_ROLES (LINK_ARM_THROTTLE | LINK_ARM_SURFACE)
2545
2547#define LINK_THROTTLE_MAX 10000u
2548
2549/* ----------------------------------------------------------------- update */
2550
2604enum {
2614 LINK_UPD_ARG0 = 9,
2615 LINK_UPD_ARG1 = 10,
2616 LINK_UPD_ARG2 = 11,
2618 /* 13 to 15 read 0. */
2620 LINK_UPD_COUNT = 32,
2621};
2622
2627#define LINK_UPD_PROTOCOL 1u
2628
2630#define LINK_UPD_BLOCK_BYTES 64u
2631#define LINK_UPD_DATA_COUNT 32u
2633#define LINK_UPD_SECTOR_BYTES 4096u
2635#define LINK_UPD_EXPECT_REGS 16u
2636
2638#define LINK_UPD_SLOT_A 0x0000u
2639#define LINK_UPD_SLOT_B 0x0001u
2643#define LINK_UPD_SLOT_NONE 0x000Fu
2644#define LINK_UPD_SLOT_MASK 0x000Fu
2646#define LINK_UPD_SLOT_TRIAL 0x0100u
2648#define LINK_UPD_SLOT_OTHER 0x0200u
2649
2663
2701
2720
2724typedef enum {
2725 LINK_UPD_DIGEST_NONE = 0,
2729
2730#ifdef __cplusplus
2731}
2732#endif
2733
2734#endif /* RCBENCH_LINK_PAGES_H */