Sunday, December 3, 2017

New project: Pocket Calculator

Recently I got interested in building a very small calculator I can carry around with me. The other calculator projects I worked on are neat, but I don't carry them around because they are too big and fragile. This time I want to make something really practical but also small enough to fit in my pocket. The smallest way I know how to do this with the chips I'm familiar with is using the same LPC1114 in DIP28 package I used for my Programmable RPN Calculator. There are a few changes I would like to make for this calculator, though. First, I want to be able to manipulate all kinds of data on the calculator's stack, such as strings, instead of just floating point BCD numbers. Second, I plan to redo the BCD format I used in the other calculators to store the least significant digits first, which should make them a little easier to deal with. Third, I plan to make all items on the stack variable length, rather than fixed length like on my other calculators. This will be necessary for this calculator since I plan to store the whole stack in the 4k RAM the microcontroller has, instead of on an external SPI RAM chip.

The main new feature I want this calculator to have is a BASIC interpreter. My experience with the first RPN calculator I worked on showed how much of the microcontroller's flash can be eaten up by interface code, so I really don't think I could fit all the calculator functions and interpreter in the LPC1114's 32k of flash. Instead, I plan to store a virtual machine on the chip that can interpret code stored on a large capacity flash or FRAM chip. Retrieving the code over SPI and interpreting it will be much slower than executing code natively on the chip, but I think it will be fast enough for the UI, BASIC editor, and maybe even the tokenizing part of the BASIC editor. On one hand I could switch to a chip with bigger flash, which I am not anxious to do, but I will need some kind of virtual machine anyway to interpret the code generated by the BASIC editor, so it is no loss to use the same virtual machine for the UI. The BASIC programs and editor data will be stored on an SPI SRAM chip, which should work fast enough to edit and tokenize programs, while all the stack and program variables will be stored on the microcontroller.

To speed up the development of the virtual machine and the UI, I started work on an assembler and simulator. There are 10 general purpose registers, mainly because that is how many I could fit on the program's main form. The assembler has simple instructions that look like C, instead of other assembly languages, since I find that more convenient. For example, instead of "ADD R0,R1,R2" I decided to use "R0 = R1 + R2." That probably does not appeal to a lot of people for an assembly-like language, but it feels more natural to me, so I went with it. The assembler puts all the assembled instructions in a simulated 512k flash space. The simulator can single step and show step by step what instruction in flash is being executed. It also highlights where in the flash, SPI RAM, or MCU RAM data is being accessed. There is a 128x128 screen, which you can see above. The simulator works well enough so far to generate the colored background and print using a variable width font.

For this project I decided to finally switch from ancient Visual Basic 6 to C#, which I honestly should have done years ago. Although there are shortcoming to Visual Basic, I got used to them a long time ago and I have come to really enjoy using the language. C# so far has had a lot of unexpected headaches, but part of it is just getting used to a new language. One thing that is strange to get used to is using the "new" keyword for even simple operations. Of course this doesn't exist in C and I have been careful about using it in the little bit of C++ I have used. In C# it is disturbingly common because the garbage collector automatically handles freeing memory. One really frustrating thing I found out is that garbage is not collected in a loop unless you call a DoEvents, which is not recommended. When running the loop that interprets the virtual machine code, my program starts using 30mb and crashes at somewhere over 400mb without DoEvents, since the garbage collector doesn't work. Another shortcoming is that there is no convenient way built into the language to work with arrays of controls, which I need a lot of, as you can see in the picture below. You have to create them all separately and then list their names in an array in the source. I find it bizarre that this worked so quickly and cleanly in Visual Basic 25+ years ago but is so unwieldy in C#, which is still being maintained. It is also ridiculous that double clicking on a control to create a method for it then deleting that method, since it is probably not the one you wanted, causes the form designer to stop working. You have to find the reference to the deleted method in the source for the design of the form and delete it yourself, which is silly considering there is no reason for Visual Studio not to do this for you automatically. Again, this is a headache that Visual Basic solved about three decades ago but somehow has come back to annoy us in 2017. The last major ridiculous thing is that some "exceptions" don't halt your program or even give you a message that something is wrong. Instead, whatever method the exception is in just ends spontaneously. This was hard to figure out at first, since this is pretty nonsensical behavior for debugging. I suppose I will get used to all of these things in C#, but the language is definitely not the sort of huge improvement over Visual Basic 6 I was expecting.

At first I was using SetPixel to modify the pixels of the picturebox on the right side of the form below, but it took about 40 seconds to interpret the code to draw the colored background, not counting the words. I played around with a few different methods to speed things up a little, but what worked best was skipping SetPixel and manipulating the pixel data directly. This method executes the code and draws the image in the picturebox in less than 300ms! This is more than fast enough to simulate what I hope to accomplish with the calculator. In fact, the 500,000 or so cycles per second the simulator can manage is at least an order of magnitude faster than what the microcontroller will be capable of. The next step is to institute input from the keyboard and start working on the UI.


No comments:

Post a Comment