Monday, June 29, 2026

BLE HID coprocessor for microcontrollers

 

Teensy in green, ESP32-C3 in blue

I have a Teensy 4.1 operating as a Commodore 64 (and Vic-20, and 128, and Apple 1) emulator.  It already supports USB Host (via 5 pin header on top) and web page helper (via USB CDC).

The Teensy doesn't have wireless capability, but I wanted to add BLE keyboard support.  So enter the ESP32-C3 as a coprocessor.  It is running a custom firmware using the NimBLE library to enumerate BLE HID devices in pairing mode, and connects as soon as it finds one. If everything works successfully, it sends HID reports as ASCII over the UART channel (received at Teensy RX pin 0).  

While the Teensy is busy driving the LCD with a bunch of connections, the ESP32-C3 is only wired at 5V input, ground, and a TX pin.  The ESP firmware is built without USB CDC support so that the Serial line defaults to GPIO.  

Shown is a USB only ESP32-C3 board with the advantage of being slightly cheaper.  When I purchased it years ago when ESP32-C3 was relatively new, it was about US$2 on AliExpress.  Looking today, there's even more choices available in all sorts of price ranges and sizes.

So the Teensy is doing what it is good at, and the ESP32-C3 is filling in a wireless connection gap.  The red jumper is provided to be able to pull power.  Though the power connection does have its advantage that the ESP32-C3 has a USB-C port, while the Teensy has a USB-Micro connector.

Look Ma -- no wires!

Mouse, Trackpad, and Gamepad/Joystick are supported as well.  Gamepads and Joysticks will require HID maps which are loaded but not interpreted yet, nor passed on the interface (work to be done).  Joystick support is not implemented yet in my emulators, but stay tuned!

Update (2026-07-03): coprocessor firmware updated to support my custom BLE CBM keyboard sources, and optionally convert standard HID reports to Commodore key scan codes.  By focusing on Commodore scan codes, the integration with the emulators is now simpler, and seamlessly supports more of my keyboards -- while also as being an option, the coprocessor can be used by those that expect standard HID bytes. (Note: no conversion from Commodore to keyboard HID, only the other way around.)

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, June 7, 2026

Extended Screen for C128




Finally, Commodore 128 can provide the 80 column screen that multiple monitor folks need - extended screen.  Spread those columns across two separate monitors for a wider view.

Instructions

  1. Download disk image, and use as is with modern tools, or image to floppy.
  2. Click the 80 column keyboard button into position to make it the default.
  3. Attach two monitors to your C128.  Composite on the left, digital RGB on the right.
  4. Start up (or reset) C128 with disk attached.  Boot sector will load and run 80DUAL by default.
  5. Enjoy screen extended 80 columns!

It works by reinitializing the VDC 8563/8568 registers to display 40 columns offset by 40 columns, and each line thereafter also offset by 40 columns.  Since the KERNAL hasn't been told any differently, it will continue to treat the VDC as an 80 column display, but the VDC settings are now to display only the right hand 40 columns.  An IRQ routine is installed to copy 5 lines from VDC RAM to VIC-II screen RAM (hardwired to address 1024 currently) and color RAM.  The effect is that as text is typed or displayed on the 80-column virtual and physical display, the hidden left-hand side of the screen will also be displayed on the composite monitor.

This is a proof of concept, and has limitations.  

  • The machine language routines use $1300-$15ff for code and data
  • The code uses self-modification techniques so can't be moved to ROM as is
  • Character set changes are not handled
  • Changing to composite screen is not handled, will continue to be overwritten from VDC RAM
  • No graphics support
  • Slow, less than 12 frames per second operation
  • Not compatible with SNAKE
  • Will interfere with programs that write text to VDC screen using own (not ROM) routines.  It has a fixed list of ROM addresses to avoid interrupting, and doesn't include RAM.
Why?
  • It was a challenge I set myself
  • Because it's ridiculous and outrageous, has little practical purpose.  I like the bizarre possibilities.
  • Related to my rgb64