mirror of
https://github.com/oltaco/Adafruit_nRF52_Bootloader_OTAFIX.git
synced 2026-10-24 10:43:28 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5b654eb5e | ||
|
|
60debfc217 | ||
|
|
2713069643 | ||
|
|
8df909f0a8 | ||
|
|
1d816c5cf3 | ||
|
|
66d1770407 | ||
|
|
8ab4774c93 | ||
|
|
1b54f0457d | ||
|
|
a004b7619e | ||
|
|
04fc396fd8 | ||
|
|
04e0df1c18 | ||
|
|
6d58633db0 | ||
|
|
15ca75d10d | ||
|
|
174e6e9724 | ||
|
|
53a99195bf | ||
|
|
8def8aee53 | ||
|
|
c51a227fd9 | ||
|
|
f3e3cefb23 | ||
|
|
73456ac80e | ||
|
|
113195eabd | ||
|
|
0eeff3e679 | ||
|
|
be5a925f72 | ||
|
|
ae28f5b425 | ||
|
|
b8a0551678 | ||
|
|
0f216b8618 | ||
|
|
52cfdaa2d2 | ||
|
|
a258c6d988 | ||
|
|
e0251415e7 | ||
|
|
12bb62eadd | ||
|
|
e2afc36dae | ||
|
|
4ea74d4600 | ||
|
|
9bc01fb061 | ||
|
|
01492634b6 | ||
|
|
05726e2575 | ||
|
|
14f87f61e6 | ||
|
|
7df44a5425 | ||
|
|
0cc0289c60 | ||
|
|
992229cf2f | ||
|
|
57aa554430 | ||
|
|
9ed3f5ea32 |
No files matched your search
@@ -54,3 +54,5 @@ dkms.conf
|
||||
src/segger/Output
|
||||
_build-*/
|
||||
bin/
|
||||
*.emSession
|
||||
*.jlink
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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):
|
||||
|
||||
```
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
Submodule lib/tinyusb updated: a1c596490a...55874813f8.
@@ -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
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user