nonolith / USB-XMEGA

USB stack for Atmel ATxmega32A4U and related parts
http://nonolithlabs.com
38 stars 13 forks source link

CRC error #2

Closed peter-lonnebring closed 11 years ago

peter-lonnebring commented 11 years ago

Hello nonolithlabs et al.,

I'm thoroughly impressed by this very slimmed down USB boot loader! I'm compiling it for ATxmega64a3u (works perfectly), programming it along with fuses—and I'm perfectly able to connect to using flash.py.

The problem is that I just can't make it accept my firmware: I get a CRC error. I've tried different APP_SECTION_PAGE_SIZEs (I'm always confused whether to use bytes or words), but that doesn't help.

Bootloader ID 9090bb01, version 1 Part ID: 1e964206 = ATxmega64A3U Flash size: 65536 (256-byte pages) Hardware: CEE Version: v2b Loading input file panelboard_atxmega64a3u.hex Size=36229; CRC=0xb07295 Erasing... done Flashing... 100% Checked CRC is 0x341ee1 CRC DOES NOT MATCH

(No, it's not a CEE board, I just haven't changed the name and version.) I have a buzzer on the board, and I make it beep when the programming starts and when the CRC is requested—the two beeps are very close in time. Nothing is programmed in the app. section; reading from the device gives me erased memory:

:10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00 :10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 :10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0 :10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0 :10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0 :10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0 ....

I'm guessing there is a compatibility issue with the sp_driver.S—is there something obvious I've missed? Anyone else with similar problems?

kevinmehall commented 11 years ago

As far as I know, the bootloader has only been used on the xmega32a4u (USB library in app code has been used on other devices), so there's definitely the potential for a compatibility issue.

sp_driver.S comes from Atmel, and I don't see a newer version of it available.

APP_SECTION_PAGE_SIZE is a #define in the device-specific header file included through avr/io.h, but it looks like it's 256 bytes (128 words) on both the xmega32a4u and xmega64a3u. What is different between the chips, of course, is the size of the app memory and location of the boot memory, which is set in the makefile. It sounds like you have that correct, though, since it's able to compile and run.

Only other thing that comes to mind is to make sure the fuse lock bits aren't configured to disable self-programming.

peter-lonnebring commented 11 years ago

I understand that chip-compatibility isn't a priority for this specific application, but I really like the no-nonsense, stripped-down bootloader so I can't help trying to fix it. (I've spent hours cutting and slicing LUFA and AVR1916 app.-note code...)

I know the APP_SECTION_PAGE_SIZE is defined in the avr headers, but I'm still suspicious since many of the tools in the toolchain use bytes for addresses and memory sizes.

The lock bits are still 11s, no locks enabled.

I'll make a small NVM/SP sample tomorrow (it's late evening now in my country) and see what I can find. I'm sure this is a simple problem; I just wanted to hear whether it was a known issue.

I'll share my findings.

Many thanks for the prompt reply!

peter-lonnebring commented 11 years ago

Finally: I now know what the problem is. I should have seen it right away.

After reading out the code from the mcu, I realized the code ended up at the wrong address. Self-programming worked perfectly after making sure that the code was executing in the boot section address range. This should have been obvious, the documentation clearly says the app. section is only programmable from boot section addresses.

However—as soon as I got the nvm code working, USB stopped working.

This too should have been obvious, but yet it took me a while to figure out: the USB descriptors are packed with the code in flash memory using the PROGMEM define and read using the pgm_read_ functions (lpm instructions). This works perfectly as long as the addresses point into the low 64 Kb space—but the boot section is above the 64K-limit. Unfortunately, the linker doesn't warn about this, so the binary was created without warnings. When executing it tried to serve USB descriptors from (boot_section + data_offset) % 0xFFFF == data_offset addresses, which in this case were empty.

There are many ways around this problem, e.g. changing the pgm_ calls into _far calls (using the elpm instruction) and treating descriptor and string addresses using larger datatypes (more than 16 bits).

The fix, in my case, was to store the USB-descriptors in its own section right below the 64K-limit. This way, I can leave most of the code unmodified.

In Descriptors.c:

#undef PROGMEM
#define PROGMEM  __attribute__ ((section (".usb_data")))

and in the makefile:

LDFLAGS += -Wl,--section-start=.usb_data=0x7C00

I don't have a nice portable fix to add to your code, but I hope the above description will be helpful to anyone ending up with the same symptoms as I did.