Skip to content

Commit

Permalink
Re-enabled self-updater with SAMD51 support.
Browse files Browse the repository at this point in the history
  • Loading branch information
tannewt committed Oct 25, 2017
1 parent ee100b0 commit 9de0794
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 42 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "lib/uf2"]
path = lib/uf2
url = https://github.com/Microsoft/uf2.git
10 changes: 6 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ $(WFLAGS)
ifeq ($(CHIP_FAMILY), samd21)
LINKER_SCRIPT=./lib/samd21/samd21a/gcc/gcc/samd21j18a_flash.ld
BOOTLOADER_SIZE=8192
SELF_LINKER_SCRIPT=scripts/samd21j18a_self.ld
endif

ifeq ($(CHIP_FAMILY), samd51)
LINKER_SCRIPT=./lib/samd51/gcc/gcc/samd51j18a_flash.ld
BOOTLOADER_SIZE=16384
SELF_LINKER_SCRIPT=scripts/samd51j19a_self.ld
endif

LDFLAGS= $(COMMON_FLAGS) \
Expand Down Expand Up @@ -80,7 +82,7 @@ NAME=bootloader
EXECUTABLE=$(BUILD_PATH)/$(NAME).bin
SELF_EXECUTABLE=$(BUILD_PATH)/update-$(NAME).uf2

all: dirs $(EXECUTABLE) #$(SELF_EXECUTABLE)
all: dirs $(EXECUTABLE) $(SELF_EXECUTABLE)

r: run
b: burn
Expand Down Expand Up @@ -117,10 +119,10 @@ $(EXECUTABLE): $(OBJECTS)

$(SELF_EXECUTABLE): $(SELF_OBJECTS)
$(CC) -L$(BUILD_PATH) $(LDFLAGS) \
-T./scripts/samd21j18a_self.ld \
-T$(SELF_LINKER_SCRIPT) \
-Wl,-Map,$(BUILD_PATH)/update-$(NAME).map -o $(BUILD_PATH)/update-$(NAME).elf $(SELF_OBJECTS)
arm-none-eabi-objcopy -O binary $(BUILD_PATH)/update-$(NAME).elf $(BUILD_PATH)/update-$(NAME).bin
node scripts/bin2uf2.js $(BUILD_PATH)/update-$(NAME).bin $@
python lib/uf2/utils/uf2conv.py -b $(BOOTLOADER_SIZE) -c -o $@ $(BUILD_PATH)/update-$(NAME).bin

$(BUILD_PATH)/%.o: src/%.c $(wildcard inc/*.h boards/*/*.h)
echo "$<"
Expand All @@ -130,7 +132,7 @@ $(BUILD_PATH)/%.o: $(BUILD_PATH)/%.c
$(CC) $(CFLAGS) $(BLD_EXTA_FLAGS) $(INCLUDES) $< -o $@

$(BUILD_PATH)/selfdata.c: $(EXECUTABLE) scripts/gendata.js src/sketch.cpp
node scripts/gendata.js $(BUILD_PATH) $(NAME).bin
python scripts/gendata.py $(BOOTLOADER_SIZE) $(EXECUTABLE)

clean:
rm -rf build
Expand Down
33 changes: 23 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ the USB MSC (mass storage).

[![Build Status](https://travis-ci.org/Microsoft/uf2-samd21.svg?branch=master)](https://travis-ci.org/Microsoft/uf2-samd21)

## UF2
## UF2

**UF2 (USB Flashing Format)** is a name of a file format, developed by Microsoft, that is particularly
**UF2 (USB Flashing Format)** is a name of a file format, developed by Microsoft, that is particularly
suitable for flashing devices over MSC devices. The file consists
of 512 byte blocks, each of which is self-contained and independent
of others.
Expand All @@ -27,7 +27,7 @@ a UF2 file is written and immediately write it to flash.

## Features

* USB CDC (Serial emulation) monitor mode compatible with Arduino
* USB CDC (Serial emulation) monitor mode compatible with Arduino
(including XYZ commands) and BOSSA flashing tool
* USB MSC interface for writing UF2 files
* reading of the contests of the flash as an UF2 file via USB MSC
Expand Down Expand Up @@ -84,12 +84,14 @@ sketch. You can copy&paste it into Arduino IDE and upload it to the device.

## Fuses

### SAMD21

The SAMD21 supports a `BOOTPROT` fuse, which write-protects the flash area of
the bootloader. Changes to this fuse only take effect after device reset.

OpenOCD exposes `at91samd bootloader` command to set this fuse. **This command is buggy.**
It seems to reset both fuse words to `0xffffffff`, which prevents the device
from operating correctly (it seems to reboot very frequently).
from operating correctly (it seems to reboot very frequently).
In `scripts/fuses.tcl` there is an OpenOCD script
which correctly sets the fuse. It's invoked by `dbgtool.js fuses`. It can be also
used to reset the fuses to sane values - just look at the comment at the top.
Expand All @@ -98,6 +100,17 @@ The bootloader update programs (both the `.uf2` file and the Arduino sketch)
clear the `BOOTPROT` (i.e., set it to `0x7`) before trying to flash anything.
After flashing is done, they set `BOOTPROT` to 8 kilobyte bootloader size (i.e, `0x2`).

### SAMD51

The SAMD51s bootloader protection can be temporarily disabled through an NVM
command rather than a full erase and write of the AUX page. The boot protection
will be checked and set by the self updaters.

So, if you've used self-updaters but want to load it directly, then you'll need
to temporarily turn off the protection. In gdb the command is:

`set ((Nvmctrl *)0x41004000UL)->CTRLB.reg = (0xA5 << 8) | 0x1a`

## Build

### Requirements
Expand Down Expand Up @@ -132,7 +145,7 @@ The default board is `zero`. You can build a different one using:
make BOARD=metro
```

If you're working on different board, it's best to create `Makefile.local`
If you're working on different board, it's best to create `Makefile.local`
with say `BOARD=metro` to change the default.
The names `zero` and `metro` refer to subdirectories of `boards/`.

Expand All @@ -153,22 +166,22 @@ make r
There is a number of configuration parameters at the top of `uf2.h` file.
Adjust them to your liking.

By default, you cannot enable all the features, as the bootloader would exceed
By default, you cannot enable all the features, as the bootloader would exceed
the 8k allocated to it by Arduino etc. It will assert on startup that it's not bigger
than 8k. Also, the linker script will not allow it.

Three typical configurations are:

* HID, WebUSB, MSC, plus flash reading via FAT; UART and CDC disabled;
* HID, WebUSB, MSC, plus flash reading via FAT; UART and CDC disabled;
logging optional; **recommended**
* USB CDC and MSC, plus flash reading via FAT; UART disabled;
* USB CDC and MSC, plus flash reading via FAT; UART disabled;
logging optional; this may have Windows driver problems
* USB CDC and MSC, no flash reading via FAT (or at least `index.htm` disabled); UART enabled;
* USB CDC and MSC, no flash reading via FAT (or at least `index.htm` disabled); UART enabled;
logging disabled; no handover; no HID;
only this one if you need the UART support in bootloader for whatever reason

CDC and MSC together will work on Linux and Mac with no drivers.
On Windows, if you have drivers installed for the USB ID chosen,
On Windows, if you have drivers installed for the USB ID chosen,
then CDC might work and MSC will not work;
otherwise, if you have no drivers, MSC will work, and CDC will work on Windows 10 only.
Thus, it's best to set the USB ID to one for which there are no drivers.
Expand Down
1 change: 1 addition & 0 deletions lib/uf2
Submodule uf2 added at d7ab98
51 changes: 51 additions & 0 deletions scripts/gendata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import sys
import os


def update_crc(new_byte, current_crc):
crc = current_crc ^ new_byte << 8
for cmpt in range(8):
if crc & 0x8000:
crc = crc << 1 ^ 0x1021
else:
crc = crc << 1
crc &= 0xffff
return crc


# Load the bootloader file
bootloader_size = int(sys.argv[1])
bin_name = sys.argv[2]
bootloader = bytearray()
with open(bin_name, "rb") as bootloader_bin:
bootloader.extend(bootloader_bin.read())

# Fill the remaining space with 0xff.
bootloader.extend([0xff] * (bootloader_size - len(bootloader)))

# Output the bootloader binary data into C code to use in the self updater.
with open(os.path.dirname(bin_name) + "/selfdata.c", "w") as output:
output.write("#include <stdint.h>\n")
output.write("const uint8_t bootloader[{}] ".format(bootloader_size) +
"__attribute__ ((aligned (4))) = {")
crcs = []
crc = 0
for row in range(bootloader_size / 16):
# Save the crc every 1k.
if row % (1024 / 16) == 0 and row > 0:
crcs.append(crc)
crc = 0
start_index = row * 16
row_bytes = bootloader[start_index:start_index+16]
formatted_bytes = ["0x{:02x}".format(x) for x in row_bytes]
output.write(", ".join(formatted_bytes) + ",\n")

# Update the crc
for b in row_bytes:
crc = update_crc(b, crc)
crcs.append(crc) # Add the last crc
output.write("\n};\n")

crcs = ["0x{:04x}".format(x) for x in crcs]
output.write("const uint16_t bootloader_crcs[] = {" +
" ,".join(crcs) + "};\n")
163 changes: 163 additions & 0 deletions scripts/samd51j19a_self.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/**
* \file
*
* \brief Linker script for running in internal FLASH on the SAMD51J19A
*
* Copyright (c) 2017 Microchip Technology Inc.
*
* \asf_license_start
*
* \page License
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the Licence at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* \asf_license_stop
*
*/


OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)

/* Memory Spaces Definitions */
MEMORY
{
rom (rx) : ORIGIN = 0x00004000, LENGTH = 0x00080000 - 0x4000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00030000
bkupram (rwx) : ORIGIN = 0x47000000, LENGTH = 0x00002000
qspi (rwx) : ORIGIN = 0x04000000, LENGTH = 0x01000000
}

/* The stack size used by the application. NOTE: you need to adjust according to your application. */
STACK_SIZE = DEFINED(STACK_SIZE) ? STACK_SIZE : DEFINED(__stack_size__) ? __stack_size__ : 0xC000;

/* Section Definitions */
SECTIONS
{
.text :
{
. = ALIGN(4);
_sfixed = .;
KEEP(*(.vectors .vectors.*))
*(.text .text.* .gnu.linkonce.t.*)
*(.glue_7t) *(.glue_7)
*(.rodata .rodata* .gnu.linkonce.r.*)
*(.ARM.extab* .gnu.linkonce.armextab.*)

/* Support C constructors, and C destructors in both user code
and the C library. This also provides support for C++ code. */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;

. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;

. = ALIGN(4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))

. = ALIGN(4);
KEEP(*(.fini))

. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;

KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))

. = ALIGN(4);
_efixed = .; /* End of text section */
} > rom

/* .ARM.exidx is sorted, so has to go in its own output section. */
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > rom
PROVIDE_HIDDEN (__exidx_end = .);

. = ALIGN(4);
_etext = .;

.relocate : AT (_etext)
{
. = ALIGN(4);
_srelocate = .;
*(.ramfunc .ramfunc.*);
*(.data .data.*);
. = ALIGN(4);
_erelocate = .;
} > ram

.bkupram (NOLOAD):
{
. = ALIGN(8);
_sbkupram = .;
*(.bkupram .bkupram.*);
. = ALIGN(8);
_ebkupram = .;
} > bkupram

.qspi (NOLOAD):
{
. = ALIGN(8);
_sqspi = .;
*(.qspi .qspi.*);
. = ALIGN(8);
_eqspi = .;
} > qspi

/* .bss section which is used for uninitialized data */
.bss (NOLOAD) :
{
. = ALIGN(4);
_sbss = . ;
_szero = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ;
_ezero = .;
} > ram

/* stack section */
.stack (NOLOAD):
{
. = ALIGN(8);
_sstack = .;
. = . + STACK_SIZE;
. = ALIGN(8);
_estack = .;
} > ram

. = ALIGN(4);
_end = . ;
}
Loading

0 comments on commit 9de0794

Please sign in to comment.