Close
0%
0%

HP 82240B IR Receiver and Printer Interface

This is an IR receiver and interface for adapting a commodity receipt printer to be 82240B-compatible.

Similar projects worth following
The HP 82240B infrared printer was developed by HP in the 1980's, and is expensive. Some folks asked about the feasibility of crufting one together from cheap receipt printer cores, and I thought that might be a fun thing to do, so here we go a-hacking...

Many folks that use HP calculators of yore like to be able to use the infrared printer. These printers are really expensive given what they are, and some folks in a separate forum wondered if a workalike could be crafted from cheap printer cores from China. I thought they could be created from a POS printer core and using the famous 'Blue Pill' development board as the interface. Since I had coincidentally just implemented the generation of the related IR protocol, I was freshly familiar with how it works, so on a lark I am now attempting this interface.

It's all in the name of fun, really. I'm expecting that the total cost of this printer knockoff will be about usd$30 as described here (e.g. there is no case to speak of, just rubber band the board to the printer!) The printer new (NOS) costs a ruinous $200 or so, but you can typically find them on eBay used for about $50, so I don't know that this will be particularly cost effective relative to a polished commercial production, but who knows, it might be of interest to someone. And the infrared-to-serial/usb part could be interesting in some as-yet unimagined way.

BluePill82240Interface-em205-20250211a.hex

current firmware

hex - 192.45 kB - 02/16/2025 at 14:05

Download

  • 1 × 58mm Micro Receipt Thermal Printer, 3.3V TTL Compatible; any of Cashino, GOOJPRT QR203, EML203, EM205 printer core; serial 3.3V 'TTL' interface. I got mine from eBay from China for USD$ 18, free shipping. The source also supports the 'Kashino' (e.g. the kind from SparkFun or AdaFruit), and an APS model. The printer support is modular, so you can add a new one relatively easily.
  • 1 × STM32F103C8T6 ARM STM32 Minimum System Development Board Module so called 'Blue Pill' development board; I got mine from eBay from China for around USD$ 2.25, free shipping
  • 1 × Vishay TSOP4133 IR receiver; I got mine from Mouser for about USD$ 1.30 It must be exactly this model number, because of AGC characteristics.
  • 1 × Power Supply; regulated, 7V, 3A Yes, you need a hefty power supply for the thermal printer. It's not about voltage, it's about power when those heaters fire. Weaker power supplies will sag under the impulse load, and you'll reset your controller board. The degree to which this is true varies by printer model, but I recommend not going over 7v to avoid stressing out the linear regulators on the boards.
  • 1 × Development Toolchain I'll describe this more later; you only need it if you are building from source. Short story: free tools from ST, STCube32MX, System Workbench, ST-LinkV2.1, etc.

View all 7 components

  • IrDA [Explosive Space] Demodulator

    ziggurat2902/15/2025 at 14:43 0 comments

    In this iteration of the demodulator for the RedEye protocol, I am using a module intended for IrDA, which operates at 4800 up to 115,200 bps and is baseband -- i.e. a '1' is indicated by 'light off' and a '0' indicated by 'light on'.  (OK, that's not strictly true:  the '0' is actually a blip that is 3/16 the full bit period, but that's about the only difference from just hooking the led straight to the uart).  So it should easily be able to detect the 32 HKz RedEye carrier.

    This implies that the ISR will now be triggered on each on each pulse received -- all 32,768/sec of them -- rather than the envelope as is the case with the Vishay TSOP device.  But the BluePill can easily handle that.

    I implemented a new state machine.  It used the same resources as the TSOP decoder, even with the same configuration (a timer clocked at 2x carrier frequency to serve as a one-shot), so that was handy.  The one-shot is set to 2/3 a half-bit which counting pulses for the 'burst' of 6-8 pulses as per protocol, or a 1/2 bit when expecting quiescence.  So it works as a series of 'expectations', the three half-bit sync pulses, and the rest are half bit pairs of 0-1 or 1-0.  Deviations from the expected sequence (including pulse count) reset the machine.

    This seemed to work reliably and recover from errors at the byte level.  (I.e. a damaged byte would not preclude syncing up correctly on the next incoming byte.)

    I wound up making a 'better' module using some stranded 30 AWG and crimped Dupont connectors with some free-wired circuitry for the support components, along with some UV-curable resin for some stress relief.

    This was fiddly to build, but it got me off the breadboard.

    I did also implement the error-correction capability using the 4 parity bits, which can correct single bit errors, and I tested this by deliberately damaging bits.  However this does not seem useful to me because the demodulator will kick out bad signal before there is a chance to correct it.  So maybe a different implementation that continues to try to receive despite obvious signal errors might enable the use of the parity correct feature.  I'm still skeptical because you can only correct single bit errors, which is a very short period of time.  I suspect most signal problems are gross in nature, like blockage for far longer than a single bit period.  Also there is not a means of knowing if the bit error is in the data, or in the parity.  Why should we consider the parity bits as authoritative and the data bits as less trustworthy?  So a conundrum.

    I did get transmitting working as well, and tested sending to a physical HP 82240B printer.  I also tested sending to a second interface board, which was kinda cool in itself.

    So this then stimulated some more features, exploding the space of my flash.

    I did add a capability to send the received IR over the USB-CDC or UART1.  The 'monitor' is usually on USB-CDC, so if you send the IR there, then that precludes the monitor.  So I added an 'escape' of "+++" (in Hayes AT tradition) to get back to the monitor so you can do things like change settings.

    This only works, though, in that one side of the half-duplex USB CDC is the received IR data, and the other remains the monitor.  So you can type commands blind even in the IR data mode (you have to, to be able to send the +++ escape sequence).  But this precludes sending IR data.

    So I need to put my product manager hat on for a bit to think some more on that.  Because I would like the interface to also fully support being a two-way RedEye USB adaptor module.  I can send now via the 'send' command I implemented, but that's not the same as what a 'proper' adapter would do.  A 'proper' adapter would present as a USB-CDC serial, and then merrily transceive RedEye data.  The code is all there to do that, but it would preclude the monitor function...

    Read more »

  • ...but is anything really ever 'done'?

    ziggurat2902/12/2025 at 14:40 0 comments

    No, it's not.  A few weeks ago a gentleman asked about procuring a completed printer interface.  It's been some 7 years since I did this project, so I had to refresh my memory.

    I recall being concerned about using the TSOP4133 in this application.  It has worked fine for me with my calculators, but I am pushing it to the limits of the specification, so notionally it could be problematic with a different calculator or different batches of TSOP's.  I had dealt with the fringe cases in software, but I was still wanting a more confidently robust alternative.  I planned to implement a new demodulator based on an IrDA module, which should definitely work with the signaling.  The code will be different, since modulated data will be received (the TSOP demodulates with envelope detection, but we'll receive the individual bursts here).  The 32 kHz carrier can easily be handled as as a direct interrupt source since the BluePill is running at 72 MHz.

    Along the way, I discovered that a feature I thought I had implemented was not:  the ability to use the interface board standalone (i.e. no printer) as an HP-IR-to-USB adapter.  The gist being that instead of directing the IR to the printer rasterizer, instead send it to the USB-CDC serial port.  So I needed to code that.

    I had started this back in 2018, but I apparently damaged my IrDA module -- possibly spending too long soldering to the tiny device.  I had recently picked up some other IrDA modules that were surplus from Electronic Goldmine -- the Sharp GP2W0004-YP.  So tiny!

    However an idea struck me to solder on some rigid wire (lead clippings from resistors) in a dispersive fan pattern, and subsequently bend them parallel to a 0.1" pitch.  Then the SMD device becomes breadboard-friendly.

    I'm not using these for actual IrDA here, but I decided to hook them to pins that could be configured to a serial port so that I can fiddle with IrDA later (for a different project).  Here those lines will be configured as an external interrupt source for the RX signal, and a PWM for the TX signal though it is not relevant in this case.  Or is it?  I mean, I've now got an emitter for free, maybe I should also support sending HP IR signals?  It's not meaningful for the original printer use-case, but might be interesting in the alternative adapter use-case.

    That particular pin when not for UART can work off timer 2 channel 3 in PWM mode.  So I can configure the TIM2 for 32768 Hz, 50% PWM, and gate the signal.  I was previously using TIM2 as the system tick, so I moved that to TIM3.  I use TIM1 as the bit clock.  Actually, it's 1/4 bit clock, because the bursts are 1/4 a bit period.

    The signaling scheme is a kind of 'biphase-level' signal where each bit has a burst in either the first or second half of the bit time (the burst lasts a quarter of the bit time).  If the burst is in the first half, it is a '1', and if it is in the second, it is a '0'.  There are 12 bits transferred (4 parity and 8 data) and 6 half-bits for framing (three for sync and three for stop).  So a total of 15 full bit times.

    In the interest of simplicity, I encode these 15 bits as 30 half-bits representing the burst/no-burst state for each half bit period.  In this way, the machine (operating at 4x the bit timing) clocks out the encoded bits in two phases: phase0 conditionally turns on the signal to start a burst if the encoded bit is '1', and phase1 unconditionally turns off the signal.  This this encoded-bit-clock is a multiple of the carrier frequency, it is possible to make a picture-perfect output waveform.  This fits in a 32-bit word and has two spare bits which I use as a sentinel for end-of-frame.

    Short story:  encode a byte by setting sync bits, computing parity, and appending data and stop bits.  Then set to phase0 and start the (quarter) bit clock.  In phase0, test the high...

    Read more »

  • If You Can't Beat 'Em, Beat 'Em Into Submission

    ziggurat2907/21/2017 at 02:34 0 comments

    Summary:

    A quirk of one of the printers, the APS EPM203-MRS, could not be disabled, but was worked-around.

    This project is now functionally complete.

    Deets:

    Yesterday I had mentioned that one of my printers, the APS EPM203-MRS has a quirk whereby it gratuitously advances the paper before printing bitmaps.  Moreover, it only does this sometimes, when there has not been prior output for 'a while'.  This made my output look weird on that printer, and I don't like weird things.  (OK, that's a general lie, but in this limited case, it's true.)

    I scoured the manual looking for some way to turn off the paper advance feature/wart/whatever.  Look as I may, and look as I might, there was no such feature found that night.  I spoke 'the uncommon words of anguish', and retired for the night.

    This morning I awoke to discover that I had turned into a giant cockroach.  This situation only lasted a few minutes, but when it had ended I was left with a kooky idea:  maybe I can just compensate for the paper advancing by doing a reverse paper feed before emitting the graphic.  The sand in that vaseline is that the paper advance only happens /sometimes/, after there has been a period of output quiescence.  If the data stream keeps coming to the printer with some reasonable pacing, no gratuitous paper feed is done.  (Thank the maker for that little blessing -- really every horizontal line of pixels is it's own distinct graphic.  It would be quite a mess if there was a paper feed between each horizontal line!)

    So, sometimes, if you are faced with an inability to make things reliably the way you want them to be, you can as an alternative approach make them reliably the way you /don't/ want them to be.  If I can make /every/ graphic output reliably have the unwanted paper feed, then I can reliably always do the workaround of the reverse paaper feed beforehand.

    The approach I took wound up being a fairly surgical change:

    • at then end of transmission of data to the printer, note the time, call it g_nLastTx.  Initialize that to 0 at boot, btw.  I'm just using the HAL_GetTick() which returns milliseconds since boot.
    • before doing ouput, compute 'now' - 'then'.  (I.e. HAL_GetTick() - g_nLastTx)  2s complement will make all your rollover worries better (mostly; more later).  Call this difference 'duration'.
    • if the 'duration' is longer than the safe amount of time to guarantee that the paper advance will happen, then sleep (via osDelay() in the CMSIS API) for the difference.
    • now you should be guaranteed that doing a 'reverse paper feed' of a few pixels will counteract the gratuitous paper feed that you know the printer is going to insert.

    OK, subtle detail on the timer rollover:  we covered the usual case of 'I started just before the counter rolled over, and checked after it did, how do I handle that' with the unsigned 2s complement subtraction, but there is another issue when you rollover twice or more.  Then the 2s complement doesn't help you.  OK, the timer rollover will happen after 49 days, so you'd have to wait twice that time, so over 3 months of powered on but disuse before you'd be at risk of it.  But I'm taking this thing to Jupiter and I can't have Hal telling me 'I'm sorry Dave, I can't open the pod bay doors until I get the output from your thermal printer.' and have to wait for 49/2=25 days while oxygen runs out.  (Hal does love its petty torments.)

    So I covered that scenario with a little hack.  A 'haque', really -- it's not that dirty.  The printer rasterizer process blocks waiting for a signal that a birmap is ready to be rasterized.  That blocking has a timeout, which I arbitrarily set at 5 seconds.  The intention of that is to let the thread awaken to realize that there hasn't been anything to do for a while, but that is nonetheless still alive, and it can just carry on blocking again.  This opportunity can be used...

    Read more »

  • Success! I'm the Operator on My Pocket Calculator

    ziggurat2907/19/2017 at 18:04 0 comments

    Summary:

    Printing to physical printer is now working with both the GoojPrt and APS EPM203-MRS units.

    I am now moving onto optimizations and enhancements.

    Deets:

    I implemented two physical printer rasterizers for two of the sample printer cores: the GoojPrt unit that I was originally going to use, and the APS EPM203-MRS unit that I got later. They both print correctly (with some caveats):

    APS EPM203-MRS output is top two, GoojPrt output is lower two. So, printing is a-happinin'! Yay!

    There are two caveats, though:

    1. as mentioned earlier, the electrical design of the GoojPrt leaves some things to be desired. As you can see in those two printouts, the output is rather faint. This is easily addressed with a command that specifies heating/resting times for the thermal head, but using that so far has only resulted in power supply droops that reset the printer, so I am holding off on addressing that now until I get a better power supply. I find this annoying, but the code must go on!
    2. also as mentioned earlier, the APS unit's firmware has the annoying tendency of advancing the paper when printing bitmaps (and everything in this printer project is treated as bitmaps so as to realize the 82240 character sets). You can see the effect in the top right printout, where there is noticeable space between the lower printed 'lines'. Those are on separate strips of output bitmap. It doesn't look incredibly horrible here, but that is just good luck. If I were to print, say, a graph, then you would see the intervening paper advances.

      That printer happens to have a 'reverse linefeed' command, which in principle I could use to compensate, but the maddening thing is that the gratuitous paper advance only happens if there is a pause in the print data stream greater than some unknown amount (around a second or less). If the pause is below that threshold, there is no advance. You can see this in the top lines of that printout, where the successive rendered bitmaps (three in that case) are output in rapid succession.

      This is maddening to me. I am scouring the datasheet to see if this is some feature that can be turned off. I may disassemble the printer's firmware to see if I can find a way to stop it (I disassembled the firmware of the Kashino last week for an unrelated activity).

    So, now I am trying to fix the power supply issue for the Gooj, and the gratuitous paper advance issue for the APS. After resolving those, the project will technically be 'done', but is anything really ever 'done'?

    As mentioned before, as an enhancement, I want to implement a command-line interface 'monitor' program that runs on the USB side. It would do things like manage settings and whatnot.

    As an additional feature, I want to be able to realize some secondary functionality such as:

    • send decoded IR to USB port; this would realize an HP82240 to PC adapter for receiving raw data from the calculator for... whatever!
    • forward data from USB to printer port; this would realize an PC to thermal receipt printer adapter
    • etc.

    After that, I should be able to mark the project 'completed'. My favorite task to cross off!

    Next:

    I want to resolve the annoying paper advance issue in the APS printer, and the annoying power suck issue in the GoojPtr.

    I need to capture a video of the printer in operation for the blog.

  • Thoroughly Removing The Uncommon Words of Anguish

    ziggurat2907/18/2017 at 14:09 0 comments

    Summary:

    Reading datasheets can be fun!

    Deets:

    While coding up the rasterizer, I was rummaging through the datasheet for the Kashino printer. I came upon this statement in the "Features" section of the User Manual:

    "Printer control panel built-in GB18030 Chinese character, thoroughly remove the uncommon words of anguish."

    I can't make this up; q.v.:

    (I don't know why the highlight is there -- it's that way in the PDF itself (with other things).)

    I do very much appreciate having access to the the document, but I think they might have fallen short of their stated goal because I did utter some words of anguish upon reading this. But maybe my words were too common to have been thoroughly removed.

    Next:

    Back to work coding printer rasterizers....

  • My Three Sons; Mike, Robbie, and Chip

    ziggurat2907/17/2017 at 23:27 1 comment

    Summary:

    I was tired of waiting for my printer to come in from China, so I bought a similar one that ships statewide. Then I realized I actually had a printer on-hand all along from a project some 4 years back. No sooner than I dug up the old printer, the other two arrived the same day. Sheesh. So now I have an embarrassment of riches.

    Now, I mount the printers and do intial tests with the integrated system -- finally!

    Deets:

    In impatience to receive my printer module, I went back to eBay and looked to see if a similar module is available from domestic shipping, which should take less time. There was, and not for not much more cost. Further, as best as I can tell, this is the more premium module on which the other module claims compatibility. This is the APS EPM203-MRS. Moreover, I could find a real datasheet on this model. Still, it would take a week or two to get it in.

    Well, this morning (Friday; sorry, late post. It takes me more time to compose these posts than it does to do the work on which I'm reporting!) I awoke with the realization that I actually already have a thermal printer from a project I was doing for a client some 4+ years back. That was a 'Kashino CSN-A2-T'. I did dig that up.

    Then when the mailman came, a miracle: both my domestically ordered APS module /and/ my Chinese 'GoojPrt' module arrived! Yikes! Too many printers! Here they are:

    Mike, Robbie, and Chip -- err... 'Kashino', 'GoojPrt', and 'APS EPM203-MRS'.

    They all three have 'TTL' serial, which I measured to be 3.3 V logic (happily; so I don't have to add level shifters). Howver, the Kashino out-of-box only does 'hail, Mary' style serial, and by that I mean there is no flow control. I can open it up and hack it it onthe controller board (it's there), but the Kashino is now less relevant since my other modules came it.

    To my dismay, the APS printer module is just the module -- no connecting cables! Yikes! But there was unexpected hope, because the GoojPrt did come with cables. Here is the 'unboxing':

    Fortunately the important connectors are the same on the GoojPrn and the APS, so the Gooj wires will work in both instance. And... since I need to solder the other end of the cable to the controller board, and since the wires are pretty long as it is, that means cutting each in two. So, another set of cables! Yay for wasting money on too many printer modules! I cut the cable assemblies and soldered some pin header terminations on one pair, which will be convenient for me to stick it in a breadboard and/or connecting to the FTDI adapter for testing before getting into the real code for the controller board.

    Now, time for a sanity check.

    I never could find documentation on the GoojPrn, but it looks suspiciously like the APS unit. I found documentation on the APS unit, and have some for the Kashino, too. The Kashino claims that you hold down the Paper Feed button while powering on, and a test print will spew out. The APS claims that you hold down the Online/Offline button while powering on, then click Paper Feed twice, and then releasing the Online/Offline. OK. None of this worked at all on any of the three printers.

    The Kashino and the APS printer just could not be made to do anything interesting with those buttons sequences, and the GoojPrt would only print CP437 once and stop. WTF? Incidentally, the GoojPrt and the APS both come with a strip of paper that is the test page printout, so I know what it should look like. If one came with the Kashino, it's been lost to time. On the Kashino, it just did a paperfeed like the paperfeed button should do, and the APS simply gave me a blank stare. Ah, the joys of documentation on these things.

    In desperation to see something interesting happen (I mean, surely all three can't be broken?) I went ahead and wired them up to my FTDI. I guessed on COM port speed -- apparently the Kashino is 19,200 and both the GoojPrn and APS are 9600 -- and sent a simple "Hello!" message. Yay! It printed! So wtf could be the problem?

    Moving on again, I...

    Read more »

  • ♫ I've Got (too much) Power! (gonna make you sweat) ♫

    ziggurat2907/13/2017 at 18:07 0 comments

    Summary:

    The BluePill board is powered directly from the 5V USB line. The printer requires more power than USB can supply, necessitating an external supply (e.g. 5V wall adapter). Wiring the 5V from an external supply then precludes the use of USB, because the circuitry would directly connect that to the computer's power bus.

    Some minor surgery was done to avoid damaging the PC when the USB is connected. This was done two ways: good, and better.

    Deets:

    The printer requires more power that the USB can supply, so an external supply of some sort is needed. It could be batteries, but in my case I am going to use a 5V regulated 'wall wart'. This presents some challenges, though. The design of the BluePill has the +5V USB line connected directly to the input of the 3.3V LDO regulator. Some things that can be done:

    1. if only the ground of the BluePill is connected to the ground of the printer, this would be OK, except then the BluePill will always have to be connected to some USB source of power. Silly.
    2. if the power supply for the printer is connected to the BluePill, this would be OK, but then it would be dangerous to connect the BluePill to the USB port of a host, because that would couple the printer power supply into the host's USB. And you know someone will do that because the jack is there, and anyway I do want to do it because I want the USB CDC functionality. Undesireable.

    So, much as I am loathe to do it, I need to do some PCB surgery. The first surgery is to disconnect the +5V USB line from the input of the regulator. Here is where it is located on the back of the board:

    So, that trace must be cut. Here it is cut:

    Now I can power the board from the external 5V supply, along with the printer module. But, it also means that I will always need the external supply to do the USB. I can fix that by adding a Schottky diode where the trace used to be. That way, USB can power the CPU board if there is no external supply, and the external supply will be blocked from powering into the host if it is there.

    Coincidentally, I have some MBR0540T1 Schottkys, which are just about the correct size. I scraped off some of the solder mask near the via (you can see the scraped area in the picture, above), and soldered the diode from that spot to the other side of the cut trace (borrowing the pad from C7 for the diode's cathode).

    As you know, we typically use Schottkys because they have a low forward voltage drop of about 0.2 V, but really, since the 5V is going into a 3.3 V regulator, you could use a typical silicon diode (0.7 V) just as well.

    Now I can use the USB with safety and confidence! Well, almost. If I want it to be really robust, I also need to add another Schottky on the external supply side, so that the USB doesn't try to power the printer if the external supply is not present. This is because the printer takes too much power for the USB to supply, so mI ight as well prevent that accident from happening, too. This won't require board surgery, but rather a through-hold Schottky can be mounted on the 5V pin of the board. (I haven't done this yet, so no picture, but this one is trivial since the 5V pin is clearly marked on the board. Just be sure the diode is pointed the correct way -- with the banded side towards the board, away from the power supply.)

    In retrospect, I'm a little surprised that the manufacturer didn't splurge on adding the diodes. They did splurge on adding two crystals, and frankly I'd rather if they simply put the one 32.768 KHz crystal, leaving the 8 MHz unpopulated, and redirected that cost into these protection diodes. The chip has a PLL that can synthesize the high frequency clock and phase lock it onto the low frequency crystal, so you wouldn't lose any capability by dropping the high frequency crystal. But, hey, I didn't design the board, and I'll definitely still take it considering the absurdly low cost.

    OK, back to printer interfacing....

    Next:

    More printer interface code.

  • ♫ Flash! (aa-aahh!) Saver of the Usersettings! ♫

    ziggurat2907/12/2017 at 19:02 0 comments

    Summary:

    It occurred to me that it would be useful to save some configuration in a non-volatile manner. This board and this chip does not have any conventional non-volatile storage (e.g. EE or external serial EE), but there's plenty of pages of unused program memory, so I use the last one to be used for infrequently changed NVRAM settings.

    Also, I validated my HP82240B rendering engine.

    Deets:

    Over the past couple weeks it occurred to me that this interface board has some utility beyond the primary intent of being an adapter to a receipt printer to emulate a HP82240B -- for instance, it could be also useful as an IR-to-serial adapter, forwarding IR data to the USB port (or UART if you need to, and don't have a printer there). This is easy enough to do and it's easy enough to set the system up in that manner, but this state will not persist boot-to-boot. So, time for some persistent settings.

    Most non-volatile memory is known for the exhaustion phenomenon, so you generally try to avoid burning/erasing except when needed. Frankly, for this application: storing user settings, the burning/erasing will naturally happen very infrequently since it is a user-initiated activity that is only occaisionally performed. I'm sure all readers of this log post will have long since passed on to the hackerspace in the sky before they have exhausted the million flash erase-write cycles for settings changes. That being said, like my friend Ming the Merciless says: "I like to play with things awhile, before annihilation." So I'm going to go a little further with this featurette.

    The flash is organized in 'pages' which is the smallest unit of erasure. On this part, the page size is 1 KiB. That should be more than enough for my setting storage -- at least until I have a need for large object like strings -- but for now it's just a few integers.

    What I'm doing in this implementation is to store a struct of my settings in the last page of flash on the device (leaving all the previous pages for the program). That last page will have zero or more copies of the settings. The last copy of the settings is considered the current values.

    So, upon boot up, the code searches for the last copy of settings, and initializes the RAM-based copy with that data. If it doesn't find any settings, then it will intialize the RAM-based copy with the baked-in default values. The rest of the system then proceeds to use whatever is in the RAM-based copy.

    I want to have the RAM-based copy because I want to be able to change settings on the fly via the monitor interface (yet-to-be-implemented; it will be on the USB CDC). When you have the device dialed in the way you like, then you can persist the settings.

    Persisting works like this:

    1. find the last valid settings image
    2. see if there is space after it for one more settings
      a) if there is, that is where we will be programming
      b) if there is not, erase the page, and let the start be the place we will be programming
    3. program the flash at the place we located

    A simple scheme, but I wanted to document it here. This way, the flash exhaustion is reduced by a factor of how ever many settings structures can be fit on a page, which presently for me is 64 (but this will go down as I add more settings, but still).

    Other News

    I did validate my HP82240 printer rasterizer functionality. It was a bit painful, but I managed to dump the image over the serial port, then meticulously hand-craft a bitmap of the data. For example:

    0E 00 00 02 00 00 02 00 04 0E 00 00 00 00 00 00 00 00 00 00 00 
    C2 07 00 02 00 38 02 00 04 08 00 00 00 00 00 00 00 00 00 00 00 
    42 B0 3C 47 04 04 87 E3 25 08 00 00 00 00 00 00 00 00 00 00 00 
    C2 53 45 42 04 38 02 14 14 08 00 00 00 00 00 00 00 00 00 00 00 
    42 50 45 42 04 40 82 17 0C 08 00 00 00 00 00 00 00 00 00 00 00 
    42 50 3D 8A 07 44 4A 14 14 08 00 00 00 00 00 00 00 00 00 00 00 
    CE 17 05 04 04 38 84 E7 25 0E 00 00 00 00 00 00 00 00 00 00 00 
    00 00 04 80 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 

    renders into:

    v       v       v       v       v       v       v       v       v       v       v
    .###.....................#.......................#................#......###...
    Read more »

  • Fontastic!

    ziggurat2907/11/2017 at 17:32 0 comments

    Summary:

    My hunting for an existing HP82240B font paid off, and a couple days drugery was avoided. I have converted the found glyph images into my personal format and have implemented the rendering engine for the HP82240B data stream.

    Now I am off to work on the physical printer driver. Or not.

    Deets:

    As mentioned in a previous post, I wanted to look for some existing TTF fonts that might already exist for the HP82240B printer. Sometimes folks create these for simulators to give an authentic look to the output. Having such would save me many hours of manually digitizing the 448 code points (well, OK, about 1/3 less than that of /distinct/ code points) from printouts since I already have a tool for rasterizing TTF to my personal font format.

    At first I found 'HP Printer' somewhere, but it was not for this printer, so no good. In the end, I never found a TTF font, but I did stumble across a printer simulator produced by Christoph Gießelink

    http://hp.giesselink.com/hp82240b.htm

    and somewhere in my travels (I can't recall where, now, alas; so much searching) I found source code bearing this imprint:

    /*
    These are the HP82240B font tables for the Roman8 and ECMA94 character set.
    
    The code is part of my HP82240B Printer Simulator available at
    http://hp.giesselink.com/hp82240b.htm.
    
    This code is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
    A PARTICULAR PURPOSE.
    
    There's no licence behind, so use it in any way you like it.
    
    May 2012, Christoph Giesselink
    */

    which I interpret as being functionally public domain.

    The data was not useable as-is because it is in column-major form, and I need row-major. So, 'big whoop', I wrote a little one-off program (significantly derived from my existing TTF rasterizer -- it wasn't that much new work) to do the relevant rotations and emit font data.

    I have no way of verifying it at this time, but the rasterizer program emits comments showing the image form of the bit pattern, so it seems to be good. Here's a couple examples:

    a couple from the ASCII section

    	//glyph for 0x37 (7), 8x6, at offset 184
    	0x00, 	//........
    	0x1f, 	//#####...
    	0x10, 	//....#...
    	0x08, 	//...#....
    	0x04, 	//..#.....
    	0x02, 	//.#......
    	0x02, 	//.#......
    	0x00, 	//........
    
    	//glyph for 0x33 (3), 8x6, at offset 152
    	0x00, 	//........
    	0x0e, 	//.###....
    	0x11, 	//#...#...
    	0x0c, 	//..##....
    	0x10, 	//....#...
    	0x11, 	//#...#...
    	0x0e, 	//.###....
    	0x00, 	//........

    and one from the high set:

    	//glyph for 0x9f, 8x6, at offset 1016
    	0x00, 	//........
    	0x0e, 	//.###....
    	0x12, 	//.#..#...
    	0x12, 	//.#..#...
    	0x12, 	//.#..#...
    	0x00, 	//........
    	0x00, 	//........
    	0x00, 	//........

    and so on, for the 'Roman 8' and 'ECMA94' sets. Yay! Time saved. (I did send a 'thank you' note to Christoph Gießelink for his work.) With that leg-up, I proceeded to implement the printer state machine, and rasterizer.

    As mentioned, for the rasterizer I am reusing some character blitting code I had already produced for another project, so that part was pretty easy. I did hack it to support wide characters and underline mode, and exploit some peculiarities of this printer.

    The state machine wound up being pretty easy, too. There's just a few states for TEXT, GRAPHICS, and ESCAPE states. The TEXT state checks for a couple special characters, and otherwise does a character blit of the incoming character. The GRAPHICS state instead sends the data to a 'bar blt' routine, which sets the pixels in a vertical bar according to the bit pattern of the received data. The ESCAPE state checks for the few known escapes and otherwise interprets the data as the 'length' parameter before transitioning to the GRAPHICS state.

    The machine invokes some callbacks that the user is expected to implement. Notably, the 'image complete' callback is invoked when a carriage return is encountered. The expected implementation would be to do something useful with the completed bitmap before returning...

    Read more »

  • Raster Blaster

    ziggurat2907/10/2017 at 15:16 0 comments

    Summary:

    Having gotten the peripheral devices supported and abstracted, I'm on to implementing the higher-level objects. The first one I'm tackling is the interpreter/processor of the HP Printer IR data stream. This will maintain the logical state of the printer (current options like font, wide char, bold/underline, X position).

    I am working on implementing the rasterizer of the HP printer data, which will create a bitmap image representing one line of output.

    Deets:

    Since the printer language the HP printer uses is quite different than that of the receipt printer (also the implied character sets), I've decided to treat everything graphically. This means first rasterizing the HP printer's output to an image, and then outputting that image to the receipt printer in it's native tongue.

    The HP 82240B printer has two character sets (the -A had only one, so it's emulation is therefor supported as well), so I'm going to have to go through the tedious process of creating the font for the 256-32=224 X 2 fonts = 448 characters. *sigh* On the positive side, I had completed some character blitting code for a different project a couple months back, so I will reuse that, along with the font format I came up with. It's richer than I need for this, but 'done' is 'done', and there's so much other stuff to do. Also, I'll need to modify it to handle 'wide' mode and 'underline' as well. So there's still some new work to do in that area.

    While I was somewhat dreading this activity as tedium -- and it will be -- there are several simplifications that I can avail myself to in this case. In particular, the HP printer is a line-by-line device, so I only need to rasterize one line's image before emitting it to the physical printer. Additionally, since the HP printer is principally a 5x7 text mode printer (i.e. 6x8 with the inter-character -line spacing), and graphics commands simply set a vertical column of pixels, this means that all my clipping logic will be trivial. Yay, it's the small things in life.

    So really, I think that generating the font data is going to be the bulk of the work for this step.

    I'm reusing a font format I concocted for a previous project. The gist of it is:

    • a header with meta info
    • an array of character descriptors; so variable character width is supported, along with partial character sets (and UCS-2LE if you really need it)
    • an array of glyph bitmaps for those characters

    This is certainly overkill for what I need here, but again, I've already written the code for blitting the characters and I'd really rather reuse that than write yet another blit routine.

    FWIW, the font header is defined as:

    ypedef struct FONT_HDR FONT_HDR;
    struct FONT_HDR
    {
        uint32_t    _nSignature;    //indicates this is a font object
        uint32_t    _nVersion;      //format version
        uint32_t    _nFlags;        //various flags
        uint16_t    _arraylen;      //how many glyphs in this font
        uint16_t    _height;        //common glyph height (pel)
    };

    The signature looks like 'FONT' in a hex editor. The version is 1. The flags indicate the packing of the glyphs (byte, word, dword), whether it is MSB/LSB first, and whether the glyph is mirrored in X and/or Y (not needed here).

    The character descriptor is defined as:

    typedef struct FONT_CHARENT FONT_CHARENT;
    struct FONT_CHARENT
    {
        uint16_t    _charval;    //UCS-2LE of this character
        uint16_t    _width;      //this glyph width (pel)
        uint32_t    _offset;     //relative offset from start of font image
    };

    So, to blit a character, you do a lookup of the character descriptor via binary search, and then you can determine the address of the glyph bitmap, the width, and the height for the blit operation.

    For bitmaps, I generally prefer LSB first. The reason is that this gives me the freedom to choose 8-bit, 16-bit, or 32-bit IO operations directly from the buffer without having to bit shuffle. (Well, on a little-endian machine, but come on, little-endian is the one true way.) This will be a minor annoyance later when I transform the HP printer bitmap into physical printer output data, since that data is MSB...

    Read more »

View all 23 project logs

  • 1
    Connect TSOP module

    This requires no additional components; just 3.3V, Gnd, and the signal connected to PB1

  • 2
    Burn Firmware

    You /can/ do this with the on-chip bootloader, though its a little bit tricky and must be done over serial.  See application note AN3155 for details.  Short story is you will need to hook a FTDI-232 to PA9 and PA10 and move the BOOT0 jumper and use some software you download from ST.  The newer "STM32CubeProg" supports various OSs.
    https://www.st.com/en/development-tools/stm32cubeprog.html#get-software
    I instead personally prefer using the ST-Link v2, clones of which can be had for about $2 an Ali Express, etc.

  • 3
    Configure System

    Freshly flashed to an erased device, the system supports a command line interface ('monitor') on the USB as a CDC serial port.  You can plug it into your computer and connect via a terminal program to change settings.  The default printer model is an EM-205.

View all 6 instructions

Enjoy this project?

Share

Discussions

Rob Jordan wrote 12/14/2022 at 15:27 point

Excellent work! The description of how you overcame the faulty demodulated output of the IR receiver was stupendous. Especially since I'd just been reading on HP forums that the TSOP4133 "won't work" due a lengthy minimum post-burst period. Your writing is fun too!

  Are you sure? yes | no

ziggurat29 wrote 12/15/2022 at 14:16 point

Thanks!  It is on the very edge of the spec.  It works reliably with my calculator, but I can see that perhaps a different calculator's signal might be beyond the edge of detection.
If I were to do it over, I'd probably use a detector designed for IrDA.  In that case, the signal would be the actual modulation, rather than the envelope.  This would mean I need to modify the code for the decoder, but I'd happily do that so that I can keep the integrated electronics goodies of the AGC and filtering. This should be very reliable across calculator variations.
I started working on that some time back, but I destroyed my module somehow, so ¯\_(ツ)_/¯.

  Are you sure? yes | no

Rob Jordan wrote 12/15/2022 at 15:06 point

I'm inspired to try both approaches, so yesterday's ebay purchases included an HP C4103A, which I think is intended for IRDA; Martin Hepperle has written about  how to adapt it for HP calculators. And I also bought some Telefunken TFMS1330, which I think are the predecessors to the Vishay part, and possibly - not sure - have a shorter gap requirement. Thanks.

  Are you sure? yes | no

ziggurat29 wrote 12/15/2022 at 16:19 point

I think the one I was trying was the TDFU4100.  The (modulated) signal looked great on the scope, so I just needed to tweak the code to work with modulated signal rather than envelope demodulated.  As mentioned I destroyed my module somehow.  I'm not sure that part is still in production, but there should be modern equivalents (and that one being SMD was a hassle, anyway).
So I think the IrDA receiver approach is viable and will lead to a more reliable solution than the 4133.

  Are you sure? yes | no

jp cuzzourt wrote 10/19/2019 at 00:16 point

I am just about to embark on a very similar project, and I ran across your write up. Excellent work. I'm starting with a Goojprt QR204 printer similar to one of yours. It is still on the slow boat from China. I also have a working HP 82240B, and several IR capable calculators. I'm planning my first attempt with TSOP38533, and I'm aware of the timing issues. I had read elsewhere that it was insurmountable, but I believed I could correctly decode the IR anyway, and I wanted to play with it. While I was ordering from Mouser anyway, I grabbed a Vishay TFBS4711-TR1 which is an SIR transceiver. I thought if the ir remote demodulator didn't work out, I'd try the SIR hoop-de-doo. 
I'm probably going to start with an arduino, but eventually I think I want to move it to an RPi 0W. I'd love to have some help along the way if I get stuck :-)

Thanks so much for sharing your work on this!

  Are you sure? yes | no

ziggurat29 wrote 12/29/2021 at 14:26 point

The IR part was not at all insurmountable for me, but maybe I got a lucky batch of receivers.  As the years went on, I now believe that a module intended for IRDA will work more predictably, though the decode algorithm will need to be changed significantly because the burst filter in the IR remote modules is effectively not there (the part that makes the output a nice square envelope around the modulated IR burst).  You'll instead get whacked for every pulse within the burst.  But this is straightforward to filter in code; just different.

  Are you sure? yes | no

merrittgene wrote 02/28/2019 at 13:50 point

What about building an interface so my HP-28S could print to any USB printer or infrared transfer to a text file?  Maybe a Raspberry Pi with an IR sensor?

  Are you sure? yes | no

ziggurat29 wrote 12/29/2021 at 14:27 point

that's conceivable.  Also, this project can be run stand-alone (without an attached printer) to serve as a HPIR-to-USB-CDC adapter, allowing your PC to capture the print stream over a serial port.

  Are you sure? yes | no

ddavidmelo wrote 07/18/2017 at 11:20 point

I saw your project, very interesting. I have a similar printer (not equal, but works with HP calculator) and I would like to do something like this with my arduino, is possible and how to do? 

  Are you sure? yes | no

ziggurat29 wrote 07/18/2017 at 11:46 point

Sure, but help me get a clearer picture.
'similar printer... works with an HP calculator'.  Meaning you already have an IR printer? And you want to print to it from an Arduino?  Can you give me a model number I can google, or a link?

  Are you sure? yes | no

ddavidmelo wrote 07/18/2017 at 13:21 point

Hello again, I have this printer [hp printer 82240b]. I would like print few words, by send them from Serial Monitor of Arduino IDE. Something like this:
[String of words] » [Serial Monitor of Arduino IDE] » [Arduino UNO] » [IR led transmitter] » [HP printer]

  Are you sure? yes | no

ziggurat29 wrote 07/18/2017 at 13:53 point

(this goofy web site, I have to reply to your previous post since I can't reply to your lastest post -- apparently too deep nesting for the platform to handle?).

OK, now I get it.  You already have an HP82240B, and you want to print to it.  OK, couple things:

1)  this project is about the reverse, making a function equivalent to the HP82240B, receiving IR, rather than sending -- not sure if you were clear on that, but....

2)   I have already done the sending part successfully in a separate project (not on this forum; it was trivial), so I definitely can help you there, too.

Good news, it's super easy.

Hardware:  You will need an IR LED and a resistor.  Strictly you will need to look at the specs of your LED to really compute the optimal value of the resistor, but you will probably do just fine to a first approximation with something like 220 ohms.

Software:  I'm unfamiliar with the Aurduino platform, so bear with me.  The gist of what you do is send a timed sequence of LED blinks.  In my case, I used two timer resources.  The first one was configured as a PWM generator, the output of which drives the LED.  The second one was configured to generated interrupts at a regular rate, which drives the encoder state machine (which turns on and off the PWM output).

If you like, I will send you my code and a brief walkthrough of what's going on.  I'm quite sure you'll need to modify it to reflect the Arduino API and also the clock speed of the board.  If you have a scope, that will help a lot in debugging, since the printer will just ignore what you send if it's not encoded correctly, and it will otherwise be hard to see if you have the timing correct, or incorrect and in what way.

  Are you sure? yes | no

ziggurat29 wrote 06/25/2017 at 16:20 point

Thanks; Mouser said they ship tomorrow, so sometime this week, hopefullly.  I'll test them the second I get them, and possibly post a screenshot of the scope traces (if I can figure out how to post images -- surely I can do that).

  Are you sure? yes | no

Arya wrote 06/25/2017 at 01:28 point

Great project, I'm very interested in the IR part =) Good luck with it!

  Are you sure? yes | no

Does this project spark your interest?

Become a member to follow this project and never miss any updates