Subscribe via RSS
29Dec/190

Vintage Trams In Amsterdam – December, 2019

Thanks to Saint Nicholas hanging around, there's a lot to see on the rails in the main center of Amsterdam. Electrische Museumtramlijn Amsterdam is located in the south of Amsterdam, but it still connected to the cities tram lines. Good news for us as this means that, at certain times of the year, they can run their vintage stock around town! Over Christmas, this happened to be from 12-5pm on the 26-30th of December.

The vintage tram's route was from the Dam itself, anti-clockwise down Rozengracht, left at Marnixstraat, straight through to Fredriksplein, north to Rembrantplein and back to the Dam. Thanks to the winter sun, there weren't too many opportunities near the Dam to take shots, but after viewing the consist, I headed west to the first corner for a photo.

DSC02858

A two-car consist had already been hiding in the shadows in the Dam, waiting in the Dam for passengers to board. How can one even get a good shot of it whilst it's half in the shade? I'd thought there'd only be one set running, but it turns out that whilst one set was doing the lap, the other was paused to advertise the route and take on passengers.

DSC02868

DSC02864 DSC02867 DSC02870

Along the way to rembrantplein, the lighting was not much better...

DSC02906

But down in the plein itself, the sun was still trying to shine!

DSC02922

DSC02925 DSC02926 DSC02929

From there, it was home time. Fortunately, we ended up in town the next day, so I tried some full nighttime shots.

DSC03048 DSC03050 DSC03053

Nicely, they were running another consist... the blue and grey was a really nice combination!

DSC03061

DSC03067 DSC03069 DSC03078

And that was about it. Great to see them running and they all happened to be full when I was watching. I'll try and check out the actual museum itself this trip; there's even a model railway shop near it!

Filed under: INTL No Comments
28Dec/190

Apeldoorn Steam Trains – December, 2019

Back to Apeldoorn, but this time to check out heritage equipment operated by the De Veluwsche Stoomtrein Maatschappij. Again, it was a very early start via Amsterdam Centraal, which coincided with the Thalys arriving from Belgium.

DSC02790

A standard Intercity was taken through to Amersfoort with a small transfer over to another service through to Apeldoorn. It was quite the dreary day, so apologies that all shots hence-forth are in low-light... the temperature was exactly as it looks!

DSC02792

The picture above is the northern side of the station and via this exit you can get to the town center. I had travelled there on December 26 and there was absolutely no point of doing so... there are no boxing day sales in regional towns in Holland! After a quick lap of the town (even McDonalds was shut), I ventured to the southern side and then to the east with a plan to intersect with the branch line that the steam engine runs along. From the station it's about a 15 minute walk.

DSC02794

DSC02795 DSC02796 DSC02797

I walked from the first level-crossing down to the next along the line in search of photo opportunities. Thanks to the weather, the sun was hidden... otherwise it'd be head-on into the lens! Regardless, there wasn't much chop, apart from straight-on photos down the line, or side-on from across the canal. Instead, I wandered back to the bridge at the first crossing and lined up a 30-degree angle with the track. This also let me see the two 'white' signals down the line.. of which I hoped would indicate occupancy, or at least triggered crossings... but did neither with the up service.

DSC02799 DSC02801 DSC02809

I was happily kept amused by the wildlife, watching my clock as the minutes clicked past the expected times on the schedule. Running around 15 minutes late, the steamer arrived and paused at the crossing right next to me!

DSC02813 DSC02815 DSC02822

DSC02818

The train had stopped as the crossing next to me required manual activation. The guard quickly alighted, unlocked the control box and triggered the gates.

DSC02826

DSC02835 DSC02833 DSC02832

DSC02831

The consist then rolled on through to Apeldoorn Station. I noted the steam pipes running through the entire length of the train, presumably for heating? Once it passed and the crossing cleared I light-footed it back as well. As I was running to make it to the opposite platform, the same gas/oil train rolled through as happened last time I was in Apeldoorn. In fact, that was the only freight I saw all day... which is really only one more than I saw last time I was here!

DSC02837 DSC02839DSC02840

DSC02842

The steamer had also already run around and was ready to roll away. After being 15 late, it still left on time! I managed to format my card before I remembered that I had a video of it on there. Whoops. After all the fun was over, I stopped for a burger at the restaurant in the station building.

DSC02851

And that was a day... it was cold enough to not want to hang around!

Filed under: INTL No Comments
27Dec/190

Emmerich – December, 2019

After visiting Geldermalsen, a station near the junction with the Betuworoute in the south of the Netherlands, I decided it was better to find the very start of the line. Sure, not all freights would traverse the entire length of the line, but at least some would have to enter/exit from the German side?

The line starts at Zevenaar, an eastern bordertown in the Netherlands that sits next to the locality of Emmerich in Germany. Getting here from Amsterdam was easy enough with a few transfers along the way.

Amsterdam Centraal

Whilst waiting at Amsterdam Centraal, the usual thing happened whilst waiting for my train; a freight passed when I wasn't ready. Even funnier that it happened whilst I was discussing the fact that there's lots of freight movements in europe, just not when you want them. It was also too bloody dark to take good photos.

DSC02623

DSC02631 DSC02632 DSC02633

DSC02636

From here, an Intercity was caught to Arhnem Centraal. It was still dark for the entire trip, with the sun rising at around 0830 each morning in Europe in winter. Something I'm still really not fond of!

At Arnhem I needed to change to a private railway. Thanks to the great setup of the ticket machines, this is a very easy task. Below you'll see the ticket validators for both companies sitting side by side. All one has to do is touch off NS and touch on Arriva to transfer. No need to exit the station!

DSC02640

Before long the diesel was humming away and we were heading east to Zevenaar. The transfer here wasn't as easy as above as we were now crossing international borders. Of course, being all in fhe EU, there's no actual passport checkpoints... You could just walk across if you wanted to. I did need a new ticket, and this was as simple as going to the DB machine. Emmmerich-Elten wasnt a valid destination, for an unknown reason, so I chose Emmerich itself.

DSC02641

I then had to turn around and bolt to the train as it had just arrived from Arhnem Centraal, ready to take everyone into the Motherland.

Emmerich

There's a big bi-directional staging yard here where freights lay over before or after crossing the border. A lot of westbound freights lined up side by side whilst I was loitering, with the german drivers alighting to let another pair take the consists further on their journeys.

DSC02645

DSC02676 DSC02675 DSC02674

DSC02677 DSC02678 DSC02679

From the platform, the views are therefore very side-on and, honestly, not the best. Every so often a freight would pass straight through, but most of them went into the yard. Fortunately, there was a diesel shunter that had just detached three tankers from a freight for delivery to a local factory. I'd arrived just in time to see it run around and take the tank wagons away.

DSC02649

DSC02647 DSC02653 DSC02672

Something interesting then happened. A coal (or possibly any other commodity) train passed through... though the carriages were eerily familiar. Was this the same train that passed me in Amsterdam Centraal? It sure looked like it... but there's probably 100 trains of similar consist on the line at any point.

DSC02661

DSC02665 DSC02666 DSC02667

A few ICE trains passed through...

DSC02686 DSC02688 DSC02691

And then I was off to the next destionation.

Emmmerich-Elten

My initial plan had always been to get to this station as it looked, from google maps, that all trains would pass through at full speed. I caught the next train westbound to check it out.

DSC02700

DSC02703 DSC02711 DSC02716

Unfortunately, the sun chose to come out just as I arrived, so all the westbound freights were hard to photograph. There were also no eastbound freights to be seen, so I quickly headed off into the small town for coffee and a pitstop.

Praest

With the initial plan not proving effective, and seeing that all the westbound freights were coming through to the yard, I chose then to head east past Emmerich to Praest.

DSC02723

DSC02717 DSC02724 DSC02739

It didn't take long for freights to pass... but I must say there weren't as many as earlier in the morning.

DSC02732 DSC02734 DSC02737

This little side-platform station was beautiful. Lush foliage with tiny platforms and a level crossing to provide forewarning of impending trains. Actually, on that note, there were three level crossings in the vacinity and they all went down at the same time... At least 8 minutes prior to a train coming! I'm not exaggerating... 8 bloody minutes!

After an hour, I was ready to head back to the big smoke, but I hadnte realised the obtuse timing of the crossing gates and ended up stuck on the wrong platform right when my train passed through! Blessing in disguise though... The shunter I'd observed earlier came in the opposite direction and in perfect light.

DSC02746

DSC02749 DSC02750 DSC02755

With the light coming from the south, I chose the southern platform where possible to take photos, but the trains all seemed to be coming from the west, meaning they were easily too close to the lens.

DSC02762

DSC02771

DSC02776

DSC02777 DSC02780 DSC02782

Thanks to missing my train, I had another hour to kill. Pretty easy though as there were numerous freighters and ICE trains passing.

Filed under: INTL No Comments
24Dec/190

Geldermalsen – December, 2019

The goal was to get close enough to a junction with the Betuweroute, the freight-exclusive railway line, of which I can't even pronounce, that links Germany to Rotterdam. Trains either run the entire length of the railway to get to the port of Rotterdam, or they exit at one of the many off-ramps onto the standard NS railway lines. Geldermalsen is one of these locations as there's a junction with the Betuweroute just a few KM south.

's Hertogenbosch

Geldermalsen is a lesser station and therefore only served by NS' Sprinter services. You can get there from either side: Utrecht or 's Hertogenbosch, another name I can't pronounce. I chose the latter.

DSC02491

DSC02493 DSC02496 DSC02498

The main station building is quite beautiful. There's a ton of throw-backs to the previous factories, or maybe even the previous station structure; I couldn't quite tell. There was also a cute little shunter on the side, not doing much at all... I wonder if the station receives freight? I didn't hang around for long though as the connections were great to get the next northbound sprinter.

Geldermalsen

This station is pretty much in the middle of nowhere, but still well patronised and very clean and tidy. There's a really handy pedestrian bridge crossing all lines, but with caternary, it doesn't provide the best view. The station has three roads per direction, including a passing lane as the final road. Further below you'll see how the freight use it to let the express trains pass.

DSC02499

DSC02500 DSC02501 DSC02502

The express trains didn't stop. They are scheduled with 30-minute head-ways and so there's always one heading in one direction or the other.

DSC02505 DSC02511 DSC02557

DSC02552

It wasn't long before a southbound freight train arrived. The consist entered the far road and held back until another express passed through.

DSC02518

DSC02527 DSC02528 DSC02529

DSC02530 DSC02533 DSC02536

There's actually a branch line to the north-west that heads off to Dordrecht. This is run by smaller consists that park at the far end of platform 1. There's then a crossover that allows the sprinters to use the same platform, but at a more convenient location, closer to the station building.

DSC02537 DSC02540 DSC02544

DSC02547 DSC02546 DSC02545

DSC02550

Another freight train passed through northbound, but also had to wait in the third road for a northbound express.

DSC02558

DSC02563 DSC02564 DSC02570

DSC02577

Culemborg

It was bloody cold, so I jumped on the next northbound sprinter; there was family to enjoy out the front o' the Rijksmuseum ... ice skating! I had a few more minutes and so I stopped at the next station north for a quick hop. Culemborg is a stanfard country station with no passing lanes. It has a great waiting room, of which I failed to take a photo.

DSC02591

DSC02595 DSC02597 DSC02599

The expresses bolt through, but there was no time to hang for a sprinter after the one that was approaching; I jumped on and returned to Amsterdam.

DSC02602 DSC02603 DSC02605

Check that last shot out! Google translate app working real-time translating whatever my phone camera was pointed at!

Filed under: INTL No Comments
20Dec/192

Amersfoort and Apeldoorn – December, 2019

It was time for another family adventure to Amsterdam, but this time for Christmas! I was just about ready for Australian summer before being shipped over into the depths of winter in The Netherlands. Lots of research had been completed: I'd found sites for photography spots, live maps of the passenger services and freight timetables. Unfortunately, the latter has been taken down in the last 4 days... can you believe it? Milliseconds before I travelled to the country, the information disappears! Despite this disappointment, I decided to trek out to the regional towns to hunt down freight.

The trip started from Amsterdam North and, thanks to the now-open Northern Metro, it was a quick 5 minutes to get there. I was then very happy to realise that my services would all be run by Koplopers (my total favourite)!

DSC02335

DSC02337 DSC02339DSC02341

That last shot is cute... the poor onboard information system had a disk failure and tried to boot... the weirdest part being that the display starts off upside-down!?

Amersfoort

This town is located south-east of Amsterdam and, via the intercity services, only about 40 minutes away. From the station, there's a large yard to the north-west which hosts infrastructure testing equipment, a train simulator for NS staff, and the shunting yard for the automotive branch. The automotive branch runs south-east from the station, down to a few factories that process half-completed cars from Germany. The goal was to exit the station and loiter near the start of the branch, near a level-crossing, to try and see something run through. Fortunately, as I was approaching the station, a small diesel was already at the head of a long rake of new cars, ready to be taken down the line.

But first... the station... some Koplopers... and the yard...

DSC02344

DSC02348 DSC02349 DSC02352

DSC02345

That shot above was a total accident... turns out you can shoot and focus at the same time and get some pretty weird effects. The top was the only one of 5 that turned out, not that I was even trying. It was a total mistake.

DSC02355

So many Koplopers, but then the yard... at the eastern end there's a stash of vintage locomotives in various liveries and owned by various companies?

DSC02360 DSC02359 DSC02358

DSC02361 DSC02363 DSC02364

One thing I need to admit is that the lighting at this time of year in the northern hemisphere is dismal! I mean, it's beautiful for an hour or so when it's 'dusk', but that's 3pm! The sun is gone by 4!

DSC02366 DSC02367 DSC02369

Wandering to the end of platform 5, I could see the car-carrier rolling towards the station. I then consulted maps and realised that it'd been shunting backwards, whilst I was arriving, to access platform 2/3, which would then let it take the branch. I was obviously in the wrong spot, at the wrong time, and therefore bolted to platform 2. Fortunately, Amersfoort is beautifully designed and there's stairs at both ends of the platform. Before-long, it rolled through...

DSC02371

DSC02372 DSC02374 DSC02377

DSC02381 DSC02379 DSC02378

DSC02401 DSC02395 DSC02387

DSC02402

Quite a few Porsches on the end! An Intercity was coming in through next, bound for Berlin, and so I exited the station to get a shot of it along the line to the east.

DSC02410

DSC02413 DSC02417 DSC02421

The NS loco-hauled services look very similar to the older SNCF locomotives in France. I wonder if they're the same manufacturer? I'll do a little research when I'm sleeping on a french train later in the month. From here, I returned to the station to check out what else was going on. Prior to actually entering, you have to cross the branch where the auto-train went...

DSC02422

The line looks like it's heavy-railed, but the smaller diesel indicates otherwise... then again, they might just be saving fuel. Out the very front of the station, there's a strange clock that seems to be offsetting the current datetime for something relevant to somewhere else?

DSC02427

DSC02428

And one can't forget an obligatory front-on shot of the station.

DSC02429

From here, things got awkward. I had time and decided I'd do a round-trip to Apeldoorn and so I approached platform 2 once more. From the yard, an oil train approached without warning. Fortunately, my camera was at the ready... but after the second shot, my camera seemed to stick in half-focused mode. I turned it off and on again, but as soon as it powered up, it did a focus, as if I had my finger on the trigger, half-pressed.

DSC02451

And so, the train passed... and I had a dead camera. I jumped on the east-bound service to Apeldoorn.

Apeldoorn

As we rolled away, I sat down and started pulling apart my camera. After having the lens, battery and memory card out, the camera finally snapped back into action. Funnily enough, as we were heading towards Apeldoorn, the conductor came over the PA and mentioned something sounding like an apology... this, of course, is a guess as my Dutch is non-existent. The guess was that we were dawdling thanks to the freighter taking its time in front of us. Soon enough, we were accelerating again and I saw a glimpse of a train in out the right windows. Turns out there's a passing loop near Stroe and the freighter had been put away... I'd get to see it again in Apeldoorn?

DSC02457

DSC02460 DSC02463 DSC02465

Amazing. Another fluke... playing leap-frog with freight trains in the middle of The Netherlands. Apeldoorn is also a branch for the Arriva Zutphen line. This is run by two-car diesels which are remarkably similar, in layout, to DERMs from the Victorian railways.

DSC02469

Anyway... after that mild success, I headed back to Amersfoort. I'd bought an initial return ticket from Amsterdam to Amersfoort and then another return from Amersfoort to Apeldoorn, so I had to exit the station to keep all my tickets valid. Another point, I took a loco-hauled intercity like the one above. Even though these are ICE carriages from DB, it seems that they operate as standard intercity services once in The Netherlands. Although I didn't actually get my ticket checked.

Back at Amersfoort

Whilst coming back in, I saw something interesting. Past a building, down near the auto branch, was a stuffed-and-mounted wooden EMU? The building seems to be an old station building, is a Gibson store/function-center, and the loco must be from Austria or Switzerland?

DSC02473

DSC02474 DSC02475 DSC02476

Very nice actually, but the sun was already ready to set. Actually, the EMU reminded me of the railway line from Palma to Port De Soller.

DSC02432

I then did a lap of the whole station and wandered over to the northern side of the yard. There's a building that used to be carriageworks that I thought was a bar, but turned out to just be a function center. One good thing was that it allowed access to the other side of the stored locomotives...

DSC02434

DSC02436 DSC02438 DSC02439

DSC02440

DSC02441

Finally, on the way back into Amersfoort station, I stumbled past a beautiful piece of stained-glass art. That's totally a Koploper!

DSC02430

And that was then it for the day... jetlag was kicking in and although a nice beer was had at De Wagenmeester on the southern side, including a great view of the tracks!,...

DSC02480

It was home time.

Filed under: INTL 2 Comments
5Dec/190

More (Bit)Bang For Your Buck

Arduinos are a great hobbyist platform for projects, but you'll often encounter speed and memory issues when you try to squeeze in too many features. Fortunately, being an open source system, one can easily bypass the standard libraries and push these little units as hard as possible. Of course, once you're past the warranties and disclaimers, you're out on your own.

I've previously had to jump out of the IDE and use 'faster' code whilst using a Dreamcast Controller for my Model Railway, but that was a little more advanced than what we're about to do here. Today's goal is to bitbang the data stream to the Red LED Sign as quickly as possible. If you check that post, you'll see I'm already using digitalWriteFast, but it seems that we can go even quicker with the SPI library.

What's SPI, you ask? To steal from Arduino: Serial Peripheral Interface (SPI) is a synchronous serial data protocol used by microcontrollers for communicating with one or more peripheral devices quickly over short distances. As it turns out, that's exactly what we want to do! We want the display to be a slave and, well, we're just going to hack the right RX/TX lines together to get the data to flow. A fellow Arduino-er has done this here whilst interfacing with a 74HC595 and provides a few hints as to problems we might run in to.

Actually, now that I think of it, the data is to be sent out in bytes, but my screen is no where near the order of a clean multiplication of bytes... will have to work on that. Also... the data I read is the top 'line' of each letter, it's not a clean char in any memory array. Hmmm...

Test Patterns

Without pulling apart my currently-hacked-together-and-functional-display, I used another Uno I had lying around and hooked it up to the two spare LED panels. The whole display came with 5 panels, but I wasn't able to smoothly run them all at once, so these two were not in use.

The hook-up is pretty straight forward. The Wikipedia article on SPI gives a little more information on the bus and, more specifically, dictates which wires we need to use. We'll need the data output wire and the clock, known as MOSI, or Master Out-Slave In, and SCLK, the serial clock. Note that some devices read the data pin when the clock transitions from LOW to HIGH, and some vice-versa. Fortunately, this can all be configured via the SPI library.

With the following code, I managed to get a test pattern on the display...

#include <SPI.h>
void setup() {
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV128);
}

bool isEvenRow = false;
void loop() {
  isEvenRow = false;
  for (int row = 0; row < 7; row++) 
  {
    if (isEvenRow) {
      SPI.transfer(B01010101);
      SPI.transfer(B01010101);
      SPI.transfer(B01010101);
      SPI.transfer(B01010101);
    } else {
      SPI.transfer(B10101010);
      SPI.transfer(B10101010);
      SPI.transfer(B10101010);
      SPI.transfer(B10101010);
    }
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(150);
    digitalWrite(row + 3, LOW);
    isEvenRow = !isEvenRow;
  }
}

Well, neat! It worked? Playing with the SPI_CLOCK_DIv variable made the loop even quicker, down to the point where I had to up the delay at the end so that the LEDs would illuminate for a longer timeframe. SPI_CLOCK_DIV determines the speed at which the data is sent out, dividing the main 16mhz clock on the Arduino. DIV2 halves it (8mhz), DIV4 = 1/4 = 4mhz, DIV8 = 1/8 = 2mhz, DIV16 = 1/16 = 1mhz, etc...

Anyway, the test pattern was great... but I needed to output text, in rows of bytes!?

What About Text?

So this is where it gets interesting. My font array has 7 rows of 5 pixels per font. I then have up to 6 characters per LED display unit, equalling a total of 30 bits each. Of course, there's 8 bits to a byte, so the neatly rounded-up value would be 32 bits. I could therefore send out 4 bytes to get each row transmitted over the wire. But do be warned, if you start the data on the first bit out, it'll 'run off the edge' of the screen as the screen is only 30 bits wide...

Bytes 00 01 02 03
Pixels -- -- 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 00 00 00
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 2 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 3 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 4 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Row 5 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 6 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00

As you can see, the text to be displayed is "TEST!" in the cute Arduino 5x7 font. Our display is 30 bits wide, so there's two columns of blank to the left. After the 2 pixel offset, we start throwing out each row of data. This won't be overly-easy either, as we need to get the rows of bits per character per font.

So, based on the current pixel to be pushed out, firstly get the character from the string array. We then need to look up the font pixel array for this character, only getting the relevant row that we're trying to display. Once we have that, we can then just send the bits out to a temporary array of bytes. As that we'll only have 5 bits per font line row, we'll actually need to merge multiple characters into each byte of the array. If we then want to scroll text, we'll have to put a little more effort in. This isn't overly different from when we were sending the data out bit-by-bit; we're just stuffing it into bytes now, making sure we get everything into the correct byte in the output array.

I jammed this calculation into one row below and the output was actually quite surprising! Mainly in the fact that it actually worked!

#include <SPI.h>
#include "myfont.h"

String serialString = "TEST! ";
const int BUFFER_LENGTH = 4;
const int DISPLAY_LENGTH = 30;
byte* datarow = new byte[BUFFER_LENGTH];

void setup() {
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV128);
}

void loop() {
  for (int row = 0; row < 7; row++) 
  {
    for (int col = 0; col < DISPLAY_LENGTH; col++) {
      datarow[((col + ((BUFFER_LENGTH * 8) - DISPLAY_LENGTH)) / 8)] |= 
        ((font[serialString[col / 5]][col % 5] & (1 << (6 - row))) 
          ? 1 : 0) << ((col) % 8);
    }
    for (int col = 0; col < BUFFER_LENGTH; col++) SPI.transfer(datarow[col]);
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(500);
    digitalWrite(row + 3, LOW);
  }
}

Everything was actually working nicely... but then I tried to extend it out to 4 displays. 120 pixels out, even at the fastest SPI, caused severe flickering. It dawned on me that I was doing some pretty hefty lifting in my display loop, presumably slowing down the drawing. It's actually a critical loop and it seems that any processing will slow down the line drawing, causing the flickering I was seeing.

With this problem in mind, it became apparent that I'd need to move the 'buffer' calculation out of the main loop. I quickly tested this theory by moving it to a once-off in the setup procedure.

#include <SPI.h>
#include "myfont.h"

String serialString = "TEST! ";
const int BUFFER_LENGTH = 4;
const int DISPLAY_LENGTH = 30;
const int DISPLAY_HEIGHT = 7;
byte* datarow = new byte[DISPLAY_HEIGHT][BUFFER_LENGTH];
void setup() {
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  SPI.begin();
  SPI.setDataMode(SPI_MODE2);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV128);

  for (int row = 0; row < DISPLAY_HEIGHT; row++) 
  {
    for (int col = 0; col < DISPLAY_LENGTH; col++) {
      datarow[row][((col + ((BUFFER_LENGTH * 8) - DISPLAY_LENGTH)) / 8)] |= 
        ((font[serialString[col / 5]][col % 5] & (1 << ((DISPLAY_HEIGHT - 1) - row))) 
          ? 1 : 0) << ((col) % 8);
    }
  }
}

void loop() {
  for (int row = 0; row < DISPLAY_HEIGHT; row++) 
  {
    for (int col = 0; col < BUFFER_LENGTH; col++) SPI.transfer(datarow[row][col]);
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(500);
    digitalWrite(row + 3, LOW);
  }
}

My text was static, so I now only built the buffer once. Would you believe it? The rendering was beautiful! I couldn't even notice a flicker. This was then short-lived when I realised I needed to scroll text. Again, there was no need to rebuild the buffer on each loop, so I wrote a procedure and only called it when there was text to move; defined by a delayed scroll rate.

This worked nicely, but there was an obvious jarring delay as the text shifted along. You could feel it re-processing in-between the character movements. I was still happy with it! I went ahead and reconfigured my initial display setup to use two Arduinos: one for the remocon+wifi and the other to receive serial data and light this dispalay.

But Wait, Why Don't I Build The Entire Text Buffer?

Whilst writing this up, it occurred to me that I was only rebuilding the buffer for the text that was visible on the display, not the entire string. If I had the full text buffer already created somewhere in memory, I then would only need to get SPI to send out the data from a specific bit offset. But, how do you start sending data via SPI from half-way through a byte? My fonts/characters were 5 bits wide and each byte had 1.5ish characters in them! I considered just shifting the pointer along the bytes, but the scrolling would be horrible.

So, I want to send out data from half way through a byte? Let's just borrow that table from above again:

Bytes 00 01 02 03
Pixels -- -- 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 00 00 00
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 2 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 3 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 4 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Row 5 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 6 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00

Officially, on the 3rd loop of scrolling, I would want to send out the green bits. I'd also then want to send out five zeroes at the other end so that the scrolling text trails off and doesn't wrap around. I can't tell SPI to start at the 4th bit of a byte? So I'll need to create a new buffer and populate this as quickly as possible, line by line, just as we're about to render it. Thanks to the glory of the internet, there's always someone else who wants to do something similar. Effectively we have an array of bytes (unsigned chars, meaning we get all 8 bits) and we'll need to shift the first one and append the next one. It'll be very much like a catepillar crawling along.

So, if we build the full text buffer array when the string comes in, we can then push the relevant chunk into the display buffer. There'll be no font calculations, just bit for bit copying, and this will hopefully still be fast enough. We can even make sure we only do it line by line, and only as required... if we're on a byte boundary, then we don't need to shift anything!

I mentioned shifting above, and that's what we'll need to do to get the chunks of bytes into the final display buffer. If you look at the table above, you'll notice I coloured the cells in light green and dark green. The first 3 bits are light green and come from the 'end' of the first byte of the text buffer. The next 5 bits are from the 'start' of the second byte in the text buffer. This chain then continues on as we shift the bits. The >> and << C operators will assist us with this task as that's exactly what they're designed to do: shift bits in a variable in a certain direction by a certain amount. Let's try some pseudo-code first....

define a string buffer that has the string to display: "TEST!";
build a buffer for this string: stringBitBuffer[7][4];
define a display buffer that is enough for 1 panel: displayBuffer = byte[7][4];
if our scroll offset is a multiple of 8
  foreach stringBitBuffer[scrolloffset /8] SPI.writeRow();
  write extra zeroes at the end.
else if our scroll offset is NOT a multiple of 8
  foreach byte in stringBitBuffer starting from (scrollOffset/8)
    shift the first block of the text buffer right scrollOffset times
    make anything to the left of the text in that byte zero.
    move the resulting value into the current displayBuffer byte.
    get the next text buffer byte. 
    take the first (8 - scrollOffset) bits and add them to the current displayBuffer byte
  next
end if

Here's an animation showing what bits we want where...

Bytes 00 01 02 03
Pixels -- -- 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 00 00 00
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 2 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 3 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 4 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
Row 5 00 00 00 00 01 00 00 01 00 00 00 00 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
Row 6 00 00 00 00 01 00 00 01 01 01 01 01 01 01 01 01 01 00 00 01 00 00 00 00 01 00 00 00 00 00 00 00
TB 00 00 00 00 00 00 00 00 01 01 01 01 01 01 01 01 02 02 02 02 02 02 02 02 03 03 03 03 03 03 03 03
Bytes 00 01 02 03

The table above shows the 8 frames that need to be copied over to the framebuffer between bytes. Once the data has shifted a whole byte to the left, then the drawing routine just needs to start from the next byte, there's no need to send out the initial bytes if they're offscreen. We need to copy the bits in the main area of the table into the buffer bytes listed on top. I've added a new row at the bottom which indicates the first bit/byte of the text buffer (TB). With the duplicated Byte row underneath, you can see how we'll need a part of one text buffer and the rest of the next to fill the gaps.

Back to that forum post I mentioned above, and the description I gave about bit shifting, we can build up our buffer. We need to, based on the scroll offset, take the first (8 - offset) bits from every byte and then the 'offset' bits from the following byte. i.e. if the offset was 3, we want the last 5 bits of byte 1 and the first three of byte 2. If we're on the last byte, then we just fill the end with zeroes. The AND masks for row 2 are shown below. Row 1 is nearly all bits set... so wouldn't be a good test case.

Bytes 00 01
Pixels 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Row 0 00 00 01 01 01 01 01 01 01 01 01 01 01 01 01 01
Row 1 00 00 00 00 01 00 00 01 00 00 00 00 01 00 00 00
AND #1 00 00 00 01 01 01 01 01 00 00 00 00 00 00 00 00
AND #2 00 00 00 00 00 00 00 00 01 01 01 00 00 00 00 00

And then we just need to shift the first 5 bits to the left... as we're stored in MSB.

#include <SPI.h>
#include "myfont.h"

int ccol = 0;
byte datarow[7][60];
int displayLength = 120;
int bytesRequired = (displayLength + (displayLength % 8) + 8) / 8;
int totalPixels = bytesRequired * 8;
byte frameBuffer[7][16];

unsigned long last_time = millis();
unsigned long scroll_time = millis();
unsigned long scroll_pause = millis();
unsigned long next_text_time = millis();
int charOffset = 0, loop_count = 0, charcol = 0;
String displayString;

void buildTextBuffer() {
  bytesRequired = ((displayString.length() * 5) / 8) + ((displayString.length() * 5) % 8 == 0 ? 0 : 1);
  totalPixels = bytesRequired  * 8;
  for (int row = 0; row < 7; row++) 
  {
    for (int b = 0; b < bytesRequired; b++) datarow[row][b] = 0;
    for (int col = 0; col < totalPixels; col++) {
      ccol = col + 8;
      datarow[row][ccol / 8] |= 
        ((font[displayString[col / 5]][col % 5] & (1 << (6 - row))) 
          ? 1 : 0) << (ccol % 8);
    }
  }
}

void buildFrameBuffer(int offset = 0) {
  int tOffset = offset / 8;
  int cOffset = offset % 8;
  int bb = 0;
  for (int row = 0; row < 7; row++) 
  {
    for (int b = 0; b < 16; b++) {
      bb = b+tOffset;
      frameBuffer[row][b] = (datarow[row][bb] >> cOffset);
      if (cOffset > 0) {
        if (bb <= bytesRequired) {
          frameBuffer[row][b] |= (datarow[row][bb + 1] << (8 - cOffset));
        }
      }
    }
  }
}

void setup() {
  Serial.begin(9600);
        
  for (int p = 0; p <= 12; p++) {
    pinMode(p, OUTPUT);
    digitalWrite(p, LOW);
  }
  
  SPI.begin();
  SPI.setDataMode(SPI_MODE3);
  SPI.setBitOrder(LSBFIRST);
  SPI.setClockDivider(SPI_CLOCK_DIV64);

  displayString = "Warming up ... ";
  buildTextBuffer();
  buildFrameBuffer(0);
}

String newString = "";
void getNextIndex() {
  for (int i = 0; i < 7; i++)
    for (int x = 0; x < 60; x++)
      datarow[i][x] = 0;
      
  if (Serial.available()) {
    newString = Serial.readStringUntil('\n');
    if (!newString.equals(displayString)) {
      displayString = newString;
      next_text_time = millis();
    }
  } else {
    displayString = "";
  }
  if (displayString.length() > 0) buildTextBuffer();
  buildFrameBuffer(0);
}

void loop() {  
  for (int row = 0; row < 7; row++) 
  {
    for (int col = 0; col < 16; col++) SPI.transfer(frameBuffer[row][col]);
    digitalWrite(row + 3, HIGH);
    delayMicroseconds(150);
    digitalWrite(row + 3, LOW);
  }

  if ((millis() - scroll_pause > 2500)) {
    if ((displayString.length() > (displayLength / 5))) {
      if (millis() - scroll_time > 30) {
        charOffset++;
        if ((charOffset / 5) > displayString.length()) {
          charOffset = 0;
          loop_count++;
          scroll_pause = millis();
          if (millis() - next_text_time > 5000) getNextIndex();
        }
        scroll_time = millis();
        buildFrameBuffer(charOffset);
      }
    } else {
      loop_count++;
      if (millis() - next_text_time > 5000) {
        getNextIndex();
        loop_count = 0;
      }
      charOffset = 0;
    }
  }
}

And it all actually worked... beautiful scrolling.

Further Possible Optimisations

We're sending the text into this Arduino from another Arduino over SoftSerial. Why send text when I could send the framebuffer bits instead? I wonder if sending (string-length * 5 * 7 * 8) bits would be quicker than the initial string and calculations on the secondary Arduino's side? Should I test it? Maybe later...

Filed under: Arduino No Comments
4Dec/190

Atari Mouse – Replacing Microswitches

I'd recently acquired an Atari 520STFM (more about that later) and the package came with two mice. One is actually optical and has a switch that allows it to also be used on an Amiga, but it really hated the kitchen bench. I do remember, back in the day, that first-generation optical mice couldn't deal with glossy single-coloured surfaces. The other mouse was the original Atari 2-Button Ball-Mouse. It tracked nicely, but the buttons were as soggy as a wet week?

DSC02237

DSC02238 DSC02240 DSC02243

DSC02241

Open 'Er Up

Very easy to do... two screws up the top-end where the cable enters. Lift at the front, up near the buttons and pull forward to clear the latch at the bottom end.

DSC02245

DSC02248 DSC02250 DSC02251

From here, the microswitches are your PCB-mounted standard, easily available from Jaycar. I toddled off and purchased some of the exact-same replacements, but also two slightly-taller switches. The latter had a much clickier click. The standard replacements were also clickier than the existing switches, but I wanted moar.

DSC02254 DSC02258 DSC02260

A quick look at the circuit board underneath saw that only one side of both microswitches was in use. You can see, per four-hole-mounting of each switch at the top left and top-right of the board, that only the bottom left and bottom right pins are used respectively. The top two are bridged, but the 4th pin on each goes nowhere.

DSC02252

Just because things change over the decades, I quickly checked that my microswitches contacted on the same dimension...

DSC02256

A simple de-soldering saw the old switches out. With the solder removed from the holes in the PCB, I could trial the clearance with the taller switches...

DSC02262

The case was easily re-assembled to test...

DSC02266

But, as you can see, the case wouldn't even close. Testing the buttons, with the case half-ajar, saw them super clicky... maybe toooo-clicky. So I switched in the new same-sized switches and these were nice!

DSC02267

Although they're not that clicky when they're just in your fingertips in the shop, they're great once mounted in the mouse!

Testing...

All soldered up and plugged in, it was time to test it all out. Previously I had to mash the left-mouse-button a few times to get one click, so I was happy to see that a single click working perfectly!

DSC02278 DSC02279 DSC02280

DSC02281

DSC02269

DSC02271 DSC02272 DSC02274

DSC02275

And yeah, straight into Railroad Tycoon... damn that Grasshopper is a slow first train!

Filed under: Retro No Comments