Compare commits

...
40 Commits
Author SHA1 Message Date
hathach f5b654eb5e update changelog 2019-03-27 13:14:54 +07:00
hathach 60debfc217 Merge pull request #60 from adafruit/develop
fix #59 incorrect button mapping for feather nrf52840
2019-03-26 23:09:27 -07:00
hathach 2713069643 fix #59 incorrect button mapping for feather nrf52840 2019-03-27 13:03:41 +07:00
hathach 8df909f0a8 Merge pull request #57 from henrygab/patch-6
Fix FAT bugs and increase file count limit
2019-03-19 04:50:52 -07:00
hathach 1d816c5cf3 Merge pull request #56 from henrygab/patch-5
Ignore additional SES and J-Link files
2019-03-19 03:02:06 -07:00
Henry Gabryjelski 66d1770407 manually add another lost comment 2019-03-19 01:01:50 -07:00
Henry Gabryjelski 8ab4774c93 Manual merge?
Pickup a couple changes that don't seem to be propagating?
Possible that there's some git merge I missed, but it's simple enough to fix manually.
2019-03-19 00:57:24 -07:00
Henry Gabryjelski 1b54f0457d PR review requested changes.
Per hathach's request, remove built-in test option.
Per hathach's request, remote __TIME__ from info file.
2019-03-19 00:37:53 -07:00
Henry Gabryjelski a004b7619e Add trailing newline 2019-03-18 22:14:52 -07:00
Henry Gabryjelski 04fc396fd8 Put macros into new file, rather than uf2.h. 2019-03-13 23:49:52 -07:00
Henry Gabryjelski 04e0df1c18 prepare to split file 2019-03-13 23:40:18 -07:00
Henry Gabryjelski 6d58633db0 Merge branch 'master' of https://github.com/adafruit/Adafruit_nRF52_Bootloader into patch-6
# Conflicts:
#	src/usb/uf2/ghostfat.c
2019-03-13 22:39:12 -07:00
Henry Gabryjelski 15ca75d10d Merge branch 'master' of https://github.com/adafruit/Adafruit_nRF52_Bootloader into patch-5 2019-03-13 22:23:08 -07:00
Henry Gabryjelski 174e6e9724 Fix Directory entries
The media would show as corrupt in CMD.EXE in Windows.
This is because the date/time fields were invalid.
Since this needed to be fixed anyways, update so that
the date and time correspond to the time that the
preprocessor parsed the source file.
2019-03-13 22:05:57 -07:00
Henry Gabryjelski 53a99195bf Raises file limit from 14 to 62 files.
Enable all four sectors of root directory to contain files.
2019-03-13 21:38:59 -07:00
Henry Gabryjelski 8def8aee53 Safer code
Add additional compile-time assertions
Add additional comments to define limitations future maintainers should be aware of.
2019-03-13 18:28:43 -07:00
Henry Gabryjelski c51a227fd9 Add static assert
This guards against future increase in number of files
causing buffer overflow when reading the first root directory sector.
2019-03-13 15:24:42 -07:00
Henry Gabryjelski f3e3cefb23 Ignore additional SES and J-Link files 2019-03-13 13:10:49 -07:00
hathach 73456ac80e Merge pull request #54 from henrygab/patch-2
Avoid returning uninitialized memory
2019-03-13 01:08:06 -07:00
hathach 113195eabd Merge branch 'master' into patch-2 2019-03-13 00:58:21 -07:00
hathach 0eeff3e679 Merge pull request #53 from henrygab/patch-3
Fix signed/unsigned bug.
2019-03-13 00:55:54 -07:00
hathach be5a925f72 Merge pull request #55 from henrygab/patch-4
Use local variable to store partially-calculated size.
2019-03-13 00:53:37 -07:00
hathach ae28f5b425 Merge pull request #52 from henrygab/patch-1
Fix media type mismatch
2019-03-13 00:46:49 -07:00
Henry Gabryjelski b8a0551678 Use local variable to store partially-calculated size.
This avoid re-entrancy problems, such as if this is ever
interrupted mid-execution, and called a second time before
the initial execution completes.
2019-03-12 13:41:33 -07:00
Henry Gabryjelski 0f216b8618 Fix spacing 2019-03-12 13:13:58 -07:00
Henry Gabryjelski 52cfdaa2d2 Fix signed/unsigned bug. 2019-03-12 13:05:21 -07:00
Henry Gabryjelski a258c6d988 Avoid returning uninitialized memory 2019-03-12 12:57:51 -07:00
Henry Gabryjelski e0251415e7 Add some additional comments. 2019-03-12 12:29:05 -07:00
Henry Gabryjelski 12bb62eadd Per request, keep hard drive type in boot block.
Update the .PhysicalDrive in boot block.
Update the first fat entries to match MediaDescriptor of boot block.
2019-03-12 12:09:49 -07:00
Henry Gabryjelski e2afc36dae Fix media type mismatch
Fix the boot sector media descriptor to match the first FAT entries.
2019-03-10 20:02:56 -07:00
hathach 4ea74d4600 Update README.md 2019-03-06 00:52:07 +07:00
hathach 9bc01fb061 Merge pull request #49 from gpshead/mdk_dongle
Support the MDK nrf52840 USB Dongle.
2019-03-05 09:49:36 -08:00
Gregory P. Smith 01492634b6 Use RGB red and blue as primary and secondary.
The code currently expects a primary LED no matter what so the
RGB led support combined with that clobbers the nice pulsing primary.
2019-03-03 21:12:30 -08:00
Gregory P. Smith 05726e2575 Initial MakerDiary MDK nrf52840 USB dongle support.
Many TODOs to address but it builds and appears at first glance to work...
2019-03-03 18:58:34 -08:00
Dan Halbert 14f87f61e6 Add 0.2.0 to changelog
@hathach Tested, so making a new release.
2019-02-22 15:52:57 -05:00
Dan Halbert 7df44a5425 Merge pull request #47 from adafruit/develop
fix #46 issue with windows 10 build 18.09
2019-02-22 15:41:58 -05:00
hathach 0cc0289c60 update dfu-flash for upgrading bootloader
clean up makefile
2019-02-22 23:55:01 +07:00
hathach 992229cf2f Merge branch 'master' into develop 2019-02-22 23:06:07 +07:00
hathach 57aa554430 update tinyusb to latest for scsi write10 complete fix 2019-02-22 14:46:16 +07:00
hathach 9ed3f5ea32 fix #46 complete uf2 writing using tud_msc_write10_complete_cb 2019-02-22 00:21:34 +07:00
16 changed files with 455 additions and 130 deletions

No files matched your search

+2
View File
@@ -54,3 +54,5 @@ dkms.conf
src/segger/Output
_build-*/
bin/
*.emSession
*.jlink
-1
View File
@@ -1,7 +1,6 @@
[submodule "tinyusb"]
path = lib/tinyusb
url = https://github.com/hathach/tinyusb.git
branch = develop
[submodule "lib/nrfx"]
path = lib/nrfx
url = https://github.com/NordicSemiconductor/nrfx.git
+6 -43
View File
@@ -28,7 +28,6 @@ SD_HEX = $(SD_PATH)/$(SD_FILENAME)_softdevice.hex
LD_FILE = $(SRC_PATH)/linker/$(SD_NAME)_v$(SD_VER1).ld
MERGED_FNAME = $(OUTPUT_FILENAME)_$(SD_NAME)_$(SD_VERSION)
RELEASE_DIR = bin/$(BOARD)
MK_DIS_FIRMWARE = "$(SD_NAME) $(SD_VERSION)"
@@ -86,7 +85,7 @@ BOARD_LIST = $(sort $(subst .h,,$(subst src/boards/,,$(wildcard src/boards/*.h))
NRF52832_BOARDLIST = feather_nrf52832
IS_52832 = $(filter $(BOARD),$(NRF52832_BOARDLIST))
ifeq ($(filter $(MAKECMDGOALS),all-board all-release help),)
ifeq ($(filter $(MAKECMDGOALS),all-board help),)
ifeq ($(BOARD),)
$(info You must provide a BOARD parameter with 'BOARD=')
$(info Supported boards are: $(BOARD_LIST))
@@ -252,6 +251,8 @@ CFLAGS += -ffunction-sections -fdata-sections -fno-strict-aliasing
CFLAGS += -fno-builtin --short-enums -fstack-usage
# Defined Symbol (MACROS)
# TODO use GIT_VERSION (numberic format)
CFLAGS += -DMK_BOOTLOADER_VERSION=0x0$(SD_VER1)0$(SD_VER2)0$(SD_VER3)UL
CFLAGS += -D__HEAP_SIZE=0
@@ -360,20 +361,11 @@ _make_all_board = $(foreach b,$(BOARD_LIST), $(call _make_board,$b,$1))
all-board:
$(call _make_all_board,clean all)
all-release:
$(call _make_all_board,clean all release)
help:
@echo To flash (with jlink) a pre-built binary with a specific version to a board
@echo $$ make BOARD=feather_nrf52840_express VERSION=6.1.1r0 flash
@echo
@echo To flash (with dfu) a pre-built binary with a specific version to a board
@echo $$ make BOARD=feather_nrf52840_express VERSION=6.1.1r0 SERIAL=/dev/ttyACM0 dfu0-flash
@echo
@echo To compile and build the current code for a board
@echo $$ make BOARD=feather_nrf52840_express all
@echo
@echo To flash current code using jlink
@echo To flash current code using Jlink
@echo $$ make BOARD=feather_nrf52840_express flash
@echo
@echo To flash current code using existing bootloader dfu
@@ -388,8 +380,6 @@ __check_defined = \
$(if $(value $1),, \
$(error Undefined make flag: $1$(if $2, ($2))))
ifeq ($(VERSION),)
# Flash the compiled
flash: $(BUILD)/$(OUTPUT_FILENAME)-nosd.hex
@echo Flashing: $<
@@ -397,26 +387,7 @@ flash: $(BUILD)/$(OUTPUT_FILENAME)-nosd.hex
dfu-flash: $(BUILD)/$(MERGED_FNAME).zip
@:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0)
$(NRFUTIL) --verbose dfu serial --package $< -p $(SERIAL) -b 115200 --singlebank
else
ifeq ($(VERSION),latest)
VERSION_FPATH = $(RELEASE_DIR)/$(MERGED_FNAME)
else
VERSION_FPATH = bin/$(BOARD)/$(VERSION)/$(OUTPUT_FILENAME)_$(SD_NAME)_$(VERSION)
endif
# Flash specific version in binary release folder
flash:
@echo Flashing: $(VERSION_FPATH).hex
$(NRFJPROG) --program $(VERSION_FPATH).hex --chiperase -f nrf52 --reset
dfu-flash:
@:$(call check_defined, SERIAL, example: SERIAL=/dev/ttyACM0)
$(NRFUTIL) --verbose dfu serial --package $(VERSION_FPATH).zip -p $(SERIAL) -b 115200 --singlebank
endif
$(NRFUTIL) --verbose dfu serial --package $< -p $(SERIAL) -b 115200 --singlebank --touch 1200
sd:
@echo Flashing: $(SD_HEX)
@@ -457,7 +428,7 @@ size: $(BUILD)/$(OUTPUT_FILENAME)-nosd.out
#******************* Binary generator *******************
.phony: genhex genpkg release
.phony: genhex genpkg
## Create binary .hex file from the .out file
genhex: $(BUILD)/$(OUTPUT_FILENAME)-nosd.hex
@@ -478,11 +449,3 @@ genpkg: $(BUILD)/$(MERGED_FNAME).zip
$(BUILD)/$(MERGED_FNAME).zip: $(BUILD)/$(OUTPUT_FILENAME)-nosd.hex
@$(NRFUTIL) dfu genpkg --dev-type 0x0052 --dev-revision $(DFU_DEV_REV) --bootloader $< --softdevice $(SD_HEX) $@
# Create SD+bootloader combo with hex & dfu package at release folder
release: combinehex genpkg
@echo CR $(RELEASE_DIR)/$(MERGED_FNAME).hex
@echo CR $(RELEASE_DIR)/$(MERGED_FNAME).zip
@mkdir -p $(RELEASE_DIR)
@cp $(BUILD)/$(MERGED_FNAME).hex $(RELEASE_DIR)/$(MERGED_FNAME).hex
@cp $(BUILD)/$(MERGED_FNAME).zip $(RELEASE_DIR)/$(MERGED_FNAME).zip
+8 -1
View File
@@ -9,6 +9,7 @@ This is a CDC/DFU/UF2 bootloader for nRF52 boards.
- Particle Argon
- Particle Boron
- Particle Xenon
- MakerDiary MDK nRF52840 USB Dongle
UF2 is an easy-to-use bootloader that appears as a flash drive. You can just copy `.uf2`-format
application images to the flash drive to load new firmware.
@@ -97,12 +98,18 @@ To build:
make BOARD=feather_nrf52840_express all combinehex
```
To flash the bootloader:
To flash the bootloader with JLink:
```
make BOARD=feather_nrf52840_express flash
```
To upgrade the bootloader using DFU Serial via port /dev/ttyACM0
```
make BOARD=feather_nrf52840_express SERIAL=/dev/ttyACM0 dfu-flash
```
To flash SoftDevice (and chip erase):
```
+10
View File
@@ -1,5 +1,15 @@
# Adafruit nRF52 Bootloader Changelog
## 0.2.10
- Fixed various FAT issues, thanks to @henrygab
- Added MakerDiary MDK nrf52840 USB dongle support, thanks to @gpshead
- Fixed incorrect button mapping for Feather nRF52840
## 0.2.9
- Fixed incomplete writes on Windows. Upated tinyusb to handle write10 completion, and use it for finalizing dfu process. Will prevent windows error message pop up. This will also give an extra time for flash writing to complete.
## 0.2.8
- Fixed OTA issue with nrfConnect on iOS
@@ -130,9 +130,9 @@ static void wait_for_events(void)
#ifdef NRF52840_XXAA
// skip if usb is not inited ( e.g OTA / finializing sd/bootloader )
extern bool usb_inited(void);
if ( usb_inited() )
if ( tusb_inited() )
{
tusb_task();
tud_task();
tud_cdc_write_flush();
}
#endif
+2 -2
View File
@@ -53,8 +53,8 @@
/* BUTTON
*------------------------------------------------------------------*/
#define BUTTONS_NUMBER 2
#define BUTTON_1 _PINNUM(0, 15)
#define BUTTON_2 _PINNUM(0, 19)
#define BUTTON_1 _PINNUM(1, 02)
#define BUTTON_2 _PINNUM(0, 10)
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
/*------------------------------------------------------------------*/
+74
View File
@@ -0,0 +1,74 @@
/**************************************************************************/
/*!
@file mdk_nrf52840_dongle.h
@author gpshead (krypto.org)
@section LICENSE
Software License Agreement (BSD License)
Copyright (c) 2019, Adafruit Industries (adafruit.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holders nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**************************************************************************/
#ifndef _MDK_NRF52840_DONGLE_H_
#define _MDK_NRF52840_DONGLE_H_
#define _PINNUM(port, pin) ((port)*32 + (pin))
/*------------------------------------------------------------------*/
/* LED
*------------------------------------------------------------------*/
#define LEDS_NUMBER 2 // TODO(gpshead): support 0.
#define LED_PRIMARY_PIN _PINNUM(0, 23) // Red
#define LED_SECONDARY_PIN _PINNUM(0, 24) // Blue
#define LED_STATE_ON 0
//#define LED_RGB_RED_PIN _PINNUM(0, 23)
//#define LED_RGB_GREEN_PIN _PINNUM(0, 22)
//#define LED_RGB_BLUE_PIN _PINNUM(0, 24)
#define BOARD_RGB_BRIGHTNESS 0x404040
/*------------------------------------------------------------------*/
/* BUTTON
*------------------------------------------------------------------*/
// TODO(gpshead): simplify, have code support 0. double reset only.
#define BUTTONS_NUMBER 2 // none connected at all
#define BUTTON_1 _PINNUM(0, 18) // unusable: RESET
#define BUTTON_2 _PINNUM(0, 19) // no connection
#define BUTTON_PULL NRF_GPIO_PIN_PULLUP
// Used as model string in OTA mode
#define DIS_MANUFACTURER "MakerDiary"
#define DIS_MODEL "nRF52840 Micro Dev Kit USB Dongle"
#define PRODUCT_NAME "MDK nRF52840 USB Dongle"
#define VOLUME_LABEL "MDK840DONGL"
#define BOARD_ID "MakerDiary-nRF52840-USB-Dongle"
#define INDEX_URL "https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/"
#endif /* _MDK_NRF52840_DONGLE_H_ */
+3 -2
View File
@@ -53,8 +53,9 @@ void flash_nrf5x_flush (bool need_erase)
{
// - nRF52832 dfu via uart can miss incoming byte when erasing because cpu is blocked for > 2ms.
// Since dfu_prepare_func_app_erase() already erase the page for us, we can skip it here.
// - nRF52840 dfu serial/uf2 are USB-based which are DMA and should have no problems. Note MSC uf2
// does not erase page in advance like dfu serial
// - nRF52840 dfu serial/uf2 are USB-based which are DMA and should have no problems.
//
// Note: MSC uf2 does not erase page in advance like dfu serial
if ( need_erase ) nrf_nvmc_page_erase(_fl_addr);
nrf_nvmc_write_words(_fl_addr, (uint32_t *) _fl_buf, FLASH_PAGE_SIZE / 4);
@@ -63,6 +63,7 @@
<file file_name="../usb/uf2/uf2cfg.h" />
<file file_name="../usb/uf2/uf2.h" />
<file file_name="../usb/uf2/ghostfat.c" />
<file file_name="../usb/uf2/macros.h" />
</folder>
<file file_name="../usb/msc_uf2.c" />
<file file_name="../usb/usb.c" />
+29 -4
View File
@@ -39,6 +39,8 @@
#if CFG_TUD_MSC
#include "bootloader.h"
/*------------------------------------------------------------------*/
/* MACRO TYPEDEF CONSTANT ENUM
*------------------------------------------------------------------*/
@@ -46,8 +48,10 @@
/*------------------------------------------------------------------*/
/* UF2
*------------------------------------------------------------------*/
static WriteState _wr_state = { 0 };
void read_block(uint32_t block_no, uint8_t *data);
int write_block(uint32_t block_no, uint8_t *data, bool quiet/*, WriteState *state*/);
int write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state);
//--------------------------------------------------------------------+
// tinyusb callbacks
@@ -59,7 +63,8 @@ int write_block(uint32_t block_no, uint8_t *data, bool quiet/*, WriteState *stat
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
void const* response = NULL;
uint16_t resplen = 0;
int32_t resplen = 0;
memset(buffer, 0, bufsize);
switch ( scsi_cmd[0] )
{
@@ -94,7 +99,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
}
// return len must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( resplen > (int32_t)bufsize ) resplen = bufsize;
// copy response to stack's buffer if any
if ( response && resplen )
@@ -110,6 +115,7 @@ int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer,
int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
(void) lun;
memset(buffer, 0, bufsize);
// since we return block size each, offset should always be zero
TU_ASSERT(offset == 0, -1);
@@ -137,7 +143,7 @@ int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
uint32_t count = 0;
int wr_ret;
while ( (count < bufsize) && ((wr_ret = write_block(lba, buffer, false)) > 0) )
while ( (count < bufsize) && ((wr_ret = write_block(lba, buffer, false, &_wr_state)) > 0) )
{
lba++;
buffer += 512;
@@ -148,6 +154,25 @@ int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t*
return (wr_ret < 0) ? bufsize : count;
}
// Callback invoked when WRITE10 command is completed (status received and accepted by host).
void tud_msc_write10_complete_cb(uint8_t lun)
{
// uf2 file writing is complete --> complete DFU process
if ( _wr_state.numBlocks && (_wr_state.numWritten >= _wr_state.numBlocks) )
{
led_state(STATE_WRITING_FINISHED);
dfu_update_status_t update_status;
memset(&update_status, 0, sizeof(dfu_update_status_t ));
update_status.status_code = DFU_UPDATE_APP_COMPLETE;
update_status.app_crc = 0; // skip CRC checking with uf2 upgrade
update_status.app_size = _wr_state.numBlocks*256;
bootloader_dfu_update_process(update_status);
}
}
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
(void) lun;
+80 -51
View File
@@ -1,4 +1,6 @@
#include "macros.h"
#include "uf2.h"
#include "flash_nrf5x.h"
#include <string.h>
@@ -47,7 +49,6 @@ typedef struct {
uint16_t startCluster;
uint32_t size;
} __attribute__((packed)) DirEntry;
STATIC_ASSERT(sizeof(DirEntry) == 32);
struct TextFile {
@@ -59,6 +60,7 @@ struct TextFile {
#define STR0(x) #x
#define STR(x) STR0(x)
const char infoUf2File[] = //
"UF2 Bootloader " UF2_VERSION "\r\n"
"Model: " PRODUCT_NAME "\r\n"
@@ -76,16 +78,27 @@ const char indexFile[] = //
"</body>"
"</html>\n";
// WARNING -- code presumes only one NULL .content for .UF2 file
// and requires it be the last element of the array
static struct TextFile const info[] = {
{.name = "INFO_UF2TXT", .content = infoUf2File},
{.name = "INDEX HTM", .content = indexFile},
{.name = "CURRENT UF2"},
};
#define NUM_INFO (sizeof(info) / sizeof(info[0]))
// WARNING -- code presumes each non-UF2 file content fits in single sector
// Cannot programmatically statically assert .content length
// for each element above.
STATIC_ASSERT(ARRAY_SIZE2(indexFile) < 512);
#define NUM_FILES (ARRAY_SIZE2(info))
#define NUM_DIRENTRIES (NUM_FILES + 1) // Code adds volume label as first root directory entry
#define UF2_SIZE (current_flash_size() * 2)
#define UF2_SECTORS (UF2_SIZE / 512)
#define UF2_FIRST_SECTOR (NUM_INFO + 1)
#define UF2_FIRST_SECTOR (NUM_FILES + 1) // WARNING -- code presumes each non-UF2 file content fits in single sector
#define UF2_LAST_SECTOR (UF2_FIRST_SECTOR + UF2_SECTORS - 1)
#define RESERVED_SECTORS 1
@@ -97,6 +110,13 @@ static struct TextFile const info[] = {
#define START_ROOTDIR (START_FAT1 + SECTORS_PER_FAT)
#define START_CLUSTERS (START_ROOTDIR + ROOT_DIR_SECTORS)
// all directory entries must fit in a single sector
// because otherwise current code overflows buffer
#define DIRENTRIES_PER_SECTOR (512/sizeof(DirEntry))
STATIC_ASSERT(NUM_DIRENTRIES < DIRENTRIES_PER_SECTOR * ROOT_DIR_SECTORS);
static FAT_BootBlock const BootBlock = {
.JumpInstruction = {0xeb, 0x3c, 0x90},
.OEMInfo = "UF2 UF2 ",
@@ -104,12 +124,13 @@ static FAT_BootBlock const BootBlock = {
.SectorsPerCluster = 1,
.ReservedSectors = RESERVED_SECTORS,
.FATCopies = 2,
.RootDirectoryEntries = (ROOT_DIR_SECTORS * 512 / 32),
.RootDirectoryEntries = (ROOT_DIR_SECTORS * DIRENTRIES_PER_SECTOR),
.TotalSectors16 = NUM_FAT_BLOCKS - 2,
.MediaDescriptor = 0xF8,
.SectorsPerFAT = SECTORS_PER_FAT,
.SectorsPerTrack = 1,
.Heads = 1,
.PhysicalDriveNum = 0x80, // to match MediaDescriptor of 0xF8
.ExtendedBootSig = 0x29,
.VolumeSerialNumber = 0x00420042,
.VolumeLabel = VOLUME_LABEL,
@@ -119,41 +140,41 @@ static FAT_BootBlock const BootBlock = {
#define NRF_LOG_DEBUG(...)
#define NRF_LOG_WARNING(...)
static WriteState _wr_state = { 0 };
// get current.uf2 flash size in bytes, round up to 256 bytes
static uint32_t current_flash_size(void)
{
static uint32_t flash_sz = 0;
uint32_t result = flash_sz; // presumes atomic 32-bit read/write and static result
// only need to compute once
if ( flash_sz == 0 )
if ( result == 0 )
{
// return 1 block of 256 bytes
if ( !bootloader_app_is_valid(DFU_BANK_0_REGION_START) )
{
flash_sz = 256;
result = 256;
}else
{
bootloader_settings_t const * boot_setting;
bootloader_util_settings_get(&boot_setting);
flash_sz = boot_setting->bank_0_size;
result = boot_setting->bank_0_size;
// Copy size must be multiple of 256 bytes
// else we will got an issue copying current.uf2
if (flash_sz & 0xff)
if (result & 0xff)
{
flash_sz = (flash_sz & ~0xff) + 256;
result = (result & ~0xff) + 256;
}
// if bank0 size is not valid, happens when flashed with jlink
// use maximum application size
if ( (flash_sz == 0) || (flash_sz == 0xFFFFFFFFUL) )
if ( (result == 0) || (result == 0xFFFFFFFFUL) )
{
flash_sz = FLASH_SIZE;
result = FLASH_SIZE;
}
}
flash_sz = result; // presumes atomic 32-bit read/write and static result
}
return flash_sz;
@@ -178,47 +199,73 @@ void read_block(uint32_t block_no, uint8_t *data) {
memset(data, 0, 512);
uint32_t sectionIdx = block_no;
if (block_no == 0) {
if (block_no == 0) { // Requested boot block
memcpy(data, &BootBlock, sizeof(BootBlock));
data[510] = 0x55;
data[511] = 0xaa;
// logval("data[0]", data[0]);
} else if (block_no < START_ROOTDIR) {
} else if (block_no < START_ROOTDIR) { // Requested FAT table sector
sectionIdx -= START_FAT0;
// logval("sidx", sectionIdx);
if (sectionIdx >= SECTORS_PER_FAT)
sectionIdx -= SECTORS_PER_FAT;
sectionIdx -= SECTORS_PER_FAT; // second FAT is same as the first...
if (sectionIdx == 0) {
data[0] = 0xf0;
for (int i = 1; i < NUM_INFO * 2 + 4; ++i) {
data[0] = 0xf8; // first FAT entry must match BPB MediaDescriptor
// WARNING -- code presumes only one NULL .content for .UF2 file
// and all non-NULL .content fit in one sector
// and requires it be the last element of the array
for (int i = 1; i < NUM_FILES * 2 + 4; ++i) {
data[i] = 0xff;
}
}
for (int i = 0; i < 256; ++i) {
for (int i = 0; i < 256; ++i) { // Generate the FAT chain for the firmware "file"
uint32_t v = sectionIdx * 256 + i;
if (UF2_FIRST_SECTOR <= v && v <= UF2_LAST_SECTOR)
((uint16_t *)(void *)data)[i] = v == UF2_LAST_SECTOR ? 0xffff : v + 1;
}
} else if (block_no < START_CLUSTERS) {
} else if (block_no < START_CLUSTERS) { // Requested root directory sector
sectionIdx -= START_ROOTDIR;
if (sectionIdx == 0) {
DirEntry *d = (void *)data;
DirEntry *d = (void *)data;
int remainingEntries = DIRENTRIES_PER_SECTOR;
if (sectionIdx == 0) { // volume label first
// volume label is first directory entry
padded_memcpy(d->name, (char const *) BootBlock.VolumeLabel, 11);
d->attrs = 0x28;
for (int i = 0; i < NUM_INFO; ++i) {
d++;
struct TextFile const *inf = &info[i];
d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
d->startCluster = i + 2;
padded_memcpy(d->name, inf->name, 11);
}
d++;
remainingEntries--;
}
for (int i = DIRENTRIES_PER_SECTOR * sectionIdx;
remainingEntries > 0 && i < NUM_FILES;
i++, d++) {
// WARNING -- code presumes all but last file take exactly one sector
uint16_t startCluster = i + 2;
struct TextFile const * inf = &info[i];
padded_memcpy(d->name, inf->name, 11);
d->createTimeFine = __SECONDS_INT__ % 2 * 100;
d->createTime = __DOSTIME__;
d->createDate = __DOSDATE__;
d->lastAccessDate = __DOSDATE__;
d->highStartCluster = startCluster >> 8;
// DIR_WrtTime and DIR_WrtDate must be supported
d->updateTime = __DOSTIME__;
d->updateDate = __DOSDATE__;
d->startCluster = startCluster & 0xFF;
// WARNING -- code presumes only one NULL .content for .UF2 file
// and requires it be the last element of the array
d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
}
} else {
sectionIdx -= START_CLUSTERS;
if (sectionIdx < NUM_INFO - 1) {
if (sectionIdx < NUM_FILES - 1) {
memcpy(data, info[sectionIdx].content, strlen(info[sectionIdx].content));
} else {
sectionIdx -= NUM_INFO - 1;
} else { // generate the UF2 file data on-the-fly
sectionIdx -= NUM_FILES - 1;
uint32_t addr = USER_FLASH_START + sectionIdx * 256;
if (addr < USER_FLASH_START+FLASH_SIZE) {
UF2_Block *bl = (void *)data;
@@ -241,21 +288,6 @@ void read_block(uint32_t block_no, uint8_t *data) {
/* Write UF2
*------------------------------------------------------------------*/
/** uf2 upgrade complete -> inform bootloader to update setting and reset */
static void uf2_write_complete(uint32_t numBlocks)
{
led_state(STATE_WRITING_FINISHED);
dfu_update_status_t update_status;
memset(&update_status, 0, sizeof(dfu_update_status_t ));
update_status.status_code = DFU_UPDATE_APP_COMPLETE;
update_status.app_crc = 0; // skip CRC checking with uf2 upgrade
update_status.app_size = numBlocks*256;
bootloader_dfu_update_process(update_status);
}
/** Write an block
*
* @return number of bytes processed, only 3 following values
@@ -263,9 +295,8 @@ static void uf2_write_complete(uint32_t numBlocks)
* 512 : write is successful
* 0 : is busy with flashing, tinyusb stack will call write_block again with the same parameters later on
*/
int write_block(uint32_t block_no, uint8_t *data, bool quiet/*, WriteState *state*/) {
int write_block(uint32_t block_no, uint8_t *data, bool quiet, WriteState *state) {
UF2_Block *bl = (void *)data;
WriteState* state = &_wr_state;
NRF_LOG_DEBUG("Write magic: %x", bl->magicStart0);
@@ -318,8 +349,6 @@ int write_block(uint32_t block_no, uint8_t *data, bool quiet/*, WriteState *stat
if (state->numWritten >= state->numBlocks) {
// flush last blocks
flash_nrf5x_flush(true);
uf2_write_complete(state->numBlocks);
}
}
NRF_LOG_DEBUG("wr %d=%d (of %d)", state->numWritten, bl->blockNo, bl->numBlocks);
+225
View File
@@ -0,0 +1,225 @@
/**
The MIT License (MIT)
Copyright (c)
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef ARRAYSIZE2_H
#define ARRAYSIZE2_H
#ifndef __has_feature
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#if __cplusplus >= 199711L
#pragma message "using Ivan J. Johnson's ARRAY_SIZE2"
// Works on older compilers, even Visual C++ 6....
// Created by Ivan J. Johnson, March 06, 2007
// See http://drdobbs.com/cpp/197800525?pgno=1
//
// Pseudocode:
// if x is not an array
// issue a compile-time error
// else
// use the traditional (non-typesafe) C99 COUNTOF expression
//
// If the argument is any of:
// object of class type, such as an std::vector
// floating-point type
// function pointer
// pointer-to-member
// then the first reinterpret_cast<> is not legal (compiler error)
//
// The type for check1 is chosen and named to help understand
// the cause of the error, because the class name is likely to
// appear in the compiler error message.
//
// If check1 succeeds, then the argument must be one of:
// an integral type
// an enumerated type
// a pointer to an object
// an array
//
// Check2 expands approximately to sizeof(check_type(x, &x)),
// where check_type is an overloaded function.
// Because this is purely a compile-time computation,
// the function is never really called or even implemented,
// but it lets the compiler apply overload resolution,
// which allows further type discrimination.
// There are three possibilities to consider:
// x is an integral type or enumerated type.
// In this case, neither of the two function overloads
// is a match, resulting in a compiler error.
// x is a pointer to an object.
// In this case, the first argument to check_type()
// is a pointer and the second one is a pointer-to-pointer.
// The best function match is the first overload of check_type,
// the one that returns an incomplete type (Is_pointer).
// However, because Is_pointer is an incomplete type,
// sizeof(Is_pointer) is not a valid expression,
// resulting in a compiler error.
// x is an array.
// In this case, the first argument to check_type()
// is an array and the second is a pointer-to-array.
// A pointer-to-array is *NOT* convertible to a
// pointer-to-pointer, so the first overload of
// check_type() is not a match.
// However, an array IS convertible to a pointer,
// and a pointer-to-array already is a pointer.
// Any pointer is convertible to a void*,
// so the second function overload is a match.
// That overload returns a complete type (Is_array).
// Because it's a complete type,
// sizeof(Is_array) is a valid expression.
// Thus, the compiler has EXCLUDED every possible type
// except arrays via compilation errors before reaching
// the third line.
// Moreover, check1 and check2 are reduced to the value zero,
// while the third line is the old type-unsafe C-style macro,
// now made entirely type-safe.
//
// Additional benefits:
// The result is itself constexpr
//
//
#define ARRAY_SIZE2(arr) ( \
0 * sizeof(reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(arr)) + /*check1*/ \
0 * sizeof(::Bad_arg_to_COUNTOF::check_type((arr), &(arr))) + /*check2*/ \
sizeof(arr) / sizeof((arr)[0]) /* eval */ \
)
struct Bad_arg_to_COUNTOF {
class Is_pointer; // incomplete
class Is_array {};
template <typename T>
static Is_pointer check_type(const T*, const T* const*);
static Is_array check_type(const void*, const void*);
};
#elif __cplusplus >= 201103L || /* any compiler claiming C++11 support */ \
_MSC_VER >= 1900 || /* Visual C++ 2015 or higher */ \
__has_feature(cxx_constexpr) /* CLang versions supporting constexp */
#pragma message "C++11 version ARRAY_SIZE2"
namespace detail
{
template <typename T, std::size_t N>
constexpr std::size_t countof(T const (&)[N]) noexcept
{
return N;
}
} // namespace detail
#define ARRAY_SIZE2(arr) detail::countof(arr)
#elif _MSC_VER // Visual C++ fallback
#pragma message "using Microsoft Visual C++ intrinsic ARRAY_SIZE2"
#define ARRAY_SIZE2(arr) _countof(arr)
#elif __cplusplus >= 199711L && ( /* C++ 98 trick */ \
defined(__INTEL_COMPILER) || \
defined(__clang__) || \
(defined(__GNUC__) && ( \
(__GNUC__ > 4) || \
(__GNUC__ == 4 && __GNUC_MINOR__ >= 4) \
)))
#pragma message "C++98 version ARRAY_SIZE2"
template <typename T, std::size_t N>
char(&_ArraySizeHelperRequiresArray(T(&)[N]))[N];
#define ARRAY_SIZE2(x) sizeof(_ArraySizeHelperRequiresArray(x))
#else
#pragma message "Using type-unsafe version of ARRAY_SIZE2"
// This is the worst-case scenario macro.
// While it is valid C, it is NOT typesafe.
// For example, if the parameter arr is a pointer instead of array,
// the compiler will SILENTLY give a (likely) incorrect result.
#define ARRAY_SIZE2(arr) sizeof(arr) / sizeof(arr[0])
#endif
#endif // ARRAYSIZE2_H
#ifndef COMPILE_DATE_H
#define COMPILE_DATE_H
#define __YEAR_INT__ ((( \
(__DATE__ [ 7u] - '0') * 10u + \
(__DATE__ [ 8u] - '0')) * 10u + \
(__DATE__ [ 9u] - '0')) * 10u + \
(__DATE__ [10u] - '0'))
#define __MONTH_INT__ ( \
(__DATE__ [2u] == 'n' && __DATE__ [1u] == 'a') ? 1u /*Jan*/ \
: (__DATE__ [2u] == 'b' ) ? 2u /*Feb*/ \
: (__DATE__ [2u] == 'r' && __DATE__ [1u] == 'a') ? 3u /*Mar*/ \
: (__DATE__ [2u] == 'r' ) ? 4u /*Apr*/ \
: (__DATE__ [2u] == 'y' ) ? 5u /*May*/ \
: (__DATE__ [2u] == 'n' ) ? 6u /*Jun*/ \
: (__DATE__ [2u] == 'l' ) ? 7u /*Jul*/ \
: (__DATE__ [2u] == 'g' ) ? 8u /*Jul*/ \
: (__DATE__ [2u] == 'p' ) ? 9u /*Jul*/ \
: (__DATE__ [2u] == 't' ) ? 10u /*Jul*/ \
: (__DATE__ [2u] == 'v' ) ? 11u /*Jul*/ \
: 12u /*Dec*/ )
#define __DAY_INT__ ( \
(__DATE__ [4u] == ' ' ? 0u : __DATE__ [4u] - '0') * 10u \
+ (__DATE__ [5u] - '0') )
// __TIME__ expands to an eight-character string constant
// "23:59:01", or (if cannot determine time) "??:??:??"
#define __HOUR_INT__ ( \
(__TIME__ [0u] == '?' ? 0u : __TIME__ [0u] - '0') * 10u \
+ (__TIME__ [1u] == '?' ? 0u : __TIME__ [1u] - '0') )
#define __MINUTE_INT__ ( \
(__TIME__ [3u] == '?' ? 0u : __TIME__ [3u] - '0') * 10u \
+ (__TIME__ [4u] == '?' ? 0u : __TIME__ [4u] - '0') )
#define __SECONDS_INT__ ( \
(__TIME__ [6u] == '?' ? 0u : __TIME__ [6u] - '0') * 10u \
+ (__TIME__ [7u] == '?' ? 0u : __TIME__ [7u] - '0') )
#define __DOSDATE__ ( \
((__YEAR_INT__ - 1980u) << 9u) | \
( __MONTH_INT__ << 5u) | \
( __DAY_INT__ << 0u) )
#define __DOSTIME__ ( \
( __HOUR_INT__ << 11u) | \
( __MONTH_INT__ << 5u) | \
( __DAY_INT__ << 0u) )
#endif // COMPILE_DATE_H
-13
View File
@@ -63,22 +63,9 @@ extern uint16_t usb_desc_str_serial[1+16];
* We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled. */
extern void tusb_hal_nrf_power_event(uint32_t event);
//------------- IMPLEMENTATION -------------//
static bool _inited = false;
bool usb_inited(void)
{
return _inited;
}
void usb_init(bool cdc_only)
{
// skipped if already inited
if ( _inited ) return;
_inited = true;
NVIC_SetPriority(USBD_IRQn, 2);
// USB power may already be ready at this time -> no event generated
+12 -10
View File
@@ -59,19 +59,21 @@ enum {
};
/*------------- Endpoint Numbering & Size -------------*/
#define _EP_IN(x) (0x80 | (x))
#define _EP_OUT(x) (x)
#define _EP_IN(x) (0x80 | (x))
#define _EP_OUT(x) (x)
// CDC
#define EP_CDC_NOTIF _EP_IN ( ITF_NUM_CDC+1 )
#define EP_CDC_NOTIF_SIZE 8
#define EP_CDC_NOTIF _EP_IN ( ITF_NUM_CDC+1 )
#define EP_CDC_NOTIF_SIZE 8
#define EP_CDC_OUT _EP_OUT( ITF_NUM_CDC+2 )
#define EP_CDC_IN _EP_IN ( ITF_NUM_CDC+2 )
#define EP_CDC_OUT _EP_OUT( ITF_NUM_CDC+2 )
#define EP_CDC_IN _EP_IN ( ITF_NUM_CDC+2 )
// Mass Storage
#define EP_MSC_OUT _EP_OUT( ITF_NUM_MSC+1 )
#define EP_MSC_IN _EP_IN ( ITF_NUM_MSC+1 )
#define EP_MSC_OUT _EP_OUT( ITF_NUM_MSC+1 )
#define EP_MSC_IN _EP_IN ( ITF_NUM_MSC+1 )
#define EP_MSC_SIZE 64
//--------------------------------------------------------------------+
// STRING DESCRIPTORS
@@ -280,7 +282,7 @@ usb_desc_cfg_t usb_desc_cfg =
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = EP_MSC_OUT,
.bmAttributes = { .xfer = TUSB_XFER_BULK },
.wMaxPacketSize = { .size = CFG_TUD_MSC_EPSIZE},
.wMaxPacketSize = { .size = EP_MSC_SIZE},
.bInterval = 1
},
@@ -290,7 +292,7 @@ usb_desc_cfg_t usb_desc_cfg =
.bDescriptorType = TUSB_DESC_ENDPOINT,
.bEndpointAddress = EP_MSC_IN,
.bmAttributes = { .xfer = TUSB_XFER_BULK },
.wMaxPacketSize = { .size = CFG_TUD_MSC_EPSIZE},
.wMaxPacketSize = { .size = EP_MSC_SIZE },
.bInterval = 1
}
}