This is the firmware for my AVR based piezo bedleveling interface for my 3D printer (Schematics and board layouts can be found on GitHub). As described on the above blogpost this board simply interfaces 4 piezo disks directly to the ATMega328P analog digital converter. The disks are biased to allow detecting both positive and negative edges. An additional external port for a capacitive (or inductive, mechanical, optical, etc.) probe is available and the board supports different modes of operation:
- Piezo only asserts the trigger output whenever the signal of the piezo disks deviated more than the configured threshold from their calibrated centerline.
- External only passes through the external sensor.
- Piezo with veto is the default mode of operation. In this mode the trigger signal is generated by the Piezos but only passed to the control logic in case the external sensor also has triggered. This allows the external sensor to act as some kind of gate.
- Piezo or external triggers whenever any of the sources triggers. This is the mode configured after flashing the board.
The host
directory contains a library to interface with the board through
I2C and a small command line client that allows one to set and get parameters
from the board. The debug commands to get data values are currently not
implemented. The host utility is currently designed to run on FreeBSD
on the RaspberryPi - but should be easily portable to other operating systems by
adding platform specific code to i2c.c
(currently planned for Linux to be
able to run on OctoPrint images). The I2C interface
can also be used directly from Marlin by using
GCodes M260
and M261
to issue commands such as recalibration or
switching trigger modes in the GCode header.
Note that this is work in progress - it currently works well enough for me to be the bed tramming method that I'm using on a daily basis but:
- Noise is really problematic. Especially noisy fans on the hotend. I have to drive to a location around 3 cm away from the bed before performing calibration
- I had to do much tuning on the sensitivity (threshold) and running
average.
- Currently I'm personally not using running average at all (alpha = 1)
- Maybe I'll try implementing a running median filter or moving on to differentials soon
All I2C commands start with the pattern 0xAA, 0x55, 0xAA, 0x55
that is immediatly followed by an OpCode as well as an length byte. The length
includes only data following the Length byte - so a simple request can have
a length of 0. It does not include the checksum byte. One can add an arbitrary
number of 0xAA, 0x55
sequences to perform resynchronization.
The whole packet is followed by the checksum byte - a XOR over all bytes should
return 0. The checksum does not include the synchronization pattern but does
include opcode and length.
All packets are protected by a simple XOR based checksum and have fixed length. Invalid packets will be silently dropped.
OpCode | Data length | Content | Response data |
---|---|---|---|
0x01 | 0 | Query device UUID | 16 byte UUID, Checksum |
0x02 | 0 | Query current threshold | 1 Byte current threshold, 1 Byte checksum |
0x03 | 1 | Set current threshold | None |
0x04 | 0 | Query current sensor readings (raw data) | 8 byte sensor readings (2 bytes per channel), 1 byte checksum |
0x05 | 0 | Query current running averages | 8 byte sensor readings (2 bytes per channel), 1 byte checksum |
0x06 | 1 | Set trigger mode (0: Piezos with veto, 1: Only Piezo, 2: Use capacitive probe) | None |
0x07 | 0 | Get trigger mode | 1 Byte data, 1 Byte checksum |
0x08 | 0 | Reset board (also erases EEPROM & reverts to default settings) | None |
0x09 | 0 | Calibrate centerline for piezos | None |
0x0A | 0 | Store settings to EEPROM | None |
0x0B | 0 | Get alpha value (moving average) 0-100 | 1 Byte data, 1 byte checksum |
0x0C | 1 | Set alpha value (moving average), 0-100 | None |