PicAxe 28X1 memory tricks
The picaxe 28X1 has some very cool memory features that can be used to free up program space or to give your robot a more convenient user interface. This post describes some of the things I’ve come up with during the last couple of weeks programming my Edward bot.
Most of the time a program begins with a long list of symbol statements defining constants and renaming variables. After a while this gets a bit messy (in my case anyway) because I lose track of which variables are being used by other subroutines and shouldn’t change during a gosub.
The first thing to do is to divide the available variables into two parts. The 28X1 has 28 byte variables b0-b27 or 14 word variables w0-w13 that overlap. So b0 and b1 use the same memory as w0.
Lets reserve the first couple of bytes for use inside subroutines. So when you’re writing a subroutine, you can always be sure that b0-b7 or w0-w3 can be used without interfering with other routines. Or b0-b11 if you prefer.
This also means that if you call another subroutine from your routine, those bytes may be overwritten. But we can also stay with these variables to pass information to and from subroutines. All the other vars should be named by using the symbol command.
If you’re experimenting with a small routine you want to use in a larger program and stick to the first 8 bytes (or 12 bytes, whatever the standard needs to be) you can copy the code into the new program without having to reshuffle variables or strange behaviour due to a var that is unkowingly overwritten by a subroutine.
Another returning pain in my previous programs was the init routine. Thats the part of the program where you load all the default values into the named variables and preset the output pins and stuff like that.
When the program gets larger and more variables are used, the init routine grows with it taking up more and more space that is only used when the robot is starting.
To free up that space, you can use a very nifty feature of the 28X1: the scratchpad. It is a block of 128 bytes that can be accessed by a pointer. It can be used as a buffer during serial communication or as a stack, but you can also use it to shrink the init routine and get more variables.
The scratchpad kan be accessed with the ptr predefined variable. This var holds a number between 0 and 127 and points to one of the locations in the scratchpad. To make it point to the last byte simply use
let ptr = 127
and to read the byte into b0 you use
let b0 = @ptr
Instead of keeping data like range or servo1position in one of the 28 variables, you can store them in the scratchpad.
Lets say we use the first scratchpad location for servo1position. We assign that name to the scratchpad addres instead of a variable and read it from the scratchpad. The following example adds 5 to the servoposition
symbol servo1position = 0
let ptr = servo1position
@ptr = @ptr + 5
Now this may seem like a waste because it uses 2 statements instead of one, which may be true in some cases but there are other things to consider.
The 28X1 EEPROM
To trim down the init routine, we’re going to use the EEPROM memory on the 28X1 chip. This part of the chip is
128 256 bytes, just like the scratchpad and can be accessed using the read and write commands. To make things more interesting, you can write to the eeprom during the program upload with the EEPROM command.
The cool thing about this statement, is that it uses up no program memory on the chip (like the symbol statement). It just tells the PC software to upload those values into the EEPROM along with the program. Our init routine will now look this.
symbol servo1position = 0 ‘define address 0
EEPROM 0,(150) ‘set the default value for servo1position
for b0=0 to 127
ptr=b0 ‘set the scratchpad pointer
read b0,b1 ‘read byte b1 from location b0
@ptr=b1 ‘write to the scratchpad
This code simply copies all 128 bytes from the eeprom to the scratchpad. Thats not a lot of code to load 128 default values. Comparable to the eeprom command, you could use table, which uses the same syntax, but stores the data in the program memory.
If you're keen on shorter writing style you can also use get and put. These commands use the same syntax as read and write, but are used to access the scratchpad without changing the ptr variable. In short style our loop now looks like this:
for b0=0 to 127
read b0,b1 ‘read byte b1 from location b0
put b0,b1 ‘write to the scratchpad
Next up: I2C
This setup still seems like a bit of a waste of space. It uses up 128 bytes of rom and 128 bytes of scratchpad area to hold 128 values. So why use the scratchpad instead of variables if you only have something like 16 variables in your program? Why not simply use the EEPROM?
1) to allow other devices to read and write those values
2) to allow you to change those values without resetting or reloading the program
Some picaxe chips support I2C. I’m not going to explain in depth how I2C works, but there are lots of docs (like axe110_i2c.pdf) out there that explain it quite well. To put it short: I2C is a serial bus over which chips can talk to each other. You can use it to communicate with an LCD or an EEPROM or with another picaxe. One device on the bus is the master and all the others are slaves. All the devices are connected with the same 2 wires.
The PICAXE 28X1 and the 40X1 are currently the only chips in the family that natively support being an I2C slave. If you set up your 28X1 to be an I2C slave, all communication with its master is done through the scratchpad. The master device simpy gets read and write access to the scratchpad of your picaxe.
This comes in very handy, because we just stuffed all the parameters for the robot in the scratchpad. An I2C master can, for example, simply instruct your robot to increase speed by changing the corresponding byte in the scratchpad.
Now that those values are stored in the EEPROM, we can change those values without uploading the entire program again. If your robot has a display and a few buttons or pots, you could write a program to edit those values. Or you could use a simple program using the serial programming cable the edit those values.
There is a small downside to storing your defaults in the picaxe rom though. Every time you upload your program, all those values get overwritten. There is nothing wrong with that, unless you’ve used your display + buttons or your serial cable to optimize those values. There is a simple solution for that.
If you use one of those nifty little EEPROM chips you can store those 128 values in there. Hook up an 8 legged EEPROM chip like the 24LC256 and voila: your settings are safe. If you don’t want to build your own board , the PICAXE 28/40 prototype board comes with I2C connections on the board and it has 1 socket for an EEPROM chip.
The init routine now looks something like this:
HI2CSETUP I2CMASTER, %10100000, i2cfast, i2cword
for w0=0 to 127
hi2cin w0,(b2) ‘read a byte from the EEPROM into b2
ptr=w0 ‘set the scratchpad pointer
@ptr=b2 ‘write the byte
But as CTC allready noticed. You need to load the values in the EEPROM first. To do that you can write a program that fills up the rom, but some of those eeproms are 32K or more which is 8 times as big as the entire program space of the PCIAXE 28X1. Or you could buy a USB-to-I2C interface and write a program on your PC, but I prefer to use that serial programming cable. I’ve written a small program (less than 500 bytes) that enables you to edit the values in the external EEPROM.
I attached the source for this program to this post. What it does is provide a very basic interface over the serial port that enables you to view parts of the EEPROM and change values in there. Here’s how to set it up:
1: Upload the program to your picaxe
2: close the picaxe program on your PC to free up the serial port
3: open a terminal emulator like hyperterm and set it to 4800 baud
4: press any key, wait for the welcome message and you’re in.
Commands are entered in sets of values separated by a newline (char 13). The values are separated by a space or comma. here is the syntax
commandletter = one of these:
d -> display a block of 128 bytes
a -> enter bytes in text format (use \n) for newline.
n -> enter values in numeric decimal format.
address = the address you want to start. It should be provided with every command.
value = a decimal number (if you’re using the n command) or typed text (using the a command). The d command has no values as it just displays the contents of the EEPROM.
Note that if you enter a value larger than 255 (i.e. a word variable) it gets written as 2 bytes.
To enter a piece of text starting at address 1024 type the following:
To enter the numbers 150 and 30000 starting at address 256:
to display the first 128 bytes in the EEPROM:
If you want to embed this program in your robot, you have to put the robot in terminal mode, or whatever you want to call it, and implement a quit command. An easy way to do this if you have no spare buttons is to add a routine for your bumper switch so that if you hold the bumper switch for 5 seconds, it enters the terminal mode.
Well that’s it. Thats about the sum of the programming ideas I got during the last few weeks of programming PICAXE Basic. I hope you will find this usefull, because you’ve had to read a lot of text without pictures to get here!