How Assembly Language became my first programming language
The beauty of PIC microcontrollers
“Hello World!” — that is where we all start programming. At least, if you have a console. My entry point into this fascinating world was slightly different. In this hello world article, I want to share my first programming experience, which was literally in 0s and 1s.
I joined a science club in secondary school. There, I was immersed in synthesising ferrofluid — a liquid that is attracted to magnets. I managed to break a few beakers in the process. There was a student in the upper year who knew a lot about micro-controllers, and for our annual school festival, he decorated the entrance to the science club exhibition with LED lights which were programmed to flicker on and off in various patterns. What was more exciting is that, he just programmed a tiny chip called microcontrollers to make the whole thing work. That was what got me excited.
A microcontroller is a tiny rectangular chip with lots of tiny legs (pins). Despite this slightly disturbing description, they are one of the cutest intelligent things you can get for $2. It is a minuscule computer in the simplest form — no monitors, no keyboard inputs, and with a bare minimum amount of memory. It can store a set of instructions in its program memory, which is executed as soon as you connect the chip to a power supply. In addition, it has a small amount of data storage and temporary memory for calculation.
So how small is small? It has been around eight years since I played with these beauties so I had to look at the data sheet. My favourite microcontroller is PIC16F628A, since it has quite a lot of functions for a very cheap price. The answer is quite mind-blowing! It has a program memory of 2048 instructions (~4KB), 128 Bytes of data memory (EEPROM), and 224 Bytes of temporary memory (RAM). The vocabulary of the programming language for this PIC consists of only 35 words!
To put this into context, a modern laptop in 2020 might have 8GB of RAM and 512GB of flash memory, so roughly speaking, we are talking about 40,000,000 times difference in RAM and 100,000 times difference in flash memory.
So why would anyone want to play with PIC? For me, the pure attraction was that (1) it is so simple and minimalist, and you can understand its functionality back to front, (2) unlike ready-made computers, you can directly integrate microcontrollers into electric circuits and control devices such as LEDs, speakers, transistors and motors. This is possible because of those many pins sticking out from PICs — each pin can either measure a voltage input or emit a voltage output. These signals can then be amplified by transistors if higher voltage signals are required, e.g. by motors. Note also that PICs are very flexible and can be integrated into more complex circuits. You can add more components to it, such as external memory, an LCD display, or a Wi-Fi module to build a custom IoT device.
If you are thinking of starting your first ever IoT project, I would probably recommend something like Arduino or a Raspberry Pi. Arduino is a microcontroller kit with many useful external components, such as USB and Ethernet ports, with a specialised software for developing more complex IoT devices. Raspberry Pi is a proper computer with an operating system, on which you can run ordinary software, despite its cheap price of just $40! On the other hand, if you are interested in the bare-bones of computers, learn how programs are translated into 0s and 1s, and see the working results in real life, microcontrollers (e.g. PIC) is the way to go!
As a 14 year old, the cheapness of a single microcontroller was what excited me the most. I probably bought a hundred of these tiny beauties, which would have been impossible had it been more expensive.
The set of instructions are really straightforward. You read voltage inputs from a block of 8 pins by reading a byte-long binary value from a port. You output voltage from a block by setting a byte-long value to a port. You can perform calculations and store intermediate results in memory. You can only make changes to a single memory address at a time. If you want to perform operations that involve more than a single address, you have to use a working register (a byte-long temporary memory storage). Available operations are addition, subtraction, AND, IOR (Inclusive OR), XOR (Exclusive OR), copy and clear. Each command requires 1 or 2 clock cycles to be executed. There is an instruction called No-Op, which consumes 1 clock cycle without doing anything. And that is 80% of the language explained in a single paragraph.
The funkiest commands in this minimalist language are GOTO, CALL and RETURN. Yes, GOTO! Pretty much all programmers will be shocked to see any GOTO statements appearing in code nowadays, which is not supported in most modern programming languages anyway. In modern languages, we have the concept of functions and loops instead. WHILE and FOR loops help programs to be broken into self-contained meaningful parts without having the unpredictability of a GOTO statement, which can potentially jump to any part of the code and cause unexpected and difficult-to-debug errors. However, replacing GOTOs with WHILE and FOR also required an additional workaround command called BREAK.
So what about IF statements? All programs require some conditionals, especially if there is an external input to be considered, which is often the case with electronic devices with switches and sensors. In Assembly, there isn’t an explicit IF statement. Instead, there are things called flags, which are set either ON or OFF every time you make a calculation. The important ones are the Zero flag and the Carry flag, which tells you additional information about the operation you have just executed. The Zero flag is set when the result is 0, and a Carry flag is set when the calculation result exceeds the numerical range that can be represented in a byte. There are two handy instructions — INCFSZ and DECFSZ, which stands for Increment [Decrement] F, Skip if Zero. When the increment / decrement operation results in 0, the next instruction is replaced with a No-Op. It is common practice to put a GOTO statement in this line if you want a branch or a loop in your program.
; In the loop
DECFSZ REG1, F
; Out of the loop
All the commands, including the labels on the left and memory addresses with human readable names are translated into either memory addresses in 0s and 1s. The amazing thing is that each command has a unique zero-one string associated with it to make the whole program unambiguous, even when there are only 0s and 1s. These 0s and 1s are saved as a .HEX file. Thankfully, we can hand over that nasty task of translation to compilers, such as MPLAB X IDE (official software produced by Microchip, which manufactures PIC). These are powerful tools that also has debugging features such as stepping through the code and inspect the values of each memory address, register and port.
Once everything is translated into 0s and 1s, it is time to write into our PIC. You mount the PIC onto a programming board, connect it to a laptop, start up a software specific to your programming board, read your .HEX file into the software and start writing into the PIC flash memory. The programming board is probably the most expensive part. You can build such programming boards from scratch, but I was lazy so I bought a ready-made board. This specific one in the picture cost about $50.
And now for the most exciting part. The program is written into the PIC. You detach the PIC from the programming board. You place it in your circuitry (never solder your PIC directly onto your circuit board because the heat can break the chip. Use a socket instead). And you switch the power supply on. I must have short-circuited about five unfortunate PICs over the course of my experiments, and many more have lost legs from being plugged in and out of the socket repeatedly, so make sure you have a resister in place, and choose your sockets wisely. If all goes well, you will have an array of LEDs blinking at you with a warm “Hello World!”.
In my next article, I write about a real project I’ve worked on using PIC, with the accompanying assembly code and circuit diagram. It is about an auditory illusion called Shepard Tones. Hope you find it interesting!