Overview

This is a scientific calculator I built that uses RPN notation. Features:

  • BCD number format with 1-255 places
  • Internal accuracy configurable from 6 to 32 decimal places
  • Two separate 200 level stacks
  • Optional scientific notation
  • Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod
  • 20x4 character LCD
  • 42 buttons

The source code is available at https://github.com/druzyek/RPN_Calculator

Software

The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.

On Windows:
gcc -o rpncalc.exe rpnmain_pc.c

On Linux:
gcc -lncurses -o rpncalc rpnmain_pc.c
Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple equation like:
X+=Y*Z-Q;
would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q));
To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:

//Before processing
void puts(unsigned char *msg)
{
     #pragma MM_VAR msg
     for (int i=0;msg[i];i++) putchar(msg[i]);
}

int main()
{     
     #pragma MM_OFFSET 200
     #pragma MM_DECLARE
     unsigned char text1[30];
     unsigned char text2[30];
     #pragma MM_END

     text1[0]='A';
     text1[1]=0;
     puts(text1);
}
//After processing
void puts(unsigned char *msg)
{
     #pragma MM_VAR msg
     for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i));
}

int main()
{     
     #pragma MM_OFFSET 200
     #pragma MM_DECLARE
     unsigned char *text1=(unsigned char*)200;
     unsigned char *text2=(unsigned char*)230;
     #pragma MM_END

     RAM_Write(text1+0,'A');
     RAM_Write(text1+1,0);
     puts(text1);
}
The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org...j/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:

The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.

When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.

Hardware

My design uses two MSP430G2553s connected to each other over UART. One of them (the master) reads the keyboard matrix, updates the LCD,...

Read more »