Languages, Assemble!
Look what I found in my closet:
This is my old Motorola 68HC11 microcontroller board. Here’s a close up photo of the microcontroller itself:
For those who aren’t familiar with these terms, a microcontroller is basically a computer on a chip. They are often very tiny and low powered, and are ubiquitous whether you realize it or not.
This is what I learned assembly language and machine language on in 2001. Machine language is basically the language of the CPU. Everything that a computer runs is in machine language. All other programming languages are compiled or interpreted down to machine code. Assembly language is a bare bones one-to-one mapping from machine codes to symbols that are barely human-readable.
I had encountered assembly language before 2001 in 3D game code, but I didn’t totally understand it, especially registers.
An Aside on 3D Game Programming
The reason I was reading 3D game code: After playing Wolfenstein 3D in the 1990s, I wanted to make similar games. So I got a book about ray casting engines. Ray casting was a method of generating the pseudo 3D graphics of early “3D” games; it was used because it was fast enough to run on those slow processors we had back then (and the GPU race had only just begun). There were a lot of tricks involved, like using trig look-up tables and sections of assembly code.
The reason they used assembly language in middle of high level code for games is that it’s an old-fashioned optimization trick—make the slowest part of the code go faster by writing it in a lower-level language. The premise is that the compiler, for instance of C++, will not make code as fast as your own version in assembly language. Compilers are very good nowadays, so this is often not worth the effort.
Unfortunately, by the time I was learning about ray casting in the late 1990s, the gaming world had already evoloved beyond that and started using BSP trees and polygonal 3D objects. I did start playing with BSP trees in 2001 by making a little Java 3D program that used BSP trees to lay out the walls (it was called the Garbage Collector, which is a joke).
And then in 2002 I was playing with polygonal 3D rendering by making a multiplayer (client-server TCP) 3D boat shooting game in C++ using Direct3D (part of DirectX) for graphics rendering.
It didn’t have much of an engine—if I recall correctly, I did a minimal amount of culling and then threw all the objects at Direct3D to render. I was also trying to make my own design of an octree based engine but it never amounted to much.
Assembly Language Education
Education-wise, I suspect that learning assembly and machine language for a relatively simple architecture like an 8-bit microcontroller is much better than learning on a more complicated architecture like Intel x86. I tutored students at NHTI for 68HC11 and Northeastern University for x86. I found that either way, assembly language was quite difficult for a lot of students to learn—and even comprehend. But it was far worse with x86.
And, with an embedded platform, the labs can be set up so you actually make lights blink and motors move. That’s way more awesome then just seeing some debug text print out on a console. It also seems to force people into the mindset of understanding what layers they are dealing with in computer architecture better and isolate their development realm (e.g. writing code in a text editor and cross-compiling) from the world of the computer processor loading the machine code and executing it.
Making Motors Move
If you want to see what the 68HC11 assembly code looks like, here you go:
* CP108 Digital Devices
* designed for M68HC11E9 EVBU
*
* Program: 2-Stage Falling-Edge J-K Counter Emulator
* Programmer: Sam Kenyon
* Desc: States are set to be a Grey Code Generator
* Revisions:
*********************************
* Data Segment
*********************************
TIC1 EQU $1010
TCTL2 EQU $1021
TMSK1 EQU $1022
TFLG1 EQU $1023
PVIC1 EQU $00E8
APORT EQU $1000 * greycode output port
PACTL EQU $1026 * Port A Control
ORG $170
QBA0 FCB %00110000 * states (QB, QA, QB_NOT, QA_NOT)
QBA1 FCB %01100000 * (buffered to be one byte)
QBA2 FCB %11000000
QBA3 FCB %10010000
PSTATE FDB $0170
*********************************
* Code Segment
*********************************
ORG $100
INIT LDS #$0041
LDAA #$7E * JMP opcode
STAA PVIC1 * IC1 pseudo vector byte 1
LDX #ISR1 * Address of IC1 service routine
STX PVIC1+1 * IC1 pseudo vector bytes 2,3
LDAA #$80
STAA PACTL * PA7 = output (6,5,4 ARE ALSO OUTPUT)
LDAA #$20
STAA TCTL2 * falling edges trigger mode
LDAA #$04
STAA TMSK1
STAA TFLG1 * clear all flags (we're using bit 2(IC1F))
CLI * enable interrupts
DO1 BRA DO1 * loop forever
*********************************
* Subroutine: ISR1
* Desc: X acts as a static variable PSTATE
* Size: ? bytes
* Stack Size: bytes
*********************************
ISR1 LDX PSTATE
CPX #$174
BNE NONEXT
LDX #QBA0 * next 4-state cyclE
STX PSTATE
NONEXT LDAA 0,X * send output to port A
STAA APORT * bits 7-4 (QB, QA, QB_NOT, QA_NOT)
INC PSTATE+1
LDAA #$04
STAA TFLG1 * clear all flags (we're using bit 2(IC1F))
RTI * Return from service routine
I wrote this code for for an exercise to control a stepper motor with gray code. The motor was small and low-power enough to be run directly off of an HC11 output. The program was a J-K flip-flop circuit emulator (it could actually emulate any 4-state counter if one modified the states in the data segment). It took an input from a function generator to define the frequency which determined the speed of the motor.
Making Motors Move with PWM
One of the most popular ways to control motors and other analog devices is with PWM (Pulse Width Modulation). Here is an example of PWM motor control that I wrote in 68HC11 assembly. Skip to the next section for my explanation of PWM.
* CP112-1B (M68HC11E9) MACHINE & ASM LANGUAGE LAB 9
* Program: PWM Motor Control
* Programmer: Sam Kenyon
* Desc: Uses the TOF and OC2 interrupts to control output
* line A7 to provide PWM (Pulse Width Modulation)
* control of a DC motor.
* Revisions:
*********************************
* Data Segment
*********************************
* Constants:
TMSK1 EQU $1022
TMSK2 EQU $1024
TFLG1 EQU $1023
TFLG2 EQU $1025
TOC2 EQU $1018 * Timer Output Compare 2 Register Pair (2 bytes)
TCTL1 EQU $1020
APORT EQU $1000 * output port
EPORT EQU $100A * input port
PACTL EQU $1026 * Port A Control
PVTOF EQU $00D0 * Pseudo Vector address
PVOC2 EQU $00DC * Pseudo Vector address
* Variables:
ORG $180
Toggle FDB $7FFF
*********************************
* Code Segment
*********************************
ORG $B600
INIT LDS #$0041
* Pseudo Vectors (3 bytes):
LDAA #$7E * JMP opcode
STAA PVTOF * TOF PV byte 1
STAA PVOC2 * OC2 PV byte 1
LDX #TOF_ISR
STX PVTOF+1 * TOF PV bytes 2,3
LDX #OC2_ISR
STX PVOC2+1 * OC2 PV bytes 2,3
CLR TCTL1 * timer disconnected from output
LDAA #$40
STAA TMSK1 * OC2 enable
LDAA #$80
STAA TMSK2 * overflow enable
STAA PACTL * PA7 = output
CLI * enable interrupts
DO BRA DO
*********************************
* Subroutine: TOF_ISR
* Desc: Timer Overflow ISR
* Size: 23 bytes
* Stack Size: 0 bytes
*********************************
TOF_ISR LDAA #$80
STAA APORT * high ouput
LDD Toggle
LDAA EPORT * input new duty cycle
STD Toggle * ->Toggle_MSB
STD TOC2 * new duty cycle affects how often OC2 interrupts
LDAA #$80
STAA TFLG2 * reset flag
RTI * return from service routine
*********************************
* Subroutine: OC2_ISR
* Desc: Output Compare 2 ISR
* Size: 9 bytes
* Stack Size: 0 bytes
*********************************
OC2_ISR CLR APORT * low output
LDAA #$40
STAA TFLG1 * reset flag
RTI * return from service routine
What is PWM?
For those who want a simple explanation of PWM: Imagine flipping a light switch on and off a thousand times per second. But sometimes you leave it on longer or off longer. For example, you have it on 700 times but off only 300 times in that one second. The overall effect is that the light is on at 70% brightness during that time.
PWM is like that. Imagine hooking your switch to a motor. If you switch it with 70% ONs the motor will spin at 70% full speed.
The other key concept is that PWM is typically used as an interface between the digital world of the computer and the analog worlds of motors. A computer processor deals with ones and zeroes—ONs and OFFs. There are outputs on computers for instance on a microcontroller like the 68HC11 in this article. The ones and zeroes are represented on those outputs with HIGH and LOW voltages. All the other devices connected will use the same standard for what is HIGH and what is LOW, e.g. 5 volts as HIGH and 0.0 volts as LOW. (That’s a bit simplified but I won’t bore you with other details right now).
So the problem is how to get those HIGHs and LOWs to control a motor, which just wants voltage. If it’s a tiny motor it can run directly off of the logic voltage (e.g. 5 V), but that’s not generally a good option. In fact, you usually want the motor power lines isolated from the computer lines.
So PWM (remember, switching really fast) is used. The computer outputs a square wave (HIGHs and LOWs) to a switch, which switches the power from another source (e.g. a battery) into the motor. The higher the percentage of ones (HIGHs) coming out of the computer, the faster the motor goes. Obviously if there is something heavy attached to the motor rotor, it won’t actually go faster, but it will try.
Why was this Exciting?
This was really awesome when I learned about it (and the aforementioned gray code exercise), because up until then my programming was not able to interface to motors. I could make a motor go by connecting a battery directly to the leads, and even add in a mechanical switch, but a single speed motor is not fun for very long.
Once you start learning how to get motors spinning from computer code, and also get inputs from sensors into the code, you start realizing that basic hobbyist robotics isn’t that difficult…
Of course, if you can’t code, then I guess you will be stuck doing the typical undergraduate mechanical engineering student trick of touching a wire from a battery directly to a motor in the contraption they just screwed together and watching the chaos unfold as it flings itself around the lab until they let go of the wire.
Code
Image Credits:
- Samuel H. Kenyon
- Samuel H. Kenyon
- http://www.schmoozd.com/2012/05/10/happy-birthday-wolfenstein-3-d/
- Samuel H. Kenyon
- Samuel H. Kenyon
- Samuel H. Kenyon
- http://www.green-house-cleaning-tips.com/2012/05/some-great-energy-saving-tips-you-should-know














[...] Visit link: SynapticNulship » Blog Archive » Languages, Assemble! [...]