HOSTMOT2(9)
๐ HOSTMOT2 ๐ โ HAL Component (section 9, she's iconic)
okay so bestie, welcome to the hostmot2 manual page. yes it's long. yes we're doing all of it. grab a snack ๐
โจ NAME โจ
hostmot2 โ the LinuxCNC HAL driver for the Mesa Electronics HostMot2 firmware. that's it, that's the girl ๐
๐ธ SYNOPSIS ๐ธ
so for Mesa card config you wanna peek at the config modparam section down below, okay? Usually you just load hostmot2 with zero parameters unless you're out here debugging.
loadrt hostmot2 [debug_idrom=N] [debug_module_descriptors=N]
[debug_pin_descriptors=N] [debug_modules=N]
debug_idrom[default:0] โ Developer/debug use only!!</p> turns on debug logging of the HostMot2 IDROM header. not for the girlies who just wanna run their machine fr.debug_module_descriptors[default:0] โ Developer/debug use only!</p> enables debug logging of the HostMot2 Module Descriptors.debug_pin_descriptors[default:0] โ Developer/debug use only!</p> enables debug logging of the HostMot2 Pin Descriptors.debug_modules[default:0] โ Developer/debug use only!</p> enables debug logging of the HostMot2 Modules used.use_serial_numbers[default:0] โ when we're creating HAL pins for smart-serial devices, this decides whether we name the pins by the board's serial number instead of which board and port they're plugged into. set it to1and your pins look likehm2_8i20.1234.currentinstead ofhm2_5i23.0.8i20.0.1.current. the identifier is the last 4 digits of the board serial number, which is normally on a sticker on the board. lowkey this makes your configs less portable, but the tradeoff is you can re-connect boards way more carelessly. pick your fighter ๐ซถ
๐ฅ DESCRIPTION ๐ฅ
hostmot2 is a device driver that hooks the Mesa or litehm2 HostMot2 firmware up to the LinuxCNC HAL. and like, by itself? it does nothing. nothing at all. the boards that actually run the firmware need their own drivers before literally anything can happen. currently drivers exist for PCI, Ethernet, SPI and EPP interfaced cards. โจ the more you know โจ
the HostMot2 firmware hands you modules like encoders, PWM generators, step/dir generators, and general purpose I/O pins (GPIOs). these things are called "Modules". the firmware gets configured, at firmware compile time, to provide zero or more instances of each of these Modules.
๐ฆ Board I/O Pins ๐ฆ
the HostMot2 firmware runs on an FPGA board. that board talks to the computer via PCI, Ethernet, SPI, or EPP, and it talks to your motion control hardware โ servos, stepper motors, all of it โ via I/O pins on the board.
every single I/O pin can be configured, at board-driver load time, to do one of two jobs:
- be a particular I/O pin of a particular Module instance (encoder, pwmgen, stepgen etc), or
- be a general purpose digital I/O pin.
by default all Module instances are enabled, and all the board's pins are used by those Module instances.
you can disable Module instances at board-driver load time by specifying a hostmot2 config string modparam. any pins belonging to Module instances you disabled automatically become GPIOs. ๐ซ
all IO pins have some HAL presence, whether they're part of an active module instance or they're full GPIOs. GPIOs can be changed (at run-time, bestie, live) between inputs, normal outputs, and open drains, and they have a flexible HAL interface. IO pins that belong to active Module instances are constrained by whatever the owning Module needs, so their HAL interface is more limited. this is all described in the General Purpose I/O section below.
๐ config modparam ๐
all the board-driver modules (hm2_pci, hm2_eth etc) accept a load-time modparam of type string array named "config". this array has one config string for each board the driver should use. each board's config string gets passed to and parsed by the hostmot2 driver when the board-driver registers the board.
the config string can contain spaces, so it's usually a good idea to wrap the whole thing in double-quotes (the " character). yes, the quotes matter. no, we're not skipping them. ๐
the comma character (,) separates members of the config array from each other.
so like, for example, if your control computer has one 5I20 and one 5I23 you might load the hm2_pci driver with a HAL command (in halcmd) something like this:
loadrt hm2_pci config="firmware=hm2/5i20/SVST8_4.BIT num_encoders=3 num_pwmgens=3 num_stepgens=3,firmware=hm2/5i23/SVSS8_8.BIT sserial_port_0=0000 num_encoders=4"
Note: this assumes thehm2_pcidriver detects the 5I20 first and the 5I23 second. if the detection order doesn't match the order of your config strings, thehostmot2driver will refuse to load the firmware and the board-driver (hm2_pcietc) will fail to load. to the best of my knowledge there is no way to predict the order in which PCI boards will be detected by the driver โ but the detection order will be consistent as long as you don't move the PCI boards around. best move is honestly to just try loading it and see what the detection order is. ๐
the valid entries in the format string are:
[firmware=F]
[num_dplls=N]
[num_encoders=N]
[ssi_chan_N=abc%nq]
[biss_chan_N=abc%nq]
[fanuc_chan_N=abc%nq]
[num_inmuxs=N]
[num_inms=N]
[num_resolvers=N]
[num_pwmgens=N]
[num_3pwmgens=N]
[num_oneshots=N]
[num_rcpwmgens=N]
[num_stepgens=N]
[stepgen_width=N]
[sserial_port_0=00000000]
[num_bspis=N]
[num_leds=N]
[num_ssrs=N]
[num_outms=N]
[num_xy2mods=N]
[enable_raw]
and here's what each one actually means ๐
firmware[optional] โ load the firmware specified byFinto the FPGA on this board. if nofirmware=Fstring is specified, the FPGA won't be re-programmed, but it may keep on running a firmware that was downloaded previously.
the requested firmware F is fetched by udev, which searches for the firmware in the system's firmware search path, usually /lib/firmware. F typically has the form "hm2/<BoardType>/file.bit"; a typical value for F might be "hm2/5i20/SVST8_4.BIT". the hostmot2 firmware files are supplied by the hostmot2-firmware packages, available from linuxcnc.org, and can normally be installed by entering the command sudo apt-get install hostmot2-firmware-5i23 to install the support files for the 5I23 for example.
newer FPGA cards come pre-programmed with firmware, and you should not use a "firmware=" string with these cards. to change the firmware on these cards you should use the "mesaflash" utility instead. it is perfectly valid and reasonable to load these cards with no config string at all. ๐ซถ
num_dplls[optional, default:-1] โ the hm2dpll is a phase-locked loop timer module which may be used to reduce sample and write time jitter for some hm2 modules. this parameter can disable the hm2dpll by setting the number to0. there is only ever one module of this type, with 4 timer channels, so the other valid numbers are-1(enable all) and1, both of which end up meaning the same thing. cute, right?num_encoders[optional, default:-1] โ only enable the firstNencoders. ifNis-1, all encoders are enabled. ifNis0, no encoders are enabled. ifNis greater than the number of encoders available in the firmware, the board will fail to register. don't do that.ssi_chan_N[optional, default:""] โ specifies how the bit stream from a Synchronous Serial Interface device will be interpreted. there should be an entry for each device connected. only channels with a format specifier will be enabled (because the software literally cannot guess data rates and bit lengths). ๐biss_chan_N[optional, default:""] โ same asssi_chan_N, but for BiSS devices.fanuc_chan_N[optional, default:""] โ specifies how the bit stream from a Fanuc absolute encoder will be interpreted. there should be an entry for each device connected. only channels with a format specifier will be enabled (again, the software can't guess data rates and bit lengths).num_resolvers[optional, default:-1] โ only enable the firstNresolvers. ifN=-1then all resolvers are enabled. this module does not work with generic resolvers (unlike the encoder module, which works with any encoder). at the time of writing this Hostmot2 Resolver function only works with the Mesa 7I49 card. ๐ญnum_pwmgens[optional, default:-1] โ only enable the firstNpwmgens. ifNis-1, all pwmgens are enabled. ifNis0, no pwmgens are enabled. ifNis greater than the number of pwmgens available in the firmware, the board will fail to register.num_3pwmgens[optional, default:-1] โ only enable the firstNThree-phase pwmgens. ifNis-1, all 3pwmgens are enabled. ifNis0, no pwmgens are enabled. ifNis greater than the number of pwmgens available in the firmware, the board will fail to register.num_rcpwmgens[optional, default:-1] โ only enable the firstNRC pwmgens. ifNis-1, all rcpwmgens are enabled. ifNis0, no rcpwmgens are enabled. ifNis greater than the number of rcpwmgens available in the firmware, the board will fail to register.num_stepgens[optional, default:-1] โ only enable the firstNstepgens. ifNis-1, all stepgens are enabled. ifNis0, no stepgens are enabled. ifNis greater than the number of stepgens available in the firmware, the board will fail to register.num_xy2mods[optional, default:-1] โ only enable the firstNxy2mods. ifNis-1, all xy2mods are enabled. ifNis0, no xy2mods are enabled. ifNis greater than the number of xy2mods available in the firmware, the board will fail to register.stepgen_width[optional, default:2] โ used to mask extra, unwanted, stepgen pins. stepper drives typically only need two pins (step and dir) but the Hostmot2 stepgen can drive up to 8 output pins for specialised applications (depending on firmware). this parameter applies to all stepgen instances. unused, masked pins will be available as GPIO. slay. โจsserial_port_N(N =0..3) โ [optional, default:00000000for all ports] ๐
ok so here's the tea ๐ซ โ you can hang up to 32 Smart Serial devices off a Mesa Anything IO board. How many you actually get depends on the firmware you're running and how many physical connections the board has. They're arranged into 1-4 ports (that's your N) of 1 to 8 channels each.
Some Smart Serial (SSLBP) cards are extra like that and offer more than one load-time configuration โ for example all inputs, or all outputs, or bonus analogue input on some digital pins. โจ
To set the modes for port 0, you'd do something like sserial_port_0=0120xxxx. A "0" in the string sets that channel to mode 0, a "1" to mode 1, and so on up to mode 9. An "x" anywhere means that channel is disabled and the corresponding FPGA pins become available as GPIO. The string can be up to 8 characters long, and if it defines more modes than the port actually has channels, the extras just get ignored, no drama. ๐
Channel numbering goes left to right, so the example above sets sserial device 0.0 to mode 0, 0.1 to mode 1, 0.2 to mode 2, 0.3 to mode 0, and disables channels 0.4 onwards.
The sserial driver auto-detects connected devices, so no further configuration should be needed. Unconnected channels default to GPIO โ but heads up: the pin values will vary semi-randomly during boot when card-detection runs, so it's genuinely best to actively disable any channel you're using for GPIO. See SSERIAL(9) for more info. ๐ฆ
num_bspisโ [optional, default:-1]
Only enables the first N Buffered SPI drivers. If N is -1 then all the drivers get enabled. Each BSPI driver can address 16 devices. ๐
num_ledsโ [optional, default:-1]
Only enables the first N of the LEDs on the FPGA board. If N is -1, then HAL pins for all the LEDs get created. If N=0 then no pins will be added at all. โญ
num_ssrsโ [optional, default:-1]
Only enables the first N of the SSR modules on the FPGA board. If N is -1, then HAL pins for all the SSR outputs get created. If N=0 then no pins will be added. ๐ธ
enable_rawโ [optional]
If you specify this, it turns on a raw access mode, which means a user can peek and poke the firmware straight from HAL. See Raw Mode below. ๐
๐ง dpll
The hm2dpll module has pins like "hm2_<BoardType>.<BoardNum>.dpll". Lowkey it's likely the pin-count will decrease in the future and some pins will become parameters โ so don't get too attached. ๐
This module is a phase-locked loop that syncs itself up with the thread in which the hostmot2 "read" function is installed, and it'll trigger other functions allocated to it at a specified time before or after that "read" function runs. It can be applied to the three absolute encoder types, quadrature encoder, stepgen, and xy2mod. ๐ฅ
- With the absolute encoders, this lets the system trigger a data transmission just prior to the moment the HAL driver reads the data.
- With stepgens, quadrature encoders, and the xy2mod, the timers can be used to reduce position sampling jitter. This is especially valuable with the ethernet-interfaced cards.
Pins
- (float, in)
hm2_<BoardType>.<BoardNum>.dpll.NN.timer-us
This pin sets the triggering offset of the associated timer. There are 4 timers numbered 01 to 04, represented by the NN digits in the pin name. Units are microseconds (ยตs). โฑ๏ธ
Generally the value for reads will be negative, and positive for writes, so that input data is sampled prior to the main hostmot read and output data is written some time after the main hostmot2 read.
For stepgen and quadrature encoders, the value needs to be more than the maximum variation between read times. -100 will suffice for most systems, and -50 will work on systems with good performance and latency.
For serial encoders, the value also needs to include the time it takes to transfer the absolute encoder position. For instance, if 50 bits must be read at 500 kHz then subtract an additional 50/500 kHz = 100 ยตs to get a starting value of -200.
The xy2mod uses 2 DPLL timers, one for read and one for write. The read timer value can be the same as used by the stepgen and quadrature encoders so the same timer channel can be shared. The write timer is typically set to a time after the main hostmot2 write โ this may take some experimentation. ๐งช
- (float, in)
hm2_<BoardType>.<BoardNum>.dpll.base-freq-khz
This pin sets the base frequency of the phase-locked loop. By default it'll be set to the nominal frequency of the thread in which the PLL is running, and you won't normally need to change it. ๐
- (float, out)
hm2_<BoardType>.<BoardNum>.dpll.phase-error-us
Indicates the phase error of the DPLL. If the number cycles by a large amount, it's likely the PLL has failed to achieve lock and adjustments will need to be made. ๐ญ
- (u32, in)
hm2_<BoardType>.<BoardNum>.dpll.time-const
The filter time-constant for the PLL. The default value is a compromise between insensitivity to single-cycle variations and being resilient to changes to the Linux CLOCK_MONOTONIC timescale, which can instantly change by up to ยฑ500ppm from its nominal value โ usually by timekeeping software like ntpd and ntpdate. Default 2000 (0x7d0).
- (u32, in)
hm2_<BoardType>.<BoardNum>.dpll.plimit
Sets the phase adjustment limit of the PLL. If the value is zero then the PLL will free-run at the base frequency, independent of the servo thread rate. That is probably not what you want. Default 4194304 (0x400000) Units not known...
- (u32, out)
hm2_<BoardType>.<BoardNum>.dpll.ddsize
Used internally by the driver, likely to disappear. ๐
- (u32, in)
hm2_<BoardType>.<BoardNum>.dpll.prescale
Prescale factor for the rate generator. Default 1. โจ
๐ Encoder
Encoders have names like "hm2_<BoardType>.<BoardNum>.encoder.<Instance>". "Instance" is a two-digit number that corresponds to the HostMot2 encoder instance number. There are "num_encoders" instances, starting with 00. ๐
So, for example, the HAL pin that has the current position of the second encoder of the first 5I25 board is: hm2_5i25.0.encoder.01.position (this assumes that the firmware in that board is configured so that this HAL object is available).
Each encoder uses three or four input IO pins, depending on how the firmware was compiled. Three-pin encoders use A, B, and Index (sometimes also known as Z). Four-pin encoders use A, B, Index, and Index-mask. ๐ฆ
The hm2 encoder representation is similar to the one described by the Canonical Device Interface (in the HAL General Reference document), and to the software encoder component. Each encoder instance has the following pins and parameters:
Pins
- (s32 out)
count
Number of encoder counts since the previous reset.
- (float out)
position
Encoder position in position units (count / scale).
- (float out)
position-latched
Encoder latched position in position units (count / scale).
- (float out)
velocity
Estimated encoder velocity in position units per second.
- (float out)
velocity-rpm
Estimated encoder velocity in position units per minute.
- (bit in)
reset
When this pin is True, the count and position pins are set to 0 (the value of the velocity pin is not affected by this). The driver does not reset this pin to FALSE after resetting the count to 0 โ that is the user's job. ๐
- (bit in/out)
index-enable
When this pin is set to True, the count (and therefore also position) are reset to zero on the next Index (Phase-Z) pulse. At the same time, index-enable is reset to zero to indicate that the pulse has occurred.
- (bit in/out)
probe-enable
When this pin is set to True, the encoder count (and therefore also position) are latched on the next probe active edge. At the same time, probe-enable is reset to zero to indicate that the latch event has occurred.
- (bit r/w)
probe-invert
If set to True, the rising edge of the probe input pin triggers the latch event (if probe-enable is True). If set to False, the falling edge triggers.
- (s32 out)
rawcounts
Total number of encoder counts since the start, not adjusted for index or reset. ๐ฅ
- (bit out)
input-a,input-b,input-index
Real time filtered values of A, B, Index encoder signals. โจ
- (bit in)
quad-error-enable
When this pin is True, quadrature error reporting is enabled. When False, existing quadrature errors are cleared and error reporting is disabled.
- (bit out)
quad-error
This bit indicates that a quadrature sequence error has been detected. It can only be set if the corresponding quad-error-enable bit is True. ๐
- (u32 in)
hm2_XXXX.N.encoder.sample-frequency
This is the sample frequency that determines all standard encoder channels' digital filter time constant (see filter parameter).
- (u32 in)
hm2_XXXX.N.encoder.muxed-sample-frequency
This is the sample frequency that determines all muxed encoder channels' digital filter time constant (see filter parameter). This also sets the encoder multiplexing frequency.
- (float in)
hm2_XXXX.N.encoder.muxed-skew
This sets the muxed encoder sample time delay (in ns) from the multiplex signal. Setting this properly can increase the usable multiplex frequency and compensate for cable delays (suggested value is 3* cable length in feet +20). ๐
- (bit in)
hm2_XXXX.N.encoder.hires-timestamp
When this pin is True the encoder timestamp counter frequency is ~10 MHz; when False the timestamp counter frequency is ~2 MHz. This should be set True for frequency counting applications to improve the resolution. It should be set False when servo thread periods longer than 1 ms are used. โฑ๏ธ
Parameters:
- (float r/w)
scale
Converts from "count" units to "position" units.
- (bit r/w)
index-invert
If set to True, the rising edge of the Index input pin triggers the Index event (if index-enable is True). If set to False, the falling edge triggers.
- (bit r/w)
index-mask
If set to True, the Index input pin only has an effect if the Index-Mask input pin is True (or False, depending on the index-mask-invert pin below).
index-mask-invert(bit, r/w) โ okay so if you set this to True, then Index-Mask has to be False for Index to actually do anything. Flip it to False and it's the Index-Mask pin that has to be True instead. They're beefing, basically. ๐counter-mode(bit, r/w) โ set it False (that's the default, bestie) for Quadrature. Set it True for Step/Dir โ and in that case Step lives on the A pin and Dir lives on the B pin. That's the whole plot twist.filter(bit, r/w) โ True is the default here, and it makes the quadrature counter need 15 sample clocks before it'll register a change on any of the three input lines. Any pulse shorter than that gets rejected as noise. Set it False and the counter only needs 3 clocks to register a change. The default encoder sample clock runs at approximately 25 to 33 MHz, but you can change it globally with thesample-frequencyormuxed-sample-frequencypin. โจvel-timeout(float, r/w) โ so when the encoder is moving slower than one pulse per driver read of the FPGA count (that's inside thehm2_read()function), estimating velocity gets hard. The driver can wait several iterations for the next pulse to show up, all while reporting the upper bound of the encoder velocity โ which it can guess pretty accurately. This parameter says how long to wait for that next pulse before it just reports the encoder as stopped. Units are seconds, bestie. โฑ๏ธhm2_XXXX.N.encoder.timer-number(s32, r/w, default:-1) โ sets the hm2dpll timer instance used to latch encoder counts.-1โ does not latch encoder counts.0โ latches at the same time as the main hostmot2 read.1..4โ uses a time offset from the main hostmot2 read, according to the dpll'stimer-ussetting.
Typically timer-us should be a negative number with a magnitude larger than the largest latency (like -100 for a system with mediocre latency, -50 for a system with good latency). A negative number means latch at the specified time before the nominal hostmot2 read time.
If there's no DPLL module in the FPGA firmware, or if the encoder module doesn't support DPLL, then this pin is not created at all. No pin, no problem.
When it is available, you should typically enable this feature โ doing so generally reduces following errors. ๐
๐ธ Synchronous Serial Interface (SSI) ๐ธ
Not to be confused with the Smart Serial Interface, okay?? They are two different girls. ๐
One pin is created for each SSI instance, no matter what the data format is: hm2_XXXX.NN.ssi.MM.data-incomplete (bit, in). This pin gets set "True" if the module was still transferring data when the value was read. When this problem is happening you'll also get a limited number of error messages printed to the UI. Use this pin to monitor whether your config changes actually fixed the problem. The solutions depend on whether the encoder read is being triggered by the hm2dpll phase-locked-loop timer (described above) or by the trigger-encoders function (described below).
The names of the pins the SSI module creates depend entirely on the format string for each channel you gave on the loadrt command line. A typical format string might look like:
ssi_chan_0=error%1bposition%24g
That would read the LSB of the bit-stream as a bit-type pin named "error", and the next 24 bits as a Gray-coded encoder counter. All the encoder-related HAL pins would begin with "position". ๐ฆ
There should be no spaces in the format string โ the low-level code uses it as a delimiter.
The format is: a string of alphanumeric characters that will form the HAL pin names, then a % symbol, then a bit-count, then a data type. All bits in the packet must be defined, even the ones you're not using. There's a limit of 64 bits in total.
The valid format characters and the pins they create:
pโ (Pad). Doesn't create any pins, it's just there to ignore sections of the bit stream you don't need. She's literally just standing there, serving cunt, contributing nothing. ๐bโ (Boolean).hm2_XXXX.N.ssi.MM.<name>(bit, out) โ if any bits in the designated field width are non-zero, the HAL pin will be"True".hm2_XXXX.N.ssi.MM.<name>-not(bit, out) โ the inverted version of the above. The HAL pin will be"True"if all bits in the field are zero.
uโ (Unsigned)hm2_XXXX.N.ssi.MM.<name>(float, out) โ the value of the bits interpreted as an unsigned integer, then scaled so that the pin value equals thescalemaxparameter value when all bits are high. (for example if the field is 8 bits wide and thescalemaxparameter was 20 then a value of 255 would return 20, and 0 would return 0.)
sโ (Signed)hm2_XXXX.N.ssi.MM.<name>(float, out) โ the value of the bits interpreted as a 2s complement signed number, then scaled similarly to the unsigned variant, except symmetrical around zero. โจ
fโ (bitField)hm2_XXXX.N.ssi.MM.<name>-NN(bit, out) โ the value of each individual bit in the data field.NNstarts at00up to the number of bits in the field.hm2_XXXX.N.ssi.MM.<name>-NN-not(bit, out) โ an inverted version of the individual bit values.
eโ (Encoder)hm2_XXXX.N.ssi.MM.<name>.count(s32, out) โ the lower 32 bits of the total encoder counts. This value is reset both by the...resetand the...index-enablepins.hm2_XXXX.N.ssi.MM.<name>.rawcounts(s32, out) โ the lower 32 bits of the total encoder counts. This pin is not affected by reset and index.hm2_XXXX.N.ssi.MM.<name>.position(float, out) โ the encoder position in machine units. This is calculated from the full 64-bit buffers so it will show a True value even after the counts pins have wrapped. It's zeroed by reset and index enable.hm2_XXXX.N.ssi.MM.<name>.index-enable(bit, IO) โ when this pin is set"True"the module will wait until the raw encoder counts next passes through an integer multiple of the number of counts specified by thecounts-per-revparameter, and then it will zero the counts and position pins, and set theindex-enablepin back to"False"as a signal to the system that"index"has been passed. This pin is used for spindle-synchronised motion and index-homing. ๐ฏhm2_XXXX.N.ssi.MM.<name>.reset(bit, in) (bit, out) โ when this pin is set high the counts and position pins are zeroed.
hโ (Split encoder, high-order bits). Some encoders (Including Fanuc) place the encoder part-turn counts and full-turn counts in separate, non-contiguous fields. This tag defines the high-order bits of such an encoder module. There can be only onehand oneltag per channel โ the behaviour with multiple such channels will be undefined. โ ๏ธlโ (Split encoder, low-order bits). Low order bits (see"h").gโ (Gray-code). This is a modifier that indicates that the following format string is gray-code encoded. This is only valid for encoders (e,hl) and unsigned (u) data types.mโ (Multi-turn). This is a modifier that indicates that the following format string is a multi-turn encoder. This is only valid for encoders (e,hl). A jump in encoder position of more than half the full scale is interpreted as a full turn and the counts are wrapped. With a multi-turn encoder this is only likely to be a data glitch and will lead to a permanent offset. This flag ensures that such encoders will never wrap. ๐ก๏ธ
๐ Parameters ๐
Two parameters are universally created for all SSI instances:
hm2_XXXX.N.ssi.MM.frequency-khz(float, r/w) โ sets the SSI clock frequency. Units are kHz, so500gives you a clock frequency of 500,000 Hz.hm2_XXXX.N.ssi.timer-number-num(s32, r/w) โ allocates the SSI module to a specific hm2dpll timer instance. This pin is only useful in firmwares that contain a hm2dpll function, and it defaults to1when such a function exists, and0when it doesn't. You can use the pin to disable reads of the encoder by setting it to a nonexistent timer number, or to0.
Other parameters depend on the data types you specified in the config string:
pโ (Pad) No Parameters. She's still not doing anything bestie. ๐bโ (Boolean) No Parameters.uโ (Unsigned)hm2_XXXX.N.ssi.MM.<name>-scalemax(float, r/w) โ the scaling factor for the channel.
sโ (Signed)hm2_XXXX.N.ssi.MM.<name>-scalemax(float, r/w) โ the scaling factor for the channel.
fโ (bitField): No parameters.eโ (Encoder):hm2_XXXX.N.ssi.MM.<name>.scale(float, r/w) โ the encoder scale in counts per machine unit.hm2_XXXX.N.ssi.MM.<name>.counts-per-rev(u32, r/w) โ used to emulate the index behaviour of an incremental+index encoder. This would normally be set to the actual counts per rev of the encoder, but it can be any whole number of revs. Integer divisors or multipliers of the true PPR might be useful for index-homing. Non-integer factors might be appropriate where there's a synchronous drive ratio between the encoder and the spindle or ballscrew. ๐
๐ BiSS ๐
BiSS is a bidirectional variant of SSI. Currently only a single direction is supported by LinuxCNC (encoder to PC). We're going one way only and honestly? Same.
One pin is created for each BiSS instance, regardless of data format:
hm2_XXXX.NN.biss.MM.data-incomplete (bit, in) โ this pin gets set "True" if the module was still transferring data when the value was read. When this problem exists there will also be a limited number of error messages printed to the UI. This pin should be used to monitor whether the problem has been addressed by config changes. The solutions depend on whether the encoder read is being triggered by the hm2dpll phase-locked-loop timer (described above) or by the trigger-encoders function (described below).
The names of the pins created by the BiSS module depend entirely on the format string for each channel specified in the loadrt command line, and they follow closely the format defined above for SSI. Currently data packets of up to 96 bits are supported by the LinuxCNC driver, although the Mesa Hostmot2 module can handle 512 bit packets. It should be possible to extend the number of packets supported by the driver if there's a requirement to do so. โจ
โจ Fanuc encoder โจ
okay so bestie, the pins and format specifier for this module are literally identical to the SSI module we just talked about, except โ plot twist โ at least one pre-configured format is provided. A modparam of fanuc_chan_N=AA64 (case sensitive, so don't play) will configure the channel for a Fanuc Aa64 encoder. The pins created are:
hm2_XXXX.N.fanuc.MM.battโ indicates battery state ๐hm2_XXXX.N.fanuc.MM.batt-notโ inverted version of above (so if batt is true, this is false, iykyk)hm2_XXXX.N.fanuc.MM.commโ The 0-1023 absolute output for motor commutationhm2_XXXX.N.fanuc.MM.crcโ The CRC checksum. Currently HAL has no way to use thishm2_XXXX.N.fanuc.MM.encoder.countโ Encoder countshm2_XXXX.N.fanuc.MM.encoder.index-enableโ Simulated index. Set by counts-per-rev parameterhm2_XXXX.N.fanuc.MM.encoder.positionโ Counts scaled by the ...scale parameterhm2_XXXX.N.fanuc.MM.encoder.rawcountsโ Raw counts, unaffected by reset or indexhm2_XXXX.N.fanuc.MM.encoder.resetโ If high/True then counts and position = 0hm2_XXXX.N.fanuc.MM.validโ Indicates that the absolute position is validhm2_XXXX.N.fanuc.MM.valid-notโ Inverted version
๐ธ resolver ๐ธ
Resolvers have names like hm2_<BoardType>.<BoardNum>.resolver.<Instance>. <Instance> is a 2-digit number, which for the 7I49 board will be between 00 and 05. This function only works with the Mesa Resolver interface boards (of which the 7I49 is the only example at the time of writing). This board uses an SPI interface to the FPGA card, and will only work with the correct firmware. The pins allocated will be listed in the dmesg output, but are unlikely to be usefully probed with HAL tools.
Pins:
(float, out) angleโ This pin indicates the angular position of the resolver. It is a number between 0 and 1 for each electrical rotation.(float, out) positionโ Calculated from the number of complete and partial revolutions since startup, reset, or index-reset multiplied by the scale parameter.(float, out) velocityโ Calculated from the rotational velocity and the velocity-scale parameter. The default scale is electrical rotations per second.(float, out) velocity-rpmโ Simply velocity scaled by a factor of 60 for convenience.(s32, out) countโ This pins outputs a simulated encoder count at 2^24 counts per rev (16777216 counts).(s32, out) rawcountsโ This is identical to the counts pin, except it is not reset by the "index" or "reset" pins. This is the pin which would be linked to the bldc HAL component if the resolver was being used to commutate a motor.(bit, in) resetโ Resets the position and counts pins to zero immediately.(bit, in) joint-pos-fbโ The Mesa resolver driver has the capability of emulating an absolute encoder using a position file (see the INI-config section of the manual) and the single-turn absolute operation of resolvers. At startup, and only if the use-position-file parameter is set to "True", the resolver driver will wait for a value to be written by the system to the axis.N.joint-pos-fb pin (which must be netted to this resolver pin) and will calculate the number of full turns that best matches the current reolver position. It will then pre-load the driver output with this offset. This should only be used on systems where axis movement in the unpowered state is unlikely. This feature will only work properly if the machine is initially homed to "index" and if the axis home positions are exactly zero.(bit, in/out) index-enableโ When this pin is set high the position and counts pins will be reset the next time the resolver passes through the zero position. At the same time the pin is driven low to indicate to connected modules that the index has been seen, and that the counters have been reset.(bit, out) errorโ Indicates an error in the particular channel. If this value is "True" then the reported position and velocity are invalid.
Parameters:
(float, read/write) scaleโ The position scale, in machine units per resolver electrical revolution.(float, read/write) velocity-scaleโ The conversion factor between resolver rotation speed and machine velocity. A value of 1 will typically give motor speed in RPS, a value of 0.01666667 will give (approximate) RPM.(u32, read/write) index-divisor (default 1)โ The resolver component emulates an index at a fixed point in the sin/cos cycle. Some resolvers have multiple cycles per rev (often related to the number of pole-pairs on the attached motor). LinuxCNC requires an index once per revolution for proper threading etc. This parameter should be set to the number of cycles per rev of the resolver. CAUTION: Which pseudo-index is used will not necessarily be consistent between LinuxCNC runs. Do not expect to re-start a thread after restarting LinuxCNC. It is not appropriate to use this parameter for index-homing of axis drives.(float, read/write) excitation-khzโ This pin sets the excitation frequency for the resolver. This pin is module-level rather than instance-level as all resolvers share the same excitation frequency. Valid values are 10 (~10 kHz), 5 (~5 kHz) and 2.5 (~2.5 kHz). The actual frequency depends on the FPGA frequency, and they correspond to CLOCK_LOW/5000, CLOCK_LOW/10000 and CLOCK_LOW/20000 respectively. The parameter will be set to the closest available of the three frequencies. A value of -1 (the default) indicates that the current setting should be retained.(bit, read/write) use-position-fileโ In conjunction with joint-pos-fb (qv) emulate absolute encoders.
๐ pwmgen ๐
pwmgens have names like hm2_<BoardType>.<BoardNum>.pwmgen.<Instance>. Instance is a two-digit number that corresponds to the HostMot2 pwmgen instance number. There are num_pwmgens instances, starting with 00.
So, for example, the HAL pin that enables output from the fourth pwmgen of the first 7I43 board is: hm2_7i43.0.pwmgen.03.enable (this assumes that the firmware in that board is configured so that this HAL object is available).
In HM2, each pwmgen uses three output IO pins: Not-Enable, Out0, and Out1.
The function of the Out0 and Out1 IO pins varies with output-type parameter (see below).
The hm2 pwmgen representation is similar to the software pwmgen component. Each pwmgen instance has the following pins and parameters:
Pins:
(bit input) enableโ If True, the pwmgen will set its Not-Enable pin False and output its pulses. Ifenableis False, pwmgen will set its Not-Enable pin True and not output any signals.(float input) valueโ The current pwmgen command value, in arbitrary units.
Parameters:
(float rw) scaleโ Scaling factor to convertvaluefrom arbitrary units to duty cycle: dc = value / scale. Duty cycle has an effective range of -1.0 to +1.0 inclusive, anything outside that range gets clipped. The default scale is 1.0.(s32 rw) output-typeโ This emulates theoutput_typeload-time argument to the software pwmgen component. This parameter may be changed at runtime, but most of the time you probably want to set it at startup and then leave it alone. Accepted values are 1 (PWM on Out0 and Direction on Out1), 2 (Up on Out0 and Down on Out1), 3 (PDM mode, PDM on Out0 and Dir on Out1), and 4 (Direction on Out0 and PWM on Out1, "for locked antiphase").(bit input) offset-modeโ When True, offset-mode modifies the PWM behavior so that a PWM value of 0 results in a 50% duty cycle PWM output, a -1 value results in a 0% duty cycle and +1 results in a 100% duty cycle (with default scaling). This mode is used by some PWM motor drives and PWM to analog converters. Typically the direction signal is not used in this mode.(bit input) ditherโ When True, dither causes the PWM output to dither between two adjacent PWM register values at the PWM frequency. This increases the PWM resolution when used for analog output purposes, increasing the maximum resolution from 12 to 16 bits. Dither is only supported with PWMGen firmware version 1 or greater and only affects PWM outputs, not PDM outputs.
In addition to the per-instance HAL Parameters listed above, there are a couple of HAL Parameters that affect all the pwmgen instances:
(u32 rw) pwm_frequencyโ This specifies the PWM frequency, in Hz, of all the pwmgen instances running in the PWM modes (modes 1 and 2). This is the frequency of the variable-duty-cycle wave. Its effective range is from 1 Hz up to 386 kHz. Note that the max frequency is determined by the ClockHigh frequency of the Anything IO board; the 5I25 and 7I92 both have a 200 MHz clock, resulting in a 386 kHz max PWM frequency. Other boards may have different clocks, resulting in different max PWM frequencies. If the user attempts to set the frequency too high, it will be clipped to the max supported frequency of the board. Frequencies below about 5 Hz are not terribly accurate, but above 5 Hz they're pretty close. The default pwm_frequency is 20,000 Hz (20 kHz).pdm_frequency(u32 rw) โ this sets the PDM frequency, in Hz, for all the pwmgen instances out here running in PDM mode (that'smode 3, bestie). Think of it as the "pulse slot frequency" โ the rate at which the pdm generator inside the AnyIO board gets to decide, each slot, whether to emit a pulse or a space. Every pulse (and every space, they come as a set) in the PDM pulse train lasts exactly1/pdm_frequencyseconds. Example time: setpdm_frequencyto2e6(2 MHz) with a 50% duty cycle and you get a 1 MHz square wave โ literally identical to a 1 MHz PWM signal with 50% duty cycle. The effective range runs from about1525 Hzall the way up to just under200 MHz. Heads up though: the max frequency is decided by the ClockHigh frequency of the Anything IO board. The5I25and7I92both have a 100 MHz clock, so their max PDM frequency is 100 MHz. Other boards may have different clocks, which means different max PDM frequencies. If you try to set it too high it just gets clipped to the max the board can actually do, no drama. Defaultpdm_frequencyis20,000 Hz(20 kHz). ๐
โจ 3ppwmgen โจ
Three-Phase PWM generators (3pwmgens, say that five times fast) are built for controlling the high-side and low-side gates in a 3-phase motor driver. The function exists to support the Mesa motor controller daughter-cards, but you can also use it to drive an IGBT or a similar driver directly. ๐ฆ
3pwmgens get names like hm2_<BoardType>.<BoardNum>.3pwmgen.<Instance> where <Instance> is a 2-digit number. You'll have num_3pwmgens instances, starting at 00. Each instance grabs 7 output pins and one input pin on the Mesa card connectors. The outputs are: PWM A, PWM B, PWM C, /PWM A, /PWM B, /PWM C, and Enable. The first three are the high side drivers, the next three are their complementary low-side drivers. The enable bit is meant to control the servo amplifier. The input bit is a fault bit, typically wired up to over-current detection โ when it's set, the PWM generator is disabled. The three phase duty-cycles are each individually controllable from -Scale to +Scale. And a lil note: 0 corresponds to a 50% duty cycle, and that's the initialization value. ๐ธ
Pins ๐
A-value,B-value,C-value(float input) โ the PWM command value for each phase, limited to+/- scale. Defaults to zero, which is a 50% duty cycle on the high-side and low-side pins (but go peek at thedeadtimeparameter, okay?).enable(bit input) โ when high, the PWM is enabled as long as the fault bit hasn't been set by the external fault input pin. When low, the PWM is disabled, with both high-side and low-side drivers low. Real talk: this is not the same as a0output (50% duty cycle on both sets of pins) or negative full scale (where the low side drivers are "on" 100% of the time). Not the same vibe at all.fault(bit output) โ shows the status of the fault bit. This output latches high once it's been set by the physical fault pin, and it stays latched until theenablepin is set to high. ๐
Parameters โญ
deadtime(u32 rw) โ sets the dead-time between the high-side driver turning off and the low-side driver turning on, and vice-versa. Deadtime gets subtracted from on time and added to off time, symmetrically. Example: with 20 kHz PWM (50 ยตs period), 50% duty cycle and zero dead time, the PWM and NPWM outputs would be square waves (NPWM being inverted from PWM) with high times of 25 ยตs. Same settings but with 1 ยตs of deadtime, and both the PWM and NPWM outputs would have high times of 23 ยตs (that's25 - (2X 1 ยตs), 1 ยตs per edge). The value is specified in nanoseconds (ns) and defaults to a rather conservative5000 ns.
๐จ Setting this parameter too low could be both expensive and dangerous โ if both gates are open at the same time there is effectively a short circuit across the supply. Do not play with this one. ๐ญ
scale(float rw) โ sets the half-scale of the specified 3-phase PWM generator. PWM values from-scaleto+scaleare valid. Default is+/- 1.0.fault-invert(bit rw) โ sets the polarity of the fault input pin. A value of1means a fault is triggered with the pin high, and0means a fault is triggered when the pin is pulled low. Default0, fault = low, so the PWM works with the fault pin unconnected.sample-time(u32 rw) โ sets the time during the cycle when an ADC pulse is generated.0= start of PWM cycle,1= end. Not currently useful to LinuxCNC. Default0.5.
On top of all those per-instance parameters, there's one more parameter that affects every instance:
frequency(u32 rw) โ sets the master PWM frequency. Maximum is approx48 kHz, minimum is1 kHz. Defaults to20 kHz.
๐ oneshot ๐
The oneshot is a hardware one-shot device โ super versatile, good for all kinds of timing, delay, signal conditioning, PWM generation, and watchdog functions. The oneshot module includes 2 timers so you can get variable pulse delays for stuff like phase control. Trigger sources can be software, external inputs, the DPLL timer, a built in rate generator, or the other timer. ๐
Oneshots have names like hm2_<BoardType>.<BoardNum>.oneshot.<Instance> where <Instance> is a 2-digit number. You'll have num_oneshots instances, starting at 00. Each instance allocates up to two input and two output pins. ๐ฆ
Pins ๐
width1(float rw) โ sets the pulse width of timer1 in ms. Default is1 ms(1/1000 s).width2(float rw) โ sets the pulse width of timer2 in ms. Default is1 ms(1/1000 s).filter1(float rw) โ sets the digital filter time constant for timer1's external trigger input. Filter time is in ms. Default filter time constant is0.1 ms. External trigger response will be delayed by the filter time setting.filter2(float rw) โ sets the digital filter time constant for timer2's external trigger input. Filter time is in ms. Default filter time constant is0.1 ms. External trigger response will be delayed by the filter time setting.rate(float rw) โ sets the frequency of the built in rate generator (in Hz).trigger_select1,trigger_select2(u32 rw) โ sets the trigger source for timer1 and timer2 respectively. The trigger sources are:0โ Trigger disabled1โ Software trigger: triggered when hal pinswtrigger1is true2โ External hardware: trigger3โ DPLL trigger: triggered by selected DPLL timer4โ Rate trigger: triggered by build in rate generator.5โ Timer1 trigger: triggered by timer1 output6โ Timer2 trigger: triggered by timer2 output
trigger_on_rise1,trigger_on_rise2(bit rw) โ when true, triggers timer1 and timer2 respectively on the rising edge of the trigger source.trigger_on_fall1,trigger_on_fall2(bit rw) โ when true, triggers timer1 and timer2 respectively on the falling edge of the trigger source.retriggerable1,retriggerable2(bit rw) โ when true, the associated timer is retriggerable, meaning the timer will reset to full time on a trigger event even during the output pulse period. When false, the timer is not retriggerable, meaning it will ignore trigger events during the output pulse period.enable1,enable2(bit rw) โ trigger enable for timer1 and timer2 respectively. True to enable.reset1,reset2(bit rw) โ if true, resets timer1 and timer2 respectively, aborting any pulse in progress.out1,out2(bit ro) โ pulse output status bits for timer1 and timer2.exttrigger1,exttrigger2(bit ro) โ external trigger input status bits for timer1 and timer2. These monitor the filtered inputs.swtrigger1,swtrigger2(bit rw) โ software trigger inputs to trigger timer1 and timer2.
๐ rcpwmgen ๐
The rcpwmgen is a simple PWM generator optimized for use with standard RC servos that use pulse width to figure out position. rcpwmgens get names like hm2_<BoardType>.<BoardNum>.rcpwmgen.<Instance> where <Instance> is a 2-digit number. There will be num_rcpwmgens instances, starting at 00. Each instance allocates a single output pin. Unlike the standard PWM generator, the rcpwmgen output is specified in width rather than duty cycle, so the pulse width is independent of the operating frequency. Resolution is approximately 1/2000 for standard 1 to 2 ms range RC servos. ๐
Pins โจ
rate(float rw) โ sets the master RC PWM frequency. Maximum is1 kHz, minimum is.01 Hz. Defaults to50 Hz.width(float rw) โ sets the per channel pulse width in (ms/scale).offset(float rw) โ sets the per channel pulse width offset in ms. You'd set this to1.5 msfor 1-2 ms servos to get a0center position.scale(float rw) โ sets the per channel pulse width scaling. For example, setting the scale to90and the offset to1.5 mswould result in a position range of+-45 degreesand scale in degrees for 1-2 ms servos with a full motion range of90 degrees. ๐
๐ซ stepgen ๐ซ
stepgens get names like hm2_<BoardType>.<BoardNum>.stepgen.<Instance>. "Instance" is a two-digit number that corresponds to the HostMot2 stepgen instance number. There are num_stepgens instances, starting with 00.
So, for example, the HAL pin that has the current position feedback from the first stepgen of the second 5I22 board is:
hm2_5i22.1.stepgen.00.position-fb
(this assumes that the firmware in that board is configured so that this HAL object is available).
Each stepgen uses between 2 and 8 IO pins. The signals on those pins depend on the step_type parameter (described below).
The stepgen representation is modeled on the stepgen software component. Each stepgen instance has the following pins and parameters:
Pins ๐
position-cmd(float input) โ target position of stepper motion, in arbitrary position units. This pin is only used when the stepgen is in position control mode (control-type=0).velocity-cmd(float input) โ target velocity of stepper motion, in arbitrary position units per second. This pin is only used when the stepgen is in velocity control mode (control-type=1).counts(s32 output) โ feedback position in counts (number of steps).position-fb(float output) โ feedback position in scaled position units. This is similar tocounts/position_scale, but has finer than step resolution.position-latched(float output) โ latched-position in scaled position units. This is similar tocounts/position_scale, but has finer than step resolution. ๐(float output) velocity-fbโ the feedback velocity, in whatever arbitrary position units per second you're vibing with ๐ซ(bit input) enableโ turns this stepgen instance on. When it's True, the stepgen does its lil job exactly like you'd expect. When it's False? No steps get generated at all, andvelocity-fbdrops straight to 0. And bestie, listen: if the stepgen is actively moving whenenableflips to False, it stops immediately โ it does not respect themaxaccellimit. Zero chill, instant halt ๐(bit input) position-resetโ resets position to 0 whenever it's True. Super handy for step/dir controlled spindles when you're switching between spindle and joint modes ๐(bit input) control-typeโ flips between position control mode (0) and velocity control mode (1). Defaults to position control (0) โจ(bit in/out) index-enableโ set this to True and the step count (which means position too, obvi) gets reset to zero on the next stepgen index pulse. And at the exact same time,index-enableitself gets reset to zero, which is the signal saying "yep, that pulse happened" ๐ฏ(bit r/w) index-invertโ if True, the rising edge of the index input pin is what triggers the position clear event (only whenindex-enableis True, ofc). If False, it's the falling edge that does it ๐(bit in/out) probe-enableโ when True, the step count (and therefore position too) gets latched on the next stepgen probe active edge. Simultaneously,probe-enableresets to zero to announce that a latch event went down ๐ธ(bit r/w) probe-invertโ if True, the rising edge of the probe input pin triggers the latch event (givenprobe-enableis True). If False, the falling edge is the trigger ๐ป
Parameters:
(float r/w) position-scaleโ converts from counts to position units. The math is:position = counts / position_scale๐งฎ(float r/w) maxvelโ the maximum speed, in position units per second. Set it to0and the driver just always uses the maximum possible velocity based on the current step timings andposition-scale. Heads up though: that max velocity will change if the step timings orposition-scalechange. Defaults to0.(float r/w) maxaccelโ maximum acceleration, in position units per second per second. Defaults to1.0. If you set it to0, the driver does not limit its acceleration at all. That means you gotta make sure theposition-cmdorvelocity-cmdpin is driven in a way that doesn't exceed what your machine can actually handle. This is probs what you want if you're gonna be using the LinuxCNC trajectory planner to jog or run G-code ๐โโ๏ธ(u32 r/w) steplenโ how long the step signal lasts, in nanoseconds โฑ๏ธ(u32 r/w) stepspaceโ the minimum interval between step signals, in nanoseconds.(u32 r/w) dirsetupโ minimum duration that the Direction signal has to stay stable before a step begins, in nanoseconds.(u32 r/w) dirholdโ minimum duration that the Direction signal has to stay stable after a step ends, in nanoseconds.(u32 r/w) step_typeโ the output format, just like thestep_typemodparam for the softwarestepgen(9)component:0= Step/Dir,1= Up/Down,2= Quadrature,3+= table-lookup mode. In this mode thestep_typeparameter decides how long the step sequence is. Also, thestepgen_widthparameter in theloadrtconfig string must be set to suit the number of pins per stepgen required. Any stepgen pins above that number become available for GPIO. This mask defaults to2. The max length is16. Note that Table mode isn't enabled in all firmwares โ but if you spot GPIO pins between the stepgen instances in the dmesg/log hardware pin list, then the option might be available ๐
In Quadrature mode (step_type=2), the stepgen spits out one complete Gray cycle (00 โ 01 โ 11 โ 10 โ 00) for every "step" it takes, so the scale has to be divided by 4 relative to standard step/dir. In table mode, up to 6 IO pins get individually controlled in an arbitrary sequence up to 16 phases long ๐ฆ
(bit input) swap_step_dirโ swaps the step and direction outputs on the selected stepgen. This parameter only exists if the firmware supports this option ๐(u32 r/w) table-data-Nโ there are 4 of these bad boys:table-data-0throughtable-data-3. Each one holds 4 bytes corresponding to 4 stages in the step sequence. For example,table-data-0 = 0x00000001would set stepgen pin 0 (always called"Step"in the dmesg output) on the first phase of the step sequence, andtable-data-4 = 0x20000000would set stepgen pin 6 ("Table5Pin"in the dmesg output) on the 16th stage of the step sequence โจ(s32 r/w) hm2_XXXX.N.stepgen.timer-number(default:-1) โ sets which hm2dpll timer instance gets used to latch stepgen counts. A setting of-1means no latching of stepgen counts at all. A setting of0latches at the same time as the main hostmot2 read. A setting of1..4uses a time offset from the main hostmot2 read, according to the dpll'stimer-ussetting.
Typically, timer-us should be a negative number with a magnitude larger than the largest latency (e.g., -100 for a system with mediocre latency, -50 for a system with good latency). A negative number means latching the specified time before the nominal hostmot2 read time.
If there's no DPLL module present in the FPGA firmware, or if the stepgen module doesn't support DPLL, then this pin simply isn't created. When it is available, this feature should typically be enabled โ doing so generally reduces following errors ๐๐
โจ Smart Serial Interface โจ
The Smart Serial Interface lets you connect up to 32 different devices โ like the Mesa 8i20 2.2 kW 3-phase drive, or 7I64 48-way IO cards โ to a single FPGA card ๐ The driver auto-detects the connected hardware port, channel, and device type. You can hook devices up in any order, to any active channel of an active port (peep the config modparam definition above for the deets).
For the full rundown on the smart-serial devices, go read sserial(9) ๐ซถ
๐ BSPI ๐
The BSPI (Buffered SPI) driver is a lil different from the rest โ it does not create any HAL pins. Instead, it exports a set of functions that a sub-driver can use for the attached hardware. Typically those get written in the "comp" pre-processing language: see http://linuxcnc.org/docs/html/hal/comp.html or man halcompile for more details. For a peek at a typical sub-driver, check out mesa_7i65(9) and the source of mesa_7i65.comp. And for the exported functions, see hm2_bspi_setup_chan(3hm2), hm2_bspi_write_chan(3hm2), hm2_tram_add_bspi_frame(3hm2), hm2_allocate_bspi_tram(3hm2), hm2_bspi_set_read_function(3hm2) and hm2_bspi_set_write_function(3hm2) ๐
The names of the available channels get printed to standard output while the driver is loading, and they look like hm2_<board name>.<board index>.bspi.<index>, e.g., hm2_5i23.0.bspi.0 ๐จ๏ธ
๐ UART ๐
The UART driver also doesn't create any HAL pins โ instead it declares two simple read/write functions plus a setup function for user-written code to use. Typically that'd be written in the "comp" pre-processing language: see http://linuxcnc.org/docs/html/hal/comp.html or man halcompile for more details. For a typical sub-driver example, see mesa_uart(9) and the source of mesa_uart.comp. Also peep hm2_uart_setup_chan(3hm2), hm2_uart_send(3hm2), hm2_uart_read(3hm2) and hm2_uart_setup(3hm2) ๐
The names of the available uart channels get printed to standard output during driver loading, and they look like hm2_<board name>.<board index>uart.<index>, e.g., hm2_5i23.0.uart.0 ๐
๐ธ General Purpose I/O ๐ธ
I/O pins on the board that aren't being used by a module instance get exported to HAL as "full" GPIO pins. Full GPIO pins can be configured at run-time to be inputs, outputs, or open drains, and they have a HAL interface that exposes all that flexibility. Meanwhile, I/O pins that are owned by an active module instance are constrained by whatever that owning module needs, so they get a restricted HAL interface ๐
GPIOs have names like "hm2_<BoardType>.<BoardNum>.gpio.<IONum>". IONum is a three-digit number. The mapping from IONum to connector and pin-on-that-connector gets written to the syslog when the driver loads, and it's documented in Mesa's manual for the Anything I/O boards ๐
So for example, the HAL pin that holds the current inverted input value read from GPIO 012 of the second 7I43 board is: hm2_7i43.1.gpio.012.in-not (this assumes the firmware in that board is configured so that this HAL object is available).
And the HAL parameter that controls whether the last GPIO of the first 5I22 is an input or an output is: hm2_5i22.0.gpio.095.is_output (this assumes the firmware in that board is configured so that this HAL object is available).
The hm2 GPIO representation is modeled after the Digital Inputs and Digital Outputs described in the Canonical Device Interface (part of the HAL General Reference document). Every GPIO can have these HAL Pins:
(bit out) in&in_notโ the state (normal and inverted) of the hardware input pin. Both full GPIO pins and IO pins used as inputs by active module instances have these pins ๐(bit in) outโ the value to be written (possibly inverted) to the hardware output pin. Only full GPIO pins have this pin.
Every GPIO can have these Parameters:
(bit r/w) is_outputโ if set to0, the GPIO is an input. The IO pin gets put into a high-impedance state (weakly pulled high), ready to be driven by other devices. The logic value on the IO pin shows up in the"in"and"in_not"HAL pins. Writes to the"out"HAL pin do absolutely nothing. If this parameter is set to1, the GPIO is an output, and its behavior then depends on the"is_opendrain"parameter. Only full GPIO pins have this parameter ๐(bit r/w) is_opendrainโ okay so this one only does anything if theis_outputparameter is True. If it's False, the GPIO is just a normal output pin: the IO pin on the connector gets driven to whatever value theoutHAL pin says (possibly inverted), and the value of theinandin_notHAL pins is undefined โ so don't go reading those, bestie. If this parameter is True, the GPIO is open-drain. Writing 0 to theoutHAL pin drives the IO pin low, writing 1 to theoutHAL pin puts the IO pin in a high-impedance state. In that high-impedance state the IO pin floats (weakly pulled high), and other devices can drive the value; the resulting value on the IO pin is available on theinandin_notpins. Only full GPIO pins and IO pins used as outputs by active module instances have this parameter. ๐(bit r/w) invert_outputโ this one only does anything if theis_outputparameter is True. If this parameter is True, the output value of the GPIO will be the inverse of the value on theoutHAL pin. Only full GPIO pins and IO pins used as outputs by active module instances have this parameter. โจ
When a physical I/O pin is used by a special function, the related is_output, and is_opendrain HAL parameters are aliased to the special function. For instance, if gpio 1 is taken over by pwmgen 0's first output, then aliases like hm2_7i92.0.pwmgen.00.out0.invert_output (referring to hm2_7i92.0.gpio.001.invert_output) will be automatically created. When more than one GPIO is connected to the same special function, an extra .#. is inserted so that the settings for each related GPIO can be set separately. For example, for the firmware SV12IM_2X7I48_72, the alias hm2_5i20.0.pwmgen.00.0.enable.invert_output (referring to hm2_5i20.0.gpio.000.invert_output) and hm2_5i20.0.pwmgen.00.1.enable.invert_output (referring to hm2_5i20.0.gpio.023.invert_output) are both created. ๐ฆ
๐ inm and inmux ๐
inm/inmuxs are input debouncing modules that support hardware digital filtering of input pins. In addition to the input filtering function, the inm/inmux modules support up to 4 simple quadrature counters for MPG use. The quadrature inputs for MPG encoders 0 through 3 are inm/inmux pins 0 through 7. MPG A,B inputs use the filter time constants programmed for inputs 0..7. Each inm/inmux input pin can have a slow or fast filter constant. Filter time constants are specified in units of scan times. inms have names like hm2_<BoardType>.<BoardNum>.inm.<Instance>. inmuxes have names like hm2_<BoardType>.<BoardNum>.inmux.<Instance>. Instance is a two-digit number that corresponds to the HostMot2 inm or inmux instance number. There are "num_inms" or numx_inmuxs" instances, starting with 00. ๐
Each instance reads between 8 and 32 input pins. inm and inmux are identical except for pin names and the physical interface. โญ
๐ธ Pins ๐ธ
(bit out) input and input-notโ True and inverted filtered input states. ๐(bit out) raw-input and raw-input-notโ True and inverted unfiltered input states. ๐(bit in) input-slowโ If True, selects the long time constant filter for the corresponding input bit, if False the short time constant is used. ๐ง(s32 out) enc0-count,enc1-count,enc2-count,enc3-countโ MPG counters 0 through 3. ๐ข(bit in) enc0-reset,enc1-reset,enc2-reset,enc3-resetโ Reset for MPG counters 0 through 3, count is forced to 0 if true. ๐จ
๐ซ Parameters ๐ซ
(u32 in) scan_rateโ This sets the input scan rate in Hz. Default scan rate is 20 kHz (50 ยตs scan period). โฑ๏ธ(u32 in) fast_scansโ This sets the fast time constant for all input pins. This is the time constant used when theinput-slowpin for the corresponding input is False. The range is 0 to 63 scan periods and the default value is 5 = 250 ยตs at the default 20 kHzscan_rate. โก(u32 in) slow_scansโ This sets the slow time constant for all input pins. This is the time constant used when theinput-slowpin for the corresponding input is True. The range is 0 to 1023 scan periods and the default value is 500 = 25 ms at the default 20 kHzscan_rate. ๐ข(bit in) enc0_4xmode, enc1_4xmode, enc2_4xmode, and enc3_4xmodeโ These set the MPG encoder operating modes to 4X when True and 1X when False. 4๏ธโฃ(u32 out) scan_widthโ This read only parameter specifies the number of inputs scanned by the module. ๐
โจ led โจ
Creates HAL pins for the LEDs on the FPGA board. ๐ก
๐ Pins ๐
(bit in) CR<NN>โ The pins are numbered fromCR01upwards with the name corresponding to the PCB silkscreen. Setting the bit to"True"or1lights the LED. ๐
โก Solid State Relay โก
SSRs have names like hm2_<BoardType>.<BoardNum>.ssr.<Instance>. Instance is a two-digit number that corresponds to the HostMot2 SSR instance number. There are "num_ssrs" instances, starting with 00. ๐
Each instance has a rate control pin and between 1 and 32 output pins. โจ
๐ Pins ๐
(u32 in) rateโ Set the internal frequency of the SSR instance, in Hz (approximate). The valid range is 25 kHz to 25 MHz. Values below the minimum will use the minimum, and values above the max will use the max. 1 MHz is a typical value, and appropriate for all Mesa cards, and is the default. Set to 0 to disable this SSR instance. ๐๏ธ(bit in) out-NNโ The state of this SSR instance's NNth output. Set to 0 to make the output pins act like an open switch (no connection), set to 1 to make them act like a closed switch. ๐(bit in) invert-NNโ Inverts the state of this SSR instance's NNth output, defaults to 0. Wheninvert-NNis set to 1, SSR output NN is closed when theout-NNpin is 0 and open when theout-NNpin is 1. ๐
๐ OutM Simple output module ๐
OutMs have names like hm2_<BoardType>.<BoardNum>.OutM.<Instance>. Instance is a two-digit number that corresponds to the HostMot2 OutM instance number. There are "num_outms" instances, starting with 00. ๐ฆ
Each instance has between 1 and 32 output pins. โจ
๐ Pins ๐
(bit in) out-NNโ This sets the state of this OutM instance's NNth output. Normally the output pin follows the state of this pin but may be inverted by theinvert-nnHAL pin. ๐ฏ(bit in) invert-NNโ Inverts the state of this OutM instance's NNth output, defaults to 0. Wheninvert-NNis set to 1, OutM output NN is high when theout-NNpin is 0 and low when theout-NNpin is 1. ๐
๐ xy2mod
Okay bestie, meet the xy2mod: it's a xy2-100 galvanometer interface ๐ชโจ. It does 16 and 18 bit data modes, and โ this is the cute part โ it includes parabolic interpolation so your position gets updated in between servo thread invocations. No dead air, no choppy motion, just smooth vibes ๐
.
๐ซ Pins
posx_cmd,posy_cmd(float in) โ the X and Y position commands. Full scale is+-posn_scale; the default full scale (set byposx_scaleandposy_scale) is+- 1.posx_fb,posy_fb(float out) โ X and Y position feedback. Full scale is+-posN_scale; default full scale is+- 1. Heads up though ๐ซถ โ this is feedback from the interpolator, not from the galvanometer itself.velx_cmd,vely_cmd(float in) โ X and Y velocity commands, in units offullscale_position/second.velx_fb,vely_fb(float out) โ X and Y velocity feedback, in units offullscale_position/second.accx_cmd,accy_cmd(float in) โ X and Y acceleration commands, in units offullscale_position/second^2.posx_scale,posy_scale(float in) โ sets the full scale range of the position command and feedback. Default is+- 1.0.enable(bit in) โ whenFalse, output data is0, all interpolator values get set to0, and the overflow flags are cleared. It must beTruefor normal operation, no cap ๐จ.controlx,controly(u32 in) โ these set the galvanometer control bits. There are 3 bits per channel in 16 bit mode but just 1 control bit in 18 bit mode, so values from0..7are valid in 16 bit mode, while only0and4are valid in 18 bit mode. Do the math, bestie ๐งฎ.commandx,commandy(u32 in) โ these set the raw 16 bit data sent to the galvanometer in command mode.commandmodex,commandmodey(bit in) โ when set, these enable command mode, where 16 bit command data is sent to the galvanometer.18bitmodex,18bitmodey(bit in) โ whenTrue, these enable the 18 bit data mode for the respective channel.posx-overflow,posy-overflow(bit out) โ when true, these indicate an attempted position move beyond the full scale value.velx-overflow,vely-overflow(bit out) โ whenTrue, these indicate an attempted velocity update move beyond the full scale value.status(u32 out) โ raw 16 bit return status from the galvanometer.
๐๏ธ Parameters
read-timer-number(s32 in) โ selects the DPLL timer number for pre-read sampling of the position and velocity registers. If it's set to-1, pre-read sampling is disabled.write-timer-number(s32 in) โ selects the DPLL timer number for post write update of the position and velocity registers. If it's set to-1, post write update is disabled.
๐ถ Watchdog
The HostMot2 firmware may include a watchdog Module. If it does, the hostmot2 driver will use it. The HAL representation of the watchdog is named hm2_<BoardType>.<BoardNum>.watchdog.
The watchdog starts out asleep and inactive ๐ด. The first time you access the board by running the hm2 write() HAL function (see below), the watchdog wakes up. From then on it must be petted periodically or it will bite ๐ญ. Pet the watchdog by running the hm2 write() HAL function.
When the watchdog bites, all the board's I/O pins are disconnected from their Module instances and become high-impedance inputs (pulled high), and all communication with the board stops. The state of the HostMot2 firmware modules is not disturbed (except for the configuration of the IO pins). Encoder instances keep counting quadrature pulses, and pwm- and step-generators keep generating signals (which are not relayed to the motors, because the IO pins have become inputs). ๐
Resetting the watchdog (by clearing the has_bit pin, see below) resumes communication and resets the I/O pins to the configuration chosen at load-time โจ.
If the firmware includes a watchdog, the following HAL objects will be exported:
Pins
has_bit(bit in/out) โTrueif the watchdog has bit,Falseif the watchdog has not bit. If the watchdog has bit and thehas_bitbit isTrue, the user can reset it toFalseto resume operation.
Parameters
timeout_ns(u32 read/write) โ watchdog timeout, in nanoseconds. This is initialized to5,000,000(5 milliseconds) at module load time. If more than this amount of time passes between calls to thehm2 write()function, the watchdog will bite โฐ๐ฆท.
๐ฌ Raw Mode
If the "enable_raw" config keyword is specified, some extra debugging pins are made available in HAL. The raw mode HAL pin names begin with "hm2_<BoardType>.<BoardNum>.raw".
With Raw mode enabled, a user may peek and poke the firmware from HAL ๐, and may dump the internal state of the hostmot2 driver to the syslog.
Pins
read_address(u32 in) โ the bottom 16 bits of this is used as the address to read from.read_data(u32 out) โ each time thehm2_read()function is called, this pin is updated with the value at.read_address.write_address(u32 in) โ the bottom 16 bits of this is used as the address to write to.write_data(u32 in) โ this is the value to write to.write_address.write_strobe(bit in) โ each time thehm2_write()function is called, this pin is examined. If it isTrue, then the value in.write_datais written to the address in.write_address, and.write_strobeis set back toFalse.dump_state(bit in/out) โ this pin is normallyFalse. If it gets set toTrue, the hostmot2 driver will write its representation of the board's internal state to the syslog, and set the pin back toFalse. ๐
๐ Setting up Smart Serial devices
See setsserial(9) for the current way to set smart-serial eeprom parameters. That's it, that's the whole section, go read that one bestie ๐ซถ.
โก FUNCTIONS
hm2_<BoardType>.<BoardNum>.read-requestโ on boards with long turn around time for reads (at the time of writing, this applies only to ethernet boards), this function sends a read request. When multiple boards are used, this can reduce the servo thread execution time. In this case, the appropriate thread order would be:
addf hm2_7i80.0.read-request
addf hm2_7i80.1.read-request
addf hm2_7i80.0.read
addf hm2_7i80.1.read
which causes the read request to be sent to board 1 before waiting for the response to the read request to arrive from board 0. Pipelining queen ๐โจ.
hm2_<BoardType>.<BoardNum>.readโ this reads the encoder counters, stepgen feedbacks, and GPIO input pins from the FPGA.hm2_<BoardType>.<BoardNum>.writeโ this updates the PWM duty cycles, stepgen rates, and GPIO outputs on the FPGA. Any changes to configuration pins such as stepgen timing, GPIO inversions, etc., are also effected by this function.hm2_<BoardType>.<BoardNum>.read_gpioโ read the GPIO input pins. Note that the effect of this function is a subset of the effect of the.read()function described above. Normally only.read()is used. The only reason to call this function is if you want to do GPIO things in a faster-than-servo thread. (This function is not available on the 7I43 due to limitations of the EPP bus.)hm2_<BoardType>.<BoardNum>.write_gpioโ write the GPIO control registers and output pins. Note that the effect of this function is a subset of the effect of the.write()function described above. Normally only.write()is used. The only reason to call this function is if you want to do GPIO things in a faster-than-servo thread. (This function is not available on the 7I43 due to limitations of the EPP bus.)hm2_<BoardType>.<BoardNum>.trigger-encodersโ this function will only appear if the firmware contains a BiSS, Fanuc or SSI encoder module and if the firmware does not contain ahm2dpllmodule (qv) or if the modparam containsnum_dplls=0. This function should be inserted first in the thread so that the encoder data is ready when the mainhm2_XXXX.NN.readfunction runs. An error message will be printed if the encoder read is not finished in time โณ. It may be possible to avoid this by increasing the data rate. If the problem persists and if "stale" data is acceptable, then the function may be placed later in the thread, allowing a full servo cycle for the data to be transferred from the devices. If available, it is better to use the synchronoushm2dplltriggering function ๐ .
๐ SEE ALSO
hm2_pci(9), hm2_eth(9), hm2_spi(9), hm2_rpspi(9), hm2_7i43(9), hm2_7i90(9)
Mesa's documentation for the Anything I/O boards, at http://www.mesanet.com
๐ LICENSE
GPL
And that's a wrap on the whole page, bestie ๐โจ you read the entire HOSTMOT2(9) โ from LinuxCNC Documentation, dated 2008-05-13. Iconic behaviour, no notes, periodt ๐
๐ฆ๐
๐ฆ where this page comes from
- debian trixie: linuxcnc-uspace 1:2.9.4-2+deb13u1 ยท GFDL-1.1-or-later
- ubuntu questing: linuxcnc-uspace 1:2.9.4-2ubuntu2
- ubuntu resolute: linuxcnc-uspace 1:2.9.4-2ubuntu4 ยท GFDL-1.1-or-later
- ubuntu stonking: linuxcnc-uspace 1:2.9.4-2ubuntu4 ยท GFDL-1.1-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms