Let's Make Robots!

PicAxe 28X1 memory tricks

Tips on EEPROMS, i2c, scratchpad and variables
EepromWriter.BAS2.45 KB

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.


Variable standards

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.


The scratchpad 

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. 




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.


EEPROM  {location},(data,data...) 


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

    next b0


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 b0



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. 


Serial Tweaking

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

        next w0



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:

a,1024,hello world!<ENTER>


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!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
For some implementation this (in VERY hasty made code) see the example here: http://letsmakerobots.com/node/2637

Nice to see someone use the 28X eeprom. Did you know the symbol commands are processed before the eeprom commands?

Code like this will work just fine:

symbol headpos = 51

symbol headmiddle = 152 

eeprom headpos,(headmiddle) 

I found one way to help keep your symbols tidy is to place the symbol commands for constants used in a subroutine at the start of the subroutine. For example with my subroutine to access Juniors additional ADC, I've assigned constants like CS (chip select) and EOC (end of conversion) pin numbers at the start of the subroutine. The Editor doesn't care where in the program they are listed and since this is the only subroutine using those constants it is also easier to write/debug the code.


I allways asumed the symbol statements were pre-compile directives and were just replaced bij their values. I didn't know that if you put a symbol statement in a subroutine, the symbol becomes scoped.

For example: if you use

getrange: {

symbol range=w0



the word range is unknown / undefined in other routines. 


I just thought it wasn't necessary to have a huge list all at the start.

P.S. I noticed in your code the use of { }. I can't find mention of them in manual 2. What are they specifying?


:{  looks like the man on a packet of pringles chips

I was amazed to discover the scoping of the symbols, because I don't think the variables are scoped. All variables are (i think) processor registers meaning that they are global. So if i define symbol leftspeed=b0 inside a subroutine, I can only use speed in the sub, but if I change its value inside the sub and return to the main program, b0 will have changed globally.

The { and } do not alter the meaning of the program. They're not used for marking code blocks the way C and Java use it, but in the picaxe program editor, the blocks marked with { and } get a [-] to the left. Click it and the code collapses: Very handy when you want to keep your screen organized. 

I didn't know this and I've read through the manuals several times. What happened to the good old days when the manual was a book with at least 300 pages and covered every nuance of a software package in detail?

Erh.. if you have read the manual several times, you should have read the very first pages, like page 10 "Variables - General", where this is quite well described IMHO :P

Actually it is "the first thing" in the manual, as close as you can get to "First page in the manual".. get it? It's there, haha! 

I used to buy computer games on the inverse weight principal.  The lighter the package, I would assume, the better the software.

The idea is, if the software is REALLY good, you don't need a manual of 300 pages to play the game :D 

RTFM! Wait I guess that wouldn't have helped...