We've got our basic requirements for the BASPLC project: Build a PLC with a set of interface modules, and base the whole thing on some low-cost MCUs. Rather than do this with a big requirements analysis up front, we'll get to more specific requirements as various topics come up.
There are a couple of places we can start with our architecture. The prototypic PLC archiecture is a controller connected to interface modules via some kind of bus. We're going to maintain that architecture, so one of the decisions we have to make is what that interconnecting bus is going to look like. Another decision is if we're going to have a consistent architecture inside the processor and/or interface modules.
Let's tackle the second task first. We could build each unit as a unique circuit, but that ignores the fact that there are common aspects. Each unit, whether a processor or interface module, needs a "front panel." Something that can indicate to an operator the state of the unit and possibly take some input. The processor in particular needs at least a run/stop switch. Interface modules that do discrete I/O (as in, input or output with binary state) usually show the state of those inputs or outputs. An 8-point module (8 discrete inputs or outputs) may have an array of 8 indicators, plus one to show a fault. Given the similarities, a common piece of hardware seems reasonable.
How the unit communicates with the bus is another area where each unit is going to have the same (or very similar) hardware. Separating that out into its own board makes sense. It makes even more sense because we have a number of options for how the bus will work and it would be nice to be able to change it around without having to redesign the whole unit.
This gives us three components per unit, whether it's a processor or interface module. The front panel, the bus communcations and the core component -- this is the component that makes one unit a processor and another unit a 16-point 5V DC discrete output module or a 4-way 12V DC motor driver.
Of course, we need a standard way of connecting these components. Two of the most common protocols used in the microcontroller world are SPI and I2C. We're going to go with SPI for a number of reasons: First, many of the chips we hope to use have built-in SPI support. SPI is also a protocol commonly used to program MCUs (In Circuit Serial Programming/ICSP.) To save on pins (a precious resource with MCUs), we can make the SPI interface do double duty as both a programming interface as well as communication between components. There are even standard connector formats for ICSP, so we can coopt those. There are even provisions to repurpose some of the ICSP pins, since we may need some more function than what that interface provides. (Without giving the game away too early, we will need those repurposed pins.) We'll call this the BASB.
Since not every chip we want to use supports SPI, we're going to put a separate MCU on each of the component boards. Another reason for doing this is so that we can offload some of the processing from the core component.
Choosing an internal archutecture for the units was pretty easy. We could have debated the advantages/disadvantages of SPI over I2C and some other details, but I think the overall architecture is pretty non-controversial. Choosing a bus architecture for communicating between the processor and interface modules is going to be a bit harder.
There are dozens, if not hundreds, of busses that might server our needs. There are different topologies such as star, ring, daisy chain and hierarchical. We could use serial or parallel busses. It's overwhelming! To get us started, here are some criteria that we can use:
- Moderate speed: We won't be moving a lot of data between the processor and modules, only a few hundred bytes at a time. Actual data rate depends on the data size in relation to the scan rate of the processor. Calculating the scan time is a bit tough since it depends on the complexity of the ladder program. I've seen some numbers in the neighborhood of 20-40ms for a moderately complex program on a commercial processor. Let's say 512 bytes transferred per scan with a scan time of 40ms. That gives us about 12.8K bytes per second or about 100K bits/second. Not something that's going to strain almost any of our possible choices.
- Electrical simplicity: If it takes more than a couple of resistors and capacitors to connect to the bus, I'm not interested. As I've said before, analog circuits drive me up the wall. A big bonus if there are off-the-shelf chips that can be used to drive whatever bus we pick.
- Expandability: We want an architecture where we can add interface modules easily. We don't want an architecture where we have to build a lot of capacity in that might not be used. One connector on the processor per (potential) module is going to waste a lot of space, or leave us limited. "Sorry, that's only an 8 module processor, if you want to go to 9 you have to get the 16 module version and waste the other 7 connectors." A maximum of 128 or 256 modules shouldn't be a problem, but a max of 8 could be.
- Reliable over moderate distances: One of the applications I've been thinking of is controlling a model train. A very large layout may be up to a hundred feet across (we're talking about club layouts), so we'd like to be able to have the bus work across that kind of distance.
- Inexpensive: This is a hobby project, for goodness sake! If we need interface chips or connectors that cost $$ it defeats some of our basic goals.
- Addressing: Each of the interface modules must be able to be statically identified. Purely dynamic addresses mean that we couldn't be sure we were turning on a motor and not opening a valve.
Let's start by eliminating the parallel busses. Lots of wires mean bigger cables and connectors, as well as more complex drivers. There are plenty of serial busses that are close to what we want, so why add the complexity of a parallel bus?
Let's drop star and ring topologies off as well. Ring topologies are rare these days and have fairly complex electrical and protocol requirements. A star topology breaks requirement #3 above. We have to have as many connectors on the processor as we might need in the future.
Busses can be peer (everybody equal) or master-slave. A peer bus can easily emulate master-slave, but it's harder the other way around. The master ends up having to arbitrate so that the other nodes can pretend that they're all the same. Fortunately for us, we've got a master-slave application, so we don't really care which kind of bus we have.
I'm going to arbitrarily limit the busses we look at, or this post would be 100,000 words long! We'll look at USB, RS-485, Ethernet, SPI, I2C and CAN.
USB is the only one of these that's explicitly hierarchical, although Ethernet can be hierarchical if you use something like IP as the network layer. USB is very popular and there's a lot of relatively cheap hardware available. Addressing is dynamic, so we'd have to add a static address and maintain a mapping in the comm component. Another, bigger downside is the USB Vendor ID and Product ID. These must be registered with USB.org or obtained through another vendor. Here's a document describing the options for using one vendor's chips. We could cheat and make up our own since these devices will only be used in a very specific setting, but being non-standard makes me nervous. USB also requires extra hardware if we want to support more than one interface module. Hubs are cheap, but add complexity.
RS-485 is a multi-drop descendant of the old RS-232 serial protocol. It's designed to go over fairly long distances. The down sides are that it requires specific cabling, including terminators. Looking at some example circuits, there's more required than a couple of resistors and capacitors to drive the interface. Finally, there's no software protocol at all. We could use IP or the CAN bus protocol. The standard DB9 connectors are also somewhat expensive.
Ethernet is everywhere! Lots of hardware and most of it is relatively cheap. Ethernet itself is a point-to-point protocol, so we need either a hub or a switch (and support IP) to handle multiple devices. I found a TCP/IP-on-a-chip, so this is certainly attractive. Like USB, there are issues with registering hardware signatures (MAC addresses) if you're not a registered vendor. There's also a lot of configuration that has to be done: MAC address, gateway IP, subnet mask and unit IP.
SPI and I2C are both intended for inter-chip communications. A search of the 'net found people who have gotten these to work over longer distances, but getting the electrical stuff right seems to be a challenge. In addition, SPI requires a separate selection line for each device; we could encode the address but that still means 7 or 8 wires just for addressing. I think we'll leave these off our list.
CAN bus was designed for use in vehicles. It's found use in industrial applications, so it's not inappropriate for our use on that basis. It's a peer network, but lacks an addressing scheme. Overlaying an address onto the 11- or 29-bit message identifier should work. The standard, though, uses DB9 type connectors with the associated expense and size issues. In order to daisy-chain units, each would require two connectors. CAN bus is the technology behind DeviceNet and CANopen, both of which are higher-level protocols used in automation and embedded systems. DeviceNet is a feature of many PLC implementations.
Hmmm... nothing definitive above that screams "use this bus!" Darn! I guess we'll pick one that seems interesting and see what happens in prototyping. This, by the way, is a really powerful reason to separate the communications into its own component. If we don't like how it works, we don't have to redo an entire processor or interface module.
So, our first candidate for prototyping is... CAN bus. It's a bit on the slow side for us (max 1Mbs), but looks interesting to play with. We may work around the expensive connector/cabling issue by cheating a bit. CAN bus should work just fine over an Ethernet-like cable.