Well it’s that time again, it’s the second day since I decided I should blog about my (mis) adventures is embedded hardware development.
Today’s adventure was implementing a few common functions without the use of stdlib or the math libraries.
Most people would argue against rewriting functions that already exist. Existing packages have been vetted, have had all their bugs worked out and hey they exist to be used right? Well unfortunately these existing libraries are designed to cover everyones use case and most (if not all) corner cases. The side effect of this is the libraries grow quite large and in the embedded environment we are very resource constrained. The HCS12 we’re using to develop our robot only has 12kb of ram for both the program and variables so you can see how loading a few 2-4kb libraries is not a good idea!
So the first problem we ran into was printf was not only big, but it was slow! Using printf in our move loops are so slow that it causes us to miss encoder segments (though part of the problem is not using interrupts, more on that later) which caused our count to be off every time we ran in debug mode. OK, so we ditched printf in favour of using the onboard LCD. This caused an unexpected issue for us, because most of our debug code was something like printf(“Left count is %d”, lCount); This caused two problems. The first was the lcd_puts command takes a pointer to the string we want to print, and here we are just outputting it. OK simple we just use sprintf and a buffer right? Well yes this worked, but of course it was still big and slow, so I opted to compose the string manually like char a[] = “Left count is “; leaving space to do a[10] = lCount and write it to the LCD.
Alas, this didn’t work for the fact that int 50 isn’t char 5 and char 0 it’s 3 in ascii so that didn’t work at all. Now we need a way to turn each part of the int into a char, here’s what I came up with.
void itoa(unsigned int number, char * out){
unsigned int result = 0;
int i = 0;
int NUM_DIGITS = 4; //The number of digits to try and print before we stop
//Convert the number to BCD
while (i < NUM_DIGITS) {
result <<= 4;
result |= number % 10;
number /= 10;
i++;
}
//Reset I
i =0;
//Shift 4 and mask to get individual characters
while(i < NUM_DIGITS){
//Mask the bottom 4 bits then add 48 because ascii 48 = 0
out[i] = (result & 0xF) + 48;
//Shift the number
result >>= 4;
//Increment I
i++;
}
};
So it looks kind of complicated to the untrained eye but the idea is simple. Say you have the number 1234. It’s composed of 1 2 3 and 4 as separate digits. In binary though it’s not 0001 0010 0011 0100 because that would be Binary Coded Decimal which is not how computers store data. So to make my life easy I converted it to BCD.
Then once we have BCD, we know each digit will be between 0 and 9 and thus only 4 bits. So we mask the value by anding the value with F (1111) so that we get the bottom 4 bits and the rest is 0s. This is the unsigned integer value of the number. We then add 48 to the value since 48 in ascii is the character for 0.
So this works, but the code has to problems. First off, as you can see that it always converts 4 digits. The first revision of this code would continue until result was 0, but unfortunately sometimes we are actually trying to convert a zero so that didn’t work. We realized all our values would be between 0 and 255 so for this application that wasn’t a big deal.
Secondly, this code can’t handle negative numbers, partially because we are dealing with the data as unsigned, and partially because it would have to insert a - symbol into the buffer before the value, neither of which is currently handled.
With those two issues in mind though, the code works great. As a side effect of using a char array buffer we can easily append values by offsetting the pointer to where we want to start in the string like itoa(value, &a[10]);
The other thing I had to implement was abs since we need an absolute value between 0 and 100 to drive the motors and some calculations would end up negative (more on that later) meaning go backwards.
So all in all I feel like this will be a long road but a fulfilling road and I can’t wait to see what’s next.
Until next time.