Function Generator
Arbitrary Waveforms
In addition to the five built-in shapes, each channel can hold one user-defined waveform table. Select waveform index 5 on a channel to play its custom table.
| CH1 | CH2 | |
|---|---|---|
| Table length | 256 points | 128 points |
| Point width | 16-bit | 16-bit |
| Selected by | Waveform index 5 | Waveform index 5 |
The two tables are completely independent. CH1 and CH2 can each hold a different custom shape and play them simultaneously in Dual mode.
Uploading
Tables are uploaded live over BLE while the instrument is running. You do not need to reflash anything, and you do not need to stop the synthesiser.
The transfer is deliberately conservative, because the link is a UART into a BLE module behind a 32-byte receive ring buffer, and a silently corrupted waveform table is a bad failure mode:
1. One line at a time, acknowledged. The host sends one point, waits for the
board’s + (accepted) or - (rejected) reply, and only then sends the next.
This stop-and-wait handshake is what stops the receive buffer overflowing.
2. Per-line checksum. Each point carries its own checksum over the index and both sample bytes. If it does not match, the board replies with a checksum error and the host re-sends that one line. A corrupted point costs one retry, not a whole upload.
3. Whole-table CRC-16 verification. After the last point, the host sends a CRC-16 computed over the entire table. The board recomputes it independently and compares. A match confirms every point landed correctly; a mismatch means the table is rejected and must be uploaded again.
Only after the CRC matches does the board consider the table valid.
The exact command grammar, checksum formula and CRC variant are in the Command Reference.
Practical notes
Upload time. 256 stop-and-wait exchanges is not instant, even at 115200. Expect a visible progress indication in the app — the round trip per point, not the raw bit rate, is what sets the duration.
Resolution versus the built-ins. The table is played back through the same 16-bit DAC and the same Sallen-Key filter as the built-in shapes, and it is stepped by the same phase accumulator at the same rate — 40 kSa/s single channel, 20 kSa/s per channel in Dual. At low output frequencies every table point is emitted; as the output frequency rises the accumulator advances by more than one table entry per tick and points are skipped, exactly as they are for the built-in waveforms. Fine detail in a custom shape therefore survives at low frequencies and is progressively lost as you approach the top of the range.
Sharp edges. The output filter exists to remove the sampling staircase, and it does not distinguish between staircase artefacts and genuinely fast edges you put in the table deliberately. A table containing a step will come out with the filter’s rise time, not an instantaneous edge.
After a power cycle. Keep the source of your shape in the app rather than only on the board, and re-send it after a power cycle if the output does not look right. Unlike the potentiometer positions, which are explicitly restored from EEPROM at boot, the custom table is not something the board reports back in its status reply, so the app cannot tell you whether it survived — re-uploading is cheap and removes the doubt.
Updated · Full project report (PDF)