• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

TashTalk: Single-Chip LocalTalk Interface

mactjaap

Well-known member
Hi Andrew,

I did see you question about the tashtalk setup. Unfortunately I have two problems

One: my RPi seems to be broken. Two. I dismantled my setup. I was cleaning up my hobby office….

So I hope someone else can help you for now!
 

tashtari

PIC Whisperer
This is sort of a non-announcement since there's no binary change from the 20210914 release, but I'm sufficiently satisfied with the positive reports from AirTalk users to release a v1.0.0 of TashTalk:


I'm contemplating making a breaking change (which will be released as v2.0.0) to mux the LocalTalk in and out pins onto the same pin (RA5), freeing up RA3 to act as !MCLR, which is the PIC's reset pin. Tying this pin high will see the chip acting the same as before, but pulling it low will hold the chip in reset and tristate all its pins, allowing for TashTalk to share its RS422 transceiver with other circuitry. @bdurbrow was interested in such a change a while back, but I was at the time contemplating implementing it with another serial command, a solution that I didn't like as much because it added too many states to the firmware and increased the chances of getting the chip into a bad state. With a hard reset pin, though, you can't miss - plus it gives another way to force the chip to a known-good state.

...We'll just have to see whether I understand my own code well enough to pull this off. =)
 

tashtari

PIC Whisperer
Aaaaand no sooner mentioned than managed! It even worked on the first try.

I guess I go forward, as I said, with putting this on track to be released as v2.0.0, but of course it's incompatible with v1.0.0 and designs that use v1.0.0 (@cheesestraws 's AirTalk and @bdurbrow 's TashTalkHat).

It'd be neat to come up with a new RPi hat that only uses one transceiver (I used the SN65HVD08). It could be pretty slim considering it mainly needs two ICs and a mini-DIN connector. I might take a crack at this myself, but as with most circuit-based things, I'd be much more comfortable working with someone else... any volunteers?
 

tashtari

PIC Whisperer
1676043170706.png
My test setup. I love these little mini-breadboards... like circuit McNuggets.

Rather than use separate drivers/receivers like before, I have RxD+/TxD+ and RxD-/TxD- shorted together on the PhoneNet dongle and it seems to work. I don't know exactly why it works, though... part and parcel of not being an electrical engineer, I suppose.
 

tashtari

PIC Whisperer
1677455892569.png
The hats are here! I have enough parts to put together a handful of kits, which I'll sell (at cost) for $12 each. Send me a DM if you're interested.
 

tashtari

PIC Whisperer
Aaaaand they've all been snapped up! Anyone else who's interested, be sure to contact me anyway, if there's enough interest, I'll make more.
 

Phipli

Well-known member
How come you don't use the MAX488? It has RxD+, RxD-, TxD+ and TxD-?
 
Last edited:

tashtari

PIC Whisperer
How come you don't use the MAX488? It has RxD+, RxD-, TxD+ and TxD-?
I suppose because I didn't feel like it should be necessary given that LocalTalk is just one differential pair instead of two. Of course, as long as the transceiver has an active-low receiver enable and an active-high driver enable, this should work fine too.

...And because I have an irrational love of 8-pin DIPs, that too. =)
 

Phipli

Well-known member
I suppose because I didn't feel like it should be necessary given that LocalTalk is just one differential pair instead of two. Of course, as long as the transceiver has an active-low receiver enable and an active-high driver enable, this should work fine too.

...And because I have an irrational love of 8-pin DIPs, that too. =)
They are 8 pin dips :)

It's the active-low receiver enable and active-high driver enable that are missing I guess.
Screenshot_20230211_220646_Drive.jpg
 

tashtari

PIC Whisperer
Oops, I was looking at the wrong chip. Hmm. I thought a driver enable would be necessary given that LT is a shared bus, but because it has transformers at every node, I suppose you could use a MAX488 with the 1.x firmware (since it has a separate input and output line)? Or I could produce a version of the firmware that didn't have a driver enable output at all, just an input and output line... I don't know. Is there an advantage to that?
 

Phipli

Well-known member
Oops, I was looking at the wrong chip. Hmm. I thought a driver enable would be necessary given that LT is a shared bus, but because it has transformers at every node, I suppose you could use a MAX488 with the 1.x firmware (since it has a separate input and output line)? Or I could produce a version of the firmware that didn't have a driver enable output at all, just an input and output line... I don't know. Is there an advantage to that?
Oh, I'm starting from a position of ignorance - the question was "forgive my stupidity, but I see the 488 has two pairs and you're using two single pair chips, what drove this choice?" Rather than "you should be using a 488". :)

I've been using some MAX488s but for a single device, rather than something working as a bus.
 

tashtari

PIC Whisperer
Ohh, I see. I was using two SN65HVD08s (single-pair chip with driver/receiver enable) in my early prototypes, but the TashTalk hat only uses one, with the TxD and RxD pins shorted together, and it works fine.
 

tashtari

PIC Whisperer
I should note here that some debugging with FinkRMT on the IRC channel has shown that the TashTalk 2 hat won't work with an Apple serial cable (not a use case for which I planned), you need to use a LocalTalk or PhoneNet dongle.
 

robin-fo

Well-known member
I should note here that some debugging with FinkRMT on the IRC channel has shown that the TashTalk 2 hat won't work with an Apple serial cable (not a use case for which I planned), you need to use a LocalTalk or PhoneNet dongle.
Thanks! That‘s why my setup didn‘t work!
 

tashtari

PIC Whisperer
Version 2.1.0 of the TashTalk firmware is out! You can get it from github here:


Nobody using TashTalk right now should feel any pressure to upgrade, as there are no bugfixes. (Knock on wood, there are no known bugs to fix...)

What this version adds is the ability to calculate and check the CRCs (a.k.a. Frame Check Sequences) of outbound and inbound frames. This may make little difference for larger embedded systems like the Raspberry Pi, which can easily handle the extra load, but for smaller scale embedded systems, the ability to outsource this function can make a significant difference in performance. The features are switchable, meaning that this version of the firmware is completely backward-compatible.

For anyone interested in what goes on under the hood, adding CRC calculation in the transmitter was relatively simple - there was enough unused space in the transmitter loop to fit the necessary code. The only trick was figuring out how to inject the calculated CRC into the data coming from the UART, but even this was accomplished without much trouble.

Fitting the CRC check into the receiver was a much bigger challenge. One of the consequences of using a UART as TashTalk's interface to its host (rather than I²C or SPI, for example) is that the firmware must be ready to receive data from the host at any time, even if it's in the middle of bitbanging LocalTalk. The PIC's UART has a FIFO but it's only two levels deep, which doesn't leave much wiggle room.

To understand what I did in the end, it is necessary to understand how TashTalk's receiver works. After receiving a clock edge, which happens every 230,400th of a second, the firmware has a limited number of cycles to get some work done before it has to start anticipating the next clock edge. It first jumps into a state machine whose function depends on whether a flag byte has been received, whether any data has been received, and whether the bit just received is a one or a zero - this does things like storing the bit into the appropriate position in the buffer and keeping track of consecutive ones so it knows when to anticipate and ignore a stuffed zero bit. Next, it jumps into a secondary function which depends on whether a byte or a flag has been completed. If a byte or a flag has been completed, the remaining time before the next clock edge is spent dealing with the consequences of that - sending the byte to the host over the UART, for example. If a byte or a flag has not been completed, the UART receiver is serviced - completed bytes are taken off the FIFO and queued for processing once the receive is finished, and the CTS signal is deasserted if the queue is more than half full, to signal to the host that it should hold off sending any more data. Thus, during normal data reception, the sequence of secondary events goes "service receiver, service receiver, service receiver, service receiver, service receiver, service receiver, service receiver, transmit byte, repeat".

This is where the opportunity to insert the CRC processing came up. The UART runs at 1 MHz, meaning that if the host is pounding it with bytes at full speed, they're coming in every 100,000th of a second (one start bit, eight data bits, one stop bit), meaning that the UART receiver needs to be serviced 100,000 times per second. Servicing it seven times per nominally-8-bit LocalTalk byte means we're servicing it 201,600 times per second (7/8ths of 230,400), roughly twice as often as we need to. What if we set things up so that we only service the receiver every other bit, and use the freed up time to check the CRC? Then we'd be servicing the receiver 115,200 times per second, which is still in excess of what it needs. Breaking the CRC logic into three independent pieces wasn't too tricky, so this is exactly what I did. The sequence of secondary events is now "service receiver, CRC part 1, service receiver, CRC part 2, service receiver, CRC part 3, service receiver, transmit byte, repeat". A given byte is factored into the CRC while the next byte is being received, with the final byte being factored in while the trailing flag is being received.

And thus was born a new feature!
 

tashtari

PIC Whisperer
Oh, I should emphasize: TashTalk 1.x and 2.x are not pin-compatible, so (if you have the capability to do so) do NOT upgrade the TashTalk on your AirTalk or bdurbrow's TashTalkHat - it will stop working.

If you have one of the TashTalk 2 RPi hats, you can upgrade but won't see any benefit from it as tashtalkd doesn't take advantage of the new CRC checking feature.
 

NJRoadfan

Well-known member
So..... I finally got a RPi. My TashTalk Hat is working with tashtalkd. I can communicate with a Powerbook 180C and Mini vMac via LToUDP. It doesn't seem to like my LaserJet 4MP's Localtalk interface though.

I can't get multitalk's bridging working at all though. Throws the below error:

Code:
ERROR   serial/tash.go:90       send failed    {"bridge": "udp", "device": "/dev/ttyAMA0", "error": "invalid packet type: $02"}
github.com/sfiera/multitalk/internal/serial.(*tt).write
        /home/user1/go/pkg/mod/github.com/sfiera/multitalk@v0.2.0/internal/serial/tash.go:90
 

mactjaap

Well-known member
So..... I finally got a RPi. My TashTalk Hat is working with tashtalkd. I can communicate with a Powerbook 180C and Mini vMac via LToUDP. It doesn't seem to like my LaserJet 4MP's Localtalk interface though.

I can't get multitalk's bridging working at all though. Throws the below error:

Code:
ERROR   serial/tash.go:90       send failed    {"bridge": "udp", "device": "/dev/ttyAMA0", "error": "invalid packet type: $02"}
github.com/sfiera/multitalk/internal/serial.(*tt).write
        /home/user1/go/pkg/mod/github.com/sfiera/multitalk@v0.2.0/internal/serial/tash.go:90
I remember it I got multitalk somehow working, but it was buggy. That is a pity because a tashtalk device with multitalk working would be great!
 
Top