Showing posts with label keyboard. Show all posts
Showing posts with label keyboard. Show all posts

Monday, June 29, 2026

Added Tab5 Keyboard support for my portable emulators for Commodore

 

Tab5 Keyboard is a convenience add-on

I added native keyboard support to my emulators already running on M5Stack's Tab5.

There were already 64/Vic-20/128 original keyboards, CardKB, web page adapter, Palm Portable Keyboard, and custom BLE support.  

Now there is also attached keyboard accessory support.  The Tab5 is a 5" ESP32-P4 handheld tablet with high resolution 1280x720 LCD.  The keyboard plugs into the bottom of the tablet, extending the size, and the capabilities.

The implementation scans all 70 keys for presses and translates to a list of C128 key scan codes into ASCII comma separated and newline terminated form, which the emulators already know how to translate into Commodore model specific keyboard scan codes.  As these are pressed scan codes, the press is persisted in the emulated system until the physical key is released.  These are symbolic mappings, not positional mappings because that is my preference.  Want different?  This is open source!

All visibly labeled keys are supported mostly as is.  Keys not Commodore specific are mapped to a Commodore PETSCII character already mapped to the proper ASCII character for the minimal environment (left arrow, underscore, caret, curly braces, pipe, backslash, backquote, tilde).  In addition, shift [Aa] supports letters, and numbers and punctuation to do the normal shifted characters.  Both [sym] and shift [Aa] do the symbols.   Additional keys worthy of documentation are:

  • _=             RIGHT SHIFT
  • tab            COMMODORE C=
  • sym tab        TAB
  • esc            STOP
  • shift esc      LOAD RUN
  • sym esc        ESC
  • ctrl sym del   STOP RESTORE
  • shift del      INSERT
  • \              £
  • sym shift \    SHIFT £
  • shift -        LEFT ARROW
  • sym shift -    SHIFT -
  • shift +        =
  • sym shift +    SHIFT =
  • sym shift *    SHIFT *
  • sym up         HOME
  • sym shift up   CLEAR
  • sym 1          F1
  • ...
  • sym 8          F8

As a reminder the emulators included are:

  • Commodore 64
  • Commodore 128
  • Commodore Vic-20
  • Environment similar to an Apple 1 (minimalistic 6502/6850/ROM/RAM plus terminal)

Links:

https://github.com/davervw/c-simple-emu6502-cbm/tree/unified-pio

Sunday, May 10, 2026

Palm Portable Keyboard for my custom Commodore Emulators

It's finally here!  After years of anticipation and a weird workaround, the ideal solution is implemented and working.   I can finally use my Palm Portable Keyboard (PPK) with my custom emulators for Commodore 8-bits.   Github: ppk_bluetooth_for_cbm

PPK BLE adapter for wearable/portable emulators of 8-bit CBM systems

History

The Palm Portable Keyboard was released for the Palm Pilot PDA lineup in late 1999.  I remember getting mine right away for US$99 from Circuit City.  The Palm IIIc came out in early 2000 and got one of those too.  To date my longest use was to write up notes on a plane ride.  (Let's just not think too much about me leaving/losing the keyboard in the seatback pocket.  Ouch!  Rushed out and got a replacement at $99.)   Back in the day, it was mostly for the cool factor.   I loved gadgets, and between the Palm III color and the keyboard, and the Kodak color camera, I had some pretty cool gadgets.  I knew I was cool, even if no one else believed.

Fast forward to 2020 when I'm enjoying building emulators for Commodore 64, 128, and Vic-20 on wearable and portable platforms based on ESP32 and similar.  One real need was to input into these devices.  With the STM32F4 I had gotten USB-OTG to work, and mapped a standard USB keyboard to trick the Commodore into thinking a normal matrix keyboard was present.  The Teensy 4.1 target was a direct port of that keyboard code as it had an optional external USB host port.  Also worth a mention of leveraging the same algorithms and data to support keyboard mapping with my Typescript port.

STM32F4 with USG OTG

Teensy 4.1 with keyboard cord off top of photo

Once I had a wearable emulator on my wrist, I also looked for keyboard solutions.  On one July 4th holiday vacation I was able to research and implement a web page helper that translated keystrokes in the keyboard and sent them as Commodore scan codes over USB serial to the emulated system.  And I also found a way to leverage this on my Android phone so it would host the web page and transmit over its USB serial (OTG) to the emulated target host.

Wires and phone required in 2023

More development later, and I had an adapter for a real Commodore keyboard to serial TX line (plus 5V/GND input), that could plug into the Grove connector of the M5Stack targets.  Sure it was fun to plug in a real C128D keyboard into a system with a 2" LCD; quite the show off I am, looking for a good laugh.  But it also worked!

More work (and purchases) later and I had M5Stack's CardKB keyboard, and wrote drivers for that to convert to scan code presses and releases for Commodore.

And then I created a Bluetooth (BLE) adapter to convert serial/I2C connections to a wireless connection.  The keyboard and the wrist emulator could be used with direct wiring.   Much to the delight of portability and more showing off.



External Commodore Keyboard Scan Code Protocol 

Out of necessity, a standardized protocol was born by accident.  Standardized to my implementations only so far, but I was for sure the beneficiary of such technological advance.

The protocol depends on two features:

1. Serial transmission of changes

2. List of Commodore 64/128 scan code values, comma separated, newline (serial only) terminated

Example:

15,7

which means left shift and up/dn key (= cursor up)

The emulators targets (see Unified branch of github.com/davervw/c-simple-emu6502-cbm) support this protocol over USB serial, Grove port (UART RX), and custom BLE service depending on hardware capabilities.   Internally the list of scan codes is used to provide feedback from I/O read/write processing from the 6502 checking to see what lines are connected.  So while I could have implemented a more binary or compact format of transmitting this data, I enjoy the diagnostic capability of seeing the values clearly when necessary.

The keyboard hosts utilizing this protocol include the key scan codes helper for the web (USB serial out), two instantiations of 25-pin matrix to UART TX supporting real Commodore keyboards, and a BLE bridge firmware with a Grove connector (e.g. on M5Stick-C).

The scenarios that work include

1. Type from my Windows keyboard, adapted to scan codes sent over USB serial (any of the targets).  Keyboard and target are both wired via USB.  A web page is making the translation and bridging between the keyboard and USB serial.

2. Connect Commodore keyboard adapter directly to Grove port on one of the various M5Stack devices: M5Core, M5Core2, M5CoreS3, Tab5.   This looks like a Commodore keyboard wired through a mess so tied to the target.

3. BLE adapter takes scenario #2 and cuts the wire between the adapter mess and the target.  The target appears free and clear of any wires (if self powered).  The adapter can be tucked into/under/next to the keyboard.  While this acts as a Commodore BLE keyboard, the keyboard itself has a mess of wires, power supply, and adapters.

The BLE adapter actually accepts THREE different inputs.  USB serial (from PC host), Grove UART RX, and Grove I2C for CardKB).  Note that CardKB isn't using my keyboard standard as an input because it has its own protocol, and I didn't feel like reprogramming it.  CardKB drivers are in both the BLE adapter, and in the emulator itself for supporting direct connection.  Both CardKB uses are converting and outputting the Commodore scan codes internally.

4. USB host adapter takes a standard USB keyboard and converts to UART TX.  This can be cross wired from Grove port to Grove port, or be used in conjunction with #3 (great!! more adapters to the mess) to appear as a USB to BLE wireless adapter.

So I've created an ecosystem of keyboard compatibility built on a custom "standard" so parts can work together and interchange/swap.  It allows for flexibility, and interconnections.  And when a new keyboard input source comes along (like PPK), implementing the current standard brings extra value to the table.

PPK BLE adapter firmware customized for Commodore

The pre-existing firmware for the Bluetooth adapter as developed by pymo took the obvious choice - present as a standard Bluetooth HID keyboard.  That solution works for Windows, Mac, Android, iPhone, and others.  It's a great standard.  But it doesn't directly translate to a great Commodore keyboard experience.  And I don't have a general BLE HID solution integrated into my emulators yet either.

With the way things are with my custom Commodore scan code protocol, it made sense to revise the PPK BLE adapter directly, take advantage of all keys present including Fn and special purpose keys, and map them to what makes sense for Commodore.   And add extra value too!

Palm Portable Keyboard

       1   2   3   4   5   6   7   8   9   0   -   =  Back     Date
    Tab Q   W   E   R   T   Y   U   I   O   P   [   ]    \     Phone
    Caps A   S   D   F   G   H   J   K   L   ;   '   Enter     To Do
    LShf  Z   X   C   V   B   N   M   ,   .   /   RShft Up     Memo
    Ctl Fn Alt Cmd {Space  Bar}Spc2 ` Done{Delete}Lt Dn Rt

Let's compare to the layout of my favorite Commodore system, which is a superset of C64

Commodore 128

    Esc Tab Alt Cap     Help LF 40/80 NoScroll     Up Dn Lt Rt         F1  F3  F5  F7

    ←   1   2   3   4   5   6   7   8   9   0   +   -   £   CH   Dl    7   8   9   +
    Cntl Q   W   E   R   T   Y   U   I   O   P   @   *   ↑   {Rest}    4   5   6   -
    RS SL A   S   D   F   G   H   J   K   L   :   ;   =   {Return }    1   2   3   {Enter}
    C=  Sh  Z  X   C   V   B   N   M   ,   .   /   {Shif} Up/Dn L/R    {0   }  .   {Enter}
               {Space                       Bar}

These are the symbolic key mappings I came up with

PPK C64 Normal

       1   2   3   4   5   6   7   8   9   0   -   =  Back     F1
    Tab q   w   e   r   t   y   u   i   o   p   [   ]    £     F3
    Cap  a   s   d   f   g   h   j   k   l   ;   '   Retrn     F5
    LShf  z   x   c   v   b   n   m   ,   .   /   RShft Up     F7
    Ctr Fn Alt Cbm {Space  Bar}Rest ` Stop{Delete}Lt Dn Rt


PPK C64 Shift

       !   @   #   $   %   ↑   &   *   (   )   ←   +   Ins     F2
    Tab Q   W   E   R   T   Y   U   I   O   P   {   }    |     F4
    Cap  A   S   D   F   G   H   J   K   L   :   "   Retrn     F6
    LShf  Z   X   C   V   B   N   M   <   >   ?   RShft Up     F8
    Ctr Fn Alt Cbm {Space  Bar}Rest ~ Stop{Delete}Lt Dn Rt


PPK C64 Fn (and Numlock)

                               7   8   9   +       =  Home     Help
                                4   5   6   -                  LineFeed
                                 1   2   3   En      Enter     40/80Display
    LShf                          0   0   .   En  RShft Up     NoScroll
                                      Esc {Home } Lt Dn Rt


PPK C64 Caps (C128 only via emulator)

       1   2   3   4   5   6   7   8   9   0   -   =  Back     F1
    Tab Q   W   E   R   T   Y   U   I   O   P   [   ]    £     F3
    Cap  A   S   D   F   G   H   J   K   L   ;   '   Retrn     F5
    LShf  Z   X   C   V   B   N   M   ,   .   /   RShft Up     F7
    Ctr Fn Alt Cbm {Space  Bar}Rest ` Stop{Delete}Lt Dn Rt

Reference

  • Fn Backspace and Fn Del maps to Home key for moving cursor to upper left on Commodore
  • Fn Shift Backspace and Fn Shift Del map to Clear key to erase Commodore screen
  • Fn = toggles NumLock mode, sends unique C128 scan codes for numeric keypad, Enter, and arrow keys.   Hold a key with Fn to send the opposite scan code if necessary.
  • Fn LShift RShift toggles shift lock mode, mimicking the positional switch on Commodore
  • Caps acts as a toggle switch to represent the positional switch on the Commodore 128.  Whether letters are shifted (capitalized), and punctuation is not shifted is the job of the C128 ROM.
  • Fn Done is Esc
  • Alt works only in the C128 mode of the emulator

The end result is a full-featured Commodore 128 keyboard for use with Commodore 128 emulation.  (And some standard ASCII keys [{}~`|] not present with Commodore, so more useful in non-Commodore emulation).  And by the way, the Commodore 64 and Vic-20 emulations map the extra C128 keys to its own matrices automatically -- unlike a real Commodore 128, etc.   For instance, the four arrow keys and numeric keypad don't work in C64 mode on a real C128, but they do in the emulated system -- appearing as if the original 64 key matrix keys were pressed instead.   This is implemented in the emulator itself.  The keyboard is optimistic and reports everything expecting a C128 on the other end.  The emulator maps extra keys down to C64 keys, and if in Vic-20 mode, unscrambles into the Vic-20 scan codes too. 

(C64 and Vic-20 share the same exact keyboard, but the lines were reordered when connected to the I/O chips.  The same keyboard would work in the C128 except for the missing keys - the C128 is a superset.  How do I know this?  I use both a real Vic-20 and real C128D keyboard interchangeably connected to my self designed Commodore to UART Tx [Grove] adapter, and they work interchangeably in my emulator.  How cool would it be to build a C128D replacement keyboard from a Vic-20 keyboard in case?  That would blow some minds.)

Operation

1. Plug in the 3D printed Bluetooth adapter and circuit into the PPK to automatically turn it on and start transmitting that it is in pairing mode (rapid Green flashes).

2. Turn on or reset the Commodore Emulated system (e.g. M5CoreS3 or Sunton)

3. Wait for Commodore to boot

4. Should be paired (occasional Green flashes)

5. Type away!

Sunton 7" tablet (Perler bead frame) and PPK BLE

Conclusion

If you have a Palm Portable Keyboard (PPK), access to a version 2 PPK BLE adapter from pymo / Xinming Chen, and you need your wearable or portable Commodore fix with access to a compatible embedded target, then of course this project is for you!   Enjoy the ultimate in retro portability without wires.  And look cool doing it!

Friday, June 20, 2025

Keyboard Editor/Driver for Commodore 64

Keymap Editor for C64

This utility (available from github) allows the user to specify how to remap physical key locations on the Commodore 64 keyboard to different PETSCII keystrokes.

The original intent is to put punctuation keys where they are supposed to go compared to modern keyboard layouts.  If one is using an authentic keyboard or equivalent then you may reach for the wrong key if trying to type an @, quotes, or colon.

Control keys revised with numeric keypad

One scenario you may not have thought of is to create a temporary palette of Commodore graphics characters in a custom configuration for programming a game or screen, where the graphics characters are not presently mapped to the keyboard, or not in intuitive locations.  You can always restore to the default keyboard mapping, or load another preferred one.

The popular scenario for non-US users is for international keyboard layouts: to match regional differences in layouts, and to support characters not present in the US character map, including corresponding character font image differences.  There are existing ROMs that include modified layouts and character images and are available at zimmers.net.  Some have slight differences, and some have great differences; changes may also be focused on the upper/lowercase character set in comparison with the upper/graphics set.

Danish ROMs example

Alternatively to having different ROMs, one could modify in RAM including the character set with a font editor, and manually revise the keyboard layouts with the utility I am describing here.

Font editor is also available

Remapping punctuation example

Here are some step by step instructions for remapping the punctuation

1. Start your Commodore 64

2. Insert c-keymaps disk (or 64keymaps.prg)

3. LOAD "64KEYMAPS 49152",8,1

4. SYS 49152

5. Navigate to full colon key with cursor keys

6. Type new key to use: single quote ', and it will appear in its place

7. Press cursor left to return to that key

8. Press home to switch to mapping when shift key is pressed

9. Type new key to use: double quote ", and it will appear in its place

10. Navigate to the punctuation in the numeric key row (still in shift key map), and update them according to your preferences, e.g. !"#$%^&*()

11. When changes are to your liking, press F7 to Save

12. The program exits to BASIC showing you a driver program entry and has typed SAVE" for you.  Complete the filename, end the quotes (probably using the original keystroke if not active yet) and add comma 8 for the disk drive, and press RETURN.

13. Once saved, you are welcome to VERIFY as well, and/or make sure your drive is not blinking red

14. To activate the driver, one need only RUN this program in memory.   Validate the keys are mapped as expected.

15. When your computer is restarted, you need only load and run the driver you saved to apply the key mapping.   The editor is the 49152 program.

16. Whenever the editor is in upper memory, you can return to it with SYS 49152.  Whatever active keyboard mapping is in effect will be displayed for editing, whether that be from ROM or RAM.

17. To return to the ROM keyboard mapping, press STOP+RESTORE and verify normal operation (but if the keyboard is not working, or system is locked up, you may have to reset the C64 computer).

18. Whenever the RAM driver is running, editing will use the new mapping, but changes are not applied until you press F7 for Save.  When the program for the driver is displayed be very careful not to LOAD over it (like a directory), or your system will lock up because the system was relying on the keyboard driver between addresses $0800 and $09FF.  To avoid this, press RUN or STOP+RESTORE first before loading a new program.   RUN will move the start of BASIC programs up to $0A00.

Advanced uses

Some keys are not typeable, or you may want to choose them visually.  Also, any navigation controls cannot immediately be typed for mapping as they will move the cursor around, etc.

So to get to the character selection screen, press RETURN on a key to edit.

Character selection "picker"

To choose a character, navigate to it and press RETURN, and the display will return to the main editor screen with that character replacing the previous one.

Alternatively, you can select most characters by typing them, and the current keyboard mapping will be displayed as navigation will move to the typed character. 

If you need to find a keystroke that is a navigation control (e.g. cursor key, RETURN), then press F3 first, and then any key, and that corresponding key will be selected.  You have the option to continue navigating, or press RETURN or STOP to return to editing.

Conclusion

While the editor is MIT LICENSE (do most anything with it, but give me credit if you republish, distribute), the driver portion is considered Public Domain as it is trivial, do with the bytes $0800-$09FF any way you see fit, though many bytes $08FC-$09FF are the mapping bytes and will be mostly copies from Commodore ROMs, so tread carefully with redistribution, or just use for personal use.

Hopefully you find this pair of utilities (editor and driver) useful and/or entertaining.  Enjoy!

Tuesday, December 24, 2024

Avoid conflicts between C64 keyboard and joystick #1

 



The Commodore 64 keyboard may display unexpected characters when joystick #1 is used.  There is a solution!  Avoid the keyboard when scanning the joystick, and exclude the joystick data when scanning the keyboard.  But somewhat easier said than done.

Tracing the source of the issue is that PORTB of CIA1 is connected to the keyboard and first joystick simultaneously.  Normally the C64 KERNAL IRQ will write zero bits to PORTA to select a row, and read from PORTB to read the columns.  And reading the joystick also is read from PORTB.  So with two devices both read from PORTB there's bound to be conflicts.

Reading from the joystick without conflict from the keyboard is the easiest solution.  Write 0xFF (all ones) to PORTA to turn off reading any of the column lines from the keyboard, and read PORTB.  The result will only be the lines from the joystick.  Any of the lower 5 bits which are zeros will mean that the corresponding joystick line is pulled low (switch is connected), meaning a direction is held and/or the fire button is pressed.

Accommodating keyboard reads ignoring the joystick is not as easy because the joystick cannot be logically disconnected in the same way, it is always connected.  The approach I took was to read the joystick, and then read the keyboard ignoring any lines active on the joystick.  This solution gives the joystick priority (as it is always connected), and skips supporting some keystrokes which would otherwise conflict with the joystick.

As inputs can change suddenly, there is debounce logic consistent with how the Commodore KERNAL already handles the keyboard.  Any reads of PORTB are followed by a comparison with PORTB, reading it twice, and making sure the values are identical.  If there is a change in values, the process is repeated without limit.  Both the joystick and keyboard in this solution both have this debounce logic.  And additionally, the joystick is read before and after the keyboard is read, so if there is a change in the joystick values, the process as a whole is repeated for that keyboard row.  As the joystick is repeatedly read, only the last value for the last keyboard row will remain until the next scan.

To implement a general fix for the BASIC Editor (which accepts keystrokes and draws characters on the screen), the IRQ scan key handler would ideally be updated to incorporate these changes.  But the challenge is that the IRQ does other things as well, and the scan key routine is not vectored.  But the key log routine is vectored, which is called when any key is pressed, so the IRQ can be intercepted to scan the joysticks, and the key log routine is intercepted.

The key log routine is responsible for interpreting raw key matrix presses, handle character set swapping, keyboard repeating, and putting keys into the keyboard input buffer.  The new code vectored here effectively throws away the old scan key handler by doing its own new scan key routine avoiding conflict with joystick #1, writing its own results to the current key scan matrix value and shift flag memory locations, and then returning to the existing key log routine to handle these filtered key presses.

The effect is a cleaner keyboard input without conflict from joysticks, and joystick values stored in memory locations 253 and 254.  The joystick values are inverted so they are 0..31 based on positioning (1=up, 2=down, 4=left, 8=right) and fire (16).

Instructions: load the machine code at absolute address, and SYS 49152 to activate it.  Only titles, copyright, and links will be displayed.  While active, keyboard and joystick #1 will avoid conflict, and joystick readings every jiffy will be available to peek from memory locations 253 and 254.  Press STOP+RESTORE to deactivate it.  When deactivated, normal operation including possible conflicts will occur.

Links: open source and d64



Saturday, December 9, 2023

Commodore keyboards go wireless for my portable emulators

The c-simple-emu6502-cbm project supports a number of ESP32 platforms to provide a subset of Commodore C64 (and Vic-20, C128) emulation, and many currently include BLE keyboard support.  Originally for CardKB only, now I have added BLE support for Commodore keyboards (20 to 25 pins) to the m5, T-Display-S3, and ESP32-8048S070-7inch ports/branches into the encapsulated BLE_commodore_keyboard_server Arduino sketch.

BLE options: (a) Commodore keyboard (b) CardKB

No expense spared for these awesome graphics, seems retro eh?


While I have wired in the full C128DCR keyboard in the past using a circuit and software sketch with an Adafruit ItsyBitsy, now I trade the wire with another ESP32 and BLE communications.

M5Stick-C with CardKB BLE connected to T-Display-S3

Actually we already had BLE CardKB support, and the protocol for the hard wired keyboard is exactly the same as sent over BLE (string of active C64 and C128 scan codes), it was just a little bit of further coding to make the choice between CardKB and hardwired keyboard.   In fact, that code was already present for CardKB or hardwired keyboard in the M5 branch itself.  The tiny bit of extra work was to duplicate that in the BLE keyboard server project.   And voila!  More options all the way around.

Wired keyboards (a) Commodore (b) CardKB (c) Chrome Browser

There were already three options for wired keyboards.  And three common Commodore keyboards were represented, because they all have compatible pinouts, and because I do have both Vic-20 and C128DCR at home.

Dropping the wire from the wearable (or other ESP32 emulators) adds convenience to mobility, and also defers the need to support wired connections to any ESP32s missing Grove connectors and any that are not 5V tolerant, as both the ItsyBitsy and CardKB use 5V interfacing.   BLE support, and improved BLE support provide more options to the emulators running on hardware such as the T-Display-S3 and the 7"LCD ports without any hardware interventions.  While these latter ports would require extra circuitry for hardwired serial or I2C connections including 5V to 3V3 interfacing, using BLE means that the existing circuit support on the M5Stick-C acting as the BLE server can wire to those keyboards instead.  Going wireless provides the equivalent functionality without requiring a hard-wired circuit to the final display device.

While wireless does have its convenience, it does require careful timing to pair correctly.  Typically if both the BLE client and server are powered or reset at the same moment, they should pair.   A few or more keystrokes may be necessary to confirm pairing is complete.  If it doesn't work, just reset and try again.

Happy C64 computing over BLE!

Monday, December 4, 2023

New! and Improved! C64 text emulator

There has been a steady stream of improvements to my wearable C64/C128 text emulators and related projects since the Summer 2023 debut at VCF West 2023 in Mountain View.  My Twitter/X account includes posts of many of these advancements.

  • used a 6502 test suite to find problems in my emulation
  • Vic-20 emulator
  • Vic-20 upscaled resolution
  • A few more hardware targets supported, including much smaller sizes
    • M5Fire 320x200
    • M5Atom S3 128x128
    • M5Stick-C 160x80
    • LilyGo T-Display-S3 320x170
  • Downscaling resolution as necessary
  • Tilt and pan for 1:1 resolution on tiny screen sizes
  • FATFS partition for files when no SD present, and when PSRAM not present
  • M5Stack CardKb support
  • wireless keyboard (BLE server/client)
And all these changes are stored on GitHub of course!

A fellow attendee at Vintage Computer Festival West 2023 sported a red M5Fire and it looked really good!  So I ordered one soon after, it arrived with some other goodies, and I quickly ported the M5Core2 and M5CoreS3 solution to the M5Fire.   Features are comparable.

Then I added keyboard support to the on-screen buttons.  Left goes up.   Right goes down.   Center is Return.  Left+Center is Shift+Run with a ROM change to make it load the first program from disk.  And Left+Right toggles between the different emulators (C64 -> C128 -> Vic-20)  This made an actual keyboard optional for demos.  I had a boot program to provide a listing of programs selectable by cursor keys and Return key.  

The only downside is that the M5Stack Fire is not watchband compatible in that the recharge circuit is in the detachable base, not in the unit itself.  Otherwise it would make a classy wearable.


Vic-20

The Vic-20 was my original home computer.  It is what I used to deep dive into Commodore, learning BASIC and 6502 Assembly Language inside and out from about 1982 to 1985.  I still have a fondness for this system.

But it has an odd screen resolution.  Text is 22 columns and 23 rows equating to 176x184 pixels.

The M5Core series controllers have an LCD 320x240.   This was just perfect to match the standard text screen of the C64 which is 320x200 pixels. 

Originally I simply increased the border sizes around 176x184 pixels.

Then I revisited my Teensy C64 which has an option for a 480x320 LCD screen.  For that project I researched upscaling, which involved scaling an 8x8 character cell to a 12x12 character cell, using color averaging.

For the M5Core series, I similarly scaled the Vic-20 8x8 character cell to 12x8.   To accomplish this, staring with pixel offset 1, an extra column is interpolated from the previous and next pixels, and repeated a total of four times.  The LCD works in 16-bit color mode with 5 bits for red, 6 bits for green, 5 bits for blue.  The color of the two pixels is broken down into its component red/green/blue parts, the corresponding color parts are averaged (totaled and divided by 2), then recombined into a 16-bit value for the interpolated pixel.

So far only the M5Cores with PSRAM have Vic-20 and C128 support.

M5Atom S3

This is the smallest target hardware I have ported to.  Downscaling was implemented to see what would happen.  The 8x8 character cell is downscaled to 3x4 pixels, so 64 pixels downscaled to 12 pixels which is a large number of pixels to through away.  Priority was given to the center pixels, so it toggles between averaging 6 (3x2) or 4 (2x2) at once.  It does a weighted average between the foreground color, and background color pixel counts, so the resulting downscaled pixel is closer to one or the other.

Surprisingly, the screen is somewhat readable even with this resolution loss.  But to compensate for loss a zoom and tilt to pan feature was implemented.  The whole screen is mounted as a single pushbutton.  Clicking it toggles between zoomed out to the downscaled resolution, and the zoomed in to the pixel perfect 320x200 resolution that is panned, by tilting the device.  Zoomed in, hold the device level with the floor, with the screen pointed to the ceiling, and you will see the top center of the C64 screen.  Tilt to the right and forward to see the top left corner of the emulated screen, and so forth to switch between one of six views of various parts of the emulated screen with every pixel shown.   Click again to zoom out for an overview of the entire screen, but downscaled.  Break out a magnifying loop or such to see the detail of the teeny tiny pixels.

This platform does not include an external storage device such as SD card.  Nor does it have PSRAM normally used by the D64 emulation.   Instead, a FATFS partition was initialized, and individual C64 PRG files were selectively uploaded to the device.   The "$" directory functionality is not present, but LOAD/SAVE/VERIFY are supported.   There is room for about 1.5MB of files in the partition size selected, that's about 9 times larger than the standard single sided C64 floppy, so not too bad!

M5Stick-C

I had forgotten about this hardware device.  It was the first M5Stack device I had purchased, and I had squirreled it away in a project box.   Obviously it was too small for a C64 screen so I didn't give it another thought.   Until I saw a post on Twitter/X showing the solution with CardKB.  Looks like it's using my text-only emulation, using LCD fonts.  Of course I respond!  That would work very well.  I've just been so focused on LCD pixelized solutions simulating the look and feel of Commodore instead of remembering the roots of my text emulation efforts with C64.   Just hook CHARIN and CHAROUT and you're golden.  You don't need a screen editor.  You can just do buffered line input (local edit), and character output.   I was laughing at myself for not pursuing this myself.  CardKB provides ASCII output (from I2C polling) of the alphanumeric characters, and other byte ranges for functions and cursor keys. 

I wanted to do CardKB, but as I have been focused on C64 scan code adapters, it seemed hard.  But here was the challenge presented on the Internet.  I had already implemented an adapter of sorts leveraging a SeeedStudio ATMEGA328P (Uno compatible) board with Grove connectors and an Arduino sketch to translate I2C reads into TTL serial scan code reports.  And it worked, but was very clunky because of all the cords and extra board.   My existing prototype solution was not great for a wearable solution.

The M5Core and such were focused on using the Grove connector as a software serial port, receiving the C64 scan codes.  I had the original C128/C64/Vic-20 keyboard to Grove adapter running on an Adafruit ItsyBitsy and that was my favorite keyboard connection because it was true to the original!  Next best was a web page to USB Serial adapter I had also developed.   The common ground was scan codes, and serial communication.  But the CardKB runs I2C.   So how to do CardKB and serial communication simultaneously on the same Grove port?   Originally I thought of getting the source to CardKB and rewriting, reflashing it to do serial communication instead.  That would make it compatible with my existing solutions.  But I was avoiding the reflashing that would also requiring rigging a programming interface, using an Uno or compatible.   

Instead, I approached the Grove port as an either or, the emulators were updated to check for an I2C response at startup, and if found, regularly read from the I2C port for keyboard presses.  Then adapt those presses from ASCII/function code presses into momentary C64 scan codes, and 1/60th of a second later, respond with no key pressed (key up) scan code response.  This is an out of the box solution that will work for others too!

M5Stick-C also leverages a FATFS partition as there is no built in SD port.  Again 1.5 million bytes.,  Though I did have to revise the partition choices manually via a JSON file as FATFS was not included in the default partition schemes presented.

But the screen resolution is 160x80, with downscaling of one character's 8x8 pixels to 4x3 pixels.  This time the pixels are halved horizontally, and vertically there is an 8 to 3 pixel translation, very similar to 
the downscaling on the AtomS3, but rotated to different axes.

This is by far the worst unreadable display for individual text characters.  More than halving the vertical resolution makes the text completely unreadable (such as the startup screen).  It's not it's fault completely, and is a cute form factor when not pretending to be a C64.

LilyGo T-Display-S3

This is another inexpensive device with a wide yet shorter display 320x170.  Oh so close to the necessary 200 pixels.  So a custom downscaling algorithm favoring the center four vertical pixels of each character cell, while averaging the top two and bottom two pixels.  This results in a very recognizable display of alphanumeric characters with some slight distortion at the top and bottom of each character.

While this device has plenty of flash storage and PSRAM comparable to the best of M5Stack Cores, there is no built in SD card, so the implementation also leverages a FATFS partition successfully.  But with the PSRAM included, D64 support could be included allowing for the floppy drive image feature.

BLE keyboard support has also been included with this one, making it full featured.

The features missing are no Grove connector, no socket for CardKB support, and Vic-20/C128 support.  A bit more effort could transfer these features with software and hardware.

CardKB

     Esc 1! 2@ 3# 4$ 5% 6↑ 7& 8* 9( 0) <x
     Tab Q  W  E[ R] T/ Y£ U| Iπ O' P" fn
  Up  Shift A; S: D  F+ G- H← J= K? L  <-
Lt  Rt  Sym Z  X  C  V  B  N  M  ,< .> __
  Dn

fn+1..fn+0 is ctrl+1..ctrl+0
fn+A..fn+Z is commodore+A..commodore+Z
Esc is stop
fn+Esc is stop+restore
tab is load+run
fn+tab is restore
fn+<x is insert
fn+up is clear
fn+right is home
fn+down is toggle case (cbm+shift)

Wireless BLE Keyboard

Taking CardKB one step farther is joining it with a M5 controller such as M5Stick-C to turn it into a Bluetooth Low Energy keyboard.  Currently integrated with M5Fire, M5Core2, M5CoreS3, and T-Display-S3, turn them both on at about the same time and they will automatically pair.  While the keyboard is wired to the M5Stick-C, another ESP32 system can be battery powered and receive keystrokes over the air with the BLE (2.4GHz) radio.  




I used to wire the full size C128 keyboard to my wrist, and it was a hilarious irony in mobile computing.

Friday, June 30, 2023

Extremely small emulated C64 and C128

 


This "portable" Commodore 64 and 128 emulator (m5 source code branch) is my work in progress, one in a series of minimalist emulators ported to different hardware targets. Only text (on LCD) with background, foreground, border colors, keyboard entry via USB serial tethered web browser, and general 6502/6510 and C64 memory management emulation is present (no, won't play games, make sound, or do bitmapped graphics) with some D64 emulation [added 7/2/2023].

(Update 7/28/2023) Now with GO 128 command.

GO 128 command


Even my son asked, "Why do you need to do that?"  Well, he has a point.  I wanted a C64 that fit in my pocket or even on my wrist.  And targeting new hardware platforms with my emulator is part of my hobby.

How does it work?  Check out my highly technical drawing.

Now I already here you asking why I didn't connect Bluetooth to the M5Core, because certainly it has Bluetooth as well, and why didn't I use a USB keyboard connected to CoreS3, because it includes USB Host.  But I've had trouble tracking down examples of HID Host examples for M5; client examples are prevalent, but host?

Pictured here is a phone is running Chrome with a custom copy of the html/javascript keyboard adapter including web-serial-polyfill because mobile Chrome doesn't directly include Serial API support.  A Palm Pilot foldable keyboard has a Bluetooth adapter, paired with the phone.   HID keystrokes are captured by the web page, converted to C64 key scan codes, and a list of the active key scan codes (or 64 when keys released) is sent over USB Serial to the M5Core device which is running the C64 ROMs which are tricked into thinking a real keyboard is attached; keystrokes are processed by the C64 KERNAL IRQ as normal.

The M5Core is being powered by the phone.   Why M5Core?  Because it's a polished packaged solution.

Yeah, we could just run a Commodore 64 emulator on the phone, but this way, I could have complete control over the keyboard emulation, what keys are present, how CTRL and Commodore keys work, etc.  And it's just because I can, not because I should.

Why the Palm Keyboard?  Because it folds in my pocket!  And because I had one from back in the day.  Any keyboard you can attach to a phone or computer should work.  And this Bluetooth adapter just makes it so cool, and easier than a tethered keyboard.

The next step is to merge this solution with my Commodore 128 keyboard adapter to completely reject the portability feature.   That would look really cool hooked up to my phone!  Update (7/31/2023): check out YouTube for connection from ItsyBitsy/keyboard to Core Port.A.


C128 Keyboard Adapter Breadboarded Prototype


7/23/2023: PCB prototype keyboard adapter w/ ItsyBitsy

I am excited about my nonsense crazy adventures. Even if only I enjoy them.

=====

Update (7/2/2023): D64 support is currently working with Core2 only (Basic Core doesn't usually have the additional SPI RAM, but not yet sure why CoreS3 is failing to attach SD).

Update (7/3/2023): Got CoreS3 working with SD switching header to M5Unified.h for that target (was M5Cores3.h) and adding special definition, override logic for SD_CS to use GPIO_NUM_4 instead of default.  See updates to M5Core.h.

Update (7/28/2023): Commodore 128D extended keyboard working with UART connection to Port.A of Core, and Commodore 128 emulation is ported as well.

=====