hathach / tinyusb

An open source cross-platform USB stack for embedded system
https://www.tinyusb.org
MIT License
5.1k stars 1.07k forks source link

Compiling cdc_msc example for SAMD21G18 works fine using -O0 but hangs using -O1 #303

Closed jeremyherbert closed 4 years ago

jeremyherbert commented 4 years ago

I'm trying to port tinyusb to the seeeduino xiao which uses the SAMD21G18A. Since this is the same chip as the feather_m0_express I used it as a template to begin. I've made the following changes:

If I build the cdc_msc example with any optimisation level other than -O0, the code just hangs. According to my JLink, it's just spinning in the Dummy_Handler function. With -O0 everything works fine.

Will try to work out which interrupt is firing.

jeremyherbert commented 4 years ago

Ok, it's a hardfault. But it seems like it is to do with the JLink programming itself; if I power cycle the microcontroller after programming it works fine...

hathach commented 4 years ago

you should check your vector ISR table, probably put atttribute((used)) in the proper place of isr vector to prevent it is optimized out.

cr1901 commented 4 years ago

I can't tell whether this applies, but last time I had a problem like this, it was because I forgot to manually mark some I/O addresses as volatile: https://github.com/hathach/tinyusb/issues/97#issuecomment-527744295

jeremyherbert commented 4 years ago

This is a bug in the J-Link tools, not in tinyusb.

jeremyherbert commented 4 years ago

Turns out this is not a bug in the segger tools, but rather a dud linker script provided by Atmel/Microchip. The script does not set the entry point of the code correctly, so it defaults to zero in the elf header. It is should be set to the address of Reset_Handler. I added the missing line in my pull request (https://github.com/hathach/tinyusb/pull/306) for this board: https://github.com/hathach/tinyusb/blob/81c4d423e2583879a3b745efa56751888c5a3c8d/hw/bsp/seeeduino_xiao/samd21g18a_flash.ld#L45

This problem appears to be present in at least the feather_m0_express linker file.

The hardfault was because the PC was being set to 0 after reset, which meant that the CPU was trying to decode the vector table as instructions.

hathach commented 4 years ago

Thanks for the findout, I will check and fix the feather m0 and/or other m0 boards as well.

hathach commented 4 years ago

I checked, but with and without

 ENTRY(Reset_Handler) 

The address of Reset_Handler doesn't change at all. Adding this is right thing to do, though I am curious which version gcc/toolchain you are using, and your OS as well.

jeremyherbert commented 4 years ago
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599]
Linux ubuntu 5.3.0-42-generic #34~18.04.1-Ubuntu SMP Fri Feb 28 13:42:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

using arm-none-eabi-readelf -e seeeduino_xiao-firmware.elf, if I have the line commented out it sets the entry point to the start of the vector table (0x2000 as it is leaving the first 8kB for the bootloader), not the address of Reset_Handler:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x2000 <<<<<<<<<<<<<<<<<<<<<<<<<< BAD
  Start of program headers:          52 (bytes into file)
  Start of section headers:          310276 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         18
  Section header string table index: 17

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00002000 002000 0025f0 00  AX  0   0  4
  [ 2] .relocate         REL             20000000 010000 002018 08  WA  0   0  4
  [ 3] .bss              NOBITS          20002018 012018 000614 00  WA  0   0  4
  [ 4] .stack            NOBITS          2000262c 012018 002004 00  WA  0   0  1
  [ 5] .debug_info       PROGBITS        00000000 012018 01e7f0 00      0   0  1
  [ 6] .debug_abbrev     PROGBITS        00000000 030808 002be4 00      0   0  1
  [ 7] .debug_loc        PROGBITS        00000000 0333ec 006e01 00      0   0  1
  [ 8] .debug_aranges    PROGBITS        00000000 03a1ed 0001c0 00      0   0  1
  [ 9] .debug_ranges     PROGBITS        00000000 03a3ad 001478 00      0   0  1
  [10] .debug_line       PROGBITS        00000000 03b825 006849 00      0   0  1
  [11] .debug_str        PROGBITS        00000000 04206e 006188 01  MS  0   0  1
  [12] .comment          PROGBITS        00000000 0481f6 000079 01  MS  0   0  1
  [13] .ARM.attributes   ARM_ATTRIBUTES  00000000 04826f 00002a 00      0   0  1
  [14] .debug_frame      PROGBITS        00000000 04829c 0005e4 00      0   0  4
  [15] .symtab           SYMTAB          00000000 048880 0029f0 10     16 622  4
  [16] .strtab           STRTAB          00000000 04b270 0008de 00      0   0  1
  [17] .shstrtab         STRTAB          00000000 04bb4e 0000b6 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x045f0 0x045f0 R E 0x10000
  LOAD           0x010000 0x20000000 0x000045f0 0x02018 0x04630 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .relocate .bss .stack

And with the entry point line it correctly points to the Reset_Handler function:

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x3525  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CORRECT
  Start of program headers:          52 (bytes into file)
  Start of section headers:          310276 (bytes into file)
  Flags:                             0x5000200, Version5 EABI, soft-float ABI
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         18
  Section header string table index: 17

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00002000 002000 0025f0 00  AX  0   0  4
  [ 2] .relocate         REL             20000000 010000 002018 08  WA  0   0  4
  [ 3] .bss              NOBITS          20002018 012018 000614 00  WA  0   0  4
  [ 4] .stack            NOBITS          2000262c 012018 002004 00  WA  0   0  1
  [ 5] .debug_info       PROGBITS        00000000 012018 01e7f0 00      0   0  1
  [ 6] .debug_abbrev     PROGBITS        00000000 030808 002be4 00      0   0  1
  [ 7] .debug_loc        PROGBITS        00000000 0333ec 006e01 00      0   0  1
  [ 8] .debug_aranges    PROGBITS        00000000 03a1ed 0001c0 00      0   0  1
  [ 9] .debug_ranges     PROGBITS        00000000 03a3ad 001478 00      0   0  1
  [10] .debug_line       PROGBITS        00000000 03b825 006849 00      0   0  1
  [11] .debug_str        PROGBITS        00000000 04206e 006188 01  MS  0   0  1
  [12] .comment          PROGBITS        00000000 0481f6 000079 01  MS  0   0  1
  [13] .ARM.attributes   ARM_ATTRIBUTES  00000000 04826f 00002a 00      0   0  1
  [14] .debug_frame      PROGBITS        00000000 04829c 0005e4 00      0   0  4
  [15] .symtab           SYMTAB          00000000 048880 0029f0 10     16 621  4
  [16] .strtab           STRTAB          00000000 04b270 0008de 00      0   0  1
  [17] .shstrtab         STRTAB          00000000 04bb4e 0000b6 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  y (purecode), p (processor specific)

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x00000000 0x00000000 0x045f0 0x045f0 R E 0x10000
  LOAD           0x010000 0x20000000 0x000045f0 0x02018 0x04630 RW  0x10000

 Section to Segment mapping:
  Segment Sections...
   00     .text 
   01     .relocate .bss .stack 
hathach commented 4 years ago

@jeremyherbert ah yeash, you are right, I wasn't doing the correct checking readelf is more precise.

Reset_Handler is at 00002fb9

$ nm _build/build-metro_m0_express/metro_m0_express-firmware.elf | grep Reset
00002fb9 T Reset_Handler

readelf without ENTRY(Reset_Handler), entry point is 0x2000 which is not Correct

$ arm-none-eabi-readelf -e _build/build-metro_m0_express/metro_m0_express-firmware.elf
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x2000 

readelf WITH addition of ENTRY(Reset_Handler), entry point is spot on with ResetHandler from nm

$ arm-none-eabi-readelf -e _build/build-metro_m0_express/metro_m0_express-firmware.elf
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           ARM
  Version:                           0x1
  Entry point address:               0x2fb9
hathach commented 4 years ago

thank you for reporting the issue, I have updated the linker for all samd board to include ENTRY . It seems no harm to use on Adafruit board since bootloader takes care of entry point. Without bootloader, it could run into hardfault since gcc doesn't emit the correct code to the entry.