Qball's Weblog

Turning it a notch down, from 1024MByte to only 128byte of memory

Tags General 

(This is a blog post I wanted to make a little while back, but never got around typing it, so here it is)

In modern days when you are coding you can almost say that you have unlimited memory and speed available. Taking a look at my system monitor tells me that I currently used 48% of my main memory, and have only 510 Mbyte left. My cpu itself has 2Mbyte available to play with, works on 3 instructions every clock cycle, and has predictors on board to predict the best predictor.
You don’t need to think really hard on how to write stuff, in what order to put the calculations. Even after you compile it and it’s running on your cpu, your system is busy optimizing it, reshuffling to make it faster, predicting what the next if() statement is going todo.

So from time to time it’s nice to take a step back, and get your hands dirty. I’ve been playing with a atmel tiny 2313.
This atmel has 2048byte program memory, 128byte sdram and 32 registers (of 8 bits) and is only 8bit. It can run at the shocking speed of 20mhz. doing 20million instructions a second. It doesn’t have predictor predictors, it doesn’t even have the predictor.

But, I am not going to get my hands really dirty, mostly because I don’t have the time (and I don’t feel like it) to code it in assembler. Instead I wrote it in C and used the gcc-avr compiler to get something I can run on it.

You might wonder what you can do in 2048bytes on a microcontroller, I can tell you, quiet allot. The atmel avr serie have extra hardware to help you. You have input/output pins, a uart modules (for f.e. serial communication with your pc’s), several timers, analog comparator, pwm’s and more.

So what did I build then? something very simple. (but still entertaining to write)
A time-clock that can turn on/off several devices (yes I know you can buy that in the store, but that aint no fun).

If you would write this for your normal pc, you can just code it, no problems and no worries. A way I can see somebody implementing it is:

typdef struct {
int enabled;
int state;
int output;
int time;
int daymask;

On your pc this would take: 532bit = 20 bytes. In Pc terms this is (almost) nothing.
Same code on the atmel would take (time being 16bit, because 60
24 > 2^8): 48bit = 6 byte.

But we don’t have very much memory, so we need to store the above data more efficient (the more efficient, the more alarms we can add).
So lets see how many bits we need:
Enabled:    1bit
State:        1bit (either you turn it on, or off)
Output:        2bit (4 outputs)
I’ve choose to split the time in hours and minutes, this is just a choice.
Time hour:    5bit (24 hours)
Time minute:    6bit (60 minutes)
Daymask:    7bit (I want every combination of of weekdays possible)

So for every alarm event we need 22 bits, this is 3 bytes.
Off course you need to take care you set the right bit in the right byte, but that is not so hard. Defines and macros can help allot here.
A quick example:
#define BIT_ENABLE 254  (this is 10000000)
To set the enable bit to 0
a &= (~BIT_ENABLE); (~BIT_ENABLE is gelijk aan 01111111)
Or set the bit to 1

We also need a clock to keep track of the time.
So we look around to what we have on board we can use for this.
I’ve used the 16bit counter in the atmel, I can make this give me a interrupt when it matches another value B, and I can also make the counter run at different speeds.
So I used an 8mhz crystal, so the counter counts to 8000000 in 1 second (this is bigger then my counter), so I let my counter run at 1/256 of the clock speed, so it counts to 31250 in 1 second.
I’ve put this value in B, now after one second I get an interrupt from the counter, first thing I do in this interrupt is set my counter back to 0, so after 1 second I get another interrupt.
This ain’t perfect, because between calling the interrupt and me setting the counter back to 0, some cycles are lost, so the next one isn’t exactly 1 second later. The question is, do we care?
Say we loose 5 cycles between the interrupt and setting the counter to 0, this means we get behind 62.7 uS every second.
So after 1.600.000 seconds we lost 1 second, this is 1 second every 18 1/2 days, I can live with that (better then the clock in my mac mini). If I can’t I could check the documentation, calculate how many cycles it takes to enter the interrupt and setting the counter, and compensate for that when setting the counter, this is one of the fun things about coding on a micro-controller, you are in control about what when happens.

There is allot more to tell, but I assume most of you already know this, and are very bored now. So I will quit for now.
When I have some more time, I’m going to spend some time optimizing my program so it uses less program space.
At the moment it uses 1998 of the 2048 bytes, and I want to add a menu system to the display so you can set the time and alarms on the device itself.
If I don’t get to much complaints I might blog about this.