Showing posts with label hardware. Show all posts
Showing posts with label hardware. Show all posts

Monday, 31 August 2026

MEGA65 Multiverse Bitstream Loader

We've got a great problem on the MEGA65 right now -- there are more cores coming out than you can fit in the 8 slots that the MEGA65 motherboard's flash can fit. But we have a JTAG port, so we have the means to push bitstreams in just a few seconds. A lot of us use a JTAG adaptor connected to a PC to do this and other things. But sometimes you just want to be able to do it without a PC or extra external cabling.  Thus this little project.

The core of the idea is to put a microcontroller on a board that connects to the JTAG port that can push bitstreams.  Now, this can't be from the existing SD cards on the MEGA65, because they're connected via the FPGA that we're trying to re-configure. So it will need an SD card slot of it's own -- which is fine, it means you can have potentially thousands of cores on there, and have the MEGA65 be able to request that it load any of them. The request mechanism will be via a UART.  

So we need JTAG, UART and microSD card.  A cheap PicoPi should be able to talk to all those. JTAG and UART are simple, and it has SPI that can talk to a microSD card. I have a pile of microSD card breakout boards around here that will help me to prototype it.

There's even a WiFi enabled version of the PicoPi, so I might even roll this into the expansion board bridge board and replace the ESP32 on there. (I might be able to make the ESP32 do the microSD card and JTAG, too, but I've not got good enough handle on the toolchain to know if that's possible -- but the PicoPi should be a doddle.)

As this is a little utility thing, I'm vibe-coding the firmware for the Pi. It _claims_ to have implemented the UART control interface and pulled in some FAT file system library etc to talk to the SD card, and adapted the m65 utility's JTAG bitstream pushing. So let's see if it can push a bitstream via UART to JTAG.

To do that, I need to work out the pinout from the Pico to the TE0790 JTAG header on the MEGA65's mainboard.

Pico pin 8 white -> TE0790 pin 2 GND
Pico pin 9 grey -> TE0790 pin 4 TCK
Pico pin 10 green -> TE0790 pin 12 TMS
Pico pin 11 blue -> TE0790 pin 10 TDI
Pico pin 12 purple -> TE0790 pin 8 TDO

With that, I can totally push a bitstream over the USB UART of the PicoPi to the MEGA65! Great news!

The not so great news is it takes 107 seconds!

Now, the UART at 2Mbps means ~5 sec per MB, so about 35 seconds for a 6.6MB bitstream, just for UART transport.  But that still leaves a full minute for the JTAG bit-bashing.

Here's the pretty picture ChatGPT drew me for the pin connections from an SD card to microSD adapter to the Pico Pi, so that I can quickly hack up a test cable: 

 

Textually, that's this:

SD pin 1 CS -> Pico GP5, physical pin 7 
SD pin 2 MOSI -> Pico GP3, physical pin 5 
SD pin 3 GND -> Pico GND (e.g. pin 13)
SD pin 4 3.3V -> Pico 3V3 OUT, physical pin 36 
SD pin 5 SCK -> Pico GP2, physical pin 4 
SD pin 6 GND -> Pico GND (e.g. pin 18)
SD pin 7 MISO -> Pico GP4, physical pin 6

Here's our little octopus (ok, heptopus) assembled, ready for testing: 



Now I just have to find a spare microSD card. I'm sure I have numerous laying around, but can't find any. So I'll go to the supermarket and grab one this morning while running errands, format it for FAT, and then see if the firmware ChatGPT built me can read from it.

Meanwhile, this looks like a great switch for the JTAG bus to allow TE0790 to operate normally, except when we want to push a bitstream: SN74CBTLV3257-Q1.

Meanwhile, I went and got a cheap 32GB SD card from the supermarket, copied some bitstreams and core files on... and it works! I can push a MEGA65 core, and it loads. Okay, it takes 18 seconds, which is annoying, but it loads. The AExp core is refusing to load, though, which I'll have to investigate the reason behind. The problem was in the JTAG closing after pushing the core.

Now it works! I can load the AExp core, for example, and see the workbench hand and load disks and things. Nice.

And with a bit of optimising I've cut the bitstream load time from ~18 sec to ~6 seconds, which feels totally reasonable -- that's about how long it takes via TE0790 with m65 -b.  I could get it down closer to 4 or so seconds by trying to speed up the JTAG, but that's not our top priority right now.

Top priority is thinking through security and physical arrangement.

Security matters here, because the UART  that controls the Pico will be accessible via the MEGA65 user mode as one of the buffered UARTs (it will take the place of the ESP32 on the previous expansion bridge board design).  That means rogue software could install and launch a rogue core that then does whatever it wants -- including fry your MEGA65 if it was nasty enough.

The simplest solution is leave the SD card read-only in this module. Then you have to open the case and take the SD card out to add cores. Doable, but not super nice.

So my two key refinements are:

1. Have a jumper accessible via the user-port cut-out that if fitted, allows writing to the SD card on the module.

2. Position the SD card on the module so that it can be accessed via the user port cut out (even if a bit fiddly so), so that no-case-opening adding of cores is possible.

So I think I'll try to design up the changes to the PCB to support all this, and then we can look to proof-of-concept native M65 software that can talk to this.  The MEGA-FLASH program might want to be updated to allow querying of the SD card for additional cores to keep a single unified core launching experience. But that's a question for after we have working hardware.

Okay, so in the meantime I've finished up an initial PCB design, then made corrections to the SPI pinout just hours after PCBWay started fabrication, so added a 2nd order with the fixed version, and then after all that improved the power circuit so that the Pi can't back-power the MEGA65 (PCBs for that not yet ordered -- I might hand-modify the revH PCBs when they arrive to do this). 

Here's the current (revJ) state of affairs:

 

And how the PCB looks:

 

So that leaves the firmware. I've been shamelessly vibe-coding this using ChatGPT, and have something that works well enough for now: It support AT-style commands on the USB serial or direct UART pins, as well as running a little web server that lets you interact wirelessly to push bitstreams:

And it works! It can load a new core in 5 - 8 seconds, depending on size of core and phase of moon.

The key remaining thing that I want to implement is allowing the Pico to download core files from a specially prepared mirror website, so that you can get all the latest cores on demand.

I'm busy bashing my head against this at the moment. First, WiFi doesn't always power up cleanly. Then when it does, sometimes it fails to join the AP. And then there's firmware bugs with the fetch logic on top of that.  Layers of failure that all have to not happen to progress. Quite annoying.

I'm making good progress on this, getting it to download a core file, and have it in a .partial file while downloading, and cleaning up the .partial files when starting a fetch. But the little TCP stack keeps failing in fascinating ways. I'll keep working on that in the background while I think about other bits.

The other main bit I'd like is to add support for hijacking the MEGA65 Serial Monitor Interface to allow loading of programs remotely etc, and wireless debugging. The question is whether this merely _sounds_ like a good idea, or whether it actually _is_ a good idea. 

Okay, we'll go back to the TCP stuff -- and it's finally working now, downloading core files at 500KB/sec from a mirror on my lan. Will likely be slower over the open internet, but it's all nice an automatic. It now has a "I'm busy updating" web page.

Okay, lots of progress to report! The PCBs arrived, and I've assembled one:


_And_ the SD card _and_ the JTAG bitstream loading on the MEGA65 worked first time! :)

That all makes me very happy. What makes me less happy, is that the JTAG-pass through from the TE0790 to the MEGA65 mainboard doesn't seem to be working. It doesn't even recognise the FPGA on the JTAG chain:

$ m65 --autodiscover --verbose
2026-07-26T07:32:04.864Z NOTE MEGA65 Cross-Development Tool 20260124.13-develo-355b567
2026-07-26T07:32:04.864Z INFO using default FPGA ID ffffffff
2026-07-26T07:32:04.884Z INFO found 0 candidate USB devices.
2026-07-26T07:32:04.884Z INFO requested id ffffffff does not match any usb interface
2026-07-26T07:32:04.884Z CRIT no matching jtag port found, aborting

There's a few possible things that could be wrong here:

1. I have the pinout messed up.

2. The JTAG bus switch is doing something dumb

3. The extra electrical load of the JTAG bus switch is slowing things.

(3) I can check by dropping the JTAG frequency.

I think I might just have spotted part of the problem. Can you spot it in the following schematic snapshot?


 

Let's just say it would be nice if Kicad had a spell checker ;)

Well, except that I had it wrong everywhere which means that it was fine. 

So why aren't I seeing 3.3V on the JTAG header power pins? Okay, forget that. I just had the MEGA65 turned off :/

Time to trace from the TE0790 back towards the MEGA65.

The TCK line is at 3.3V on pin 3 of the TE0790 header. But it's like 0.5V at the input TE0790 relay header on the expansion connector board. This is odd, because those two pins should be directly connected.

Okay, I've definitely screwed things up: On the old connector PCB I apparently flipped the order of the pins of the TE0790 relay to make routing it out on the expansion board easier.  But on the new one I haven't done that. Which means that pins are totally wrong, fortunately not in a let-the-smoke-out kind of way. But certainly in a no-hope-of-the-jtag-working kind of way.

I've fixed that on the schematic. It would be nice to be able to test the electrical path without having to wait for a new PCB spin, but it's not really practical.  The main thing is that I've found a highly probable cause, and can test it out easily once I get the new PCBs spun.

If I'm going to get a batch of those PCBs, I should also get a batch of the M1565 external drive boards made, since I can't find the ones that I'm sure I had made previously. It's a 100x100 2-layer board, so it is only like US$5 to get another 5 made.  The question is whether I have the parts for assembling one lurking around, too, and if so, where on earth I've stashed them. 

I do hate having to prepare BoMs from schematics. So the sooner it's started the sooner its done. And if I order everything today, it should show up by next weekend, all going well.

Digikey parts: 

5mm LED - 732-5016-ND

1565 mini-din - MD-90SM 

A pile of 3.3K Ohm resistors -- those I almost certainly have on hand.

And 1K Ohm resistors.

8-way DIP switch - CT2088-ND 

74LS125 - 296-1638-5-ND

74LS85 - 296-14900-5-ND

74LS595 - Okay, those are like $30 each in LS series! Fortunately HC are cheap still: 296-1600-5-ND

74LS165 x2 - 296-14885-5-ND

74LS04 -  296-1629-5-ND

Okay, I'll order enough parts to make 3 to get free shipping.

Then I just need a mini-din cable that suits the MD-90SM.

For the cable, I also hate soldering mini-DINs, so I'm just going to buy a random one off ebay. This one claims Australian stock, so I'll go with them:

https://www.ebay.com.au/itm/336344275528

Well, cable, PCBs and components all ordered. So that's all I can do on this project until the bits arrive.

It's the following weekend, and the revJ PCBs have arrived, along with a batch of M1565 external drive PCBs... which of course means that I found the ones I already had out in the shed this morning when I went to assemble the revJ board.

I also realised I still hadn't updated the outline of the revJ PCB for the microUSB cable access to the Pi Pico. Nor moved the SD card slot back a bit to make insertion/removal easier.  So RevK here we come.

But the good news: The revJ works, and the TE0790 via the relay port now also works! So we have integrated JTAG with the web interface (and it came up on WiFi on first boot :) and a connected TE0790 works again, too, now :)  The JTAG switch is indeed doing its thing -- if the Pico is JTAGing, then the TE0790 sees an empty JTAG chain.

The next step is to see whether we can talk to the Pico via UART from on the MEGA65 itself. It should work, provided I haven't got the UART pins backwards.

My plan is to test the UART using megacom, the little minicom-like terminal program I made and used in this blog post: https://c65gs.blogspot.com/2026/01/megaphone-cellular-modem-and-power.html which currently lives here https://github.com/MEGA65/megaphone-modular/tree/main/src/telephony.

The UART pins themselves are on P1HI(2) (RX for MEGA65) and P1HI1(1) (TX for MEGA65). But either I'm not using the right bitstream for the MEGA65 core, or megacom doesn't work, because I don't see any UART signalling on either pin when I use MEGAcom to talk to buffered uart 0, which is what (I believe) it's mapped to. And it's not mapped to any of the higher numbered buffered UARTs (just tried them all in MEGAcom).

I can't see what the problem is, but suspect I might be using an old bitstream. So I'm rebuilding a 932-* bitstream, and we'll see if that helps.

Okay, I'm back investigating this again after too long a break.

First up, it looks like the PMOD pins were declared high-impedance above where they get assigned to the UART plumbing. That matches what I'm seeing, in that the pins are floating, rather than driven. So I'll cook a bitstream to test that and see if that gets those pins behaving: Specifically TX pin should be driven high, and the RX pin should still be floating.

First attempt didn't fix it. I'm suspicious that Vivado might be caching some build thing, so I'm re-running it now with make clean first.

Nope, the pins are still floating.

And I'm not getting anything useful out of the keyboard-connector 2nd UART, either. So I'll put a super-simple loopback on the PMOD pins. If that doesn't work, then there's something really really wrong going on.

Well, connecting clocks to the pins I've at least allayed my fear that I had fried those FPGA pins.  So now to work my way slowly back up from this foundation, first by looping back the pins in VHDL, and then after that connecting them to the buffered UARTs.

I think part of the issue is that I'd assumed the p1hi pins were the top row on the PMOD. They're not. They're the bottom physical row which is the high-numbered pins. That probably explains a lot of my headless-chicken chasing.

And that was indeed the root cause. So I have buffered UART 0 talking again on the PMOD, and buffered UART 1 on the keyboard connector.

So the next step is to finally see whether we can talk to the Pi Pico via the PMOD relay to the expansion board. And it looks like I have the UART pins on the PMOD backwards. So I'll fix that, and then check if I can finally talk to the Pi Pico.

Ok -- confirmed that the pins have switched. Now to see whether I can get the Pi to talk to me via the UART.

Hmm.. I got something at 2Mbps, but it was quite garbled.

That said, I can get the same garbled output by typing ATI + CRLF into it repeatedly. 

Yup, looks like it's receiving commands from the UART just fine, but the output coming back is all messed up. 

I've just fixed a bunch of bugs in the Pi Pico firmware, and now AT+JTAGLOAD= works to load a core from the MEGA65 :)

I should probably make a native utility that reads the list and lets the user pick one to start.  I'll probably try getting an LLM to make the proof-of-concept code for that, based on the megacom stuff. It won't be particularly elegant, but it will be a basis on which a real human can build something better. Ideally it would eventually be integrated with the NO SCROLL on boot core loader. And maybe some little program you can put on a floppy, and have it autoboot using the C65/MEGA65 ROM's autoboot.c65 file thing. That way you could have a "kickstart" disk that when inserted and you reset the machine really boots it into an amiga.  And another for C64 mode etc.

Anyway, here's the little thing the LLM hacked up for me from the megacom source (that had the necessary UART code in it). The source is in https://github.com/MEGA65/megaphone-modular/blob/main/src/telephony/jcore.c.

So at this point, we have all the bits we need. 

And that feels like a good place to end this post.  The next one will probably be tackling some of the MEGAphone stuff that all this UART work has setup.

 

Tuesday, 2 December 2025

MEGAphone Case Design

I've been thinking about this part of things for a while, because it's clear that the first iteration of the modular MEGAphone is going to be larger than originally planned, and subject to more evolution for a while.  The goal is to make something that is easy to work on software-wise, as well as being easy to fabricate, and then switch out initial larger modules for smaller more integrated modules later.

So instead of going for a custom machined case, it occurred to me in the shower this morning, that I can just use Pelican style tough cases, with some inserts to hold everything in place.

Doing it this way, we can even allow for the inclusion of a full MEGA65 keyboard, which will make the earlier stages of testing easier.  Similarly, a larger screen could be included.

The more I think about this, the more I like the idea.  Basically we will be making a small number of portable MEGA65s, with cellular capability -- so all the existing development tools and work-flows will still work.

The keyboard PCB is ~32x15cm, and a standard MEGA65 mainboard is smaller than that, so there'd even be room to route standard HDMI to a larger screen in the lid.

It looks like the Tactix Large tough cases will be a good size. And they even come in a nice blue that suits an 8-bit device.  So I've gone and grabbed one, and also fished out the 15" LCD panel I had in the shed from a previous iteration of making a laptop MEGA65. I also have some SVGs with the right cut positions for a MEGA65 keyboard, too.  So this is looking like a good and fast way to build a prototype.

I also have a different prototype MEGAphone that was designed as a land-line, but still has integration of dialer and cellular modem onto a MEGA65 core.  I could in principle fit that into this case and make a working luggable MEGAphone.

Let's start with fitting the LCD, since I'll need that, regardless of what hardware I put in the bottom half of the case. I'll mock it all with MDF panels that I can easily crock up here at home. Then once I know the dimensions of the panels and locations of cut-outs, I can order machine cuts ones online from one of the various fabricators.

The LP154WU1 panel I have is a bit old now, but can still be found online for AU$100 - AU$200 in small quantities, which is all we need for now. The only issue is the driver boards seem to vary with the control button placement. But I can work around that by designing my own, as their interface is extremely simple.  So let's work out how we'll hold the panel in place.  

The panel is just over 5mm thick around the edges, so I could order some 5mm thick shims with a selection of screw hole offsets, so that the screen position and fit can be trimmed a bit, without having to vary the position of holes on the front of the panel.  I'll probably go for 2 screws on either side and on the bottom, and four on the top, with one shim on each side and the bottom and two on the top edge. That should hold in firmly enough if I then have panels that sit behind them and go behind the edges of the panel --- and be safer for allowing variance in the exact dimensions of the panels.

I'll also need a rear panel onto which the driver PCBs can be mounted. That can probably sit in the bottom of the lid, and will have to be a bit smaller to allow for the curve radius of the lid. That panel can probably be fixed to the brace I'll put across the rear of the panel.

Now, that's all a lot of words, so I'll start mocking up the pieces for this, and then convert that to a set of pieces. If I can get all clever, it should be possible to make it able to be cut from a single panel, if the diagonal is long enough to accommodate the back brace, or I do some other horrible hack.  

Anyway, let's start by cutting the aperture for the LCD panel and working out where everything needs to go.

Well, that was helpful in some ways. But it got way too fiddly too fast. So I checked and found our local Maker Space is open on Saturdays, signed up, and went in and did an initial MDF laser cut to test the measurements I'd made.  One of the nice volunteers ran it for me, because I haven't done the laser cutter induction yet:

So much nicer than me hacking away with a jigsaw: 
There were of course lots of holes in the wrong places, so I marked up the MDF and will go back during the week with the updated file: 
 
 
 


In the meantime, I can probably start planning the same for the lower-half.

Years ago I started work on making a laptop MEGA65, and did make SVG outlines for the keyboard cut-out, which would save me a bunch of time about now.  The question is whether I can find it... Nope. So I'll just have to start from scratch. I might be able to save some time by using the MK-II keyboard layout to trace the key blocks.    

Okay, so I've done that, and also gone and picked up a pile more MDF panels ready for testing and revising with the laser-cutter.

So let's finish out the design:  The lower case is deeper, and will need to have, keeping it very modular for now:

1. Keyboard

2. Main logic board

3. Cellular and related modules board

4. Power management board

5. Batteries

6. Solar panel(s)

My plan of using a regular MEGA65 mainboard slightly complicates things, in that it needs 12V DC in, which means we'll need another higher output-voltage DC:DC converter that can be switched by the low-power FPGA.  This is really the trickiest part of the whole thing, because I can't find a DC:DC converter that will go from 2.5V (lowest single-cell LiFePO4 cell voltage) to 12V in a single go -- and that can provide ~2A output.  (The 15" LCD uses about 0.8A, and a MEGA65 uses about 0.3A -- so allowing for some in-rush head-room, 2A feels safe).

Now, the MEGA65 can start with >9V, but the LCD panel's backlight probably really needs 12V, so we'll have to stick with 12V for now.

What I'm looking at right now is one of these eval boards: TPS61088Q1EVM-037, which in theory can Just Do It All :tm:. It even has a nice EN line, so we can control the power from the low-power FPGA board.

So I'll order one, and try it out. The only issue with it is that whoever designed it made lots of components big to allow experimentation... except the resistors that set the output voltage. Those are 0402 fly-poop sized. Fortunately there's a couple of test points I can solder a through-hole resistor to, and then use the soldering iron to erase the corresponding piece of fly poop.

Anyway, that board's ordered. 

Thinking through the other bits and pieces, if I use an R3 or R3A board (or an R2 for that matter), then it has on-board speaker drivers and amplifiers that can be used for the ringer.  I'll use an actual hand-set on this unit, because I have a cellular carrier board on-hand that has audio CODEC and handset drivers -- the benefit of modular design strikes again!

So now I just need to make sure that the board stack will physically fit in the depth of the case, and design a simple board stack that everything can be attached to, and that can attach to the shell of the tough case. This will need a few layers:

1. Top layer to retain the keyboard.

2. Second layer to prevent the keyboard shorting on anything below it.

3. Third layer to hold the MEGA65 main board, low-power FPGA board, battery/charge controller.

4. Fourth layer to hold cellular communications board and 12V regulator board.

5. Fifth layer which is the bottom, to hold the batteries in place, and allow fixing to the shell.

The fifth and possibly fourth layers will need to be slightly smaller to accommodate the curvature at the back of the case.  

Now we need to work out the vertical spacing required between each of those layers, and confirm that it doesn't exceed the total case depth. 

Okay, I've been at the laser cutter in the Makerspace iterating away.  I'll save you the 90 minute build montage, and just show the results so far:



So basically we have the screen bezel and related bits and pieces to go in the top of the case.  The last remaining challenge there is working out where to drill the four holes.  This is a bit of a pain, as they have to be located correctly, as well as have the correct spacing, so that the screen bezel is correctly located.

I've also been iterating on the cuts for the lower-half, to hold the keyboard, phone handset, MEGA65 components as well as the power control and other circuits.  As expected, those are being similarly fiddly to get everything right, as we have quite a few boards and other components to fit in.  I've been working from the top down, and have drafts for the top deck to which the keyboard is screwed, then the deck below that that really just has the floppy drive and phone handset mounts, then the deck below that which hosts the MEGA65 mainboard and the 1S battery to 12V adaptor board. There is space on that one for the power management FPGA, the solar/battery charge controller board and a few other bits and pieces.

Below that I'll still need the cellular communications deck, and then the batteries will sit behind that --- and like the screen in the lid, we'll need some way to hold it in place. 

The cellular comms deck might need to be two panels, so that none of the screws or hole-throughs from the cellular communications deck can contact the batteries.

Okay, I'm back in the Adelaide Maker Space to work on this.  In the meantime I have got the upper-half all fitting, and even put enough of the lower-half together to be able to fire up the MEGA65, even if the lower-half doesn't fit in the case yet.

So let's start with the upper half:

Oops! No cut-outs to allow cables to feed from the top to the bottom half.  Fixed that, and adjusted the hole sizes for the LCD control board in the lower-right, and I can now connect it to power and VGA, and thus to a MEGA65 main-board.  It looks pretty nice, if I say so myself. I'm thinking that I'll likely spray the exposed panels white or "C65 beige" at some point, which I think will look really nice with the blue case:

So let's focus on the lower-half now.  This will be a bit of a slide-show, that doesn't quite reflect the number of iterations or the fiddling about to get everything right.

Let's start with the handset recepticle -- since working as a phone is kind of the whole point of this.  A nice 1990s corporate desk phone handset, itself a bit yellowed, works really nicely for this, and does just fit next to the keyboard:

With a bit of fiddling about, we can pseudo-assemble this (even though the MEGA65 main board is sitting outside the box at this point, out of screen-shot:
But we can load something up :) This show below shows more of the layers of the "PCB Torte" assembled -- in the shot below the MEGA65 main-board is actually in the stack. It's just that the stack doesn't yet fit in the box properly. Only power is being provided externally.
And just a short video snippet, showing it running. Oh, yes, and you can see a floppy disk can be inserted via the cut-out in the upper right into the floppy drive that is hiding under the blank area behind the keyboard.  That would be a great spot for a logo and some real or fake ventilation slots for improved visual effect.

 

So let's tackle the speaker for the ringer next. By using a MEGA65 R3 or R3A mainboard, we can use their on-board speaker drivers. They're not great for long-running audio, as the speakers get rather warm due to high-frequency noise (which is why we discontinued them on the R4+ boards), but for 30 seconds of phone ringing from time to time, they will be totally fine.  So time to measure them up: 

 

 Make sure they fit the cut-outs I've designed for them:

  

Speaking of cut-outs, I learned the hard-way that it's a really good idea to put cut-outs in these panels to make it easier to insert and remove cables: 

 Then it was time to do a bunch of further trimming of the board sizes so that the whole stack can fit in the box.  I also reworked the phone handset holder area, so that the handset could sit a few mm lower, thus allowing the lid to close:

 

With all that done, we can see that it's possible to sit everything at a reasonable depth in the case: 


Okay, so now let's work on the cellular modem board and antennae. This was a real pain, as the cellular eval module board uses big chunky antennae (that should get great reception), but were too tall to mount on the board.  So I designed up set of tabs that allow their mounts to be rotated 90 degrees, thus allowing the height between decks to remain withing the ~26mm limit I can fit:

The tabs are held in place from the rear-size using 3mm screws and spacers.  It's a bit clunky, but works quite well:
 
 
 So also on this deck is where we are putting the big LiFePO4 cells.  They need to be held in place, so a fence of 3mm screws and nylon spacers works for those, too. As they are not 26mm thick, I'll put some spacing material above and below them, or simply make a little brace piece that holds the battery pressed against the lower board.
 
 
And that's really the last of the problems that I had to solve with the case, we've successfully done the (1) Case design; (2) Fabricated the case; (3) Managed to assemble one; and (4) Remediated and mitigated a whole pile of fitment issues via various means:
 
 
I do like the cold-war nuclear codes football vibe that this gives off. Already a few folks in the MEGA65 community have expressed interest in building one of their own -- so it's a case of the aesthetic helping to foster interest. 
 
The source code for the laser-cut files are all up at: https://github.com/gardners/mega65-rugged-case. There's a certain elegance to how simple the design has worked out to be -- five laser-cut panels plus one off-the-shelf case, that you can buy from Bunnings here in Australia, or find something equivalent easily enough wherever you are.   
 
And, look, the lid even shuts!
 

So the next steps here are that I've ordered the parts I need to build up 2 or 3 more of these to distribute to the MEGA65 developer community, once all the software is complete.













Sunday, 23 March 2025

MEGAphone Bluetooth module

The next module on the list is something that can do BlueTooth to talk to a headset. For security reasons, I'd prefer something that is BlueTooth only, if I can find it. The problem is that the ESP32 is probably otherwise the obvious choice, but I'm not totally sure that it can be trusted. But then, there is lots of alternative firmware available for it, and at the end of the day, if you are using wireless to talk to a headset, then you have already compromised your own security.

But let's look at the options...

1. Requirements Analysis

The requirements relating to this module are:

Requirement 2.1.1, Bluetooth host module that can connect to headsets and other audio devices. Must support UART or I2C control, and audio interfaces that we can easily implement from the FPGA, such as I2S audio.

Desirable 2.1.2, Bluetooth host module support for keyboards and other HID peripherals. 

Note that 2.1.2 was previously listed as a requirement, but it is not required in the milestones, and so I have allowed it to be relaxed to a desirable. I'll document this in the repository.

2. Key Component Selection

 I do have a BM63 eval kit laying around, which I had originally intended for this use-case, but I believe it is only able to act as a sink (headset/speaker), not a source (phone).  But chatgpt is trying to tell me that it can do both -- and I fear it is hallucinating this, as much as I'd like to believe that it could do it.

So the IS2083 IC can be both source or sink. But I think that's in the BM83, not the BM63. 

Confirmed -- I need the BM83, not BM63.

This all feels vaguely familiar, like I explored this in the past. I'm staring at the BM63 eval kit I have here, and wondering if I didn't get a BM83 kit as well at some point. It would be nice if I did, as they are A$500+ each. 

Ah, it _is_ a BM83 kit -- its just my aging eyes in the dim light here in the middle of the night! Hurrah!

So I can immediately start setting that up, and trying to make it pair with a BT headset, and see how it goes.

I'm starting to read through the documentation, so that I can do some basic testing of this module to make sure it works -- I want it to pair with a headset and pretend to start sending audio to it, and also be able to pretend to start a voice call. I should be able to hear the difference in noise in the ear piece of the old Bose QC35s I have here to tell the difference.

The BM83 supports an "AT command set". Now, this is _not_ a modem-style Hayes-AT command set, but rather an Audio Transceiver Command Set, which is binary in format.

But looking at the commands, it looks like everything I should need is there.  Time for sleep now, but I'll start setting up the board in the morning.

Okay, so now I'm reading my way through the BM83 Evaluation Board User's Guide, with the intention of powering it up and talking to it via UART. That board has a PIC32 microcontroller on it, which I don't want to use, so I may need to figure out which of the many switches need to be set correctly to run the BM83 in stand-alone UART controlled mode.

Following the instructions in section 4, I can put it into pairing mode and make it pair with my phone -- thus confirming that the module is superficially working, which is great.  Except that after pairing, the phone refuses to actually connect with it. But it's a cheap android phone, so it could be that. Also it shows up on my phone under "Other devices" which might mean that it doesn't recognise the set of profiles its offering. After some more pressing the MFB button in semi-random ways, I have gotten it to pair, and it is showing support for HD-Audio AAC, Telephone calls and audio media, which is great. The buttons to control the volume etc, however, are still not causing anything to happen.  But I don't care too much about that right now, as I intend for it to be used primarily in the reverse direction: as the phone, rather than the headset.

Switching SW300 on lets me seemingly switch the BM83 eval board into "test mode" where I can talk directly to it via the USB UART.

Then I can use the isupdate.exe tool from Microchip to talk to it.

I had a frustrating half hour where I could make it connect, and it would even identify it as BT5511_002 in a little box, but then fail to connect.  After some googling around, I found this post, with this sage piece of advice:

Put the TTY into raw mode:

stty -F /dev/ttyACM0 raw
 

With that, I was able to flash the main firmware, the DSP firmware and the application firmware (you have to do them all -- there is a way to "rehex" them to make a single file for convenience, but I didn't do that) with SW300 set to on, and then turn it off again after flashing everything.

This also confirms that SW300 should be off for normal operation.  I did find that if I press RESET_N and then long-press (~1 sec) the MFB button, that the BM83 does output something that looks like the kind of AA + checksum packet format we expect:

AA 00 03 30 00 00 CD
AA 00 03 2D 05 01 CA

So let's try to understand how those should be decoded.

Except I can't even get it to do that reliably now.  I suspect the PIC32 MCU on the eval board might still be doing things and getting in the way.

Let's try to get to the bottom of this.

We want "host mode", where the BM83 expects an MCU to be connected via UART. That's good, because we have the host firmware loaded.

But the eval board will be expecting to have the PIC32 act as the MCU in this case. We need to disable that. I'm finding the documenation for this evaluation board quite frustrating, to be honest. For example, there is a big fat JP303 connector with 40 signals brought out onto it -- but it isn't even mentioned in the user's guide. And it's not like its a different PCB revision that lacks it -- you can see the big 2x20 0.1" header at the top of the PCB in this screenshot, and how there is carefully nothing pointing at it. JP303, which is silkscreened next to it isn't event mentioned once in the manual.

Fortunately despite this seemingly intentional ignorance of it, it has various signals identified on it in silkscreen. Those of interest to us are:

HCI_RXD

HCI_TXD

Indeed HCI_TXD follows the UART TX line from the USB UART adaptor. So my bits are getting that far at least.  And HCI_RXD really seems to be connected to the BM83, because I see those responses that I've been seeing when pressing the MFB ("Multi-Function Button", by the way).  The MFB pin is also routed out onto this JP303.

A bit more digging indicates that S400 selects bewteen onboard PIC32 and an external microcontroller. It was already set to external, which is what I want. So most probably the PIC32 isn't actually being a problem.

So why doesn't the firmware talk to me in any more sensible way?

The first assumption is that the "application" firmware that I loaded on isn't the right one, or doesn't support the UART packetised commands.

So I have perhaps found a clue on this page. It talks about running the config utility to enable the BM83's UART. Maybe RX on the UART has to be enabled? But I find it a bit odd that the UART can send, but not receive.

The datasheet does seem to indicate that this GUI config tool is required to configure host mode. The problem is that that is windows-only software, and I haven't figured how to get it running under Wine yet. Or rather, I can run it, but it so far makes no sense at all. It doesn't seem to communicate with the module but rather allows loading and saving of configurations, without a great deal of clarity as to how to actually drive it.

To add to the fun, there is corrupted copy of the documentation for this config tool in the SDK:

./Tools/Config Tool
./Tools/Config Tool/~$208x_Config_GUI_Tool Release Note.docx
./Tools/Config Tool/is208x_config_gui_tool v1.3.23.exe
./Tools/Config Tool/~$BT5511_Config_Parameter_Table_R0.xlsx
./Tools/Config Tool/is208x_config_default_table.ini
./Tools/Config Tool/IS208x_Config_Parameter_Table_R0.ihlp 

So I know there is some sort of documentation for it, but it's not included.

There is some instructions on use in:

https://ww1.microchip.com/downloads/en/DeviceDoc/BM83-Bluetooth-Audio-Development-Board-User-Guide-DS50002902B.pdf

So let's see what it explains.

Ok, so the tool is quite a bit newer than in the documentation. And the order of the options has changed.

But broadly speaking, it can be followed, and when you save it, it writes a .HEX file that can then be flashed onto the device using the isupdate.exe program.

After a lot of poking around, it looks like the MSPKv2_1.03.0406_SPP firmware is missing many of the UART commands that we'd need. But potentially they are in the v1.3 era. But finding that old firmware is proving non-trivial.  It's not helping that the Microchip website is under maintenance for a few hours right now.

Actually, it looks like the firmware I downloaded fresh is not the latest according to this post. There should be a 2v1.3.5 instad of the 2v1.2.4 that I have. Now to try to find a link where I can download it...

I've since posted a question on the Microchip forum and emailed my local FAE for their distributor to see if I can get some help with this, as I'm just spinning my wheels, when I have much more that I need to get on with. 

I'm going to work on the assumption that there will be some solution to this problem at some point, and since the module does pair with things, that it fundamentally works.  In short, I can get on with designing a module to carry the BM83.

3. Schematic Layout

So for this one, we really just need to host the BM83, and work out which of its 50 pins we actually care about. So let's take a look:

Okay, so that's our pin out. Let's now work out which ones we definitely need, which we definitely don't need, and if there are any we aren't sure about.
 
BM83 Module Pin Description
Pin Number Pin Name Required? Description
1DR1YES (I)I2S interface: digital left/right data
2RFS1YES (I/O)I2S interface: digital left/right clock
3SCLK1YES (I/O)I2S interface: bit clock
4DT1YES (O)I2S interface: digital left/right data
5MCLK1YES (O)I2S interface: master clock
6AOHPRNOR-channel analog headphone output
7AOHPMNOHeadphone common mode output/sense input
8AOHPLNOL-channel analog headphone output
9MICN2NOMIC 2 mono differential analog negative input
10MICP2NOMIC 2 mono differential analog positive input
11AIRNOR-channel single-ended analog input
12AILNOL-channel single-ended analog input
13MICN1NOMIC 1 mono differential analog negative input
14MICP1NOMIC 1 mono differential analog positive input
15MICBIASNOElectric microphone biasing voltage
16GNDYES (P)Ground reference
17DMIC_CLKNODigital MIC clock output
18DMIC1_RNODigital MIC right input
19DMIC1_LNODigital MIC left input
20P3_2MAYBE (I/O)GPIO (default: AUX_IN DETECT)
21P2_6MAYBE (I/O)General purpose I/O port
22ADAP_INNO (P)5V adapter input / USB DFU / battery charge
23BAT_INYES (P)Power supply input (3.2V–4.2V)
24SYS_PWRNOSystem power output (internal use only)
25VDD_IOYES (P)I/O power supply (internal use)
26PWR (MFB)YES (I)Multi-function push button
27SK1_AMB_DETMAYBE (I)Temperature sense channel 1
28SK2_KEY_ADMAYBE (I)Temperature sense channel 2
29P8_6 / UART_RXDYES (I/O)GPIO / UART RX data
30P8_5 / UART_TXDYES (I/O)GPIO / UART TX data
31P3_4 / UART_RTSYES (I/O)GPIO / UART RTS / Mode select
32LED1MAYBE (I)LED driver 1
33P0_2MAYBE (I/O)GPIO (default: play/pause)
34LED2MAYBE (I)LED driver 2
35P0_6MAYBE (I/O)GPIO
36DMNO (I/O)USB D-
37DPNO (I/O)USB D+
38P0_3MAYBE (I/O)GPIO (default: reverse)
39P2_7MAYBE (I/O)GPIO (default: volume up)
40P0_5MAYBE (I/O)GPIO (default: volume down)
41P1_6 / PWM1MAYBE (I/O)GPIO / PWM1 output
42P2_3MAYBE (I/O)GPIO
43RST_NYES (I)System reset (active-low)
44P0_1MAYBE (I/O)GPIO (default: forward)
45P0_7MAYBE (I/O)GPIO
46P1_2 / TDI_CPU / SCLMAYBE (I/O)GPIO / Debug / I2C SCL
47P1_3 / TCK_CPU / SDAMAYBE (I/O)GPIO / Debug / I2C SDA
48P3_7 / UART_CTSMAYBE (I/O)GPIO / UART CTS
49P0_0 / UART_TX_INDYES (I/O)GPIO / Codec reset (Embedded) / TX_IND (Host)
50GNDYES (P)Ground reference

So that's 15 yeses and 18 maybes. That would make 33 total, if we include everything that we could feasibly want (given we are only using this to send and receive I2S audio. I am a bit concerned about whether the BM83 can convey bidirectional audio from a call via it's digital I2S interface, but we can live without that for this initial version, as the microphone array on the MEGAphone unit itself will be fine to use for many use-cases. For true hands-free operation, e.g., a headset in a bike helmet, like I use from time to time, we'd need it though. But as said, we will defer that for now.
 
Back to our 33 pins, that means that we need at least a 2x17 module, which would be 1.7 inches long.  The BM33 is 22mm from the bottom to where the PCB antenna starts, i.e., ~0.9 inches. So if we want all those extra pins, we will end up using more board realestate than we'd like.  So let's prune out the bluetooth fuction buttons, e.g., reverse, volume up, down, forward, play (5 pins), the temperature sensor (2 pins), the stray GPIOs (5 pins), and that leaves us with 21 pins, which would fit just about perfectly -- and still leave us with the most likely pins we'd need. The updated table would look like this: 
 
BM83 Module Pin Description
Pin Number Pin Name Required? Description
1DR1YES (I)I2S interface: digital left/right data
2RFS1YES (I/O)I2S interface: digital left/right clock
3SCLK1YES (I/O)I2S interface: bit clock
4DT1YES (O)I2S interface: digital left/right data
5MCLK1YES (O)I2S interface: master clock
6AOHPRNOR-channel analog headphone output
7AOHPMNOHeadphone common mode output/sense input
8AOHPLNOL-channel analog headphone output
9MICN2NOMIC 2 mono differential analog negative input
10MICP2NOMIC 2 mono differential analog positive input
11AIRNOR-channel single-ended analog input
12AILNOL-channel single-ended analog input
13MICN1NOMIC 1 mono differential analog negative input
14MICP1NOMIC 1 mono differential analog positive input
15MICBIASNOElectric microphone biasing voltage
16GNDYES (P)Ground reference
17DMIC_CLKNODigital MIC clock output
18DMIC1_RNODigital MIC right input
19DMIC1_LNODigital MIC left input
20P3_2NOGPIO (default: AUX_IN DETECT)
21P2_6NOGeneral purpose I/O port
22ADAP_INNO (P)5V adapter input / USB DFU / battery charge
23BAT_INYES (P)Power supply input (3.2V–4.2V)
24SYS_PWRNOSystem power output (internal use only)
25VDD_IOYES (P)I/O power supply (internal use)
26PWR (MFB)YES (I)Multi-function push button
27SK1_AMB_DETNOTemperature sense channel 1
28SK2_KEY_ADNOTemperature sense channel 2
29P8_6 / UART_RXDYES (I/O)GPIO / UART RX data
30P8_5 / UART_TXDYES (I/O)GPIO / UART TX data
31P3_4 / UART_RTSYES (I/O)GPIO / UART RTS / Mode select
32LED1MAYBE (I)LED driver 1
33P0_2NOGPIO (default: play/pause)
34LED2MAYBE (I)LED driver 2
35P0_6NOGPIO
36DMNO (I/O)USB D-
37DPNO (I/O)USB D+
38P0_3NOGPIO (default: reverse)
39P2_7NOGPIO (default: volume up)
40P0_5NOGPIO (default: volume down)
41P1_6 / PWM1NOGPIO / PWM1 output
42P2_3NOGPIO
43RST_NYES (I)System reset (active-low)
44P0_1NOGPIO (default: forward)
45P0_7NOGPIO
46P1_2 / TDI_CPU / SCLMAYBE (I/O)GPIO / Debug / I2C SCL
47P1_3 / TCK_CPU / SDAMAYBE (I/O)GPIO / Debug / I2C SDA
48P3_7 / UART_CTSMAYBE (I/O)GPIO / UART CTS
49P0_0 / UART_TX_INDYES (I/O)GPIO / Codec reset (Embedded) / TX_IND (Host)
50GNDYES (P)Ground reference

So let's filter out all the NOs and see how it looks:
BM83 Module Pin Description
Pin Number Pin Name Required? Description
1DR1YES (I)I2S interface: digital left/right data
2RFS1YES (I/O)I2S interface: digital left/right clock
3SCLK1YES (I/O)I2S interface: bit clock
4DT1YES (O)I2S interface: digital left/right data
5MCLK1YES (O)I2S interface: master clock
16GNDYES (P)Ground reference
23BAT_INYES (P)Power supply input (3.2V–4.2V)
25VDD_IOYES (P)I/O power supply (internal use)
26PWR (MFB)YES (I)Multi-function push button
27SK1_AMB_DETMAYBE (I)Temperature sense channel 1
28SK2_KEY_ADMAYBE (I)Temperature sense channel 2
29P8_6 / UART_RXDYES (I/O)GPIO / UART RX data
30P8_5 / UART_TXDYES (I/O)GPIO / UART TX data
31P3_4 / UART_RTSYES (I/O)GPIO / UART RTS / Mode select
32LED1MAYBE (I)LED driver 1
34LED2MAYBE (I)LED driver 2
43RST_NYES (I)System reset (active-low)
46P1_2 / TDI_CPU / SCLMAYBE (I/O)GPIO / Debug / I2C SCL
47P1_3 / TCK_CPU / SDAMAYBE (I/O)GPIO / Debug / I2C SDA
48P3_7 / UART_CTSMAYBE (I/O)GPIO / UART CTS
49P0_0 / UART_TX_INDYES (I/O)GPIO / Codec reset (Embedded) / TX_IND (Host)
50GNDYES (P)Ground reference

Okay, so I relented, and added the temperature sensor back in, because I think it might be good to know the internal temperature of the unit, and I'd miscounted pins, so this still leaves us at just 22 pins, which feels acceptable. 

Ah, there are also two GND pads, so that saves us a pin. Also, the VCC_IO pin isn't needed either, apparently, according to the footprint that I'm using. The footprint is annoying in that it has a keep-out zone for copper surrounding the GND pads on the rear of the PCB! I've just modified that so that it allows vias, so that I can still connect those pads to GND.

The end result is a very simple schematic:

Note that we feed 3.3V to the modules VBAT input. This is so that we can still switch power on and off to this module, rather than running it directly from the battery.

4. PCB Layout

The PCB layout is also trivial, with the pin assignments on the module being mapped so that all routing happens on the front, except for the power and ground which are routed on the rear.
 

5. Requirements Cross-Check

Requirement 2.1.1, Bluetooth host module that can connect to headsets and other audio devices. Must support UART or I2C control, and audio interfaces that we can easily implement from the FPGA, such as I2S audio.

Met -- in that we have the Bluetooth module, and the necessary interfaces for I2C and I2S and UART.

Desirable 2.1.2, Bluetooth host module support for keyboards and other HID peripherals. 

Met if and only if the BM83 can be configured to talk to HID devices. This remains unknown, but as this is only a desirable rather than a requirement, we are fine.

In short, we have this module finished!