Showing posts with label External RAM Preprocessor. Show all posts
Showing posts with label External RAM Preprocessor. Show all posts

Sunday, December 27, 2015

Makevention 2015


Makevention went really well! I was able to show everything I have been working on, although I didn't have time to finish everything. I made a poster board explaining some concepts related to calculators like RPN, BCD, and CORDIC on the left side with information about my RPN Scientific Calculator on the right. I also had a print out of how my external RAM preprocessor works. A few of the people who came by my table were programmers and understood the solution.

On the table itself I had different calculators and projects laid out in roughly chronological order. The first was an MK-61 RPN calculator I added to my collection over 10 years ago. Of course I didn't make it but I wanted to show an example of an RPN calculator and what inspired me to first make calculators. When I first got the calculator out to test it, it didn't show anything on the screen and I was afraid it was broken. I took it completely apart and looked for burst capacitors. I also brushed off the battery contacts since they didn't look very clean. When I turned it on, it still didn't show anything but when I pressed a number it showed up! It seems the calculator just doesn't display anything when first turned on, instead of the zero I was expecting. Somehow I had forgotten that in the 10 years its been since I last used it.

The Casio Algebra FX 2.0 was included to show the RPN stack program I wrote for it in 2002 or so. That program was designed to make the calculator function more like the HP-48GX I had at the time which I admired so much. First, I had to buy a calculator to replace the Algebra FX 2.0+ I sold in college. Loading the program onto the calculator took quite a while to figure out! In 2002 I used a serial cable, which I think was an SB-87, to load programs without any trouble. Nowadays I don't have a serial port, so I bought an FA-124 USB cable. It turns out that this cable doesn't work on Windows 7. I also couldn't get it to work correctly under Windows XP running in an emulator. Next I tried a lot of different third-party software and finally got the program to load using FlashCOM 1.4v and an FTDI cable. For the link port I bought a 2.5mm plug that I could easily wire to the FTDI cable. After that, the program I loaded kept crashing and I thought the transfer was corrupt. After more fiddling I got Turbo C up and running in an emulator and compiled the program source myself, which produced a fairly stable program that was good enough for exhibiting, although it did crash a couple times during Makevention. Someday I would like to fix the program up and make it more stable.

The next thing I showed was a launchpad hooked up to a breadboard with a button and blinking LED to show how easy it is to get started with electronics. The next step was my binary LED calculator. I soldered a coin battery holder on to the board. After that I showed the RPN Scientific Calculator and explained that it was not too difficult to move to this stage after I managed to finish the binary LED calculator. The Programmable RPN Scientific Calculator was next. I printed temporary a colored keypad on poster paper which I taped to it, but it did not work very well. Unexpectedly, the calculator showed random keypresses when I put my hand near it. All the keys were in the same column on the keyboard, which makes me thing there is a bad connection in that row of the key matrix.

Next I showed the Improved 6502 Virtual Trainer up and running on my laptop, along with the first 6502 Virtual Trainer. I also showed what I had accomplished with the 6502 graphing calculator. So far, I have most of the hardware for it installed but I am having problems keeping the buffer chips for driving the LCD at the appropriate voltage level. Maybe the pins joining the sections of the calculator together aren't making a good connection. In any case, I showed the calculator taken apart into its sections. I also showed the Logic Tool I have been using to debug the graphing calculator and the EEPROM programmer I built. The last thing I showed was the TI-86 I bought to hook up to an ESP8266. My plan was to relay text from the calculator over WiFi to a computer running Matlab or similar software to allow the calculator to solve more complex equations. I still haven't gotten the ESP8266 voltage levels to work right, but I want to finish this project when I have time.

All in all it was a great day and I really enjoyed showing the public all the things I have been working
on.

Sunday, July 12, 2015

New Project: Programmable RPN Calculator

One of the projects I started on for my Summer Hackathon is a new version of my RPN calculator. This version uses an LPC1114 instead of the two MSP430s the last version used. Hopefully this version will be much smaller and faster. Even though I'm not yet at a good stopping place I wanted to make a post about it so that the last post is not overly long.

Porting the code from the MSP430 was not too difficult. The only real trouble was moving some of the memory registers from the external RAM to the internal RAM of the LPC1114. This really increases calculation speed since it eliminates the bottleneck of accessing external memory. On the MSP430 version I used a preprocessor function to identify and replace any array access to the external RAM with functions calls. This worked well since all of the registers were stored externally but caused a few headaches on the new version since internally stored registers need to be handled differently. One idea I had was to use 32 bit pointers, which wouldn't cause the performance hit they do on a 16-bit system, to somehow encode not only the memory address, but also the memory bank and whether an address is stored externally or internally. It also seems like it would make more sense to allocate memory buffers on a stack as they are needed, rather than hardcoding them in memory. This got me thinking about how other systems handle this problem and I decided to add a way to do that to my 6502 project with a CPLD.

Along the way I also noticed a few areas where I could improve my code. For some reason I got in the habit of reusing generic counter variables like x or i in an effort to save memory. This just makes everything harder to read and does not save any memory since GCC optimizes how variables are used anyway. BCD numbers should also be stored with the smallest places first since that way extending the number by a decimal place only involves incrementing the length field rather than moving every byte of the number one space. In retrospect 255 decimal places is probably way too much for such a simple calculator. This didn't make much difference when I had lots of external RAM but is inconvenient now that I am trying to fit as many registers as I can into the LPC1114's memory.

To read and write the external RAM I'm using the chip's SPI peripheral. It turned out to be somewhat difficult to configure since several of the steps to get it to work have to be done in a certain order. Debugging this was a lot easier with a logic analyzer. After I had it working and got the memory registers straightened out, I was a little surprised to see that calculating sine was slower than on the MSP430. This was a shock since it was so much faster in my microcontroller comparison. I tried raising the SPI peripheral speed to 24MHz, even though the max speed of the RAM is 20MHz, but it was still slower. My next step is to try and measure the clock speed of the SPI with the logic analyzer to make sure it really is going that fast. After I got sine to work, I uncommented other parts of the program in parts to see how much would fit in the flash. Compiling with GCC's -O3 option for speed optimization quickly overflowed the flash but all of it fit in less than 20KB with -Os. One of my gripes with GCC is that it doesn't tell you by how much the firmware is too large, so you have no clue how much you would need to shave off for it to fit.

Initializing and toggling the pins of the LPC1114 is a bit more complicated than on the MSP430 since different pins have different configuration bits and the pins themselves are not mapped into memory in order. I had a look at the HAL library and it seems to use quite a bit of code for what I want to accomplish so I wrote a simple class for handling pins. Luckily I can use C++ since I am just compiling with GCC, unlike with OpenSTM32 where I was stuck with plain C. One neat thing someone showed me was how to use operator overloading so that something like "Pin=1;" does the same as "Pin.high();"

Since I have so much space left over in the flash, I started adding a keystroke programming function. This was one of the neat things I have always liked about earlier calculators. I am nearly done with the editor on the screen for it, which I'm working on with the PC version of the program since it is much faster to test. The next time I do a project like this I will put the PC and embedded version in the same file and enable them with include statements instead of copying the changed sections of the PC version. So far I am only adding the ability to repeat keys and not loop or branch since I want to finish this and at least one other project in time for Makevention in August. When I have more time I hope to add that functionality.

Wednesday, June 12, 2013

RPN Scientific Calculator: Software Update

Work continues on my calculator. Each byte of a BCD number now holds only one digit instead of two. This eliminates the functions that were needed to align and pad numbers when every byte held two numbers. It also makes calculations a little simpler and reduces the amount of space the functions take up in the Flash.

Another improvement is that arrays can be stored in the external SRAM and accessed similarly to how internal memory is accessed. To read or write anything to the external memory a function has to be used. That means a simple equation like this:
X+=Y*Z-Q;
would become this if those variables were stored externally:
 RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q));
This is difficult to decipher and inconvenient to use when writing code. My solution was to make a small program that preprocesses the source code and replaces any variables that should be stored externally with their corresponding read and write commands. These variables are marked off with #pragma directives. #pragma is a note to the compiler to do something special that may be specific to that compiler. If the compiler doesn't recognize the directive, it is ignored. Here is an example of what the preprocessor would do.

This is unprocessed code:
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);
}
 This is preprocessed code:
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);

}
Arrays are converted to pointers that store offsets to the external memory. This way none of the function prototypes have to be changed. The code should work the same way whether the variables are stored in internal or external RAM. External memory can be turned off if needed to make tracking down bugs easier. One disadvantage to this is that function arguments must be either internally or externally stored but a function can't accept both types for one argument. For things that need both I will need a wrapper function. The preprocessor doesn't support all of the C standard since I only spent about a day on it. Adding support for all of the possible ways there are to access a variable would take a lot more work and I wouldn't be likely to use that functionality anyway. Things like variable names that span multiple lines or variable assignments inside of other statements aren't supported but I didn't end up using any of those features in my code.

The new code for adding and subtracting BCD numbers fits in about 2K, including LCD driving code. Using the preprocessor to store all the values externally adds another 500 bytes. The code for multiplication is also much smaller than the last version.