You can define UART sections at the top level of the config file and refer to them where they are used:
uart1:
txd_pin: gpio.0
rxd_pin: gpio.4
rts_pin: gpio.13
baud: 115200
mode: 8N1
uart2:
txd_pin: gpio.22
rxd_pin: gpio.21
baud: 115200
mode: 8N1
uart0 is the USB serial console one; you cannot define or change it because it is so important for startup messaging.
Within a Spindle class, you can still use the old syntax where there is a subordinate "uart:" subsection, or, alternatively, you can refer to an externally-defined uart section with:
NowForever:
uart_num: 1
modbus_id: 1
Trinamic UART devices like TMC2208 and TMC2209 no longer support the subordinate "uart:" subsection (making that work was just too hard); you must use the external UART section with "uart_num: N":
axes:
x:
motor0:
tmc_2209:
uart_num: 2
addr: 2
...
z:
motor0:
tmc_2209:
uart_num: 2
addr: 1
...
With this scheme it should be possible to use, say, 5 TMC UART devices by using two UARTs, getting around the limitation of 4 device addresses.
Dynamixel2 is like Trinamic; you must use "uart_num: N":
axes:
x:
motor0:
dynamixel2:
uart_num: 1
id: 3
The Dynamixel driver, as currently written, can use only one UART for all the Dynamixels.
UART channels create a new Grbl interface on a UART. This is designed for displays, pendants and external controllers. It can use a report interval so the client does not need to query status. You will get a prompt status update when anything major changes and regular updates when the axes are moving.
We have some starter code if you want to make your own display or interface.
uart_channel1:
uart_num: 2
report_interval_ms: 75
message_level: info
The new channel will accept input just like the USB serial channel, the telnet channels, the websocket channels, etc.
You can also do uart_channel1 or uart_channel2. uart_channel0 is the implied USB serial channel and is always on by default
There are only three physical UART engines on ESP32, so if you try to do too much you will run out of UARTs. If you are using a UART for a VFD spindle and another for TMC drivers, you can't make another uart_channel . UARTs can only be shared among like devices, such as multiple TMC drivers or multiple modbus VFD spindles.
None of this is on any released firmware. See discussion here. This wiki page section is just gathering info from the discussion on Discord
This covers ways of adding I/O over a UART channel. For example: An MCU with inputs (switches, etc) and outputs could be connected via UART. This could potentially be used by senders, the WebUI, or websockets.
When an input pin changes state, or immediately after the pin is initialized, the new value will be reported via a two-character sequence that encodes the pin number and its state. The sequence is as follows:
For pins that are inactive, the first character is 0xc4 and the second is 0x80+pin_number. For pins that are active, the first character is 0xc5 and the second is 0x80+pin_number.
(This encoding is a UTF8 representation of 0x100+pin_number for inactive pins and 0x140+pin_number for active pins.)
All commands from FluidNC to the expander are acknowledged with Expander_ACK(0xB2) if the command succeeded or Expander_NAK (0xB3) if the command failed.
The following commands are currently defined. An IO Expander should either ignore commands that it does not recognize, or if the expander implements serial passthrough, should forward them to the passthrough port.
A pin is specified by a pin_spec like io.N, where N is a number from 0 to 63 or (only for GET:) * for all pins.
The INI command initializes a pin and defines its characteristics. The parameter for INI: is pin_spec=key,key,..., with key values as described. If the pin can be initialized with the given characteristics, the expander must respond with Expander_ACK; otherwise it must respond with Expander_NAK. After the ACK or NAK, if the pin is an input, the expander must send a pin value report with the pin's current value.
The keys for an INI: command are as follows. The pin type is mandatory and must be the first key in the list. The rest are optional and their order does not matter.
For example:
[INI: io.1=in,low,pu] ; Initialize io1 as an input with pullup, active low
[INI: io.2=out] ; Initialize io2 as an output, active high (default)
[INI: io.3=pwm,hz:5000,low] ; Initialize io3 as pwm at 5000 Hz, active low
The SET command sets the state (active or inactive) of an output pin or the duty cycle of a PWM pin. The parameter for SET: is pin_spec=value, where value is 0 (inactive) or 1 (active) for an output pin or a floating point number between 0 and 1, representing the duty cycle, for a PWM pin. The expander must respond with Expander_ACK if the command succeeded or Expander_NAK otherwise (the command could fail if the pin_spec or the numerical value is invalid). For example:
[SET: io.2=1] ; Set the output to 1
[SET: io.3=0.5] ; Set the duty to 50%
Similarly to the code sequence used for input pin state reports, an output or PWM pin's state can be set with a short UTF-8 code sequence. Whereas input reports go from the expander to FluidNC, SET sequences go in the opposite direction, from FluidNC to the expander. For ordinary output pins with two states, the sequence 0xC4, 0x80+pin_number sets a pin to the inactive state, while 0xC5, 0x80+pin_number sets it to the active state. This is the UTF-8 encoding of the numbers 0x100+pin_number for inactive, 0x140+pin_number for active.
Setting a PWM pin's duty cycle requires a longer sequence to accomodate not only the 6 pin_number bits but also the extra bits for the duty cycle. The duty cycle is represented by a number from 0 to 1023, where 0 is always-inactive, 1023 is always-active, and intermediate values represent proportional duty cycles. The encoding is the UTF-8 representation of the number 0x10000 + pin_number * 0x400 + duty_cycle which is a 4-byte sequence. In binary, that is 1ppppppdddddddddd - p for pin number bits and d for duty cycle bits. The byte sequence per UTF-8 encoding rules is, in binary, 11110000 1001pppp 10ppdddd 10dddddd. In hex, it is 0xf0, 0x90+(pin_num>>2), 0x80+((pin_num&3)<<4)+(duty_cycle>>6), 0x80+(duty_cycle&0x3f). A UTF-8 encoder routine would generate the sequence with utf8_encode(0x10000 + (pin_number << 10) + duty_cycle).
The 10-bit duty_cycle representation reasonably approximates one-decimal-point percentages from 0.0% to 100.0%.
The GET command requests an input pin state report. The parameter for GET: is a pin specifier. This command is usually unnecessary because the expander sends input pin states whenever they are initialized or their state changes. The response to a GET command must be Expander_ACK if the pin_spec refers to a valid input pin or Expander_NAK otherwise. After Expander_ACK, the expander must send state reports for all of the requested pins. For example:
[GET: io.1] ; Get the value of io1
[GET: io.*] ; Get the values of all input pins.
# For 6x Controller
uart1:
txd_pin: gpio.27
rxd_pin: gpio.25
baud: 921600
mode: 8N1
uart_channel1:
report_interval_ms: 75
uart_num: 1
user_outputs:
digital0_pin: uart_channel1.0
digital1_pin: uart_channel1.1
digital2_pin: uart_channel1.2
digital3_pin: uart_channel1.3
digital4_pin: uart_channel1.4
digital5_pin: uart_channel1.5
digital6_pin: uart_channel1.6
digital7_pin: uart_channel1.7
coolant:
mist_pin: uart_channel1.8
flood_pin: uart_channel1.9
Device should report an error via NAK if it cannot comply.
It is possible to make an IO expander with a second UART channel that can be used for a downstream pendant. In that case, the expander should forward everything that it receives on its primary UART to the downstream UART, and similarly should send everything that it receives on its downstream UART to its primary UART. To avoid bottlenecks and buffer overrun, both UARTs should use the same baud rate.