• 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

tashtari

PIC Whisperer
While I've been mostly talking about this project in the IRC channel, it occurred to me that 68kmla has (or, by some definitions, is) a forum, so I thought I'd better make a thread about it to document it and see what folks think.

Introducing... TashTalk!


Elevator Pitch

It's a LocalTalk interface, contained entirely within a single Microchip PIC12F1840 (8 pins, ~$1.50) microcontroller.

It handles all the time-sensitive aspects of LocalTalk, bidirectionally bitbanging the SDLC and FM0 (a.k.a. differential Manchester) based protocol at the data link and physical layers, sending and responding to control frames with CRC calculation and checking, and collision avoidance and retransmission. It can also respond to any number/combination of node IDs for use in bridging applications. It can be interfaced directly to user-mode software on a Raspberry Pi or BeagleBone or full PC, or it can be part of a larger embedded system. It slices, it dices, etc.


Project Status

Code-complete and passing basic testing, but not yet rigorously tested. What I've seen is encouraging, but I'm not yet ready to say there aren't game-breaking bugs.


Caveats

Because of the PIC12F1840's limited memory and the way its UART is used, the host's UART needs to be able to handle a baud rate of 800 kbps. Conventional UARTs don't expect to be pushed beyond 115.2 kbps. In addition, the PIC has a 128-byte receiver queue, which is considerably smaller than the largest possible LocalTalk frame (605 bytes). As such, the host needs to respect when the CTS hardware flow control line is deasserted so the queue doesn't overflow and be quick about resuming transmission when CTS is reasserted so the queue doesn't underflow either.

Also, "single-chip" doesn't include the separate and necessary driver/receiver chip for RS-422/485. Sorry. =)


What's Next

For testing, I'm using a PIC I knocked together as a crude serial bridge that receives at 115.2 kbps and then retransmits at 800 kbps, but there are limits to how much I can do with this, so I have an FTDI breakout (https://www.sparkfun.com/products/10275) on order, with the idea that I can use it to fashion a protocol bridge of some kind on the host - either to EtherTalk frames on the host side or to LToUDP for use with minivmac. I'd like to eventually be able to build this (probably with some help) into a Raspberry Pi 'hat' board that can be used with a purpose-built image to run macipgw and netatalk 2.x, forming an accessible turnkey solution for getting one or more vintage macs on the internet as well as accessing a file server.


Code



Shoutouts to @cheesestraws and everyone else on the IRC channel (many of whose forum IDs I don't know, sorry!) who gave advice and encouragement along the way! Would love to hear from anyone interested in using this or working it into another project, referrals to relevant projects or prior art, questions, comments, well-wishes...
 

dougg3

Well-known member
That's super awesome! Nice work! So basically you've made a LocalTalk-specific SCC replacement that's way cheaper than a brand new SCC? I've been trying to find time to finish my LocalTalk bridge project that needed an MCU for talking to an SCC to handle its timing sensitive stuff (it had a ton of buffering too, like in the kilobytes range). It seems like what you've designed would be able to replace both the MCU and the SCC, as long as an RPi could keep up with the serial communication with the PIC. That's really impressive!
 

tashtari

PIC Whisperer
as long as an RPi could keep up with the serial communication with the PIC
Thanks! Yeah, the RPi's UART is definitely a known unknown. Clocking it to that kind of speed appears to be cumbersome but doable (per https://fw.hardijzer.nl/?p=138) but I think experimentation will have to tell whether the queues can all be kept filled down the line. There is reason to be hopeful, though - if I read the RPi peripherals document (https://datasheets.raspberrypi.org/bcm2835/bcm2835-peripherals.pdf) correctly, it has a 16-position transmit FIFO and CTS is handled at the hardware level, so as long as the operating system driver keeps the FIFO full at least most of the time, we should be good. Even if the RPi comes up short, my chip should be useful for offloading most of the painful stuff when paired with a bigger microcontroller.
 

mactjaap

Well-known member
LocalTalk is really my thing. Made some stuff to use TCP/IP over LocalTalk (see www.macip.net ).
So anything what would make LocalTalk possible over new hardware is really my biggest wish on vintage Mac Stuff.
If you need testers or anything...just let me know. I will be looking at this thread a lot!
 

tashtari

PIC Whisperer
As it turns out, while you do need to fiddle with config.txt some, you no longer need to recompile the kernel to achieve baud rates above 115.2 kHz on the RPi's UART; that's nice. However, available baud rates seem to be limited and 800 kHz is not one of them. The options in that neighborhood jump from 576 kHz right on up to 921.6 kHz and 1 MHz.

The chip needs to be able to put two bytes through its UART in the time it takes to receive eight LocalTalk bits (34.722 μs), which, funnily enough, works out to a baud rate of exactly 576 kHz. Trouble is, there's no margin for error. If the mac is even slightly fast and we're in a situation where there are two consecutive characters that have to be escaped, the PIC's UART has a write collision and everything goes to hell. The other trouble is that the baud rate of the PIC's UART has to be the quotient of 8 MHz (the oscillator frequency divided by four) divided by some integer, and 576 kHz is too big a number to get near with any accuracy.

On that basis, 800 kHz seemed like a good compromise, but apparently not. Next-best option is 1 MHz (921.6 kHz doesn't evenly divide into 8 MHz), so I did some cocktail-napkin math and estimated that my firmware could just about keep up with 1 MHz, and... so far, testing seems to agree! The RPi's UART appears to be behaving just as I'd hoped with regard to the CTS line, and the transmission of large frames takes place reasonably gracefully, without even having to keep the whole frame in memory. Magic!
 

tashtari

PIC Whisperer
LocalTalk is really my thing. Made some stuff to use TCP/IP over LocalTalk (see www.macip.net ).
So anything what would make LocalTalk possible over new hardware is really my biggest wish on vintage Mac Stuff.
If you need testers or anything...just let me know. I will be looking at this thread a lot!
Cool stuff! My knowledge of networking has some holes in it, but my general understanding is that with the TashTalk chip communicating with a RPi over UART, it should be possible to create a tap and write a user-mode daemon that translates frames coming in from LocalTalk into EtherTalk, as well as sending appropriate EtherTalk frames out over LocalTalk. Your MacIPpi image looks like it already does what I was thinking of when I was talking about a RPi image to support the board (once a board is made, whether by me or someone else), so with the addition of the daemon (once that is created) it'd really be a one-stop shop for anyone who wants a LocalTalk router.
 

Gorgonops

Moderator
Staff member
Conventional UARTs don't expect to be pushed beyond 115.2 kbps.

FWIW your bog-standard FIFO 16550 UARTs from 90's PCs *could* in theory support 1Mbit/plus baud rates but they're limited because the standard clock they're driven by in PC compatibles is 1.8432MHz and the minimal divisor is 16x. (1,843,200 /16 = 115,200) Old-tyme PCs never got faster crystals (This speed dates back to the 8250 in the original async serial card for IBM PC) because everyone hammered on the bare registers to set baud rates and changing it to something else would have broken register compatibility with older software.

(One arguable reason it used such a low crystal meant for speeds 600 baud and faster you only had to set one byte instead of both in the divisor latch to get a good range of "already standard" speeds. But in exchange it meant the divisor resolution was bad at the top end, meaning for instance PC serial ports can't be set up for MIDI's 31.25k data rate.)

FWIW some USB to serial devices support baud rates up to 12Mhz so slapping one of those on the south side might be an interesting possibility.
 

dougg3

Well-known member
Cool that 921600 worked! The solution that I’ve been (slowly) working on actually creates an “lt0” LocalTalk network interface in Linux, so it automagically works with netatalk and stays in the kernel. There are ways to add an in-kernel device on top of a UART in Linux. I was originally doing a TTY line discipline, but I think there are other newer approaches now that you can activate with device tree. However, I can also see a lot of advantages to a userspace solution. The in-kernel Linux AppleTalk/LocalTalk stack is pretty buggy…
 

aperezbios

Well-known member
On that basis, 800 kHz seemed like a good compromise, but apparently not. Next-best option is 1 MHz (921.6 kHz doesn't evenly divide into 8 MHz), so I did some cocktail-napkin math and estimated that my firmware could just about keep up with 1 MHz, and... so far, testing seems to agree! The RPi's UART appears to be behaving just as I'd hoped with regard to the CTS line, and the transmission of large frames takes place reasonably gracefully, without even having to keep the whole frame in memory. Magic!
Awesome, congrats on the progress so far. This is really neat.
 

Scott Squires

Well-known member
Been enjoying hearing about this in IRC. Tashtari is a PIC assembly wizard.

My default UART speed has been 2Mbps for at least a decade... even the most pitiful micros can do this. Get with the program, rpi! :ROFLMAO:
 

aperezbios

Well-known member
@tashtari which RPi model and UART are yo using? I ask because:

The baud rate scaling is the same issue as seen on RPI 3 and 3B+ - namely that the UART used on the GPIO pins gets its clock from the system bus clock which changes depending on system load.

If you absolutely need to use GPIO 14&15 and if you don't use bluetooth devices, then add "dtoverlay=pi3-disable-bt" to config.txt which will automatically swap the UART to the PL011. If you do need to use bluetooth devices, then add "core_freq_min=500" to config.txt to prevent core frequency scaling (but will result in increased idle power consumption).

If you can shift which GPIO pins you use, then there are many more UARTs on Pi4 - see
https://github.com/raspberrypi/linux/bl ... ADME#L2367
 

tashtari

PIC Whisperer
which RPi model and UART are yo using?
I'm currently using an RPi 3 model B, and I'm using the PL011 UART, not the "mini UART" that's tied to the system clock - it's necessary because the "mini UART" doesn't support the hardware flow control that I require. It's my understanding that the RPi 3 by default gives the PL011 UART to the bluetooth device, but there's a device tree overlay that switches it around. It's called something different in the current version of Raspberry Pi OS (née Raspbian), though I can't remember what offhand. The UART situation on RPi boards is all rather confusing...
 

tashtari

PIC Whisperer
Cool that 921600 worked! The solution that I’ve been (slowly) working on actually creates an “lt0” LocalTalk network interface in Linux, so it automagically works with netatalk and stays in the kernel. There are ways to add an in-kernel device on top of a UART in Linux. I was originally doing a TTY line discipline, but I think there are other newer approaches now that you can activate with device tree. However, I can also see a lot of advantages to a userspace solution. The in-kernel Linux AppleTalk/LocalTalk stack is pretty buggy…
I'd feel (marginally) more comfortable with 921.6 kHz, but alas, the PIC won't do that because of the need to pick an integer divisor of 8 MHz, so the slowest adequate rate that both RPi and PIC can agree on is the full 1 MHz. So far so good, though...

I'm happy to have advice on how best to handle the RPi (or BeagleBone or PC or something else) side of things, as I'm not terribly well versed in the area. I was worried that the Linux kernel's AppleTalk/LocalTalk support might be suffering from bit rot; it seems like the sort of thing that is unlikely to have gotten much attention for a long time. For that reason, there's certainly appeal to doing something in userspace, but the UART interface makes a lot of different approaches possible, and I'm content with any that will work.
 

bdurbrow

Well-known member
FWIW, if I am doing the math right; the ESP8266 should be able to handle a 1Mhz baud rate exactly... I might drop one of these in to my MacESP8266+ project to handle LocalTalk frames. 🤔
 

ronan

Well-known member
Hi,

What about using a simple STM32 with DMA : you can get an infinite (well limited by RAM of course) buffer.

It would also work as a single chip thing and some have usb hardware so that you can emulate a serial port over usb and get quick transfer speed. :)

Well this is true with many other microcontrollers, just talking about stm32 because I'm more confortable with them :)
 

dougg3

Well-known member
I'd feel (marginally) more comfortable with 921.6 kHz, but alas, the PIC won't do that because of the need to pick an integer divisor of 8 MHz, so the slowest adequate rate that both RPi and PIC can agree on is the full 1 MHz. So far so good, though...

Whoops! I misread your previous message. Either way, still sounds good…

I was worried that the Linux kernel's AppleTalk/LocalTalk support might be suffering from bit rot; it seems like the sort of thing that is unlikely to have gotten much attention for a long time. For that reason, there's certainly appeal to doing something in userspace, but the UART interface makes a lot of different approaches possible, and I'm content with any that will work.

You’re absolutely right about bit rot. I don’t think too many people have been testing/using it. I recently fixed a loopback bug that’s been around for a long time with LocalTalk network interfaces due to LocalTalk having a shorter header than Ethernet. Also, there was a long period in the 5.x kernels where AppleTalk was completely broken and the module wouldn’t even load. Someone accidentally broke it in a patch for better error handling and evidently didn’t test their changes. Anyway, you make a really good point. Since it’s a UART, there’s a lot of flexibility on how it ends up being used. Very nice!
 

tashtari

PIC Whisperer
FWIW, if I am doing the math right; the ESP8266 should be able to handle a 1Mhz baud rate exactly... I might drop one of these in to my MacESP8266+ project to handle LocalTalk frames. 🤔
That'd be cool! I'd love to see this get used in other projects.
 
Top