Ex-Japanese Rolling Stock in Manila
Manila was nothing like I'd expected... I suppose I had no idea what to expect, but after hearing of kidnappings, dangerous weather and chaotic traffic, I hadn't painted the best picture. Turns out it's all crap. I mean, they've had a few blows from Mother Nature in the past, but this hasn't hampered what is a bustling and vibrant city.
Apart from shopping for cheap electronic goods, I had a goal to check out as many of their modes of transport as possible. Google helped me find the Philippine National Railways ... and this then lead me down a rabbit-warren of information. It turns out the railway has been restarted many times. It used to expand all over the country, but squatters came in each time the railway closed/suspended lines. This has now lead to difficulties reclaiming the right-of-way and resuming the services. The result, currently, is that there are a limited number of services to catch and I chose one that worked out nicely when transferring from other modes of transport.
Another reason to check out PNR was that they utilise hand-me-downs from Japan. Quoting the PNR Wikipedia Page:
Surplus sleeper coaches from Japan Railways were recently acquired by PNR, and were delivered on November 2010. More used rolling stock from Japan Railways was recently acquired by PNR, and arrived in 2011 which included some 203-series EMU, Kiha 52 and Kogane Train (Kiha 59).
Judging by Google Maps and Wikipedia's page on Rail Transport in the Philippines, I worked out a path that would allow me to ride a few of the 'light rail' systems and the PNR. This meant catching the LRT from EDSA Station to Carrieda Station and then walking to Tutuban. It turns out the area from Carriedo to Tutuban is Chinatown and therefore full of markets. From Tutuban, the PNR was traversed to end up at PNR EDSA Station. This was a 45min suburban route and allowed viewing of the real Manila. A quick walk to MRT-3 Magallanes Station then allowed a trip north to Santolan Station near Greenhills shopping center for some much needed retail therapy.
LRT-1
The Manila Light Rail Transit System - Line 1 is the first of the LRTs in Manilla and runs from Baclaran to North Avenue.
LRT-2
Walking north along Rizalo Avenue until Recto Avenue allowed the viewing of the end of LRT-2. The weather was a little temperamental and (especially at night) the high overhead railway gave the whole neighbourhood a Blade Runner feel.
I couldn't quite work out if there were plans for expansion or if the track was simply extended to allow for a turn-back.
PNR Tutuban Station
PNR EDSA Station
A quick jog to the bridge let me get a few departing photos of the service I arrived on.
PNR 203-series KIHA Rollingstock
Ex Japanese Railway stock. Towed along by a General Electic 900-Class diesel (build in GE Montreal, Canada.) I love it that they've left the pantographs on the roof.
MRT-3
Do note to be mindful of the station staff. Don't take direct photos of them and if they tell you not to take photos, do respect their wishes!
...must get back there...
Table Railway – Continued
It's been green for a while.. but I thought I might as well provide a long-overdue update. The table layout has received a fresh coating of grass and it's in quite a reasonable state after moving house. It coped with being held upright through doorways and thrown around in the back of a car... so it seems my process of painting, gluing and spraying ballast and foliage worked well.
Painting the base scenery
The last thing one needs is white plaster showing through the scenery base. It really does ruin all of your hard work very quickly. To prevent this I coated the entire base with an appropriately-coloured paint. Japan's scenery is ultra-lush, so a dark green here will work well.
Adding the grass
Adding grass to the green paint brings it to life. Texture is the key here and un-even-ness is to be achieved. Don't be scared to glue layer upon layer upon layer. I've used a glue/water ratio of around 3-10 to make sure everything sticks. It's a little thicker than you'll need for a layout that won't be thrown around as much as this one will.
Sinking and Ballasting the track
I'd done this before on my previous railway and the effect is much more realistic. Although the plastic ballast that comes with Unitrack isn't ugly, it easily removes from the realism of a layout. To get around this I've cut a trench for the track and glued ballast down the sides. Be careful not to completely cover the track with glue...
The best part? My 300 Series Shinkansen bolted round the loops at full-tilt... I really wasn't expecting it to cope. It's about time to add a city.
Yet another layout…
It was about time to fill the table I'd bought from an op-shop a long time ago. I'd attempted a layout for this prior using the Arduino and CAN Bus to control it... but I somehow lost interest and demolished it. Hence we begin with the 810mm(Squared) Table Layout Version 2.0.
The space was relatively small and, thanks to my previous attempt, I knew there wasn't going to be much more than a loop-the-loop. The whole reason for building this was to run my 300 Series Shinkasen and that meant wide curves and wide clearances. For some reason I then decided that a loop-the-loop was boring and that I could fit a loop-the-loop-the-loop in.
I set to work on Anyrail.Net and found that a triple-loop was going to be tight. Unitrack had enough different radii curves to get the loops in, but I'd have to be using the tightest available... not too good for a 7-car Shinkansen. So... I started breaking the mould and making everything not-quite-fit together in the layout software. This meant slightly wider curves but potentially dangerous track joins where I would be 'stretching' the limits of unitrack to fit. Fortunately it turns out to be pretty forgiving.
I went to a not-so-local hobby store and found they had a HUGE selection of Japanese stock. I had my list printed from Anyrail and went about collecting. I also got some Walthers gradient foam for my crazy layout.
After a little fiddling the track was laid out and temporarily elevated into place. It all worked... but was a squeeze. With nothing stuck down you'd attempt to get track to connect in one spot and it'd fall out of alignment in another... I don't really recommend jamming Unitrack together in odd formations!
The result was a successful session of test running with all of the stock I could find!
Sleeper Trains to be retired by 2015
This was sad news... Japan has a brilliant selection of sleeper trains and, although they have been phasing a lot of them out over the years, to hear that they're getting rid of the top-notch services was heart-breaking.
My experiences on sleeper trains in Japan has always been fantastic. The staff are amazing, dedicated to their work and more than happy to help out a non-fluent Japanese speaker. Currently my checklist includes the Twilight Express, Nihonkai, Kitaguni and Hokutosei, but I'm think I need to get the others ticked before they're scrapped.
So, here's the original article and here's the english version. Noteable points:
-
Reasons for the cancellation of Sleeper Trains:
- The opening of the Shinkansen from Tokyo to Sapporo
- Age of fleet (30+ years)
- Decreased patronage of Sleeper Trains (thanks to aircraft)
-
Cancellation schedule:
- Akebono by March 2014
- Hokutosei by 'Fiscal 2014' (but will continue services during Obon in August and the New Year Holiday)
- Cassiopeia by 'Fiscal 2015'
- Twilight Express by 'Fiscal 2015'
Update: To be retired Spring 2015
The Japanese Fiscal Year runs from April of said year to March 31st of the next. So 'End of Fiscal 2014' would be March 31st 2015 and 'End of Fiscal 2015' would be March 31st 2016.
Note that the Sunrise Seto and Sunrise Izumo will continue to run.
I can understand that they're scrapping the older (although very well maintained) services ... but it's astonishing that JR East is scrapping the services that have just received brand new locomotives to haul them! The EF510-500 Series locomotives were only introduced in 2010 to pull both the Casseiopeia and Hokutosei services.
Something random to check out: Here's a link to EF81-104 (one of the Twilight Express Locomotives) being chopped up. Turns out that's the one I travelled behind back in July 2009. RIP.
Pictures of the Sleeper Trains
Nihon-Kai
Twilight Express
Hokutosei
Kitaguni
Unfortunately, I've never seen the Casseiopeia in the flesh... Will need to do so before they cut that up too.
Kato Unitrack vs. Moisture/Humidity from setting plaster
It probably should've been obvious, but I've just found out the hard way of the effects of drying plaster (Woodland Scenics Plaster Cloth) and Kato Unitrack when kept in a small enclosed space.
I've been building a new layout recently in a coffee table I acquired from a secondhand store. It's around 80x80cm and fits a nice loop-the-loop-the-loop layout.
After planning and purchasing the track, I started to build up the scenery. Once the foam was down, the plaster was laid. Due to wanting to be neat, I returned the setting/drying scenery back into the table each night to dry. I noticed on the second day that the plaster hadn't really dried that much, so I chose not to run any locos (there had been a C50 steamer sitting in the table overnight too!.)
The next day I then noticed that the track had a strange tinge to it. I attempted to run the steamer, but the performance was terrible (although this was second hand and hadn't run 100% in the first place.) Another locomotive didn't do much better.
The cause was obvious on closer inspection...
(First image: notice that left track is shiny and right is dull. Second image: see mould.)
After 'phoning a friend' on the JNS Forums, a few possible options came up... the most probably one being the chemicals used in the plaster cloth. These could well have hung around inside the glass table whilst the plaster was drying and adversely affected the track.
I'm still in the process of cleaning it all up (a quick once-over with a cleaning block worked fine)... the sides of the rails are still tarnished. Currently alcohol-wipes are doing the best job of cleaning this mess up!
Misfiring AW11 4AGZE Supercharger
Just got my car back from the mechanic... he does a really good job, but I'll leave the name out of it for all intents and purposes.
Turns out I'd done too much off-roading in my poor little MR2 and had filled the engine bay with dirt/dust/grime. Mechanic took the liberty to wash it all out... looks great!
Unfortunately, it didn't run so good anymore.
Symptom
Upon acceleration, the tacho would get to 1,500rpm and then it felt like the rev-limiter kicked in. The engine would burst about 100rpm, then drop back to 1,500, then back up and down, on and off.
It felt terrible to drive... if you timed it right, you could stop accelerating at 1,459rpm then gun it and it'd jump to 2,000rpm and continue... BUT THE SUPERCHARGER LIGHT STAYED OFF.
Something had gotten into the wiring and was going haywire. Stopped the car, got a torch and checked everything. All was connected apart from a cracked up vacuum tube. Thought it was the culprit, but upon sealing the connection it was still failing.
I could see the supercharger clutch engaging when I feathered the throttle, but it would pop back out just as quick when the engine dropped revs.
So... resorted to Google and found this: http://forums.club4ag.com/zerothread?id=89527
Reading the second post, the user indicates that the TPS was causing his engine to start/fail/start/fail... same symptom as mine.
So, went back to the engine and popped off the TPS connector.
FULL OF WATER.
Solution
Dried it up and ... the MR2 is back to bat-out-of-hell status... I love my little green Supercharger light!
I'm only posting this so that other people can find this information easier.
Eizan Dentetsu (Eiden) Kyoto, Japan
Was just travelling via Google Earth and decided to check out North Kyoto. The Eizan Electric Railway runs one and two-car EMUs from Demachiyanagi Station up to either Mount Kurama or Mount Hiei. I haven't travelled up to Hiei-san yet, but I do love the trains that travel up to Kurama.
Usually google maps satellite photography is taken at random hours and doesn't capture anything interesting, but it seems this time they have captured a Kirara 900 Series about to pass an 800 Series at Ninose Station.
Just thought I'd take a snapshot and record it... it's a beautiful area of Kyoto and everyone must visit at least once!
Meanwhile... here's a few old shots of my visits there including these two EMUs.
I could go on about this railway forever .... go and visit it now.
First CAN Node: LEDs and Sensors
Despite my layout being tiny, I've decided that my layout will need two nodes. One will do the sensing of trains + management of LEDs and the other will control the throttle, points and isolation. I've now finished the building and wiring of the first node. One note for below: I've used Frame IDs to differentiate the messages across the network; unique numbers are used to define the message type and each node will have filters applied to only receive nodes that are specifically for them.
Detecting Trains
Train sensing has been implemented via light sensors. I needed 24 sensors around the track and decided that multiplexing was the only way to read them all. 3x 4051 ICs came in handy and were configured as per the schematic below. You can find a better explanation on light sensor implementation in the article here.
I've simplified the code for reading the sensors as I'll ensure all of them have sufficient lighting and therefore 'stable' values. The circuit waits a second after power-up to read the initial sensor values. It then marks each one as 'active' if the value is greater than 20 'points' above the initial value. If a reading comes in lower then the initially read value then that value is lowered accordingly. I've also created a special command (frame id: 0x333) to allow a reset of all sensor values (specifically if ambient light proves a problem.)
The node sends out the sensor values and then pauses 100ms. The CAN packet with sensor data has the frame ID 0x111 and then fills three bytes with the 24 sensors states. A '1' is used for occupied and a '0' for vacant. The message will be received by any node on the network with the appropriate filters set.
Controlling LEDs
To control the LEDs I've re-used the previous MAX7219 ICs that I had lying around. There's a much more in-depth article here on how to use this chip. The MAX7219 requires three wires to the Arduino... but I'd already used up all the digital pins. Fortunately you can use the Analog pins just as easily.
As the MAX7219 can receive bytes per row to control the LEDs I simply pass through the data from the CAN bus when appropriate. It would only take one CAN message as they contain 8 bytes of data. The Frame ID for this message is 0x222. You can see that I'm being pretty wasteful with Frame IDs but, fortunately, I don't have many specific messages to send.
Completed Sensor+LED Node
So, it was soldered and wired... quite a mess really. The CAN Controller was on-board but there was no 'direct communications' interface to the PC. This meant I had to pop the chip out (atmega328) each time I wanted to change the code... tedious and dangerous!! I managed to bend pins and confuse myself every now and then. Don't do this at home!
Controller Node
I've got a third node hooked up to the computer via my trusty old Arduino Mega. This node transmits data from the CAN Bus to the PC via the standard serial-over-USB connection. A .NET application then shows the layout and allows you to interact with the LEDs and sensors accordingly. It shows the status of the sensors at any point in time and allows you to create rules in a sequence which can determine the speed and direction of the train.
The physical design of this node is simply the Arduino Mega plus the CAN schematic as seen in my previous blog post on implementing the MCP2515 controller.
if (CAN.buffer0DataWaiting()) { CAN.readDATA_ff_0(&length,frame_data,&frame_id, &ext, &filter); Serial.write("X"); Serial.write(frame_data[0]); Serial.write(frame_data[1]); Serial.write(frame_data[2]); } while (Serial.available() >= 9) { // read the incoming byte: b = Serial.read(); if (b == 'L') { for (int i = 0; i < 8; i++) frame_data[i] = Serial.read(); frame_id = 0x222; CAN.load_ff_0(8, &frame_id, frame_data, false); } else if (b == 'D') { for (int i = 0; i < 8; i++) frame_data[i] = Serial.read(); frame_id = 0x666; CAN.load_ff_0(8, &frame_id, frame_data, false); //printBuf(frame_id, frame_data); } else if (b == 'R') { for (int i = 0; i < 8; i++) frame_data[i] = Serial.read(); frame_id = 0x333; CAN.load_ff_0(8, &frame_id, frame_data, false); } else if (b == 'P') { for (int i = 0; i < 8; i++) frame_data[i] = Serial.read(); frame_id = 0x777; CAN.load_ff_0(8, &frame_id, frame_data, false); } }
LED+Sensor Node Code
The sensor code consisted of an initial sensor read and then constant sensor checking. The sensors were then determined to be either 'occupied' or 'vacant' and then the data was sent. There are no 'smarts' here... the sensor data is simply hammered over the network.
The receive buffers are also checked for a Frame ID of 0x222 or 0x333. The filters are set appropriately to ensure that only these messages trigger the interrupts. The LED data is sent to the MAX7219 controller on the 0x222 message and the sensors are reset on 0x333.
void loop() { send_data[0] = 0; send_data[1] = 0; send_data[2] = 0; for (sens = 0; sens < 8; sens++) { setOutputBit(sens); sensor_read = readInput(0); if (sensor_read < sensor[sens]) sensor[sens] = sensor_read; send_data[0] |= (((20 + sensor[sens]) <= sensor_read) << sens); sensor_read = readInput(1); if (sensor_read < sensor[sens]) sensor[sens] = sensor_read; send_data[1] |= (((20 + sensor[sens + 8]) <= sensor_read) << sens); sensor_read = readInput(2); if (sensor_read < sensor[sens]) sensor[sens] = sensor_read; send_data[2] |= (((20 + sensor[sens + 16]) <= sensor_read) << sens); } frame_id = 0x111; CAN.load_ff_0(3, &frame_id, send_data, false); frame_data[0] = 0; data1 = CAN.buffer0DataWaiting(); data2 = CAN.buffer1DataWaiting(); if (data1 || data2) { if (data1) CAN.readDATA_ff_0(&length, frame_data, &frame_id, &ext, &filter); if (data2) CAN.readDATA_ff_1(&length, frame_data, &frame_id, &ext, &filter); if (frame_id == 0x222) { for (int i = 0; i < 8; i++) lcl.setRow(0, i, frame_data[i]); } else if (frame_id == 0x333) { for (sens = 0; sens < 8; sens++) { setOutputBit(sens); sensor[sens] = readInput(0); sensor[sens + 8] = readInput(1); sensor[sens + 16] = readInput(2); } } } delay(100); }
Controller Node Code
The controller was the middle-man for translating PC code to the CAN bus and vice-versa. Sensor data from the CAN bus was converted to serial data with a leading 'X' byte. On the contrary LED commands were received from the PC with a leading 'L' byte. The following 8 bytes were sent as a single message onto the CAN bus once this character was seen.
using System.IO.Ports; SerialPort _serialPort; private void SetupComPort() { _serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One); _serialPort.Handshake = Handshake.None; _serialPort.DataReceived += new SerialDataReceivedEventHandler(HandleData); _serialPort.Open(); } private void cb_CheckedChanged(object sender, EventArgs e) { Byte[] bytesToSend = new Byte[9]; bytesToSend[0] = (byte)'L'; for (int i = 0; i < 8; i++) { for (int z = 0; z < 8; z++) bytesToSend[i+1] |= (byte)((LEDs[(i*8) + z].Checked ? 1 : 0) << z); } _serialPort.Write(bytesToSend, 0, 9); } private void UpdateSpeed() { Byte[] bytesToSend = new Byte[9]; bytesToSend[0] = (byte)'D'; bytesToSend[1] = (byte)(direction ? 1 : 0); bytesToSend[2] = (byte)hSpeed.Value; bytesToSend[3] = (byte)points[0]; //for loop? probably should. bytesToSend[4] = (byte)points[1]; bytesToSend[5] = (byte)points[2]; bytesToSend[6] = (byte)points[3]; bytesToSend[7] = (byte)points[4]; bytesToSend[8] = (byte)points[5]; _serialPort.Write(bytesToSend, 0, 9); Console.WriteLine("Sent: D" + bytesToSend[1] + "-" + bytesToSend[2]); }
Notes learnt from hooking all this up
- CAN Filters work, but you can still see messages
On the CAN controller you can set filters to only allow specific messages through. It actually turns out that, regardless of the filter being set, if you constantly poll either buffer for a message that, if there has been a message sent, it will be available and can be received from the network. Filters simply prevent the message from triggering the 'message waiting in buffer' interrupts. So, the best bet is that you check for a message in a buffer first rather than simply constantly attempt to receive messages. Let the CAN IC tell you that a message is waiting! - You can easily spam a CAN network
Sending too many messages over the network will delay or prevent transmission of other nodes' messages. One node can send too many messages over the network preventing another from successfully getting messages into a third nodes' buffers. It's all down to how quickly the third node can receive the messages. If both receiving buffers are full then the message will fly on past and not be seen. - Inserting and removing ICs
PLEASE only do this when you need to and do this with care! Lever them out from both ends and DO NOT just use your fingers. Insert them evenly as well. It's too damn easy to destroy these delicate and expensive components.
...next will be a node to control the thottle, isolated blocks and point-servos.
Arduino + Controller Area Network (CAN)
Stolen from Wikipedia: The CAN (controller area network) bus is a vehicle bus standard designed to allow microcontrollers and devices to communicate with each other within a vehicle without a host computer. This bus standard includes it's own messaging protocol for communications between nodes on the network.
One of the most popular uses for this technology is in the automobile where the network provides a communication channel between the ECU, Transmission, airbags, braking systems, etc...
As you'll have noticed, I've recently been investigating OpenLCB which uses this technology for communications between its nodes on a model railway. The article below will show how the CAN bus can be incorporated with an Arduino to allow communications between different microcontrollers/nodes on your network.
Topography
The OpenLCB project dictates that the CAN bus implemented via their standards must not be in the form of a ring. When I initially saw the Railstars:io prototype I expected that a ring would be required; the prototype shows an 'in' and 'out' communications port. Little did I realise that, upon closer inspection, the io could act as a termination point for the CAN bus that it connects to. We therefore will implement a layout as follows on our railways...
The OpenLCB project will use standard RJ45 cables (i.e. ethernet cables) due to the requirement of twisted pair technology to guarantee data transmission.
Interfacing with the Arduino via SPI
The Serial Peripheral Interface is a communication standard used to provide communications between integrated circuits. The Arduino has an SPI library and therefore allows us to easily communicate to the CAN interface.
We'll be using the MCP2515 and MCP2551 integrated circuits to transmit/receive our data from SPI onto the CAN bus. This setup has been done before in Sparkfun's CAN-BUS Shield, the CAN-CAN, the Universal CAN Library (Universelle CAN Bibliothek) and the CANduino. The CAN-CAN Schematic and Sparkfun's schematics provide a great reference point for hooking the whole lot up. Of course, you could also just grab their shield if you don't want to build everything yourself.
Schematic
The image below should be pretty self-explanatory. See the next section for the exact pins for the SPI interface. RESET and INT can go to any digital pin.
Building, troubleshooting and talking to one's self
I built two at the same time to be able to test node-to-node communications. There was nothing overly tricky in the construction... I just chose to use relatively tight pcb prototyping boards which didn't leave much room for error. The above schematic was followed and the devices were hooked up to my Arduino(s).
I tried the loopback test from the canduino project and got random responses... the data going in was not the same as the data coming back. I started the debugging process after letting out a little sigh.
It turns out that, on all Arduinos, the SPI interface can only be used on specific pins:
SPI Pin | Arduino Mega | Smaller Arduinos (168,328) |
---|---|---|
SS/CS | 53 | 10 |
MOSI | 51 | 11 |
MISO | 50 | 12 |
SCK | 52 | 13 |
Note that the CAN library also then required a change as the pins in it are hard-coded to a 168/328 Arduino and wouldn't have ever worked with the Mega. You can find my fix for this down below.
I finally had responses after the pins were in the correct locations... but not the responses I wanted to see; I looked at the crystals next. My Arduinos all used 16.000MHZ crystals, but my local hobby shop only had 4mhz, 8mhz or 20mhz. This concerned me and I google'd and google'd to work out if, in the same circuit, multiple ICs could be driven off different oscillation rates. I decided that, since the 'SPI' interface had it's own 'bus rate' and the CAN bus also had it's own 'bus rate' that the crystals therefore did not affect these speeds. Also, the Arduino would dictate the speed of the SPI interface since it was the master (and slower.) I therefore bought 20mhz crystals for the MCP2515 chips, with my fingers crossed. Of course, this could have been the next issue.
Fortunately, from my previous attempts at barebones Arduinos, I had a 16mhz crystal on-hand. I swapped out the 2 capacitors and the 20mhz for the 16mhz and hooked it all up again. Nothing...
So, I then whipped out my Atmega328p 'barebones' Arduino and hooked it up to that. The SPI pins were different, as per above, so I made sure they were correct... and the CAN library from the canduino source had to be modified back to the required pins. After putting it all together I checked the serial output in the Arduino Serial Monitor and saw the correct response. The loop back test was working!
WTH... there was no reason that it should... except that maybe the SPI interface on my Mega was fried? I then, just because I hate caution and feed it to the wind all the time, swapped the 20mhz crystal and capacitors back in. It STILL WORKED! Good... I could keep the 16mhz for my other barebones Arduino.
So... with a known-working CAN node, I swapped it back onto the Mega. WTH... it worked. I now had my CAN nodes (by this time the other node built was also functioning thanks to it's guinea pig brother) talking to themselves. It was time to get them to talk to each other!
Talking in the CAN
Hah... there's an unwritten rule to not talk whilst in the toilet, but in our situation we'll make an exception. From the start I'd built the bus and was just itching to get the damn thing transmitting messages. The setup was simple: terminal blocks were used at junctions and standard dodgy speaker wire was the main network cable. 120ohm resistors were the terminators as per the standard CAN specification.
The only real issues here were the source code (or my lack of knowledge of how it worked) and the usage of crystals. Yes, they came back to haunt me... it turns out that, whilst I had the loopback going, I'd left a 16mhz on one node and a 20mhz on the other. In the source code you specify the 'CAN Bus Speed' which, of course, was configured the same on both Arduinos. The actual issue was that, when the Arduino told the CAN controller to run at bus speed '1000', the CAN nodes did this but, due to their differing crystals, their calculations of what '1000' meant were incorrect! Since one was running 4mhz faster (20mhz vs. 16mhz) it must've been communicating on the bus at a different rate and therefore confusing the hell out of the other node.
The next issue was the code... I looked over it and thought that each node would take turns in transmitting and recieving... I was wrong: you had to actually set one as the sender and one as the receiver. I configured this based on the Arduino class (by #IFDEF just as the SPI pins were configured) and then had communication! My nodes were live and functional!
RX/TX LEDs
The final step was wanting RX/TX activity LEDs. It turns out that the MCP2515 supports this, but you need to do a little configuration. If you view the datasheet at microchip you'll note that the RXnBF Pins can be configured as 'nothing', 'general outputs' or 'low on RX buffer full'. I was hoping that obe would be 'high on TX buffer', but no such luck. It actually turns out that the chip has two RX buffers and therefore two RXnBF Pins. LEDs attached to these pins will, once configured as per below, illuminate once the associated RX buffer is full. If you ever see both full then you might be losing data?
Second option: It turns out that in the MCP2515 Demo Board PDF that you can just put two LEDs on the RXCAN(1)/TXCAN(2) pins of the MCP2515.
Third option: It seems that you can also configure the INT pin to fire on TX buffer 'emptying'. You'll have to disable the pin firing on all other error situations to do this. By default, this pin is usually pulled 'high' by the MCU, so you must either disconnect that, use a resistor between the MCU and MCP2515 or just pull the pin high normally via a pullup resistor and then connect an LED in parallel with this to the INT pin. I imagine that in more complicated scenarios you'd actually want to know once the MCP2515 has generated an interrupt.
IDs: Standard or Extended?
All messages sent on the network have a 'frame id' of either (standard mode) 11-bits or (extended mode) 29-bits. It must be understood that this 'frame id' does not actually identify a node! It is simply an identifier for the actual message being transmitted. This identifier can contain any form of information you want; the bits are yours to play with.
One main use for this identifier is to record the intended recipient of the message you are sending. Depending on the amount of nodes in your network (don't forget to think of future scalability!) you can use anywhere up to 29-bits to uniquely identify them. Of course, this identifier could just be used to identify the 'class' of node and then you could put further data in the message to indicate the exact recipient. You could also go the other way and only use a portion of the identifier for the recipient code and have the rest for other uses.
The MCP2515 has in-built filtering to work on the identifier of incoming messages. If you're only using standard mode then the filters also apply to the first two bytes of the message. The filtering works inside the MCP2515 and therefore doesn't saturate your SPI link as the messages are stopped prior to being put into the RX buffer.
MCP2515 Modes
There's 5 modes that you can set the MCP2515 into. These are as follows:
Mode | Description |
---|---|
Configuration | This mode allows the developer to update settings. The following settings require this mode to be set first: CNF1,CNF2,CNF3,TXRTSCTRL,MASKS,FILTERS. |
Normal | Standard operating mode. RXM0 and RXM1 per buffer do not apply in this mode. All filters and Masks do apply. |
Sleep | Low-power mode. SPI remains active, and the MCP2515 will wake up if there is activity on the CAN bus if the WAKIE/WAKIF interrupts are enabled. After woken, the chip will be in Listen Mode. |
Listen | Make sure there are two or more nodes on the CAN bus. Whilst in Listen mode, the chip won't output a thing, so if another chip sends a message then the message will constantly circulate on the bus if there is no other node to 'ACK' it. Another node must be there to stop the message transmission. RXM0 and RXM1 per buffer apply in this mode and the masks/filters also do too. |
Loopback | All messages sent are returned via the RX buffers, filtered first. No messages are sent out over the CAN. No messages are received from the CAN. |
Buffers
It needs to be noted that the MCP2515 has two receiving buffers known as Buffer 0 and Buffer 1. Messages will go to the first if it's free (and not filtered) and then the second. Filters can be set on both, but the second buffer is much more flexible with four filters.
I don't know the exact reason for the MCP2515 containing two buffers, and then why one is more flexibile than the other, but in the end it's up to the developer as to how to use them. Filters can be configured to allow specific message 'types' on each buffer. This then means that, for example, the developer could configure the second buffer to only allow emergency messages such as 'STOP THAT TRAIN' whilst the first deals with the standard communications.
Filtering CAN Messages via the MCP2515
With the base configuration, an MCP2515 controller will accept any messages sent across the network. This therefore means that your nodes need to filter each individual message coming across the bus to determine if they themselves are the intended recipient. Fortunately the MCP2515 has in-built configurable filtering to allow only messages intended for the node to be passed through its RX buffers.
The MCP2515 has 6 configurable filters with 2 masks. The first mask works in conjunction with the first two filters and applies to the first receiving buffer whereas the second mask works with the final 4 filters and works with the second receiving buffer. Filtering is enabled when any bit of a mask is '1' and disabled when the masks are completely zero'd out.
You may be wondering why both a mask and a filter are needed? As mentioned above, you may not have used the entire 'identifier' area of the sent message to indicate the recipient. Therefore, when you're checking an incoming message, you wont want to filter the entire identifier. As the identifier bits can be a '1' or '0', you need to initially specify which bits you want to check (mask) and then whether or not they are a '1' or '0' (filter).
Node 1 ('101') | Node 2 ('110') | |
---|---|---|
Identifier | 10110 | 10110 |
Mask | 00111 | 00110 |
AND'd | 00110 | 00110 |
Filter | 00101 | 00110 |
Match? | False | True |
In the table above, you can see that Node 1 failed to match. The filter applied was looking for '101' (5 in decimal) but the lower 3 bits identifier (that's what the mask was looking for) was actually '110' (6 in decimal). You can see that the actual result was '110' after the mask was applied to the identifier. The second node matched as the filter is actually looking for '110'.
Now, we have to use the full registers when we apply this to the MCP2515. This means filling out 29bits of data. When in doubt, fill everything else with zeroes. Each register in the MCP2515 is 8bytes, this therefore means that you need 4 bytes per filter and 4 bytes per mask. The 6 filters and 2 masks that were mentioned above are located in the following areas:
Mask 0 | Filter 0 | Filter 1 | Mask 1 | Filter 2 | Filter 3 | Filter 4 | Filter 5 |
---|---|---|---|---|---|---|---|
0x20 | 0x00 | 0x04 | 0x24 | 0x08 | 0x10 | 0x14 | 0x18 |
0x21 | 0x01 | 0x05 | 0x25 | 0x09 | 0x11 | 0x15 | 0x19 |
0x22 | 0x02 | 0x06 | 0x26 | 0x0a | 0x12 | 0x16 | 0x1a |
0x23 | 0x03 | 0x07 | 0x27 | 0x0b | 0x13 | 0x17 | 0x1b |
Right, now that you know you need 4 bytes for a filter and then 4 bytes for a mask... and you know where to store them... you'll probably now need to know how to construct a mask and filter. We'll start with a mask that looks for the value 11 (decimal!) [0x0b in hex, 1011 in binary] in the standard 11-bit identifier. As you can guess, I've just provided the filter by representing the value in binary; we simply need to zero-out the bits to the left to ensure we provide the correct number. Have I provided the mask? No! Look at the truth table below if we were to use 1011 as the mask.
Node 1 ('11011') | Node 2 ('01111') | Node 3 ('01011') | |
---|---|---|---|
Identifier | 11111 | 11011 | 01011 |
Mask | 01011 | 01011 | 01011 |
AND'd | 01011 | 01011 | 01011 |
Filter | 01011 | 01011 | 01011 |
Match? | True | True | True |
They all matched!?!?!? Since we were only checking the 'exact' value via the mask, we weren't actually looking to see if any of the bits around the value were set. The basic principal is that we need to know the maximum length of the value we could be looking for and then use that as the mask. For example, if you have up to '11111' (32 including '0') ids on your network, then you want to make sure that your mask is '11111' and that your filter is the exact number of the node checking if the message is theirs.
Node 1 ('01011') | Node 2 ('01111') | Node 3 ('11011') | |
---|---|---|---|
Identifier | 11111 | 11011 | 01011 |
Mask | 11111 | 11111 | 11111 |
AND'd | 11111 | 11011 | 01011 |
Filter | 01011 | 01011 | 01011 |
Match? | False | False | True |
That's better! Make sure your values are correct! So, in the example below we'll use '11111' as the max value and therefore the mask. We'll then use 01011 as the value of the node we're pretending to be and we'll insert these into the correct registers (being Mask 0 and Filter 0.)
Message Acceptance Process
So, two buffers with differing filters... what happens when a message arrives? The basic idea is that a message will hit the first buffer and, if not accepted, attempt to hit the second buffer. The message is then discarded if the second buffer is also configured to not accept this message.
Note: There are also two bits (RXM0 and RXM1) in the RXBnCTRL (where n is either 0 or 1 depending on the buffer) that determine how messages are accepted. Note: My code currently has the ability to set these registers; for the life of me I cannot actually get the chip to function as per the datasheet when these registers are set. If anyone else has succeeded in using the RXM bits successfully then please leave a comment and tell how you did it!
RXM0 | RXM0 | Description |
---|---|---|
0 | 0 | [Default] Enable reception of all valid messages as determined by the appropriate acceptance filters. (See the pseudo-code below as to how the masks and filters apply.) |
0 | 1 | Only accept standard messages. Filters are useless if the EXIDE bit does not match with this value. For example, if you put an extended filter on buffer 0 but you disable extended messages to buffer zero with this configuration then that filter will never be used. |
1 | 0 | Only accept extended messages. The same rules apply that any standard filters on a buffer with this setting will not be used. |
1 | 1 | Receive ALL messages regardless of filters. Also recieve messages that have caused an error during transmission. The fragment of message received in the buffer prior to the error will be brought through. This mode should really only be used for debugging a CAN system. |
So, as long as the RXM bits are both set to '0', the message buffers will then process through the following procedure to accept or deny messages.
for EACH BUFFER b: (initially 0) if (MASK 'b' is ZERO) { //mask 0 for buffer 0 and mask 1 for buffer 1 Accept new message on Buffer b } else { using FILTERs 0,1 (if b equals 0) OR FILTERs 2,3,4,5 (if b equals 1) if (both the message and filter are 'extended') or (both the message and filter are 'standard') then for each '1' in MASK as 'x', does FILTER[x] equal message[x]? if all match then accept message else check next filter as this filters bits do not match the relevant message bits. else check next filter as this filter type does not match this message type. if still not accepted then TRY BUFFER 1 }
A mask is disabled when all its bits are '0'. As soon as a bit is '1' then that mask applies to the relevant buffer. As per the section above, the bits in the filter are then checked against the relevant message bits based on what bits the mask specifies the process to check.
On the contrary, a filter is not 'disabled' when all bits are '0'; instead you have configured two filters, on the buffer related to the mask, which will only permit standard messages where the identifier is zero. If you set the mask on a buffer to anything other than 0 and then don't touch the filters, this will prevent extended messages from coming through (as both filters have '0' as the EXIDE bit) and also prevent any standard messages that do not have an identifier of zero.
In the event that you don't want to receive a specific message type, you must put a mask on both receiving buffers and then an appropriate filter to block out the specific identifier bits. On the contrary, make sure that your masks and filters are smart enough to capture all other data required for your CAN node.
If in doubt, write an 'all-seeing' debugging application to view all traffic on your bus... it'll allow you to diagnose why messages are landing where you might not want them to. As per above, setting both RXM bits to 1 will bypass your filters; this way you don't have to muck around with your own configuration too much. Just make sure you have more than two other nodes on the bus if you want another in Listen mode. Having one node on the bus, or two with one in listen mode, will mean that any message transmitted will stay perpetually on the wire. A message must be consumed by another node for it to disappear.
Storing Masks and Filters on the MCP2515
Scroll up to see the register addresses for the masks and filters. The contents of each of these registers looks as follows:
Filter/Mask | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
---|---|---|---|---|---|---|---|---|
Byte 0 (RX[F|M]nSIDH)* | SID10 | SID09 | SID08 | SID07 | SID06 | SID05 | SID04 | SID03 |
Byte 1 (RX[F|M]nSIDL)* | SID02 | SID01 | SID00 | –– | EXIDE/––** | –– | EID17^ | EID16^ |
Byte 2 (RX[F|M]nEID8)* | EID15 | EID14 | EID13 | EID12 | EID11 | EID10 | EID09 | EID08 |
Byte 3 (RX[F|M]nEID0)* | EID07 | EID06 | EID05 | EID04 | EID03 | EID02 | EID01 | EID00 |
- *: 'n' is the filter number, i.e. RXF0SIDH is the 'Standard ID High Receive Register Filter 0'.
[F|M] means that the name is 'RXF1SIDH' for Filter 1 and 'RXM1SIDH' for Mask 1. - **: 'EXIDE': set this to '1' and this filter will only apply to Extended IDs, '0' means it will only apply to standard IDs.
This byte is unimplemented for Masks. Just leave it as zero. - ^: These two bits are not used if you are in standard mode as you only need 16 bits to check the first two bytes of data.
Have I lost you yet? Each filter and mask needs to be able to store both the Standard ID bits and the Extended ID bits. As mentioned before, if you're in standard mode then the 'lower' two bytes (i.e. bits 16 to 0 [17,18 are ignored!]) of the extended area are for matching against the first two bytes of data. You can disable this by ensuring that the associated mask has zeroes in the extended area. On the contrary, if you wanted to check the first byte in the data for a specific value then you would pass in '001111111100000000' as the extended area of the mask with the relevant extended bits set in filter.
Somewhere up above I mentioned we'd use '11111' for the mask and '01011' for the node id. We'll now store this in the registers. We'll use Mask 0 and Filter 0 for this and we'll make sure the rest are all zeroes so they don't apply. You'll note that the first register (RXM0SIDH) starts with zeros; as per above this means that the identifier could actually contain any data in this area and, since the mask is '0' for these bits, the acceptance process wont care at all! The registers will need to be set as follows:
Register | Data | Register | Data |
---|---|---|---|
RXM0SIDH [0x20] | 0b00000011 | RXF0SIDH [0x00] | 0b00000001 |
RXM0SIDL [0x21] | 0b11100000 | RXF0SIDL [0x01] | 0b01100000 |
RXM0EID8 [0x22] | 0b00000000 | RXF0EID8 [0x02] | 0b00000000 |
RXM0EID0 [0x23] | 0b00000000 | RXF0EID0 [0x03] | 0b00000000 |
Note: All other Registers in the RXF/RXM space need to be zero'd out! |
So, as you can see above, we've put the mask 0b00000011111 in the 'standard id area' of Mask 0 and 0b00000001011 in the 'standard id area' of filter 0. Based on our logic above this will then only allow messages through that match the above requirements. Below is the code to actually do this on the Arduino.
#define MASK_0 0x20 #define FILTER_0 0x00 void CANClass::setMaskOrFilter(byte mask, byte b0, byte b1, byte b2, byte b3) { setMode(CONFIGURATION); setRegister(mask, b0); setRegister(mask+1, b1); setRegister(mask+2, b2); setRegister(mask+3, b3); setMode(NORMAL); } //set MASK 0 for RXB0 a mask checks all bits of the standard id. CAN.setMaskOrFilter(MASK_0, 0b11111111, 0b11100000, 0b00000000, 0b00000000); //set Filter 0 to 0x555. Therefore only messages with frame id: 0x555 are allowed through this buffer. CAN.setMaskOrFilter(FILTER_0, 0b10101010, 0b10100000, 0b00000000, 0b00000000);
Note that only setting this for buffer 0 will mean that any message that doesn't match will come through on buffer 1. You'll need to also set a mask on buffer 1 to stop the messages completely. Of course, you can also only ever check buffer 0 for messages and not care if buffer 1 has anything waiting.
Filters in action: Guessing game.
Ok, who would've thought you could make microcontrollers play a game together. You know the old trick, someone else chooses a 'random' number and you get to 'randomly' guess it. Why don't we make our Arduino's play the same game?
We'll set the filter on buffer 0 to the number the receiver is thinking of. This means that the sender will only actually get a message through to the receiver if they guess the correct identifier. Both controllers will then swap roles. Just to make life easier we'll limit the range of numbers allowed, but we'll still make the guessing as 'random' as possible.
I could paste the full code here, but instead I'll just post the general idea.
Main setup | |
---|---|
Set Mask of Buffer 0 to the 11-bit standard identifier Set Mask of buffer 1 to the same 11-bit id set filter 2 (first filter of buffer 1) to a specific ID for messages that aren't guesses. Set one node to RX and one to TX Initialise the random generator. |
|
Receiver Role | Transmitter Role |
|
|
Source code (including my version of the CAN Library)
The final piece of the puzzle is always the source code. I've included the guessing game example as well. Note that my code is based off the canduino and I intend to send changes upstream where possible to make life easier for everyone.
Arduino + Thermal Printers (Sparkfun, IBM 4160-TF6)
I've always wanted to print my own receipts... devious activities come to mind; but the following usage of receipt printers is nothing sinister at all. My goal is to print out activities for trains on the layout; certain locations will have a new reporting mechanism!
I'd seen a few printers on eBay, most being USB. Serial was always to be my preferred method and I had the components on hand. I then saw the Thermal Printer at Sparkfun and decided that it'd be my first guinea pig.
Sparkfun Thermal Printer
The Sparkfun themal printer is, like most of their products, targetted at the Arduino. Thanks to this there is a wealth of information on their page on how to connect and use it. After hooking up a proper power supply (they recommend 9v @ 2Amps, so use a 7809 with a heatsink!) the printer just started spewing out whatever I threw at it.
The easiest way to use this is via the library found here: Displaying on Paper – Thermal Printer + Arduino. bildr.org is actually a really cool site full of interesting projects for the Arduino, check it out when you can!
There's a forum for discussing the above library, in which I've already posted my praises to the developer. If you need a hand then go over and ask away... they're always open to feedback and improvements to the library too!
Note that this printer uses small rolls of 58mm paper. I found a 10-pack of these at OfficeWorks (Australia) for AUD$9.95.
IBM 4610-TF6 (on Windows)
I'd finally found a dirt cheap printer on eBay that was RS-232. It was a chunky/retro IBM thermal printer and really was just a larger, more robust version of the Sparkfun thermal printer above. It didn't come with a power supply and, after purchasing, I realised that it wanted 38v! What the hell? It seems that the 'thermal' side of it uses a lot of current to burn the paper! It also wanted 3 AMPS at 38v... where the hell would I find that?
I installed the printer drivers here on a Windows XP 32-Bit machine (DOES NOT WORK WITH 64-Bit!) and provided it 12v @ 2A. The LED came on, but the printer showed up as 'offline'. All attempted connections via Hyper-Terminal showed the port as 'already open'; the printer driver would've been the cause. I uninstalled it and rebooted, but Hyper-Terminal wasn't receiving any responses after connecting successfully.
I then found a second 12v power supply and chained them together... Prior to this I'd re-installed the printer drivers and, upon the boost to 24v, the printer flicked to 'online' and the LED glowed slightly brighter. I could now also use the line-feed button on the top of the printer! I opened notepad, loaded a text file from the Arduino directory and, without thinking, hit print. The printer control panel window showed the job spooling up to 20 pages and then the printer started .... and kept going ... for an hour. It printed at a rate of about 1 line per 5 seconds.
I had no idea how to cancel it... so I had to let it go.
IBM 4610-TF6 (on the Arduino)
It was now time to make this printer talk to my Arduino Mega. I hooked it all up based on how the Sparkfun printer wiring and attempted to use the same code; nothing happened. I then used the code from Tom Taylor's Microprinter blog post. Once uploaded, I had junk coming out of the printer... It occurred to me that I probably needed a MAX232 in the middle to raise the voltages to proper RS232 levels (as per everyone elses examples!)
I hooked up the MAX232 as per the schematic below and then had a functional printer from my Arduino! Determining the actual commands to send it came next.
Fonts, spacing, etc...
Right, this gets tricky... you can either put 58mm or 80mm paper in this printer. 80mm is recommended as it has better chances of staying aligned with the paper cutter (coming out diagonally is actually an issue.) I had started with the 58mm but quickly went and bought 80mm paper (AUD$12 for 4 80x80 rolls) as I also wanted the extra printing space.
You can work out how many characters per line based on the font chosen, character spacing. It is pretty much expected that you're using 80mm paper. Font A is 10x20, Font B is 12x24 and Font C is 8x16. The Cash Receipt print line is 72 mm (2.83 inches) long. There are 576 dots per line and 203 dots per inch.
The Application Guide provides the following calculations:
- 20 CPI ⇒ 8-dot wide character + 2-dot space (Font C) ⇒ 57 characters/line
- 17 CPI ⇒ 10-dot wide character + 2-dot space (Font A) ⇒ 48 characters/line
- 15 CPI ⇒ 10-dot wide character + 3-dot space (Font A) ⇒ 44 characters/line
- 12 CPI ⇒ 12-dot wide character + 5-dot space (Font B) ⇒ 33 characters/line
Printing a Barcode
In a comment below, Jonas has asked how to print a barcode from any programming language via the serial port... Here's a list of instructions to do so:
- Set the Font (0x00 or 0x01):
0x1d 0x66 FONT 0x0a
- Set the Text Location:
- 0x00 - None
- 0x01 - Above
- 0x02 - Below
- 0x03 - Both
0x1d 0x66 POSITION 0x0a
- Set Barcode Width:
0x1d 0x68 WIDTH 0x0a
- Set Barcode Height:
0x1d 0x77 HEIGHT 0x0a
- Print a Barcode. 'CHARS' is the list of characters to print.
- 0x00 - UPC-A
- 0x01 - UPC-E
- 0x02 - JAN13 (EAN)
- 0x03 - JAN8 (EAN)
- 0x04 - CODE 39
- 0x05 - ITF
- 0x06 - CODABAR
- 0x07 - CODE 128 (c)
- 0x08 - CODE 93
- 0x09 - CODE 128 (a, b)
0x1d 0x6b BARCODE_TYPE CHARS 0x00
A 'Hello World' example of point 4 would be:
0x1d 0x6b 0x00 0x48 0x65 0x6C 0x6C 0x6F 0x20 0x57 0x6F 0x72 0x6C 0x64 0x00
IBM SureMark Thermal Printer Library for Arduino 1.0
IBM provides a great reference document for this collection of printers: Application interface specification for IBM 4610 printers. I found it to be a little hit-and-miss as to what commands are available on the TF6, but most worked well. Either way, I built the following library which provides the following functionality:
- Text Styles: Bold, Underline, Overline, Inverted, Arbitrary Font Scaling, Double Height/Width, Rotated, Upside-down
- Barcode Printing: UPC-A, UPC-E, JAN13 (EAN), JAN8 (EAN), CODE 39, ITF, CODABAR, CODE 128 (c), CODE 93, CODE 128 (a, b)
- Image Printing from data stream, image storing to printer RAM and image printing from printer RAM
- Message storing to printer RAM and printing from printer RAM
- Beeper sounds. (Example below has 'Mary had a little lamb')
- Paper cutting, line spacing, line feeding, etc...
Other references
It turns out that, if I'd google'd more, I would've found a lot more help around the traps... here's a few locations to check out: