FORTHdsPIC gets Embedded and Walks Alone
Last year I embarked upon a project to write a FORTH language interpreter/compiler from scratch to run on a Microchip PIC24 or dsPIC microcontroller. So far most of the development has taken place on an RS Embedded Development Platform using Microchip PIM processor modules. By Version 0.4, FORTH programs could be compiled and run in the device RAM with an attached host PC providing terminal emulation. Now with Version 0.5 user programs can be transferred to the device non-volatile Flash memory and run without the host PC. In other words FORTHdsPIC can now be used in embedded applications.
It walks without wires attached....
Prior to Version 0.5 compiled FORTH code resided only in RAM and is lost when the power is turned off. On-chip programming of Flash memory, as opposed to ‘Flashing’ from a host PC running MPLAB IDE is necessary if stand-alone embedded applications are to be developed. The host PC is still required for creating the source code using a basic text editor such as Windows Notepad. In this case the host also runs a terminal emulator program such as Tera Term enabling direct interaction with FORTHdsPIC and the uploading of FORTH source code files to its interpreter/compiler. I pensioned off the old laptop I’d been using for this purpose and now use a Windows 7 desktop.
Now the RS EDP and Microchip Explorer 16 development boards are great for benchtop program work but you wouldn’t want to build either into a ‘production’ unit. A rather more compact format is called for; such as an Arduino, but based on a PIC24 or dsPIC. I located such a thing on Ebay from a company based in Hong Kong. The specification was perfect: takes a 28-pin DIP package dsPIC, with on-board regulators, on-board UART to USB bridge chip and the programming header for a Microchip PICkit debug/programmer. A close inspection revealed that the header for the PICkit was the wrong way round, the DC power socket was actually positive pin not as shown on the schematic and the power switch was inoperative. After all this was sorted out it worked perfectly. Well it was cheap and I just have to remember to plug the PICkit in upside down when a new version of the firmware needs to be programmed!
The Arduino-format dsPIC processor board
The new version introduces some new FORTH words including SETFLSH and FLASH. The latter took a lot of work as Microchip documentation can be very difficult to penetrate sometimes. SETFLSH is normally included at the start of a source code file to tell the compiler that the code is to run in Flash program memory and to set pointers accordingly. However, to simplify things the compiled code initially goes to the RAM as usual. It won’t run though, because code pointers have been set to the PSV RAM area in Flash program memory. The next step is to run FLASH. This copies the user vocabulary and code area in RAM to the corresponding area in Flash memory. The top-level word in a ‘Flash’ program must be called ‘MAIN’. Typing MAIN will start the program running. Press Reset and FORTHdsPIC checks to see if Flash memory has been programmed and then looks for MAIN. If neither condition exists, pointers are reset to RAM and the interpreter waits for terminal input. RAM is cleared on reset and Flash memory is erased by FLASH before programming takes place. One problem with the DIP chip is the shortage of I/O pins. Nearly all the pins have a large number of options set by special function registers and this version of the firmware has code to assign four Output Compare (PWM) pins and two pins for UART1.
I wanted it to control a small 4-servo humanoid robot as a test for the stand-alone capability. For some obscure reason the power supply regulators are only rated at 500mA, so I thought it would be pushing it to hang on the extra load of four servos. I then remembered that Parallax make an Arduino-compatible prototyping board (781-3027) for robotic type projects. At the opposite end of the design/build/documentation quality scale to the processor board, it provides the four servo headers required, a breadboard, 1A regulators and well thought-out switches that work. The processor board plugs into standard Shield connectors underneath the Parallax and with the addition of a 5 x AA battery box I had the hardware for a stand-alone (walk-alone when programmed) robot. The battery plugs into the processor board and supplies the regulators on both boards; each having its own power switches.
As I wrote at the outset, the FORTHdsPIC project provided an excuse to play around with assembler code and each successive version has not only seen new features added, but existing code improved in size and speed. This iterative approach to programming is not exactly the most efficient way of producing an application but it is good for familiarizing yourself with the architecture and instruction set of a new microcontroller; in this case a Microchip dsPIC33 part. Modern devices are packed with ADCs, serial bus controllers and specialist hardware such as PWM controllers and Quadrature Encoder interfaces for motor control. All this lot is driven by a program via Special Function Registers. The embedded software engineer needs to be a lot more familiar with the hardware both inside and outside the processor than a basic software programmer. During the course of this project I’ve created code modules using those basic instructions and addressing modes common to many other chips. Once the overall program was up and running I began investigating machine instructions and addressing modes peculiar to the dsPIC to see if machine code modules could be reduced in size and execution time.
Previous blog posts have presented some examples of this process. Here are a couple more examples of improved code, this time taking advantage of instructions linked to special hardware that speed up program loops by making them ‘zero-overhead’. The dsPIC has two such instructions: REPEAT n and DO <label>.
REPEAT just repeats the next instruction n+1 times. DO allows a block of instructions down to the labeled line to be executed n+1 times. See how REPEAT makes the FORTH word CMOVE copy a block of data from one area to another with minimal code:
CMOVE = Copy RAM block
CMOVE: mov [--w13],w0 ;Pop number of bytes
mov [--w13],w1 ;Pop destination address
mov [--w13],w2 ;Pop source address
mov.b [w2++],[w1++] ;Copy data bytes
Here's an example of how DO replaces a number of instructions including ‘Increment counter and test if final count reached’, etc. The loop counter is held in a special register and the test for end count is done by hardware; no loop control instructions are involved after the initial DO statement hence ‘zero-overhead’. This type of instruction makes for accurate timing when the processor is programmed to generate repetitive waveforms on port pins or sample an input at precise intervals.
UM/MOD = 32 / 16 to 32-bit quotient Unsigned Divide
MSM: mov [--w13],w0 ;Pop divisor
mov [--w13],w2 ;Pop MS dividend
mov [--w13],w1 ;Pop LS dividend
clr w4 ;Clear MS Remainder
clr w3 ;Clear LS Remainder
do #31,MSM1 ;Loop 32 times
sl w1,w1 ;Shift MS bit of dividend into..
rlc w3,w3 ;..LS bit of remainder
sub w3,w0,w5 ;Trial subtraction of divisor
bra nc,MSM2 ;Test Borrow flag
mov w6,w4 ;Update partial remainder
MSM2: rlc w7,w7 ;Shift result bit into quotient
MSM1: rlc w8,w8
mov w3,[w13++] ;Push LS Remainder
mov w7,[w13++] ;Push LS Quotient
mov w8,[w13++] ;Push MS Quotient
Now that FORTHdsPIC has evolved to the point where it can be built into practical embedded systems, I’ll produce some better documentation including a proper user guide. In the meantime I want to try out a Microchip Microstick (749-6445) as an embedded controller; it’s a small DIP module that plugs nicely into the breadboard of the Parallax prototyping board…
If you're stuck for something to do, follow my posts on Twitter. I link to interesting new electronics components and development kits (some of them available from my employer!) and retweet posts I spot about robot, space exploration and other issues.
CommentsAdd a comment
"An achievement certainly, but frankly I'd by far rather program in PIC Assembler code than Forth! About time someone finally drove a stake into the heart of that truly awful language! Sorry to sound bitter, but Forth very nearly drove me to a nervous breakdown in the mid 80's!"
Forth always did prevoke extreme reactions! :-) I find that the biggest problem is structuring the source code so that it can be understood by others or even by myself months later. The programmer must keep a mental image of the parameter stack as they work through it and this can be difficult if "colon" defintions of new words are long and rambling with few comments. It also helps to minimize the use of stack-manipulation words such as SWAP, ROT and PICK by arranging the code so that parameters are pushed on the stack in the right order to be popped off, with clever use of Duplicate (DUP) to make a copy of an item to be used again later on in the same definition. Personally I find the 'optimization' process of re-arranging things to make SWAPs and ROTs redundant quite satisfying, as is examining the FORTHdsPIC code itself seeking ways to improve the assembler code. The best bit is defining a new word in Forth, realising it would be useful as a 'core' definition and then re-writing it in assembler for maximum speed. I recently did this for the code that fetches the address in RAM of a particular item in an array. I know I need to get out more and locate a life!
An achievement certainly, but frankly I'd by far rather program in PIC Assembler code than Forth! About time someone finally drove a stake into the heart of that truly awful language! Sorry to sound bitter, but Forth very nearly drove me to a nervous breakdown in the mid 80's!