Friday, January 31, 2014

RPN Scientific Calculator: Hardware

In the last two months I have made a lot of progress with my calculator. The software is now finished. As well as cleaning up a few bugs I also added a battery meter to the settings page. There was enough memory on the external RAM for two separate stacks with 200 levels each. All of the code is now on a GitHub page: https://github.com/druzyek/RPN_Calculator.

For the hardware I soldered everything on to perfboard. It didn't power up the first time I plugged it in but after fixing one power connection everything started up and worked fine. Here is a picture:


For the power supply I am using 4xAA batteries with an LM1117 adjustable regulator. My local shop didn't have the resistors I needed to get 3.6v from the regulator so it is running closer to 3.5v. On the left side you can see female headers for the keyboard outputs to be plugged into and on the lower left a repurposed DIP socket for the LCD and keyboard inputs to be plugged into. The red, white, and blue wires were the smallest single strand gauge one store had and worked fairly well. When I ran out of that I switched to an even smaller gauge (the brown wires) I got form another store and it was even more convenient. It works so much better than breadboard wire and I definitely plan to use it again. If you look closely you will see two pins for power so that the whole board can be powered from the LaunchPad if needed. Each MSP430 also has its own set of programming pins so that they can be programmed in circuit. One strange thing I noticed on this project is that solder will sometimes spill through the holes and onto the other side of the board. This may be because the smaller gauge wire lets the solder through more easily. One problem I had while testing the connections were two adjacent socket pins that seemed to be bridged, even after desoldering everything around them. After removing the socket itself, I saw that a drop of solder had flowed to the other side of the board and shorted the two legs in the space between the board and the socket.

Here is everything connected and running:


 Here is a circuit schematic of the whole system:


For the case I soldered together some clad which I was able to get really cheaply. It feels pretty solid. It needs a coat of paint and I need to adjust the holes in the faceplate for the keyboard and screen. Here is what it looks like so far:


As was my goal, I submitted the project to the Project of the Month Competition at 43oh.com. Thankfully it was extended an extra month so I had some time to finish most of what I wanted to finish. Voting starts tomorrow!

Friday, November 29, 2013

RPN Scientific Calculator: Update

As I mentioned in the last post about this project, I added a second MSP430 because the firmware was getting too large. In the end hardware UART turned out to be a good choice for communication between them. It works very fast and is reliable. The first MSP430 is responsible for reading the keyboard, controlling the LCD, handling the interface, and performing checks such as division by zero before passing on the addresses of the values  to be calculated to the second MSP430. The firmware for the first chip comes to a little over 13KB. The second MSP430 does all the actual calculating since it is connected to the SRAM. Its firmware is about 10KB.

The software part of this project is almost finished. One thing I added was a settings page. The accuracy of calculations can be set anywhere between 6 and 32 decimal places. There are also options to use scientific notation and switch between degrees and radians for trig functions. The only things left to add are a battery meter and support for two stacks. A second stack is not really necessary but as it is now, only one half of the 128KB SRAM is usable since the 17th address pin is not hooked up. I plan to add a button so that the second half of memory can be used as a separate stack.

Although I planned on adding programming features at the beginning, I may not have time. The 43oh forum is having a project of the month competition I would like to enter this project in and I will need to hurry to finish putting together the hardware and making a case for it. If there is time left at the end of the month I may add a simple key stroke programming mode. It is a little disappointing that I did not get to this but on the other hand, it is convenient to have a firm end to this project. It would be easy to keep adding features but even now I feel like I have stretched the project beyond what the hardware can reasonably handle. I have plans for other calculators that will be programmable but they will use a more powerful chip than the MSP430G2553 and they won't use SRAM controlled by shift registers.

One change I made to the hardware was to use a different LCD. The new LCD is also 20x4 but it was much cheaper. The old LCD was quite expensive and I would like to keep using it rather than commit it to this project. The new LCD is 10cm wide instead of 8cm like the old one so I decided to turn the keypad long ways to save room. Here is the layout I plan to use:



Wednesday, October 30, 2013

Microcontroller Showdown, Part 2

Here are the results for the tests I did with the MSP430 and the LPC1114. Lately I have been busy with work so I haven't had a chance to do anything with the other three chips. I do have tool chains set up for them and I plan to run the same tests on them soon too.

To time the tests I used an MSP430 LaunchPad which waited for a pulse from the tested chips to begin and end timing. The timer was run from the VLO which is accurate to ±3% so the results are not exact but they give a rough idea of the difference in speed. The tests were done inside two nested loops which iterate altogether 2,400,000 times. Each operation is done once per iteration except adding and GPIO operations which are done 10 times since they should be much faster. At first I did each test 5 times and took the average but then I did them only once since the results were usually very close and some of the later tests took quite a while. To begin with I timed how long the empty loop took then I subtracted that time from the results to get the actual time the operations took. For both chips I used gcc to compile with both -Os and -O3, although there wasn't really a difference except for the BCD routine tests.

As you can see from the table, the LPC1114 was much faster than the MSP430, even running from the bottlenecked flash. The results would be even faster if the tests had been copied to RAM and run from there. I was also surprised to realize that the LPC1114 has a barrel shifter which is very handy. Another neat feature is GPIO masking. Each mask is memory mapped so individuals pins can be toggled with a single write to memory. This allows GPIO operations to be much faster than the traditional load, modify, and store routine.

Monday, September 30, 2013

Microcontroller Showdown, Part 1

Recently I bought some LPC1114 microcontrollers from NXP. They come in DIP packages and feature an ARM Core M0. Although comparing the clock speeds of different architectures is not the best indicator of speed, I would still expect this chip running at 50MHz to be faster than the MSP430s running at 16MHz that I have been using until now. Later I found out that the flash of the LPC1114 only runs at 20MHz, which will bottleneck any programs running from there. Running from RAM would be much faster but the chip only has 4KB of SRAM. On the other hand, it does have a three-stage pipeline. Value-line MSP430s only have instruction-prefetch. All of this makes it a bit difficult to know how much faster one chip would be than another, so I have decided to run a few benchmarks.

Another architecture I have been interested in lately is the 8051. This is much older than the other two architectures I want to check but it remains popular with some people. Instructions take 12, 24, or 48 cycles to execute, which is less efficient compared to an MSP430 which needs only 3-6. Some modern 8051s feature a full-pipeline and clock speeds over 30MHz. These are interesting to me because I think they may be able to outperform the MSP430 in some ways. I was able to sample some AT89LP6440s from Atmel and a DS89C450 from Maxim Integrated which both come in DIP packages. The AT89LP6440 can fetch one byte per clock cycle from memory, meaning that it should in practice run slower than 1 MIPS per MHz but still much faster than other 8051s. It does have a hardware multiplier which surprised me to find out. The datasheet for the DS89C450 lists it as one clock-per-machine cycle, so it should run faster MHz per MHz than the AT89LP6440. It can also run at 33MHz compared to the AT89LP6440 at 20MHz.

The last microcontroller I will test is the Z16F from Zilog. This is a 16-bit CISC design descended from the 8-bit Z80. According to the Zilog website, it outperforms many RISC designs in the same class. It can do 32-bit ALU operations, has a hardware multiplier, and does some pipelining. I know the least about this chip but the design is interesting and I may use it in a future project if it performs well.

Here are some specifications of the microcontrollers that will be involved:

Microcontroller   Clock Speed   RAM   Flash   Core
MSP430G255316MHz0.5KB16KBMSP430
LPC1114FN2850MHz4KB32KBARM Core M0
AT89LP644020MHz4KB64KB8051
DS89C45033MHz1KB64KB8051
Z16F281020MHz4KB128KBZNEO

There are many factors that need to be taken into account when choosing a microcontroller. For this test I have decided to test only calculation speed and to ignore other factors such as the peripherals. Consequently, the results will not be relevant to some people. This also will not tell me which microcontroller is the best overall. These particular chips are dissimilar in many ways and this is not a comparison of microcontrollers from the same class. They are only being compared because I am curious about them.

One good reason to do this test is so that I have an excuse to set up the tool chains and programmers for all of these chips. This will take some time so I will release the results in a few parts. It will give me a break from the RPN Scientific Calculator I am making.

Sunday, September 8, 2013

RPN Scientific Calculator: Second MSP430

The next step for the calculator is the interface. The code for handling input ended up being fairly long but now entering numbers works as well as the basic math functions. A lot of flash space was taken up by the mathematical checks that must be done with trig functions to convert them to useable forms and ensure that they are within a valid range.
 
At this point the firmware took up about 14KB, which is close to the 16KB I have to work with. There probably isn't enough space left to add all of the functions and accompanying checks so I decided to add another MSP430. This will give me more more space but also make things more difficult since I will have to coordinate communication between the two. Moving to another chip with more Flash would be an option but I have plenty of MSP430s on hand and I don't want to move chips now that I have everything working well together.

Since I only have one LaunchPad I had to program the second MSP430 on a breadboard. This is pretty easy to do. The LaunchPad has jumpers on the RST and TEST lines where the programming signals can be diverted and used elsewhere. In this case they go to the breadboard, and a dip switch is used to select whether the programming signals go back to the LaunchPad or to the breadboarded chip.

With two chips I have a lot of left over pins. This let me eliminate the read and write shift registers used with the SRAM. The data port is now connected to one whole port of the second MSP430 instead and should work a little faster. The next step was to establish communication between the two chips. Using one pin for data and another as a clock signal, I was able to do some simple data transfers. Unfortunately this caused an error, usually after several thousand successful transfers. It's not clear whether the error was caused by hardware problems like breadboard crosstalk or if there was a timing error of some kind in my code. My plan now is to use hardware UART between the chips instead. Hopefully this will be more reliable.

There are now also enough pins to drive the LCD directly instead of using a shift register. When I tried doing this before with a 16x2 LCD it worked well but at some point in the project it began to randomly stop working. In retrospect I think it may have started after adding some of the other components to the project. In any case, sending signals to the 20x4 LCD from the LaunchPad does not work at all. This problem will have to wait until I can replace my broken multimeter and test all the voltages involved.

Saturday, August 17, 2013

RPN Scientific Calculator: Tweaks

Recently I was able to get some new components and took the chance to make a few tweaks to the calculator. First of all, I hooked up a new 20x4 character LCD to replace the 16x2 version I was using before. It is gray with black letters and I like how it looks. With this I will be able to make the bottom row of the screen a menu like the kind some of the later HP calculators use. The LCD itself came with male headers so it can be plugged into a breadboard, but there was no convenient place to put it so I decided to run wires from the headers to the breadboard instead. The LCD worked fine at first but quickly became corrupted after I wound the wires into a loop to make them neater. This was causing crosstalk and the problem disappeared when I separated the wires.

I also added a CMOS 555 timer to generate the negative voltage for the LCD. This frees up a microcontroller pin that I am now using to independently drive the input shift register of the RAM. Now I can read the external RAM and the keyboard at the same time without worrying about coordinating interrupts. In order to save energy I decided to use the smallest capacitor and the largest value resistors I could for the timer. Unfortunately, none of the resistor values I had on hand would give me the 30 Hz or so the microcontroller was generating. 48 Hz was the closest I could get using a 0.1 uF capacitor and 100k ohm resistors for R1 and R2. Adding a 470 ohm resistor to the output of the 555 gave a good contrast and should also keep the contrast constant if I try to run everything from a battery later.

The last thing I did was to expand the CORDIC tables to 32 bits wide instead of 16. Using a 16 bit wide table gives around 14 decimal places of accuracy which is sufficient for calculating logarithms. A problem arises, however, when that logarithm is used to calculate things like exponents because those 14 places of accuracy also include the whole part of the answer. A simple calculation like 8^9 only offers 5 decimal places of accuracy after the decimal since the whole part is 9 digits long. The new version takes about 6 seconds to calculate "atan(tan(37))" This is very slow so I will let the user set the precision in settings.

Monday, July 29, 2013

RPN Scientific Calculator: More CORDIC Routines

After finishing the CORDIC routine for logarithms I started on the CORDIC routine for trig functions. For this I needed a different look up table and a different function, but it didn't take up much room in the flash. The table for pre-computed logarithms is stored compactly in flash and the same routine that unpacks it into the external memory is also used to unpack the trig table. With this I can calculate sine, cosine, tangent, and arctangent. It should also be possible to calculate arcsine as well but I haven't tried yet.

To test these new function I tried calculating atan(tan(37)). When using 16 decimal places for the calculations this gives the answer 36.9999999999999781, which is pretty accurate. Unfortunately, this took over two seconds, which is just too slow. The logarithm and powers of e functions were at least twice as fast. In order to speed things up I tried to eliminate as many reads and writes to the external memory as I could. One thing I didn't notice when I wrote the original functions is that the loop condition for a for loop is recalculated each iteration. When the condition depends on a variable in external memory, the variable is fetched on every iteration, which is wasteful if the variable hasn't changed. After changing the code to use local copies of external variables whenever possible, I was able to cut down external memory access by almost 25%.

25% wasn't quite enough so I looked at the code I was using to right shift. This allows me to divide numbers by 2 quickly but takes some extra coding since shifting in BCD is a little more complicated than a normal binary shift. Because of the extra work involved in keeping everything straight during BCD shifting, I was doing shifts one bit at a time. This means a 58 bit shift, for example, would simply do 58 shifts of 1 bit each. As you can imagine this is not efficient and was a big part of the slow down in the code. My solution was to use as many 4-bit shifts as needed, then a few 1 bit shifts at the end to finish it off.

Shifting by 4 bits in BCD is fairly easy. As you probably know, shifting by 4 bits is the same as dividing by 16, and dividing by a number (16 in this case) is the same as summing the results of dividing each decimal place by that number. Since there are only 10 possibilities (0-9) for each decimal place, I stored the results of dividing each possibility by 16 in a look up table and used that to sum the results. Here is an example:

789 ÷ 16 = 700/16 =   4375
                  80/16 =     5000
             +     9/16 =      5625
                               49.3125

The values 4375, 5000, 5625, etc are stored in the look up table. The sum of these results are stored in local RAM since 6 bytes is enough to keep track of the summing long enough to deal with any carries before finally writing the last byte to the external RAM. Doing it like this I only need to read and write every decimal place once per 4-bit shift. This cuts down the number of external memory accesses down to almost one third of what it was at the beginning and allowed me to calculate atan(tan(37)) in a little over a second. All of this fits in 8.1K of Flash meaning I just broke the halfway mark of what the MSP430G2553 chip I am using can hold. If there is any space left over at the end, I would like to implement a similar 8-bit shift routine as well to speed things up even more.