HP Forums

Full Version: Scientific RPN Calculator (with ATTINY85)
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Pages: 1 2 3
Hello all!

I proudly present SCARY - my "Scientific RPN Calculator" based on an ATTINY85 chip.
It took me many hours to implement this many functions to fit in the 8k memory of the ATTINY.

See more at:
or see a short video at:

Very nice indeed! I see you're using doubles, so presumably the limited precision is a consequence of the algorithms you're using for the transcendentals?
Thanks for the compliment.

Actually the ATTINY85 is an 8-bit processor and (programmed with the arduino-suite) it uses 4 bytes for both the float and the double data type.

So the real precision of this calculator is relatively low. There are only 6 (maybe seven) digits "trustable". Hence the SHOW function (with 7 digits) is sufficient.

And as my professor said: "Calculating technical stuff with 3 reliable digits is sufficient". ;-)

Nice device, the code looks very tight with plenty of space savers. I like \( \sqrt{x} = e^{\frac{ln (x)}{2}} \) and the common routine for both ex and the trigonometric functions.

It also reaffirms the miracle of the HP 35 with its 7680 bits of ROM and the Sinclair Scientific with its 3520 bits of ROM.

I just noticed that the first four arguments to push and pull are always &x, &y, &z, &u. Not passing these might save some bytes???

Thanks for these great compliments from one of the most honorable members of this forum and idol of every "calculator programmer".

Actually I am working on implementing and extending this code for an arduino (pro micro, 30k memory, 2k5 EEPROM, USB to PC) to get more features like programming - and to get closer to my favorite HP calculators (15c, 35s, WP34s).

Yes - I fought many weeks for every byte - and I am still searching for resources to eliminate bugs and implement more functions.

One thing to save memory is to use local variables. So I did with declaring the stack variables (xyzu) local. So I have to send to the push and pop subroutine the 4 variable pointers.
But I use this subroutine relative often - and did not check if it is worth to declare the stack as global variables. I will check.

Thanks again and regards
woah, nice!

The 35 and the Sinclair did not use different integrated circuits instead of a rom? I did not know.

Another wonderful DIY project... Do you think it would be possible to cut away enough of these display/keyboard PCBs to join two of them seamlessly? This would result in a 16 digit display and a decently sized keyboard. Together with an Arduino mini or nano (Atmega 328 processor) a landscape calculator with a single shift key and no menus should be feasible.


NB: I just found these boards on eBay and ordered some (they only cost 2,19 Euros a piece - who knows how this is possible)...
(03-06-2018 02:23 PM)deetee Wrote: [ -> ]One thing to save memory is to use local variables. So I did with declaring the stack variables (xyzu) local. So I have to send to the push and pop subroutine the 4 variable pointers.
But I use this subroutine relative often - and did not check if it is worth to declare the stack as global variables. I will check.

Checking is easy (pull is similar):
#define push(a,b,c,d) push_stack()
static void push_stack(void) { // Push stack
  *u = *z; *z = *y; *y = *x;

I declared the function static because some compilers can do better knowing they are always local. Improved calling conventions etc. I don't think I seen a case where doing so produced larger code.

Another trick that sometimes works is to reduce the optimisation level used when compiling -- paradoxically smaller/faster code is sometimes produced.

Another thought that came overnight is to not use the library mathematical function -- they usually trade space for speed, check for edge cases in detail and probably implement the IEEE standard.

(03-06-2018 02:28 PM)pier4r Wrote: [ -> ]The 35 and the Sinclair did not use different integrated circuits instead of a rom? I did not know.

The 35 had three 256 word ROMs, all external to the processor ICs. The gave 768 10 bit instructions. The Sinclair had everything in one IC and had 320 11 bit instructions in total.

Thanks for all compliments and hints (particularly those which "came overnight").

The boards are really cheap - I ordered a hand full from aliexpress on black friday for less than $2 each.

The idea to join two boards seamlessly (16 digits, 32 keys) is very charming, but "seamless" might not be possible because the connection pins and some circuit lines (mainly in the keyboard area) on the PCB are "out of the width" of the display.
On the other hand I tried to desolder the keys and connect a slightly bigger (higher) PCB with bigger and write-on buttons. But desoldering/soldering on the surface of a PCB is hard and not very reliable.

What really would be great (but I did not find yet) is a "good" 8-digit LCD display to save power. Together with some "sleep code" (if there is spare memory) I could replace the switch with a "software switch" - and replace the AAA battery with a smaller pile (ie LR2032).

Well done! An excellent low cost project and a quick win for those not confident in scratch building their own hardware.

The keyboard is always the problem. My last approach was to conjoin two soft-action, 16 key pads. This actually worked out very well and was easy to label. That project, and others, are outlined in my RPN-duino thread under "Not quite HP Calculators".

Re displays: 64x128 OLEDs, with 4-line I2C connectivity are great but they are a bit RAM hungry with respect to 8 bit micro-controller platforms. This was not an issue for my ARM based Arduino Due project.
I just submitted a pull request that saves almost 850 bytes of flash in the ATTINY image for no other cost.

I think I can see some other space savers but I'll need to figure out a way to test the resulting code.
Hi Pauli!

Sorry for not beeing fast enough for you. I am highly interested in your hints and private lessons but right now short with time.

But I have tried your push_stack() quick check to "globalize" the local stack and reduced the code from 8118 bytes to 7666 bytes - 452 bytes reduced - that is amazing!!!

Maybe doing this with pull() saves me several bytes too. Fantastic.

I think version 2 of ScArY seems to be close. :-)

I made some other changes which also saved some bytes.

Clever idea, I ordered a TM1638 pcb to try your calculator. So nice to use such an inexpensive board Smile
Hi Pauli!

Which changes did you make to save more memory?
Did you attach a file?

I submitted a pull request to the git repository:


You should be able to look at this and merge it to the master branch with a couple of clicks.

The space savers included:
  • Declaring const arrays static const.
  • Having two two different pull functions, the full stack pull calls the other pull rather than having duplicate code. It might be better to have these call the library function memmove rather than having assignments. They could also be done more tightly in assembly code via two entry points into the one function.

Things to try include:
  • Changing the key to byte mapping to some less human readable.
  • Using a function table to dispatch instead of a switch. This would benefit from a reorganisation of the command codes so the dispatched functions start for 0x00 and are contiguous.
  • I think buttoncast can be done with the tables by renumbering the KC use 0x00 - 0x0F and some bit operations. A straight log2 of the key scan could be the key code but changes elsewhere (checking for digits using ranges) would need modification. There might be a smarter way.
  • I suspect switch statements are expensive. E.g. moving the atan code into its own case increases code size but it should be a saving since it has no relationship with the other code surrounding where it is now.
  • The asinh and acosh code could be merged.
  • Avoid calling both log10 and log.

Pages: 1 2 3
Reference URL's