Hmm, yes, clearly it wasn’t going to be as easy as all that.
While creating the PCB layout for the SmartParallel serial to parallel printer interface, I shuffled a few of the pin assignments on the Atmel ATMEGA328PB microcontroller. The reason was simply to make routing a tad easier. But I had a nagging feeling that this might cause a few software issues. And yeah, I was right.
What I had in mind was that the new layout would screw up my careful grouping of related pins on to specific ports. Let me explain.
Microcontrollers typically arrange the GPIO pins into groups. The ATMEGA328PB, for example, has four ports – B with eight pins, C with seven pins, D with eight pins and E with four pins.
Each of these ports has a data direction register (eg, DDRB for port B) and two registers for setting an output signal – eg, PORTB – or reading an input value – eg, PINB.
To set a value of an output pin high – let’s say PB2 (pin 2 of port B), you use something along the lines of:
PORTB |= (1 << PB2);
The reason it’s handy to group related signals into a single port is that you can use one register for all of them. For instance, I have the three signals that control a shift register all on PORTB. That means I can use a single register – DDRB – to manage the direction (input or output) of these pins. And when setting the state of an output pin, or reading the state of an input pin, I can use the PORTB and PINB registers for all of them.
In my code, I can use defines such as:
#define SHIFTREG_DDR DDRB
#define SHIFTREG_REG PORTB
The subsequent coding becomes easier. I can write shift register functions where the registers are always SHIFTREG_DDR or SHIFTREG_REG regardless of which individual pin is involved. It means passing fewer values around – for example, to functions. If I create a function for the shift register, I can take the input and output registers for granted.
Not too bad
So, when I created the original schematic for the SmartParallel board, I grouped pins in this way. But then that got messed up a little when I shuffled a few during the PCB layout. It turns out that the results weren’t too disastrous, though.
There are several input signals coming from the printer – Error, Busy, Paper End, Select and ACK. It turns out I’d mostly shuffled these from port D to port E – all except for ACK which, luckily, I’d left where it was.
The reason that was lucky is because ACK is used to trigger an interrupt on the microcontroller (INT0 on pin PD2), so it needs to be on that specific pin. The ACK signal from the printer is a pulse – typically lasting around 5µs on the Epson MX-80. So it’s not a signal the microcontroller needs to read, as such, but just respond to. So, while I do set up the I/O pin as an input (and even that’s not strictly necessary), I don’t need to mess with input or output registers for this signal. So having ACK on a separate port from the other inputs isn’t a big deal.
But… another of those inputs – Error – is also meant to trigger an interrupt. I’d originally had it on pin PD3, also known as INT1. Having forgotten about the interrupt thing, during the PCB layout I’d moved this signal to pin PE0. Now, I could conceivably leave it there and set up that pin as a ‘pin change interrupt’. But it’s much better to use INT1.
The reason for this is that pin change interrupts fire whenever the state of the pin changes – regardless of whether it’s from low to high or high to low. I specifically want to cause an interrupt only when the Error signal goes low (it’s active low). My current code sets up both INT0 and INT1 to trigger on falling edges, thus:
EICRA = 0b00001010; // INT0 & INT1 to trigger on falling edge
EIMSK |= ((1 << INT0) | (1 << INT1)); // enable INT0 & INT1
EIFR |= ((1 << INTF0) | (1 << INTF1)); // clear the interrupt flags
sei(); // enable global interrupts
What’s currently occupying PD3 is the serial port’s RTS signal. But that got me thinking – do I really want that?
I do have plans for the CTS line, but haven’t been able to think of any use for RTS. I could ditch it easily (removing a track from the PCB in the process) and re-route the Error signal back to PD3.
The thought of doing that re-routing was a tad daunting. In the end, it turned out to be trivial. I deleted the track for RTS and the Error signal just moved along two pins, from pin 3 to pin 1. The change in the routing was so minute it’s not even worth showing.
Then the OCD kicked in. The serial port connector – a row of six DuPont-style pins – was left with one unconnected pin. That’s not a problem; it just gives me an itch. I could reduce the row to five pins, but that wouldn’t match the six connectors on an FTDI cable. That would open the way to error and confusion, as well as giving me a bigger itch.
Also, it left one GPIO pin on the microcontroller going begging. That seemed sad.
And lo! By some miracle it turned out that the newly vacant microcontroller pin was just a short and easy route from the currently useless header pin. A few seconds in KiCad and the itch had gone. RTS is still there should I want it.