FFFFFFUUUUUUUU

UPDATE: I wish to retract all negative statements I have made about Paul and his company PJRC, in particular in reference to his “Teensy” product. Effective immediately all support for the the TeensyHID bootloader is withdrawn and the source code deleted from the LUFA tree per Paul’s request.


I didn’t want to update so soon before the next LUFA release, but today’s waste of time really takes the proverbial cake, throws it onto the ground, jumps up and down on it, and sets it on fire. I need to vent to avoid throwing my keyboard – which, since this is a laptop, means the rest of my computer along with it – out the window.

Today I finished my university assignment that has been causing me grief, due to a spectacularly poor lecturer. To celebrate, I thought I’d do a little bit of recreational coding to relax. Oh, how wrong I was. On that note, I apologize again to everyone – and it does seem like everyone – who has emailed me this week, since I’ve been too busy to respond to the bulk of them. I’ll work through them all in the next few days as fast as I can.

So, I thought I’d finally give updating the LUFA TeensyHID bootloader a go, as it currently only works on the Teensy 2.0 boards and not the rest of the Teensy range. This has bugged me for a while, but I simply haven’t had the time to look into it properly, what with all the other more important things I’ve been working on in LUFA. The TeensyHID loader is the only alternative to Paul’s official bootloader, and many folk want to load it on their own custom boards (or boards from other manufacturers) as the TeensyLoader GUI is very simple to use a cross-platform. It’s a tad too simple for my tastes, but it does fill a need and people want it.

Paul’s official bootloader is absolutely tiny, at only 512 bytes of hand-crafted assembly. That’s an amazing feat, but it comes at a cost – it’s not totally compliant to, well, any specification and you can’t do neat things like jump to it from the user application without having to reset all the AVR’s hardware. My LUFA version is four times the size when compiled – just a hair under or over 2KB depending on the target – but it’s written in C, uses the base LUFA core, and can be jumped to without doing anything special from the user application. Paul also doesn’t distribute his bootloader, so if you manage to wipe it from your board it’s gone forever.

Now, Paul’s been kind enough to give out some source code to a command line programmer client on his site, plus some “documentation” on the protocol his custom bootloader uses. From that I was able to make my own LUFA bootloader many months ago, which worked great on the Teensy 1.0 board. However, users remarked that it failed on the newer Teensy or Teensy++ boards when Paul’s GUI was used. What was going on?

In an effort to make his GUI easier to use, Paul’s implemented some undocumented changes between bootloader models for each AVR – the HID usage page differs for each version of Teensy. In addition, the HID report size is altered for the larger devices, to account for the larger flash page size in the AVR. The problem with all this is that it’s not bleeding documented anywhere. I had no idea why my bootloader would work fine with the command line programmer, but not the GUI until I started comparing every part of my bootloader with a genuine Teensy. The GUI app is no help; rather than displaying an error (“incorrect report size for device”, “incorrect HID page value”) it just says “error”, with nothing printed in the debug output.

Not to worry, I got that figured all out today and now the GUI is happy with any of my USB AVR boards, and correctly determines which USB AVR model I’ve attached. But the larger USB AVRs (used on the official Teensy++ boards) wouldn’t program correctly. I double-checked, re-checked and triple-checked my code, and couldn’t spot anything. Now what was wrong?

Here’s the documentation for the Teensy programming protocol, emphasis mine:

To write a 128 byte block, simply send this 130 byte control transfer. The first 2 bytes are the address, which should be aligned to a 128 byte block boundry.

Now, the problem here should be obvious to everyone but me until I had enough coffee – pop quiz, how many bytes of flash does a 64KB 128KB (thanks Michael!) AVR have? What’s that in HEX? How many bytes does it occupy?

If you answered “too damn many for a uint16_t” you’d be spot on, although I didn’t twig for quite a while (a big failure on my part). Paul’s answer to this is to change the addressing scheme on the larger AVRs. This isn’t documented anywhere, unless you delve into his posted source code:

if (code_size < 0x10000) {
 buf[0] = addr & 255;
 buf[1] = ( addr >> 8 ) & 255;
 } else {
 buf[0] = ( addr >> 8 ) & 255;
 buf[1] = ( addr >> 16 ) & 255;
 }

That little chunk of code cost be a good portion of this afternoon – when I finally went over his CLI code again carefully and spotted, I slapped my palm to my forehead pretty darn hard. After modifying the bootloader so that on the AT90USB1286 the address is cast to a uint32_t and shifted left 8 bits everything now works.

TLDR version; damn proprietary application and incorrect/non-existent documentation cost me half a day. Gaah.

 

Comments: 1

Leave a reply »

 
 
 

You know, when I saw that “Write Block” command while back on Paul’s site. I hadn’t looked at the actual source code or written code yet but I had interpreted it to mean the “address” was a 128 byte block index, which would address way beyond 128k.
I wouldn’t have even thought it was a byte address
since it was called a “Write Block” command.
A block number seemed like an obvious choice since the data has to 128 byte aligned anyway.
Bummer, I feel your pain.

— bill

 

Leave a Reply

 
(will not be published)
 
 
Comment
 
 

 

Vital Stats

  • 35 Years Old
  • Australian
  • Lover of embedded systems
  • Firmware engineer
  • Self-Proclaimed Geek

Latest Blog Posts

RSS