Teletype I2C protocol

a thread to discuss and document teletype i2c protocol.

devices/firmwares that currently support it:

  • teletype
  • white whale / original
  • white whale / orca
  • white whale / kria
  • meadowphysics
  • earthsea
  • ansible / levels
  • ansible / cycles
  • ansible / meadowphysics
  • ansible / kria
  • ansible / earthsea (eventually)
  • ansible / tt expander (up to 4 devices)
  • ansible / midi
  • telex txo (up to 8 devices)
  • telex txi (up to 8 devices)
  • just friends
  • w/ (up to 4 devices)
  • er-301 (up to 3 devices)
  • faderbank
  • matrixarchate (up to 3 devices)
  • crow (multiple devices?)

i’m listing different firmwares separately, since we want i2c address to be unique per firmware, not per device, to support cases like using 2 ansibles in different modes. that’s over 40 unique addresses.

it appears we’ve been operating with the wrong assumption that the address space is 256 possible addresses - it looks like addresses are 7 bit, so we actually have 128 addresses available. also as i and @bpcmusic discovered, address 0 is reserved as “send to all” (more on this below). one of the questions is - do we want to use any other of the reserved addresses as defined in the specification (0000xxx and 1111xxx)? that’s 16 addresses which still leaves us plenty (but i don’t know how many addresses crows will use).

address 0 - it appears asf already supports it, so we can’t use it for any specific firmware, but we could use it to our advantage to support things like global clock, global reset etc. for such global commands we do need to also standardize/reserve a range, since all followers will respond to them, so if a follower already uses that command for something else it will create a conflict. i propose to reserve a range for such global commands, since we have 256 commands available that should still leave plenty for firmware specific commands (since those wouldn’t need to be unique across all firmwares).

basically, here is what i propose to do:

  • assign addresses to all supported devices (keep the currently assigned address wherever possible)
  • fix all the incorrect addresses we have right now (by doing &0x7F) - this will need to be tested
  • update 1 - right now it lists both follower addresses and commands, they need to be clearly separated
  • document reserved addresses
  • define a reserved range for global commands and document

protocol documentation:


first pass at ii.h. i’ve separated addresses and commands and defined allowed ranges. i’m reserving 64 commands for global commands, which leaves 192 available for each firmware - i think that should be more than enough (i have some ideas for global commands).

in terms of addresses if we convert 8bit addresses to 7bit we have 2 conflicts - faderbank conflicts with the global address, and er-301 conflicts with meadowphysics. @bpcmusic will be updating the faderbank address, and i can change meadowphysics at some point to use a different address (which is easier than changing er-301 i think).

does aleph use any addresses?

all the existing commands are fine as is, no change required.

// each device must use a unique address (0x01-0x7F)
// 0 is RESERVED for global commands

#define WW                  0x10
#define WW_KRIA             0x10 // ww kria uses ww address

#define II_ANSIBLE_ADDR     0x20
#define II_ANSIBLE_ADDR_2   0x21
#define II_ANSIBLE_ADDR_3   0x22
#define II_ANSIBLE_ADDR_4   0x23
#define II_MID_ADDR         0x24
#define II_ARP_ADDR         0x26
#define II_KR_ADDR          0x28
#define II_MP_ADDR          0x2A
#define II_LV_ADDR          0x2C
#define II_CY_ADDR          0x2E

#define MP                  0x30
#define ER301               0x30 // conflicts with meadowphysics!
#define ER301_2             0x31
#define ER301_3             0x32
#define MATRIXARCHATE       0x38
#define MATRIXARCHATE_2     0x39
#define MATRIXARCHATE_3     0x3A

#define ORCA                0x40

#define ES                  0x50

#define FADER               0x60

#define JF_ADDR             0x70
#define WS_ADDR             0x71
#define WS_ADDR_2           0x72
#define WS_ADDR_3           0x73
#define WS_ADDR_4           0x74

// new commands can overlap with existing ones
// 0b11xxxxxx (0xC0-0xFF) range is RESERVED for global commands

#define WW_PRESET       0x11
#define WW_POS          0x12
#define WW_SYNC         0x13
#define WW_START        0x14
#define WW_END          0x15
#define WW_PMODE        0x16
#define WW_PATTERN      0x17
#define WW_QPATTERN     0x18
#define WW_MUTE1        0x19
#define WW_MUTE2        0x1A
#define WW_MUTE3        0x1B
#define WW_MUTE4        0x1C
#define WW_MUTEA        0x1D
#define WW_MUTEB        0x1E

#define MP_PRESET       0x31
#define MP_RESET        0x32
#define MP_SYNC         0x33
#define MP_MUTE         0x34
#define MP_UNMUTE       0x35
#define MP_FREEZE       0x36
#define MP_UNFREEZE     0x37
#define MP_STOP         0x38

#define ORCA_TRACK      0x40
#define ORCA_CLOCK      0x41
#define ORCA_DIVISOR    0x42
#define ORCA_PHASE      0x43
#define ORCA_RESET      0x44
#define ORCA_WEIGHT     0x45
#define ORCA_MUTE       0x46
#define ORCA_SCALE      0x47
#define ORCA_BANK       0x48
#define ORCA_PRESET     0x49
#define ORCA_RELOAD     0x4A
#define ORCA_ROTATES    0x4B
#define ORCA_ROTATEW    0x4C
#define ORCA_GRESET     0x4D
#define ORCA_CVA        0x4E
#define ORCA_CVB        0x4F

#define ES_PRESET       0x51
#define ES_MODE         0x52
#define ES_CLOCK        0x53
#define ES_RESET        0x54
#define ES_PATTERN      0x55
#define ES_TRANS        0x56
#define ES_STOP         0x57
#define ES_TRIPLE       0x58
#define ES_MAGIC        0x59

#define II_GET              128
#define II_ANSIBLE_TR       1
#define II_ANSIBLE_TR_TOG   2
#define II_ANSIBLE_TR_POL   5
#define II_ANSIBLE_CV       6
#define II_ANSIBLE_CV_OFF   8
#define II_ANSIBLE_CV_SET   9
#define II_ANSIBLE_INPUT    10

#define II_MID_SLEW     1
#define II_MID_SHIFT    2

#define II_ARP_STYLE    0
#define II_ARP_HOLD     1
#define II_ARP_RPT      2
#define II_ARP_GATE     3
#define II_ARP_DIV      4
#define II_ARP_ROT      5
#define II_ARP_SLEW     6
#define II_ARP_PULSE    7
#define II_ARP_RESET    8
#define II_ARP_SHIFT    9
#define II_ARP_FILL     10
#define II_ARP_ER       11

#define II_KR_PRESET    0
#define II_KR_PATTERN   1
#define II_KR_SCALE     2
#define II_KR_PERIOD    3
#define II_KR_POS       4
#define II_KR_LOOP_ST   5
#define II_KR_LOOP_LEN  6
#define II_KR_RESET     7
#define II_KR_CV        8
#define II_KR_MUTE      9
#define II_KR_TMUTE     10
#define II_KR_CLK       11

#define II_MP_PRESET    0
#define II_MP_RESET     1
#define II_MP_STOP      2
#define II_MP_SCALE     3
#define II_MP_PERIOD    4
#define II_MP_CV        5

#define II_LV_PRESET    0
#define II_LV_RESET     1
#define II_LV_POS       2
#define II_LV_L_ST      3
#define II_LV_L_LEN     4
#define II_LV_L_DIR     5
#define II_LV_CV        6

#define II_CY_PRESET    0
#define II_CY_RESET     1
#define II_CY_POS       2
#define II_CY_REV       3
#define II_CY_CV        4

#define JF_TR       1
#define JF_RMODE    2
#define JF_RUN      3
#define JF_SHIFT    4
#define JF_VTR      5
#define JF_MODE     6
#define JF_TICK     7
#define JF_VOX      8
#define JF_NOTE     9
#define JF_GOD      10
#define JF_TUNE     11
#define JF_QT       12

#define WS_REC  1
#define WS_PLAY 2
#define WS_LOOP 3
#define WS_CUE  4

This is what I have in my TT branch:

#define WS_ADDR     0xF1
#define WS_REC      1
#define WS_PLAY     2
#define WS_LOOP     3
#define WS_CUE      4

I remember talking at length with @tehn about why the address 0xF0 for JF ever worked in the first place. In my header for the ii implementation in JF i use #define II_ADDRESS (0xF0 << 1), which admittedly doesn’t make sense. I wonder if JF will already respond to a 0x70 address?

I was of the understanding that the avr32 library put the address in the 7MSBs hence the LSB would always be zero. But then we assigned W/ to 0xF1 and it works as expected, so I’d guess the MSB is being thrown away and we’ve had these collisions already without realizing.

Regarding W/ I had spoken to @tehn about reserving 0xF1 through 0xF4 for future expansion. I don’t have any clear design goals to use them yet, but wanted to keep that option open.

1 Like

my theory about the JF address:

libavr32 specifies it as 0xF0 which is 1111 0000. ASF only uses 7LSB, so the address becomes 111 0000. when it’s transmitted over the wire it’ll take that and append the R/W bit, 0 for W, so the first byte in the transmission will be 1110 0000. which is 0xF0 << 1. so my guess is if we change it on the TT side it shouldn’t require any changes on the JF side. i can test this scenario.

if we apply this theory to W/ then we have:

11110001 - address specified in ii.h
1110001 - address used by ASF
11100010 - the first byte (0xE2)

do you have it defined as 0xF1 << 1 in W/? because then it matches (0xF1 << 1 == 0xE2).

added W/ to the list!

i’ve tested both JF and ER-301 with the corrected address (clearing the MSB) and both worked, so i think it’s safe to change all the addresses to the new scheme.


As an engineer myself, this thread makes me quite gleeful… even if it isn’t my project.

Love the collaboration. Keep it up :slight_smile:

1 Like

First off, major thanks to @scanner_darkly for spearheading this. Super-necessary as things are getting confusing with the growth of devices on the bus. So great. :slight_smile:

I’ve taken a look at the proposed i2c file revisions and noted the following things:

  • We need to add in the range for the TELEX modules (0x60-0x6F).

  • Fix the conflict with the 16n (FADER) - the proposed address (0x60) is the same as the first TXo.

  • Fix the conflict with the ER-301 (colliding with Meadowphysics)

  • Add in the (tentative) addresses for a Tetrapad integration

How about these changes/additions?

// ER-301
#define ER301_1 0x31
#define ER301_2 0x32
#define ER301_3 0x33

// 16n
#define FADER 0x34

// Tetrapad (in-development)
#define TP_1 0x35
#define TP_2 0x36
#define TP_3 0x37

#define TO 0x60
#define TO_0 0x60
#define TO_1 0x61
#define TO_2 0x62
#define TO_3 0x63
#define TO_4 0x64
#define TO_5 0x65
#define TO_6 0x66
#define TO_7 0x67

#define TI 0x68
#define TI_0 0x68
#define TI_1 0x69
#define TI_2 0x6A
#define TI_3 0x6B
#define TI_4 0x6C
#define TI_5 0x6D
#define TI_6 0x6E
#define TI_7 0x6F

Thanks again!! :slight_smile:


for er-301 i’m thinking it might be just easier to update meadowphysics (or just leave them be).

will include your changes! (i’ll expand the const names as shorter names might conflict with some existing defines).

1 Like

Seems to me ER301 would be much easier to change as the module is still actively being developed.
Does anyone here know if OD is shipping i2c support in current modules? Looks like they’re sold out currently, but unclear if any units have even shipped with support yet (hence a much easier platform to update).

1 Like

i was considering it in terms of communications required and potential confusion - it’d be easier to offer new versions of mp and tt at the same time than coordinating er-301 and teletype (or answering questions on why a particular version of er-301 doesn’t work with a particular version of tt). although since it’s all pretty new and we don’t even have an official tt release that supports er-301 maybe it’s not so bad (and there is a workaround since we already support 3 addresses for er-301). i’m good either way.

1 Like

here is the proposal on universal (global) commands: Universal ops

i was also thinking of adding a feature to teletype where it would query all possible addresses and display the list of all the i2c devices that are currently connected. perhaps a shortcut in live screen? this would be super useful when you move modules around and want to make sure all your i2c connections are okay.


I agree. ER is still an active beta and the users are used to periodically updating the OS via SD card. No need to force an update on Meadowphysics. :slight_smile:

would you be able to coordinate er-301 update with brian? at this point i think i’ll just do one final beta which will have the new address, but can’t really say when it’ll be ready. worst case scenario i can create another beta for people who update their er-301.

Sure - I’ll coordinate with Brian at Orthogonal. Let’s also coordinate on that beta as some things will need to change on the TT side to use any renamed defines.

1 Like

do you mean faderbank? yeah we’ll need to figure out the sequence of updates.

edit: i think the best way to handle it would be to include the faderbank change in my currently open PR, merge that, i’ll update my tt branch to point to that, and then do a new PR for the er-301 change.

1 Like

faderbank and ER-301 code would be trivially affected.

i’ve added your changes to my PR, can you take a look when you get a chance? (once it’s merged i’ll do a PR for the er-301 change).

Hi, sorry just a quick question about TT and Ansible via i2c … the first post mentions “ansible / midi”: Is it actually possible to send midi from Teletype via Ansible or is it only Midi to Teletype via Ansible ? Thanks.

it’s to control some midi and arp parameters on ansible in midi mode from teletype. you can see available teletype ops here:

1 Like

Ok, I see, thanks for your reply! maybe not I’m looking for but I will read the manual of Ansible :wink: