I use the ICS511 as a clock multiplier. using that inside its own PLL loop you could divide instead of multiply. But thats a bit complicated.
In your case, you could use an HEF4060. It will divide the clock to whatever you need. Sometimes, I just use simple 74HC74 ICs in series, and taps off of that for each clock speed. I dont know if you can get a programmable divider. But I do know the ICS511 is a programmable multiplier.
As far as ethernet, You could use the arduino Wiznet module/IC? But I dont know if it will allow anything outside its built-in stacks though. But eh...
You should definitely set one up bbraun! I need to find a convenient way to share the code. How about mac68k.info SVN? Can we get a repository set up for the code? I can also share a list of connections I've made and parts I'm using. I think the board I'm using may be discontinued, which probably means I should be switching to a board that's still in production (and has ethernet). I got this one for free from Newark, so that's why I've been using it.
techknight: thanks for the tips about clock dividers/PLLs! Those look very interesting. I'll definitely take a look in the future. I was just curious what was out there...
The options I basically have at this point are:
1) Just use the LPC1114's UART at a fast baud rate (3 Mbps) with some simple framing to send/receive packets to/from a Linux device that handles the Ethernet side of things, which I find pretty interesting and probably feasible.
2) Switch to something like an LPC1769 that can do Ethernet. Probably more challenging, but fun, and may be necessary anyway because the board I'm using is out of production. Would still be compatible with option #1.
3) Some sort of Ethernet SPI controller like techknight suggested
I'm not really sure yet. The LPC1769 would give me up to a 120 MHz system clock instead of 48 MHz and more RAM. Breadboarding Ethernet is probably a challenge. The Linux idea would probably rapidly get something working and be easier to debug. The SPI controller idea is interesting, but I'd probably prefer something native especially since the LPC1114 doesn't have a DMA controller.
BTW, I did some packet sniffing with tcpdump. Looks like the RTS/CTS thing is specific to LLAP, which makes sense given the fact that Ethernet has its own collision detection methods and meeting the timing requirements for the handshake would have been impossible with Ethernet involved. So the handshaking will have to be emulated for packets headed between Ethernet and LocalTalk.
I should totally get my sniffer to create files that Wireshark can read...
whatever you decide to do, the localtalk to ethernet needs to be self contained. the 3Mbps datapump kinda kills that, however this might work ok for experimenting and reverse engineering. I wonder if the larger ARM, or a beaglebone/RPI processor could handle it all?
Anyone with a forum account should be able to access it with their forum credentials.
As for the device and approach to take, it seems up to you. Personally, it seems like a simple localtalk to ethertalk bridge is the lowest value proposition, although the simplest and easiest for people to understand.
Personally, with localtalk capable hardware, I'm interested in something a little more robust. By connecting it to an rpi or full on computer, possibilities are unlimited. You could have a simple localtalk to ethertalk bridge, but you can also have a local (portable!) fileserver to expand limited local storage, and it can bridge foreign protocols to be presented as an AppleShare, and do all kinds of macip proxying. For example, the rpi could transparently bridge you onto the avpn network. Or bridge a web forum to appear as an AppleShare. Or become an SSL proxy, since a lot of the older software either doesn't handle SSL, or can only handle MD5 signed SSL certificates which are now obsolete.
It plugs in nicely to a breadboard and appears to be about the same size as the board I'm using. It costs about $30 on Digi-Key. I do plan on eventually making my own PCB, but not until I have some more things proven on the breadboard.
techknight: I'm not sure if I understand what you mean by it having to be self-contained. It seems to me like the microcontroller just has to do the tough task of keeping timings on LocalTalk and the SCC and from then on, it's just a matter of getting the data in/out quickly enough to something else, whether that something else is a built-in Ethernet controller or a separate Linux device hooked up through some sort of high-speed interface.
My initial thought is: when the final board is designed, why not leave room for both? If you populate the Ethernet components on the board, it can be standalone. If you leave those components off, you can use it in tandem with something else. The firmware you put on it would determine the difference. Maybe it could even be in the correct form factor to be a cape that can plug into a BBB or something similar that can drop on top of a RPi. I don't know how tough it would be to leave room for both possibilities, but it seems like it should be possible.
I wasn't even close to thinking of some of the cool ideas you have for that bbraun. Pretty amazing. I can't wait to see if we can turn them into reality.
Edit: The code is uploaded now. I cleaned it up a little bit. The delay code is pretty ugly, need to find a reliable and easy to use method for delays.
OK. I've switched to the LPC1769 board. I'm running it at the max clock rate of 120 MHz. It should have plenty of processing power for whatever we want to do with it now. New projects default to running the chip at 100 MHz, which essentially makes it act as an LPC1768. I had to change the clock rate to get something that could do the 3 MHz UART bit rate, so I figured why not go for the max? I rearranged my breadboard to accommodate the LPC1769 board's pinout and I'm pretty happy with what I have now:
I was still able to maintain P2.0 to P2.7 going to the SCC's data pins, which was a nice bonus for making the software easier to write. I think the new breadboard arrangement is cleaner too. I tried to pick pins that were all on the same side of the board, which was not possible to do on the last board while still maintaining 8 consecutive GPIO register bits.
It would probably be wise to switch to some sort of interrupt-based handling so that the processor isn't stuck in a loop constantly polling the SCC when nothing's happening. We'll see.
I have deleted the old LPC11xx projects and added new projects to the repository for the LPCxpresso. BTW, I'd highly recommend installing Subclipse in LPCxpresso. It gives you SVN integration directly inside of the IDE and works well for sharing and checking out projects, along with automatically making sure source files you create are added to the repository. I installed the 1.8 release inside of Eclipse. I checked everything except for Subclipse Integration for Mylyn 3.x (Optional).
I had some fun troubles with this board today. When I was initially tacking the headers onto the board prior to doing real soldering on each pin, I failed to realize there were some tiny surface mount components near the headers. This board is a lot more complex than the LPC1114 board, I'm guessing partly because it has an Ethernet PHY on it. After I was done, I noticed that one of the components was missing (right under the R31 silkscreen text). Sure enough, I accidentally removed it. I wasn't even trying to be careful. Luckily there's a schematic. Unfortunately every resistor and capacitor is not labeled, but I was able to figure out which resistor I accidentally took out. It was a 12k resistor. bbraun has a board and he was able to double check to make sure it's really 12k. For some reason I decided to buy a big kit of resistors from SparkFun last week, and both of the pads go out to through hole pins, so I was able to replace it with a 10k resistor in series with a 2.2k resistor. I got super lucky on that one! There's also another missing component by the U9 silkscreen text, but that one's supposed to be unpopulated.
PCLK is connected to 8 MHz oscillator output
RTxCA is connected to 3.6864 MHz oscillator output
D0-D7 are connected to P2.0 through P2.7
CE is connected to P0.4
RD is connected to P0.5
WR is connected to P2.8
A/B is hardwired to 5V for channel A
D/C is connected to P2.10 <-- this pin is special and not wise to use as an input, because if it's low on boot, the LPC1769 will enter its on-chip bootloader and not run your program. Using it as an output is safe.
RxDA is connected to an RS-485 transceiver's "R" pin
INTACK is hardwired to +5V, we may want to change this when we do interrupt-based stuff.
+5V is connected to an external 5V power supply I have
GND is connected to GND
I'm using TI SN75176BP transceivers. Their RE and DE pins are hooked to ground to put it in receive mode. Its "A" pin is hooked to the TxD+ pin on my breakout board and its "B" pin is hooked to the TxD- pin. The whole A/B naming convention is weird because in other places it's backwards. On these transceivers, though, A is + and B is -. At least it works that way...haven't tried it backwards.
The LPC's P0.2 pin (configured for UART0 TX in the software) is connected to my USB to 3.3V TTL serial adapter's RX pin. When the other direction is working, P0.3 will be used for RX.
It's been two and a half months since I looked at this, but I haven't forgotten. I've had a lot going on. No guarantees on how much time I'll be able to spend on this project, but I've made a little more progress.
I read some of the relevant chapters of Inside AppleTalk. I'm starting to understand LLAP and ELAP, as well as a little bit of DDP, which is the next layer up that they both have in common. I'm still unsure of exactly how much router capability I have to implement in order to make it work. bbraun and I were talking on IRC today about it and we both doubt that the EtherWave Printer Adapter did much, if any, routing. Still, I wanted to see what's going on. I did some traffic sniffing between my IIci and Mac mini (with the EtherWave in between). For now, I'm only sniffing packets that go from the IIci to the EtherWave. The Mac mini is running Linux with netatalk.
The IIci is sending extended-form DDP headers, which are only necessary if the IIci is aware that it's talking to something outside of its own LocalTalk network. When I parse the extended-form DDP headers, I see that the IIci's address is network 0xFEFF, node 0x01. The Mac mini's address is network 0xFF00, node 0x56. The node IDs I don't care about because there are algorithms that determine them either from past history or randomness, but I'm a little confused about where the network numbers came from. The Mac mini's network number makes sense -- 0xFF00 is the first of a range of network numbers (up to 0xFFFE) that are automatically chosen when a router is unavailable. What I can't figure out is how the IIci decided that its network number should be 0xFEFF. It makes me suspicious that the EtherWave was involved in that choice, but I don't know for sure. The other thing I can't figure out is that LLAP requires that a node sends out an RTS, receives a CTS from the destination node, and then sends an actual data message. The IIci (node ID 0x01) sends an RTS to node ID 0x81, and the EtherWave responds with a CTS from node ID 0x81 to node ID 0x01. I'm wondering if the EtherWave is actually being given a node ID (0x81) on the LocalTalk network and the IIci knows that it is supposed to send all packets through it. This starts sounding like the IIci knows that the EtherWave is a router. I might need to actually parse every LLAP message sent and received when the EtherWave and IIci start up in order to figure out exactly what's going on.
In the meantime, I noticed that Inside AppleTalk has some ugly sample Pascal code in the back of the book for sending and receiving frames. I'm hoping I can use the methods they describe there to get things going for transmitting, which I haven't really paid attention to until now. Before I figure out how to get that working, I decided to clean up the code a bit. I pulled out my scope and looked at my timing delays for the SCC. I tried to change the code to get as close to the actual timing requirements as possible (previously, I was delaying for way too long). I ended up turning on a debugging register in the LPC1769 which counts clock cycles (8.3 nanoseconds per cycle at 120 MHz), and I'm using that register to try to handle delays in the tens and hundreds of nanoseconds. It's not exact, especially since there's overhead in setting up the loop for using it, but it's close enough. On an AVR, you could just count the cycles and use NOPs and stuff like that. On an ARM Cortex-M3 it's more complicated because a NOP is not guaranteed to cause a delay due to pipelining. This seemed to be the most accurate method I could find, and it's good enough.
So...I'm reasonably confident that my scc_read() and scc_write() functions are working reliably and as tightly as possible. It's time to start following Apple's recommendations for working with the SCC and get some test packets transmitting. There are plenty of test packets I should be able to try sending out. Once I can get sending working, it's a matter of figuring out how much AppleTalk junk has to be implemented before it actually bridges between LLAP and ELAP. I hope it doesn't take another 2.5 months to get any more progress, but we'll see.
OK, summarizing what I believe is going on. I'm going to approach how the EtherWave works from two sides:
The LocalTalk Side:
When the EtherWave boots up, it obtains a server node ID on the LocalTalk network it's hooked up to (it gets 0x81 in my case). It also makes sure it doesn't have a name conflict with anything else on the network. It pretends to be a router by periodically sending out a small routing table in an RTMP packet. This routing table is only used by the LocalTalk computer that the EtherWave is hooked up to. It serves two purposes: 1) it tells the computer that its tiny LocalTalk network's ID is 0xFEFF. 2) It tells the computer that networks 0xFF00-0xFFFE can be accessed through the EtherWave (node 0x81).
Without the EtherWave posing as a router, I don't think the computer hooked up to it on the LocalTalk port would have any idea how to respond to a received packet that came from networks 0xFF00-0xFFFE, which are the network IDs that are automatically used by EtherTalk devices.
The Ethernet Side:
I was starting to expect that we'd see a similar thing on the Ethernet side, but nope. There are no RTMP packets on the Ethernet side, confirming that the EtherWave is not a router. On the Ethernet side, the EtherWave grabs a node address on network 0xFF00, just as if it were another EtherTalk computer. It appears to me that it uses this EtherTalk node address to spoof anything on the LocalTalk side so that it appears as if it was coming from this EtherTalk address.
So for example, my LocalTalk IIci's address is network 0xFEFF, node 1. My EtherWave's address is network 0xFF00, node 93. As far as I can tell, all other EtherTalk devices think that my IIci is an EtherTalk device with the address "network 0xFF00, node 93". It has no idea that it is actually a LocalTalk device. The EtherWave spoofs the addresses when communication goes in and out of the LocalTalk side. Nothing on the Ethernet network is even aware that the network 0xFEFF exists. Each EtherWave Printer Adapter makes a little mini 0xFEFF network that is only visible to itself and the computer/printer it's connected to.
It's actually pretty genius, and it makes a lot of sense. It makes me feel a lot more comfortable about the feasibility of this project. I don't think this is going to be difficult to implement at all. You just have to step into the DDP layer and spoof addresses--not sure if any other layers will contain addresses--if they do, they may need to be spoofed too. The main drawback of this method is that every individual LocalTalk device must have a separate adapter. You can't hook multiple LocalTalk devices to a single EtherWave Printer Adapter because the address spoofing isn't that smart. In order to do that, I think you would need to implement a real router. But that would be complicated and is probably beyond the initial scope of this project.
Got my test program working for receiving with code based on the sample code from Inside AppleTalk. The new code seems more reliable than what I was doing before. It was pretty tough to get this new code working, though. I was running into this really weird problem. The SYNC/HUNT bit (bit 4) of the SCC's read register 0 is supposed to be able to tell me whether another device on the bus is transmitting. Unfortunately the bit was stuck at the value 0, which means that it always thinks there is another device transmitting. I found some comments in the MESS source code that showed how Apple initializes the SCC. I was basically doing the same thing in a different order, but Apple's initialization sequence worked and mine didn't. It had me puzzled. Turns out I wasn't initializing WR15, which defaults to having some interrupt-related options turned on. Now that I explicitly turn everything off in WR15, it's working fine. I went ahead and changed my code to use Apple's initialization sequence to be safe.
I wouldn't consider it normal for a chip to default to turning some interrupts on...just one of those peculiarities.
The code is starting to look nice, and now I need to implement transmitting. This is starting to get fun!
LLAP is now pretty much completely working, aside from automatic address reconfiguration if you try to use a node ID already in use. But I don't really care about that right now, that's just a boring edge case that will probably never even matter for this project. I do want to implement it eventually, but not now.
I'm testing the whole thing by sending an AppleTalk Echo Protocol (AEP) packet to my IIci and printing out the response I get. The API looks like this:
I think this API should be a breeze to use. It automatically handles all the RTS/CTS stuff and just lets you deal with sending/receiving LLAP data frames. As I said before, most of what I implemented is just using the sample algorithms provided in Inside AppleTalk. It does take over the entire microcontroller main loop whenever it's sending or receiving an LLAP frame, so hopefully anything I do ethernet-wise on the same processor can be interrupt-driven and hold off for the few milliseconds it takes for an LLAP frame to be sent/received. Either that or the LLAP algorithm can be rewritten to work asynchronously or with interrupts or something. Dunno.
Anyway, here's a glimpse at what it looks like on the scope after I send a frame like I showed above:
Yellow is me, cyan is the IIci. From left to right:
1) RTS from me
2) CTS from IIci
3) AppleTalk Echo Protocol request from me
llap_check() is called many times, and finally finds something...
4) RTS from IIci
5) CTS from me
6) AppleTalk Echo Protocol reply from IIci
llap_receive() returns the received packet that was polled in during llap_check()
The only real problem I'm seeing so far is that I am starting to transmit before the IIci has finished its abort sequence of all 1s, as can be seen in the two close-ups below:
There might be a status register I can poll in the SCC (possibly break/abort bit of RR0?) to make sure that the other side is completely finished. It's working fine as-is, but I'd prefer to get rid of the overlap.
At this point it should be very possible and very easy to modify the code to send/receive frames on the UART and get fancier things working on a BeagleBone or Raspberry Pi. I may or may not start experimenting with the LPC1769's internal ethernet controller next, but it may be a while before I touch that.
They're going to know a little bit about the underlying Netatalk code. I don't think they'll be of too much use on the hardware end, but at least they might be able to help out on the software sector.
EDIT: Braindump: Wouldn't it be easier to use a Raspberry Pi? You'd have to fake RS422 traffic going out through ... I'm going to say two but four or better yet, five (to use the GPi pin for overclocking) one of the GP I/O pins, but there's some of those on a R-Pi board.
Thanks for the suggestions! I actually have a pretty good idea of what's going on now, thanks to Inside AppleTalk and Wireshark. I'm essentially to the point where I need to figure out a few things on the Ethernet side and then I should be able to throw something together running on Ubuntu.
For now, a Raspberry Pi or BeagleBone Black is precisely the plan. It should be possible to wire the LPC1769's UART to a UART on the RPi/BBB, and then run a Linux program on it that sends/receives EtherTalk frames, and sends/receives data over the UART to instruct the LPC1769 to send/receive LLAP frames. It's essentially ready for software. The LPC1769 also has a built-in Ethernet controller, but I'd definitely want to get things running through a RPi or BBB first before attempting anything like that.
I don't think it would be easier to use a RPi/BBB by itself. Since they're running Linux, you don't get guaranteed real-time performance, at least not without patches to the kernel. It could result in lost bytes when communicating with the SCC. If you wanted to skip the SCC altogether, it would be even more difficult to bit-bang LLAP manually. It might be possible to meet the time constraints for talking to the SCC with in-kernel code, but honestly this project is a good application of using a microcontroller to ensure time constraints are being met. It is probably possible to emulate the SCC with bit-banging in the LPC1769, but difficult. I doubt I'll be attempting that...
The faster clocking will take software modifications on the Mac side. I probably won't be touching that part of the project unless someone makes a driver. But I definitely think it will be possible to make it do MacIP.