Merge commit 'e067fcbe30' as 'stm32f103c8t6-bootloader'
This commit is contained in:
commit
3ca6ea3e9e
34 changed files with 15445 additions and 0 deletions
3
stm32f103c8t6-bootloader/.gitignore
vendored
Normal file
3
stm32f103c8t6-bootloader/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
build/*
|
||||
src/.local.vimrc
|
||||
.vscode
|
||||
16
stm32f103c8t6-bootloader/LICENCE_ISC.md
Normal file
16
stm32f103c8t6-bootloader/LICENCE_ISC.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# ISC licence
|
||||
|
||||
Copyright (c) 2019, fruchti<fruchti@gvfr.de>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||
SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
11
stm32f103c8t6-bootloader/README.md
Normal file
11
stm32f103c8t6-bootloader/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# punt
|
||||
|
||||
*punt* is a small USB bootloader for STM32 microcontrollers, designed to fit into 2 KiB flash. Currently, only STM32F103x8 devices are supported. A Rust library for communicating with the bootloader can be found [here](https://github.com/fruchti/punt-rs).
|
||||
|
||||
## Aim
|
||||
|
||||
Consider this project, at this point, as very experimental. Apart from that, *punt* is not meant to be a secure bootloader in any case. There is no encryption nor signing planned so it can be as small as possible. Without any safety and security features like these, full access to the microcontroller via its bootloader is always possible and reliable operation with unknown input cannot be guaranteed anyway.
|
||||
|
||||
## Licence
|
||||
|
||||
The header files in the third_party directory are provided by ARM Limited and ST Microelectronics and contain their own licence information. Everything else is ISC licenced.
|
||||
1
stm32f103c8t6-bootloader/build_number.txt
Normal file
1
stm32f103c8t6-bootloader/build_number.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
434
|
||||
9
stm32f103c8t6-bootloader/compile_flags.txt
Normal file
9
stm32f103c8t6-bootloader/compile_flags.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
--std=c99
|
||||
-Isrc
|
||||
-Ithird_party/core
|
||||
-Ithird_party/device
|
||||
-DSTM32F103x6
|
||||
-D_DEFAULT_SOURCE
|
||||
-Wall
|
||||
-Wextra
|
||||
--target=arm-none-eabi
|
||||
50
stm32f103c8t6-bootloader/ld/common.ld
Normal file
50
stm32f103c8t6-bootloader/ld/common.ld
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Unified Cortex Startup - GNU ld linker script file
|
||||
*
|
||||
* This file is in public domain
|
||||
*
|
||||
* Put together by Paul Sokolovsky based on article by Vanya Sergeev
|
||||
* http://dev.frozeneskimo.com/notes/cortex_cmsis/ , GNU ld documentation
|
||||
* and numerous other public resources.
|
||||
*
|
||||
*/
|
||||
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
SECTIONS {
|
||||
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.vectors))
|
||||
KEEP(*(.cortex_vectors))
|
||||
KEEP(*(.vendor_vectors))
|
||||
*(.text*)
|
||||
*(.rodata*)
|
||||
_end_text = .;
|
||||
} >flash
|
||||
|
||||
_start_init_data = LOADADDR(.data);
|
||||
|
||||
.data :
|
||||
{
|
||||
_start_data = .;
|
||||
*(.data*)
|
||||
_end_data = .;
|
||||
} >sram AT >flash
|
||||
|
||||
.bss :
|
||||
{
|
||||
_start_bss = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
_end_bss = .;
|
||||
} >sram
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
_start_stack = .;
|
||||
|
||||
PROVIDE(_end_stack = ORIGIN(sram) + LENGTH(sram));
|
||||
}
|
||||
|
||||
_end = .;
|
||||
7
stm32f103c8t6-bootloader/ld/stm32f103c8t6_flash.ld
Normal file
7
stm32f103c8t6-bootloader/ld/stm32f103c8t6_flash.ld
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
MEMORY
|
||||
{
|
||||
flash (rx) : ORIGIN = 0x08000000, LENGTH = 64K
|
||||
sram (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
|
||||
}
|
||||
|
||||
INCLUDE ld/common.ld
|
||||
129
stm32f103c8t6-bootloader/makefile
Normal file
129
stm32f103c8t6-bootloader/makefile
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
PROJECT = punt
|
||||
SOURCE_DIRS = src
|
||||
ADDITIONAL_SOURCES =
|
||||
INCLUDE_DIRS = third_party/core third_party/device
|
||||
EXCLUDE_SOURCES =
|
||||
BUILD_DIR = build
|
||||
|
||||
DEBUG := yes
|
||||
|
||||
H_DEVICE = STM32F030x6
|
||||
STARTUP_SOURCE_DIR = src
|
||||
STARTUP_SOURCES = $(STARTUP_SOURCE_DIR)/startup.S
|
||||
LD_SCRIPT = ld/stm32f103c8t6_flash.ld
|
||||
|
||||
ifeq ($(DEBUG),yes)
|
||||
DEBUG_FLAGS = -DDEBUG -g3
|
||||
endif
|
||||
|
||||
ifneq ($(V),1)
|
||||
Q = @
|
||||
endif
|
||||
|
||||
CFLAGS = -mcpu=cortex-m3 -mthumb \
|
||||
-Os -fno-common \
|
||||
-Wall -Wextra -Werror \
|
||||
-nostartfiles -nodefaultlibs -nostdlib \
|
||||
-Xlinker --gc-sections \
|
||||
-D$(H_DEVICE) -D_DEFAULT_SOURCE -T$(LD_SCRIPT) \
|
||||
-Wl,-Map=$(BUILD_DIR)/$(PROJECT).map -std=c99 \
|
||||
$(addprefix -I,$(SOURCE_DIRS) $(INCLUDE_DIRS)) $(DEBUG_FLAGS)
|
||||
|
||||
RM = rm -f
|
||||
CC = arm-none-eabi-gcc
|
||||
OBJCOPY = arm-none-eabi-objcopy
|
||||
SIZE = arm-none-eabi-size
|
||||
OBJDUMP = arm-none-eabi-objdump
|
||||
|
||||
BUILD_NUMBER_FILE = build_number.txt
|
||||
BUILD_ID_FLAGS = -Xlinker --defsym -Xlinker __BUILD_DATE=$$(date +'%Y%m%d') \
|
||||
-Xlinker --defsym -Xlinker __BUILD_NUMBER=$$(cat $(BUILD_NUMBER_FILE))
|
||||
|
||||
CURRENT_BUILD_CONFIG := $(shell cat makefile | md5sum) DEBUG = $(DEBUG)
|
||||
LAST_BUILD_CONFIG := $(shell if [ -e $(BUILD_DIR)/build_config.txt ] ; then cat $(BUILD_DIR)/build_config.txt ; fi)
|
||||
|
||||
SOURCES = $(filter-out $(addprefix %/,$(EXCLUDE_SOURCES)),$(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))) \
|
||||
$(ADDITIONAL_SOURCES)
|
||||
OBJECTS = $(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(basename $(notdir $(SOURCES)))))
|
||||
DEPENDS = $(addprefix $(BUILD_DIR)/,$(addsuffix .d,$(basename $(notdir $(SOURCES)))))
|
||||
STARTUP_OBJECTS = $(patsubst $(STARTUP_SOURCE_DIR)/%.S, $(BUILD_DIR)/%.o, $(STARTUP_SOURCES))
|
||||
|
||||
.DEFAULT_GOAL = all
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
define define_compile_rules
|
||||
$(addprefix $(BUILD_DIR)/,$(addsuffix .o,$(basename $(filter-out $(EXCLUDE_SOURCES),$(notdir $(wildcard $(1)/*.c)))))): $(BUILD_DIR)/%.o: $(1)/%.c
|
||||
@echo " CC $$@"
|
||||
$(Q)$$(CC) $$(CFLAGS) -o $$@ -c $$<
|
||||
|
||||
$(addprefix $(BUILD_DIR)/,$(addsuffix .d,$(basename $(filter-out $(EXCLUDE_SOURCES),$(notdir $(wildcard $(1)/*.c)))))): $(BUILD_DIR)/%.d: $(1)/%.c
|
||||
@#echo " DP $$@"
|
||||
$(Q)set -e; rm -f $$@; $$(CC) -MM $$(CFLAGS) $$< > $$@.$$$$$$$$; sed 's,\($$*\)\.o[ :]*,build\/\1.o $$@ : ,g' < $$@.$$$$$$$$ > $$@; rm -f $$@.$$$$$$$$
|
||||
endef
|
||||
|
||||
$(foreach directory,$(SOURCE_DIRS),$(eval $(call define_compile_rules,$(directory))))
|
||||
|
||||
# Additional sources
|
||||
define define_compile_rule
|
||||
$(addprefix $(BUILD_DIR)/,$(notdir $(1:.c=.o))): $(1)
|
||||
@echo " CC $$@"
|
||||
$(Q)$$(CC) $$(CFLAGS) -o $$@ -c $$<
|
||||
|
||||
$(addprefix $(BUILD_DIR)/,$(notdir $(1:.c=.d))): $(1)
|
||||
@#echo " DP $$@"
|
||||
$(Q)set -e; rm -f $$@; $$(CC) -MM $$(CFLAGS) $$< > $$@.$$$$$$$$; sed 's,\($$*\)\.o[ :]*,build\/\1.o $$@ : ,g' < $$@.$$$$$$$$ > $$@; rm -f $$@.$$$$$$$$
|
||||
endef
|
||||
|
||||
$(foreach src,$(ADDITIONAL_SOURCES),$(eval $(call define_compile_rule,$(src))))
|
||||
|
||||
$(STARTUP_OBJECTS): $(BUILD_DIR)/%.o: $(STARTUP_SOURCE_DIR)/%.S
|
||||
@echo " AS $@"
|
||||
$(Q)$(CC) $< -c -o $@ $(CFLAGS)
|
||||
|
||||
$(DEPENDS):| $(BUILD_DIR)
|
||||
|
||||
include $(DEPENDS)
|
||||
|
||||
$(BUILD_DIR)/$(PROJECT).elf: $(OBJECTS) $(STARTUP_OBJECTS) $(BUILD_NUMBER_FILE)
|
||||
@echo " LD $@"
|
||||
$(Q)$(CC) $(OBJECTS) $(STARTUP_OBJECTS) $(CFLAGS) $(BUILD_ID_FLAGS) -o $@
|
||||
|
||||
$(BUILD_DIR)/$(PROJECT).bin: $(BUILD_DIR)/$(PROJECT).elf
|
||||
@echo " OC $@"
|
||||
$(Q)$(OBJCOPY) -O binary -S $< $@
|
||||
|
||||
$(BUILD_DIR)/$(PROJECT).lst: $(BUILD_DIR)/$(PROJECT).elf
|
||||
@echo " OD $@"
|
||||
$(Q)$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
$(BUILD_DIR):
|
||||
$(Q)if [ ! -d "$(BUILD_DIR)" ]; then mkdir "$(BUILD_DIR)"; fi
|
||||
|
||||
$(BUILD_NUMBER_FILE): $(OBJECTS) $(STARTUP_OBJECTS)
|
||||
$(Q)if ! test -f $(BUILD_NUMBER_FILE); then echo 0 > $(BUILD_NUMBER_FILE); \
|
||||
else echo $$(($$(cat $(BUILD_NUMBER_FILE)) + 1)) > $(BUILD_NUMBER_FILE) ; fi
|
||||
|
||||
# Rebuild everything in case of a makefile/configuration change
|
||||
.PHONY: all
|
||||
ifneq ("$(CURRENT_BUILD_CONFIG)","$(LAST_BUILD_CONFIG)")
|
||||
all: clean incrementalbuild
|
||||
else
|
||||
all: incrementalbuild
|
||||
endif
|
||||
|
||||
.PHONY: incrementalbuild
|
||||
incrementalbuild: $(BUILD_DIR) $(OBJECTS) $(STARTUP_OBJECTS) $(BUILD_DIR)/$(PROJECT).elf $(BUILD_DIR)/$(PROJECT).bin $(BUILD_DIR)/$(PROJECT).lst
|
||||
@echo "Finished build $$(cat $(BUILD_NUMBER_FILE)). Binary size:"
|
||||
@echo " SZ $(BUILD_DIR)/$(PROJECT).elf"
|
||||
$(Q)$(SIZE) $(BUILD_DIR)/$(PROJECT).elf
|
||||
@echo "$(CURRENT_BUILD_CONFIG)" > $(BUILD_DIR)/build_config.txt
|
||||
|
||||
.PHONY: program
|
||||
program: $(BUILD_DIR)/$(PROJECT).bin
|
||||
@#if ps -e | grep openocd ; then arm-none-eabi-gdb -batch -x flash.gdb ; else st-flash --reset write $(BUILD_DIR)/$(PROJECT).bin 0x8000000 ; fi
|
||||
st-flash --reset write $(BUILD_DIR)/$(PROJECT).bin 0x8000000
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo " RM $(BUILD_DIR)/*"
|
||||
$(Q)$(RM) $(BUILD_DIR)/*
|
||||
13
stm32f103c8t6-bootloader/src/buildinfo.h
Normal file
13
stm32f103c8t6-bootloader/src/buildinfo.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define BUILD_VERSION_MAJOR 0
|
||||
#define BUILD_VERSION_MINOR 2
|
||||
#define BUILD_VERSION_PATCH 0
|
||||
|
||||
#define BUILD_DATE ((uint32_t)&__BUILD_DATE)
|
||||
#define BUILD_NUMBER ((uint32_t)&__BUILD_NUMBER)
|
||||
|
||||
extern char __BUILD_DATE;
|
||||
extern char __BUILD_NUMBER;
|
||||
59
stm32f103c8t6-bootloader/src/commands.h
Normal file
59
stm32f103c8t6-bootloader/src/commands.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
#pragma once
|
||||
|
||||
// Legend:
|
||||
// -> is a transmission via endpoint 2 (out) from the host to the MCU
|
||||
// <- is a transmission via endpoint 1 (in) from the MCU to the host
|
||||
|
||||
typedef enum
|
||||
{
|
||||
// Does nothing
|
||||
CMD_NOP = 0x00,
|
||||
|
||||
// Basic bootloader info. Returns 19 to 64 bytes (cf. BootloaderInfo_t):
|
||||
// <- Build date: u32 (YYYYMMDD as an unsigned integer)
|
||||
// <- Build number: u32
|
||||
// <- Flash application base address: u32
|
||||
// <- Maximum application size: u32
|
||||
// <- Major version: u8
|
||||
// <- Minor version: u8
|
||||
// <- Patch version: u8
|
||||
// <- Identifier string (variable length, not zero-terminated)
|
||||
CMD_BOOTLOADER_INFO = 0x01,
|
||||
|
||||
// Calculate a CRC32 of a memory region:
|
||||
// -> Start address: u32
|
||||
// -> Length: u32
|
||||
// <- CRC32: u32
|
||||
CMD_READ_CRC = 0x02,
|
||||
|
||||
// Read memory contents
|
||||
// -> Start address: u32
|
||||
// -> Length n: u32
|
||||
// <- Data: n bytes
|
||||
CMD_READ_MEMORY = 0x03,
|
||||
|
||||
// Erase a single 1 KiB flash page
|
||||
// -> Page number: u8
|
||||
// <- Return code (0 for success): u8
|
||||
CMD_ERASE_PAGE = 0x04,
|
||||
|
||||
// Program flash
|
||||
// -> Start adress: u32
|
||||
// -> Data: n bytes (n must be even)
|
||||
CMD_PROGRAM = 0x05,
|
||||
|
||||
// Exit bootloader and start application software
|
||||
CMD_EXIT = 0xff
|
||||
} Command_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t build_date;
|
||||
uint32_t build_number;
|
||||
uint32_t flash_application_start;
|
||||
uint32_t flash_application_size;
|
||||
uint8_t version_major;
|
||||
uint8_t version_minor;
|
||||
uint8_t version_patch;
|
||||
char identifier[];
|
||||
} __attribute__((packed, aligned(1))) BootloaderInfo_t;
|
||||
66
stm32f103c8t6-bootloader/src/flash.c
Normal file
66
stm32f103c8t6-bootloader/src/flash.c
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#include "flash.h"
|
||||
#include "usb.h"
|
||||
|
||||
#include "ownership.h"
|
||||
MODULE_OWNS_PERIPHERAL(FLASH);
|
||||
|
||||
static inline void Flash_Unlock(void)
|
||||
{
|
||||
FLASH->KEYR = FLASH_KEY1;
|
||||
FLASH->KEYR = FLASH_KEY2;
|
||||
}
|
||||
|
||||
static inline void Flash_Lock(void)
|
||||
{
|
||||
FLASH->CR = FLASH_CR_LOCK;
|
||||
}
|
||||
|
||||
Flash_Status_t Flash_ErasePage(unsigned int page)
|
||||
{
|
||||
if(page >= FLASH_PAGES)
|
||||
{
|
||||
return FLASH_PROHIBITED;
|
||||
}
|
||||
uint32_t page_start = FLASH_BASE + page * FLASH_PAGE_BYTES;
|
||||
|
||||
Flash_Unlock();
|
||||
|
||||
while(FLASH->SR & FLASH_SR_BSY);
|
||||
FLASH->CR = FLASH_CR_PER;
|
||||
FLASH->AR = page_start;
|
||||
FLASH->CR = FLASH_CR_STRT | FLASH_CR_PER;
|
||||
while(FLASH->SR & FLASH_SR_BSY);
|
||||
|
||||
// Flash_Lock() clears the PER bit, so we don't have to reset that
|
||||
Flash_Lock();
|
||||
|
||||
// Verify
|
||||
for(uint32_t i = page_start; i < page_start + FLASH_PAGE_BYTES; i += 4)
|
||||
{
|
||||
if(*(uint32_t*)i != 0xffffffff)
|
||||
{
|
||||
return FLASH_VERIFY_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return FLASH_SUCCESS;
|
||||
}
|
||||
|
||||
void Flash_ProgramFromPMA(uint32_t flash_adress, uint16_t pma_offset,
|
||||
uint32_t length)
|
||||
{
|
||||
Flash_Unlock();
|
||||
|
||||
uint16_t *pma = (uint16_t*)(USB_PMA_ADDR + 2 * pma_offset);
|
||||
volatile uint16_t *flash = (uint16_t*)flash_adress;
|
||||
FLASH->CR = FLASH_CR_PG;
|
||||
for(unsigned int i = 0; i < (length + 1) / 2; i++)
|
||||
{
|
||||
*flash++ = *pma++;
|
||||
pma++;
|
||||
while(FLASH->SR & FLASH_SR_BSY);
|
||||
}
|
||||
|
||||
// Flash_Lock() clears the PG bit, so we don't have to reset that
|
||||
Flash_Lock();
|
||||
}
|
||||
22
stm32f103c8t6-bootloader/src/flash.h
Normal file
22
stm32f103c8t6-bootloader/src/flash.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "stm32f103x6.h"
|
||||
|
||||
#define FLASH_PAGE_BYTES 1024U
|
||||
#define FLASH_BOOTLOADER_PAGES 2U
|
||||
#define FLASH_PAGES 64U
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FLASH_SUCCESS = 0,
|
||||
FLASH_PROHIBITED = 1,
|
||||
FLASH_VERIFY_FAILED = 2
|
||||
} Flash_Status_t;
|
||||
|
||||
#define FLASH_APPLICATION_BASE (FLASH_BASE \
|
||||
+ FLASH_BOOTLOADER_PAGES * FLASH_PAGE_BYTES)
|
||||
|
||||
|
||||
Flash_Status_t Flash_ErasePage(unsigned int page);
|
||||
void Flash_ProgramFromPMA(uint32_t flash_adress, uint16_t pma_offset,
|
||||
uint32_t length);
|
||||
119
stm32f103c8t6-bootloader/src/main.c
Normal file
119
stm32f103c8t6-bootloader/src/main.c
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#include "main.h"
|
||||
|
||||
// Configure clocks based on a 8 MHz external crystal for:
|
||||
// SYSCLK, AHB, APB2 72 Mhz
|
||||
// APB1, ADC 36 MHz
|
||||
static inline void Clock_Init(void)
|
||||
{
|
||||
// Activate HSE and wait for it to be ready
|
||||
RCC->CR = RCC_CR_HSEON | RCC_CR_HSION;
|
||||
while(!(RCC->CR & RCC_CR_HSERDY));
|
||||
|
||||
RCC->CFGR = RCC_CFGR_SW_0;
|
||||
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_0);
|
||||
|
||||
FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY_1;
|
||||
|
||||
// Set PLL to x9 (-> 72MHz system clock)
|
||||
RCC->CFGR = RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC | RCC_CFGR_PPRE1_2
|
||||
| RCC_CFGR_SW_0;
|
||||
|
||||
// Activate PLL and wait
|
||||
RCC->CR = RCC_CR_PLLON | RCC_CR_HSEON | RCC_CR_HSION;
|
||||
while(!(RCC->CR & RCC_CR_PLLRDY));
|
||||
|
||||
// Select PLL as clock source
|
||||
RCC->CFGR = RCC_CFGR_PLLMULL9 | RCC_CFGR_PLLSRC | RCC_CFGR_PPRE1_2
|
||||
| RCC_CFGR_SW_1;
|
||||
|
||||
// Disable all interrupts
|
||||
RCC->CIR = 0x00000000;
|
||||
|
||||
// Enable peripheral clocks
|
||||
RCC->APB2ENR = RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
|
||||
RCC->APB1ENR = RCC_APB1ENR_PWREN | RCC_APB1ENR_BKPEN | RCC_APB1ENR_USBEN;
|
||||
RCC->AHBENR = RCC_AHBENR_CRCEN;
|
||||
}
|
||||
|
||||
static inline bool Bootloader_EntryCondition(void)
|
||||
{
|
||||
// Activate pull-up for test point
|
||||
GPIOA->CRH = (0x44444444
|
||||
& ~(0x0f << (PIN_TEST_POINT * 4 - 32)))
|
||||
| (0x08<< (PIN_TEST_POINT * 4 - 32))
|
||||
;
|
||||
GPIOA->BSRR = (1 << PIN_TEST_POINT);
|
||||
|
||||
// The first word in the application frame is the stack end pointer
|
||||
const uint32_t *application_start = (uint32_t*)FLASH_APPLICATION_BASE;
|
||||
// If it is not a valid RAM address, we can assume there's no application
|
||||
// present in flash and thus enter the bootloader
|
||||
if((*application_start & 0xffff8000) != 0x20000000)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check RTC backup register 1 for magic value
|
||||
PWR->CR = PWR_CR_DBP;
|
||||
if(BKP->DR1 == 0xb007)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if test point is held low externally
|
||||
if(~GPIOA->IDR & (1 << PIN_TEST_POINT))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void Bootloader_Exit(void)
|
||||
{
|
||||
// Reset RTC backup register
|
||||
BKP->DR1 = 0x0000;
|
||||
|
||||
// Reset peripherals
|
||||
RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
|
||||
RCC->APB2RSTR = RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_AFIORST;
|
||||
RCC->APB1RSTR = 0x00000000;
|
||||
RCC->APB2RSTR = 0x00000000;
|
||||
|
||||
// Reset peripheral clock enable registers to their reset values
|
||||
RCC->AHBENR = 0x00000014; // Disable CRC
|
||||
RCC->APB2ENR = 0x00000000; // Disable GPIOA, GPIOB, AFIO
|
||||
RCC->APB1ENR = 0x00000000; // Disable USB, PWR, BKP
|
||||
|
||||
// Set vector table location
|
||||
SCB->VTOR = FLASH_APPLICATION_BASE - FLASH_BASE;
|
||||
|
||||
// Set stack pointer and jump into application
|
||||
uint32_t application_stack_pointer = *(uint32_t*)FLASH_APPLICATION_BASE;
|
||||
uint32_t application_reset_handler = *(uint32_t*)(FLASH_APPLICATION_BASE
|
||||
+ 4);
|
||||
__asm__ volatile(".syntax unified \n"
|
||||
"msr msp, %[stack_pointer] \n"
|
||||
"bx %[reset_handler] \n"
|
||||
:
|
||||
: [stack_pointer] "r" (application_stack_pointer),
|
||||
[reset_handler] "r" (application_reset_handler));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Clock_Init();
|
||||
|
||||
if(Bootloader_EntryCondition())
|
||||
{
|
||||
USB_Init();
|
||||
|
||||
while(USB_Poll());
|
||||
|
||||
// Delay to allow answer token to be fetched by host
|
||||
Util_Delay(100000);
|
||||
}
|
||||
|
||||
Bootloader_Exit();
|
||||
}
|
||||
|
||||
10
stm32f103c8t6-bootloader/src/main.h
Normal file
10
stm32f103c8t6-bootloader/src/main.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "stm32f103x6.h"
|
||||
#include "pinning.h"
|
||||
#include "usb.h"
|
||||
#include "flash.h"
|
||||
#include "util.h"
|
||||
|
||||
int main(void);
|
||||
12
stm32f103c8t6-bootloader/src/ownership.h
Normal file
12
stm32f103c8t6-bootloader/src/ownership.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#define _PASTE(x, y) x ## y
|
||||
#define PASTE(x, y) _PASTE(x, y)
|
||||
|
||||
#define MODULE_OWNS_PERIPHERAL(peripheral) \
|
||||
void *_PERIPHERAL_OWNERSHIP_ ## peripheral \
|
||||
= (void*)(peripheral)
|
||||
|
||||
#define MODULE_OWNS_PIN(gpio, pin) \
|
||||
void *PASTE(_PIN_OWNERSHIP_ ## gpio ## _, pin) \
|
||||
= (void*)(gpio + pin)
|
||||
16
stm32f103c8t6-bootloader/src/pinning.h
Normal file
16
stm32f103c8t6-bootloader/src/pinning.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
// Port A
|
||||
#define PIN_LIGHT_SENSOR 1 // PA1
|
||||
#define PIN_TEST_POINT 8 // PA8
|
||||
#define PIN_UART_TX 9 // PA9 - USART1_TX
|
||||
#define PIN_UART_RX 10 // PA10 - USART1_RX
|
||||
#define PIN_USB_DM 11 // PA11 - USB_DM
|
||||
#define PIN_USB_DP 12 // PA12 - USB_DP
|
||||
#define PIN_USB_PULLUP 15 // PA15 - 1.5 kΩ to D+
|
||||
|
||||
// Port B
|
||||
#define PIN_LED 0 // PB0 - Status LED
|
||||
#define PIN_SELECT 4 // PB4 - Bus select line
|
||||
#define PIN_SCL 6 // PB6 - I2C1_SCL
|
||||
#define PIN_SDA 7 // PB7 - I2C1_SDA
|
||||
88
stm32f103c8t6-bootloader/src/startup.S
Normal file
88
stm32f103c8t6-bootloader/src/startup.S
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
.syntax unified
|
||||
.thumb
|
||||
.fpu softvfp
|
||||
|
||||
.global Reset_Handler
|
||||
.type Reset_Handler, %function
|
||||
Reset_Handler:
|
||||
init_data:
|
||||
ldr r2, =_start_init_data
|
||||
ldr r3, =_start_data
|
||||
ldr r1, =_end_data
|
||||
|
||||
init_data_loop:
|
||||
cmp r3, r1
|
||||
bhs zero_bss
|
||||
ldr r0, [r2], #4
|
||||
str r0, [r3], #4
|
||||
b init_data_loop
|
||||
|
||||
zero_bss:
|
||||
ldr r3, =_start_bss
|
||||
ldr r1, =_end_bss
|
||||
movs r0, #0
|
||||
|
||||
zero_bss_loop:
|
||||
cmp r3, r1
|
||||
bhs init_finished
|
||||
str r0, [r3], #4
|
||||
b zero_bss_loop
|
||||
|
||||
init_finished:
|
||||
bl main
|
||||
|
||||
infinite_loop:
|
||||
b infinite_loop
|
||||
|
||||
.size Reset_Handler, .-Reset_Handler
|
||||
|
||||
// Only the core interrupt vectors, since the bootloader code does not use
|
||||
// interrupts. Saves a few bytes to omit the interrupt vector table.
|
||||
.section .cortex_vectors, "a"
|
||||
.word _end_stack
|
||||
.word Reset_Handler
|
||||
.word NMI_Handler
|
||||
.word HardFault_Handler
|
||||
.word MemManage_Handler
|
||||
.word BusFault_Handler
|
||||
.word UsageFault_Handler
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word 0x00000000
|
||||
.word SVC_Handler
|
||||
.word DebugMon_Handler
|
||||
.word 0x00000000
|
||||
.word PendSV_Handler
|
||||
.word SysTick_Handler
|
||||
|
||||
.type Dummy_Handler, %function
|
||||
Dummy_Handler:
|
||||
b Dummy_Handler
|
||||
|
||||
.weak NMI_Handler
|
||||
.thumb_set NMI_Handler, Dummy_Handler
|
||||
|
||||
.weak HardFault_Handler
|
||||
.thumb_set HardFault_Handler, Dummy_Handler
|
||||
|
||||
.weak MemManage_Handler
|
||||
.thumb_set MemManage_Handler, Dummy_Handler
|
||||
|
||||
.weak BusFault_Handler
|
||||
.thumb_set BusFault_Handler, Dummy_Handler
|
||||
|
||||
.weak UsageFault_Handler
|
||||
.thumb_set UsageFault_Handler, Dummy_Handler
|
||||
|
||||
.weak SVC_Handler
|
||||
.thumb_set SVC_Handler, Dummy_Handler
|
||||
|
||||
.weak DebugMon_Handler
|
||||
.thumb_set DebugMon_Handler, Dummy_Handler
|
||||
|
||||
.weak PendSV_Handler
|
||||
.thumb_set PendSV_Handler, Dummy_Handler
|
||||
|
||||
.weak SysTick_Handler
|
||||
.thumb_set SysTick_Handler, Dummy_Handler
|
||||
264
stm32f103c8t6-bootloader/src/usb.c
Normal file
264
stm32f103c8t6-bootloader/src/usb.c
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
#include "usb.h"
|
||||
#include "usb_descriptors.h"
|
||||
#include "usb_util.h"
|
||||
#include "usb_com.h"
|
||||
#include "util.h"
|
||||
|
||||
#include "ownership.h"
|
||||
MODULE_OWNS_PERIPHERAL(USB);
|
||||
MODULE_OWNS_PIN(GPIOA, PIN_USB_PULLUP);
|
||||
MODULE_OWNS_PIN(GPIOA, PIN_USB_DM);
|
||||
MODULE_OWNS_PIN(GPIOA, PIN_USB_DP);
|
||||
|
||||
uint8_t USB_DeviceStatus[2] = {0x00, 0x00};
|
||||
volatile unsigned int USB_Address = 0;
|
||||
|
||||
void USB_Init(void)
|
||||
{
|
||||
// Free PA15 (pullup for D+) for use as GPIO
|
||||
AFIO->MAPR = AFIO_MAPR_SWJ_CFG_JTAGDISABLE;
|
||||
|
||||
// Initialise USB GPIOs to AF mode, set pullup high
|
||||
// Note: This will reset the test point pin to an input without pullup
|
||||
GPIOA->ODR = 1 << PIN_USB_PULLUP;
|
||||
GPIOA->CRH = (0x44444444
|
||||
& ~(0x0f << (PIN_USB_DM * 4 - 32))
|
||||
& ~(0x0f << (PIN_USB_DP * 4 - 32))
|
||||
& ~(0x0f << (PIN_USB_PULLUP * 4 - 32)))
|
||||
| (0x0b << (PIN_USB_DM * 4 - 32)) // AF mode, 50 MHz
|
||||
| (0x0b << (PIN_USB_DP * 4 - 32)) // AF mode, 50 MHz
|
||||
| (0x01 << (PIN_USB_PULLUP * 4 - 32)) // Push-pull output, 10 MHz
|
||||
;
|
||||
|
||||
Util_Delay(100000);
|
||||
|
||||
// Analog power up
|
||||
USB->CNTR = (uint16_t)USB_CNTR_FRES;
|
||||
// Minimum delay: 1 µs
|
||||
Util_Delay(3000);
|
||||
|
||||
USB->CNTR = (uint16_t)0;
|
||||
USB->ISTR = (uint16_t)0;
|
||||
USB->CNTR = (uint16_t)(USB_CNTR_RESETM | USB_CNTR_CTRM);
|
||||
}
|
||||
|
||||
static inline void USB_HandleReset(void)
|
||||
{
|
||||
// Remove reset flag
|
||||
USB->ISTR = (uint16_t)~(USB_ISTR_RESET);
|
||||
|
||||
// Set buffer table origin
|
||||
USB->BTABLE = USB_BTABLE_OFFSET;
|
||||
|
||||
// Control endpoint 0 (64 bytes size)
|
||||
USB_BTABLE_ENTRIES[0].COUNT_RX = USB_EP_RXCOUNT_BL_SIZE | (1 << 10);
|
||||
USB_BTABLE_ENTRIES[0].ADDR_RX = 0x40;
|
||||
USB_BTABLE_ENTRIES[0].COUNT_TX = 0;
|
||||
USB_BTABLE_ENTRIES[0].ADDR_TX = 0x80;
|
||||
|
||||
USB_SetEPR(&(USB->EP0R), USB_EPR_EP_TYPE_CONTROL
|
||||
| USB_EPR_STAT_TX_NAK | USB_EPR_STAT_RX_VALID);
|
||||
|
||||
// Endpoint 1: In (buffer size 64)
|
||||
USB_BTABLE_ENTRIES[1].COUNT_TX = 0;
|
||||
USB_BTABLE_ENTRIES[1].ADDR_TX = 0xc0;
|
||||
USB_BTABLE_ENTRIES[1].COUNT_RX = 0;
|
||||
USB_BTABLE_ENTRIES[1].ADDR_RX = 0;
|
||||
|
||||
USB_SetEPR(&(USB->EP1R), USB_EPR_EP_TYPE_BULK
|
||||
| USB_EPR_STAT_TX_NAK | USB_EPR_STAT_RX_DISABLED
|
||||
| (1 << USB_EP1R_EA_Pos));
|
||||
|
||||
// Endpoint 2: Out (buffer size 64)
|
||||
USB_BTABLE_ENTRIES[2].COUNT_RX = USB_EP_RXCOUNT_BL_SIZE | (1 << 10);
|
||||
USB_BTABLE_ENTRIES[2].ADDR_RX = 0x100;
|
||||
USB_BTABLE_ENTRIES[2].COUNT_TX = 0;
|
||||
USB_BTABLE_ENTRIES[2].ADDR_TX = 0;
|
||||
|
||||
USB_SetEPR(&(USB->EP2R), USB_EPR_EP_TYPE_BULK
|
||||
| USB_EPR_STAT_TX_DISABLED | USB_EPR_STAT_RX_VALID
|
||||
| (2 << USB_EP2R_EA_Pos));
|
||||
|
||||
// Enable
|
||||
USB->DADDR = USB_DADDR_EF;
|
||||
}
|
||||
|
||||
static inline void USB_HandleIn(void)
|
||||
{
|
||||
if((USB->DADDR & USB_DADDR_ADD) != USB_Address)
|
||||
{
|
||||
USB->DADDR = USB_Address | USB_DADDR_EF;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline bool USB_HandleSetup(void)
|
||||
{
|
||||
bool exit_bootloader = false;
|
||||
|
||||
USB_SetupPacket_t sp;
|
||||
USB_PMAToMemory(&sp, USB_BTABLE_ENTRIES[0].ADDR_RX,
|
||||
sizeof(USB_SetupPacket_t));
|
||||
|
||||
const void *reply_data = NULL;
|
||||
int reply_length = 0;
|
||||
uint8_t reply_response = USB_EP_TX_STALL;
|
||||
|
||||
if((sp.bmRequestType & (USB_REQUEST_TYPE | USB_REQUEST_RECIPIENT))
|
||||
== (USB_REQUEST_TYPE_STANDARD | USB_REQUEST_RECIPIENT_DEVICE))
|
||||
{
|
||||
switch(sp.bRequest)
|
||||
{
|
||||
case USB_REQUEST_GET_STATUS:
|
||||
if(sp.wValue == 0 && sp.wIndex == 0 && sp.wLength == 2)
|
||||
{
|
||||
reply_length = 2;
|
||||
reply_data = USB_DeviceStatus;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_REQUEST_GET_DESCRIPTOR:;
|
||||
USB_DescriptorType_t descriptor_type = sp.wValue >> 8;
|
||||
int descriptor_index = sp.wValue & 0xff;
|
||||
reply_length = sp.wLength;
|
||||
USB_HandleGetDescriptor(descriptor_type, descriptor_index,
|
||||
&reply_data, &reply_length, &reply_response);
|
||||
break;
|
||||
|
||||
case USB_REQUEST_SET_ADDRESS:
|
||||
USB_Address = sp.wValue & USB_DADDR_ADD;
|
||||
reply_response = USB_EP_TX_VALID;
|
||||
break;
|
||||
|
||||
case USB_REQUEST_SET_CONFIGURATION:
|
||||
// There is only one configuration, so this request is ignored
|
||||
// (but still accepted)
|
||||
reply_response = USB_EP_TX_VALID;
|
||||
break;
|
||||
|
||||
default:
|
||||
reply_response = USB_EP_TX_STALL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if((sp.bmRequestType & USB_REQUEST_TYPE) == USB_REQUEST_TYPE_VENDOR)
|
||||
{
|
||||
reply_response = USB_EP_TX_VALID;
|
||||
if(!USB_HandleCommand(&sp))
|
||||
{
|
||||
exit_bootloader = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unknown request
|
||||
reply_response = USB_EP_TX_STALL;
|
||||
}
|
||||
|
||||
if(reply_data)
|
||||
{
|
||||
// Reply with data
|
||||
USB_MemoryToPMA(USB_BTABLE_ENTRIES[0].ADDR_TX, reply_data,
|
||||
reply_length);
|
||||
USB_BTABLE_ENTRIES[0].COUNT_TX = reply_length;
|
||||
USB->EP0R = (USB_EP_TX_NAK ^ USB_EP_TX_VALID)
|
||||
| USB_EP_CTR_RX | USB_EP_CTR_TX | USB_EPR_EP_TYPE_CONTROL | 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Send response
|
||||
USB_BTABLE_ENTRIES[0].COUNT_TX = 0;
|
||||
USB->EP0R = (USB_EP_TX_NAK ^ reply_response)
|
||||
| USB_EP_CTR_RX | USB_EP_CTR_TX | USB_EPR_EP_TYPE_CONTROL | 0;
|
||||
}
|
||||
|
||||
return !exit_bootloader;
|
||||
}
|
||||
|
||||
bool USB_Poll(void)
|
||||
{
|
||||
if(USB->ISTR & USB_ISTR_RESET)
|
||||
{
|
||||
// Reset happened
|
||||
USB_HandleReset();
|
||||
return true;
|
||||
}
|
||||
uint16_t istr;
|
||||
while((istr = USB->ISTR) & (USB_ISTR_CTR))
|
||||
{
|
||||
if(istr & USB_ISTR_CTR)
|
||||
{
|
||||
// Correct transfer
|
||||
int ep = istr & USB_ISTR_EP_ID;
|
||||
switch(ep)
|
||||
{
|
||||
case 0:
|
||||
// Determine transfer direction
|
||||
if(istr & USB_ISTR_DIR)
|
||||
{
|
||||
// Out transfer
|
||||
if(USB->EP0R & USB_EP0R_SETUP)
|
||||
{
|
||||
// Clear CTR_RX and set RX status to VALID (from
|
||||
// NAK)
|
||||
USB->EP0R = USB_EP_CTR_TX
|
||||
| (USB_EP_RX_NAK ^ USB_EP_RX_VALID)
|
||||
| USB_EPR_EP_TYPE_CONTROL | 0;
|
||||
|
||||
// Setup packed received and check if a command to
|
||||
// exit the bootloader was received
|
||||
if(!USB_HandleSetup())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only setup packets are supported, so other out
|
||||
// transfers are just ignored
|
||||
|
||||
// Clear CTR_RX and set RX status to VALID (from
|
||||
// NAK)
|
||||
USB->EP0R = USB_EP_CTR_TX
|
||||
| (USB_EP_RX_NAK ^ USB_EP_RX_VALID)
|
||||
| USB_EPR_EP_TYPE_CONTROL | 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In transfer
|
||||
|
||||
// Clear CTR_TX
|
||||
USB->EP0R = USB_EP_CTR_RX | USB_EPR_EP_TYPE_CONTROL | 0;
|
||||
|
||||
USB_HandleIn();
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Data in endpoint
|
||||
|
||||
// In transfer finished. STAT_TX gets set to NAK
|
||||
// automatically.
|
||||
|
||||
// Clear CTR_TX
|
||||
USB->EP1R = USB_EPR_EP_TYPE_BULK | 1;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Data out endpoint
|
||||
|
||||
// Clear CTR_RX and set RX status to VALID (which is NAK
|
||||
// after a correct transfer)
|
||||
USB->EP2R = (USB_EP_RX_VALID ^ USB_EP_RX_NAK)
|
||||
| USB_EPR_EP_TYPE_BULK | 2;
|
||||
|
||||
// Out transfer finished
|
||||
USB_HandleEP2Out();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
130
stm32f103c8t6-bootloader/src/usb.h
Normal file
130
stm32f103c8t6-bootloader/src/usb.h
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "stm32f103x6.h"
|
||||
|
||||
#include "pinning.h"
|
||||
|
||||
#define USB_TOKEN_OUT 0b0001
|
||||
#define USB_TOKEN_IN 0x1001
|
||||
#define USB_TOKEN_SOF 0b0101
|
||||
#define USB_TOKEN_SETUP 0b1101
|
||||
#define USB_TOKEN_DATA0 0b0011
|
||||
#define USB_TOKEN_DATA1 0b1011
|
||||
#define USB_TOKEN_DATA2 0b0111
|
||||
#define USB_TOKEN_ACK 0b0010
|
||||
#define USB_TOKEN_NAK 0b1010
|
||||
#define USB_TOKEN_STALL 0b1110
|
||||
#define USB_TOKEN_NYET 0b0110
|
||||
#define USB_TOKEN_PRE 0b1100
|
||||
#define USB_TOKEN_ERR 0b1100
|
||||
#define USB_TOKEN_SPLIT 0b1000
|
||||
#define USB_TOKEN_PING 0b0100
|
||||
|
||||
#define USB_REQUEST_DIRECTION (1 << 7)
|
||||
#define USB_REQUEST_DIRECTION_OUT 0
|
||||
#define USB_REQUEST_DIRECTION_IN (1 << 7)
|
||||
#define USB_REQUEST_TYPE (0x3 << 5)
|
||||
#define USB_REQUEST_TYPE_STANDARD 0
|
||||
#define USB_REQUEST_TYPE_CLASS (1 << 5)
|
||||
#define USB_REQUEST_TYPE_VENDOR (2 << 5)
|
||||
#define USB_REQUEST_TYPE_RESERVED (3 << 5)
|
||||
#define USB_REQUEST_RECIPIENT 0x1f
|
||||
#define USB_REQUEST_RECIPIENT_DEVICE 0
|
||||
#define USB_REQUEST_RECIPIENT_INTERFACE 1
|
||||
#define USB_REQUEST_RECIPIENT_ENDPOINT 2
|
||||
#define USB_REQUEST_RECIPIENT_OTHER 3
|
||||
|
||||
#define USB_REQUEST_CLEAR_FEATURE 1
|
||||
// wValue = <feature>, wIndex = 0|<interface>|<endpoint>, wLength = 0
|
||||
#define USB_REQUEST_GET_CONFIGURATION 8
|
||||
// wValue = 0, wIndex = 0, wLength = 1
|
||||
#define USB_REQUEST_GET_DESCRIPTOR 6
|
||||
// wValue = <descriptor type>:<descriptor index>, wIndex = 0|<language>, wLength = <descriptor length>
|
||||
#define USB_REQUEST_GET_INTERFACE 10
|
||||
// wValue = 0, wIndex = <interface>, wLength = 1
|
||||
#define USB_REQUEST_GET_STATUS 0
|
||||
// wValue = 0, wIndex = 0|<interface>|<endpoint>, wLength = 2
|
||||
#define USB_REQUEST_SET_ADDRESS 5
|
||||
// wValue = <address>, wIndex = 0, wLength = 0
|
||||
#define USB_REQUEST_SET_CONFIGURATION 9
|
||||
// wValue = <configuration value>, wIndex = 0, wLength = 0
|
||||
#define USB_REQUEST_SET_DESCRIPTOR 7
|
||||
// wValue = <descriptor type>:<descriptor index>, wIndex = 0|<language>, wLength = <descriptor length>
|
||||
#define USB_REQUEST_SET_FEATURE 3
|
||||
// wValue = <feature selector>, wIndex = 0|<interface>|<endpoint>, wLength = 0
|
||||
#define USB_REQUEST_SET_INTERFACE 11
|
||||
// wValue = <alternate setting>, wIndex = <interface>, wLength = 0
|
||||
#define USB_REQUEST_SYNCH_FRAME 12
|
||||
// wValue = 0, wIndex = <endpoint>, wLength = 2
|
||||
|
||||
#define USB_EPR_STAT_TX_DISABLED 0x00
|
||||
#define USB_EPR_STAT_TX_STALL USB_EP0R_STAT_TX_0
|
||||
#define USB_EPR_STAT_TX_NAK USB_EP0R_STAT_TX_1
|
||||
#define USB_EPR_STAT_TX_VALID (USB_EP0R_STAT_TX_0 \
|
||||
| USB_EP0R_STAT_TX_1)
|
||||
|
||||
#define USB_EPR_STAT_RX_DISABLED 0x00
|
||||
#define USB_EPR_STAT_RX_STALL USB_EP0R_STAT_RX_0
|
||||
#define USB_EPR_STAT_RX_NAK USB_EP0R_STAT_RX_1
|
||||
#define USB_EPR_STAT_RX_VALID (USB_EP0R_STAT_RX_0 \
|
||||
| USB_EP0R_STAT_RX_1)
|
||||
|
||||
#define USB_EPR_EP_TYPE_BULK 0x00
|
||||
#define USB_EPR_EP_TYPE_CONTROL USB_EP0R_EP_TYPE_0
|
||||
#define USB_EPR_EP_TYPE_ISO USB_EP0R_EP_TYPE_1
|
||||
#define USB_EPR_EP_TYPE_INTERRUPT (USB_EP0R_EP_TYPE_0 \
|
||||
| USB_EP0R_EP_TYPE_1)
|
||||
|
||||
#define USB_PMA_ADDR 0x40006000UL
|
||||
#define USB_BTABLE_OFFSET 0x00
|
||||
#define USB_EP_RXCOUNT_BL_SIZE (1 << 15)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
volatile union
|
||||
{
|
||||
volatile uint16_t ADDR_TX;
|
||||
volatile uint16_t ADDR_RX_0;
|
||||
volatile uint16_t ADDR_TX_0;
|
||||
} __attribute__((aligned(4)));
|
||||
volatile union
|
||||
{
|
||||
volatile uint16_t COUNT_TX;
|
||||
volatile uint16_t COUNT_RX_0;
|
||||
volatile uint16_t COUNT_TX_0;
|
||||
} __attribute__((aligned(4)));
|
||||
volatile union
|
||||
{
|
||||
volatile uint16_t ADDR_RX;
|
||||
volatile uint16_t ADDR_RX_1;
|
||||
volatile uint16_t ADDR_TX_1;
|
||||
} __attribute__((aligned(4)));
|
||||
volatile union
|
||||
{
|
||||
volatile uint16_t COUNT_RX;
|
||||
volatile uint16_t COUNT_RX_1;
|
||||
volatile uint16_t COUNT_TX_1;
|
||||
} __attribute__((aligned(4)));
|
||||
} __attribute__((aligned(8))) USB_BufferTableEntry_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bmRequestType;
|
||||
uint8_t bRequest;
|
||||
uint16_t wValue;
|
||||
uint16_t wIndex;
|
||||
uint16_t wLength;
|
||||
} __attribute__((packed, aligned(2))) USB_SetupPacket_t;
|
||||
|
||||
#define USB_BTABLE_ENTRIES \
|
||||
((volatile USB_BufferTableEntry_t*)(USB_PMA_ADDR + USB_BTABLE_OFFSET))
|
||||
|
||||
void USB_Init(void);
|
||||
|
||||
// Because no interrupts are used, the interrupt flags have to be polled in a
|
||||
// loop. This functions checks the flags and handles the interrupt requests. It
|
||||
// has thus to be called in a loop. It returns false if the bootloader should
|
||||
// exit and the application be started.
|
||||
bool USB_Poll(void);
|
||||
189
stm32f103c8t6-bootloader/src/usb_com.c
Normal file
189
stm32f103c8t6-bootloader/src/usb_com.c
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
#include "usb_com.h"
|
||||
#include "usb_util.h"
|
||||
#include "commands.h"
|
||||
#include "buildinfo.h"
|
||||
#include "flash.h"
|
||||
|
||||
static const BootloaderInfo_t BootloaderInfo =
|
||||
{
|
||||
.build_date = BUILD_DATE,
|
||||
.build_number = BUILD_NUMBER,
|
||||
.flash_application_start = FLASH_APPLICATION_BASE,
|
||||
.flash_application_size = (FLASH_PAGES - FLASH_BOOTLOADER_PAGES)
|
||||
* FLASH_PAGE_BYTES,
|
||||
.version_major = BUILD_VERSION_MAJOR,
|
||||
.version_minor = BUILD_VERSION_MINOR,
|
||||
.version_patch = BUILD_VERSION_PATCH,
|
||||
.identifier = "STM32F103T8U6"
|
||||
};
|
||||
|
||||
|
||||
static Command_t USB_PendingCommand = CMD_NOP;
|
||||
|
||||
static void USB_EP1Transmit(const void *data, uint16_t length)
|
||||
{
|
||||
USB_MemoryToPMA(USB_BTABLE_ENTRIES[1].ADDR_TX, data, length);
|
||||
USB_BTABLE_ENTRIES[1].COUNT_TX = length;
|
||||
|
||||
// Assume that STAT_TX is currently NAK (which is the case after a reset or
|
||||
// after a correct transfer, just not if the function is called multiple
|
||||
// times without an actual transfer in between)
|
||||
USB->EP1R = (USB_EP_TX_NAK ^ USB_EP_TX_VALID)
|
||||
| USB_EP_CTR_RX | USB_EP_CTR_TX | USB_EPR_EP_TYPE_BULK | 1;
|
||||
}
|
||||
|
||||
bool USB_HandleCommand(const USB_SetupPacket_t *sp)
|
||||
{
|
||||
// The command is stored in the second byte (bRequest field) of the setup
|
||||
// packet
|
||||
Command_t command = sp->bRequest;
|
||||
|
||||
const void *reply_data = NULL;
|
||||
int reply_length = 0;
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case CMD_BOOTLOADER_INFO:
|
||||
reply_data = &BootloaderInfo;
|
||||
reply_length = sizeof(BootloaderInfo)
|
||||
+ strlen(BootloaderInfo.identifier);
|
||||
break;
|
||||
|
||||
case CMD_READ_CRC:
|
||||
// The command will be executed as soon as the start address and
|
||||
// length are transferred via EP2
|
||||
USB_PendingCommand = CMD_READ_CRC;
|
||||
break;
|
||||
|
||||
case CMD_READ_MEMORY:
|
||||
// The command will be executed as soon as the start address and
|
||||
// length are transferred via EP2
|
||||
USB_PendingCommand = CMD_READ_MEMORY;
|
||||
break;
|
||||
|
||||
case CMD_ERASE_PAGE:
|
||||
// The command will be executed as soon as the page number is
|
||||
// transferred via EP2. Since only a single byte is needed for the
|
||||
// page index, this would also be technically be possible with just
|
||||
// one setup packet. Since this is the only command, this minor
|
||||
// USB bandwith saving is not worth the extra special case.
|
||||
USB_PendingCommand = CMD_ERASE_PAGE;
|
||||
break;
|
||||
|
||||
case CMD_PROGRAM:
|
||||
USB_PendingCommand = CMD_PROGRAM;
|
||||
break;
|
||||
|
||||
case CMD_EXIT:
|
||||
return false;
|
||||
|
||||
default:
|
||||
// Invalid commands get ignored
|
||||
break;
|
||||
}
|
||||
|
||||
if(reply_length > 0)
|
||||
{
|
||||
USB_EP1Transmit(reply_data, reply_length);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void USB_HandleEP2Out(void)
|
||||
{
|
||||
// Read how many bytes have been received by EP2
|
||||
int packet_length = USB_BTABLE_ENTRIES[2].COUNT_RX & 0x3ff;
|
||||
|
||||
// The meaning of the received data depends on the command transmitted via
|
||||
// a setup packet before it
|
||||
switch(USB_PendingCommand)
|
||||
{
|
||||
case CMD_READ_CRC:
|
||||
if(packet_length == 8)
|
||||
{
|
||||
uint32_t buff[2];
|
||||
USB_PMAToMemory(buff, USB_BTABLE_ENTRIES[2].ADDR_RX,
|
||||
sizeof(buff));
|
||||
uint32_t *addr = (uint32_t*)(buff[0]);
|
||||
uint32_t length = buff[1];
|
||||
|
||||
CRC->CR = CRC_CR_RESET;
|
||||
|
||||
// TODO: Add basic sanity checks so it isn't possible to crash
|
||||
// the bootloader with this command (or at least not as easy)
|
||||
while(length > 4)
|
||||
{
|
||||
CRC->DR = *addr++;
|
||||
length -= 4;
|
||||
}
|
||||
CRC->DR = *addr & (0xffffffffU >> (32 - 8 * length));
|
||||
|
||||
buff[0] = CRC->DR;
|
||||
USB_EP1Transmit(buff, 4);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_READ_MEMORY:
|
||||
if(packet_length == 8)
|
||||
{
|
||||
uint32_t buff[2];
|
||||
USB_PMAToMemory(buff, USB_BTABLE_ENTRIES[2].ADDR_RX,
|
||||
sizeof(buff));
|
||||
uint8_t *start = (uint8_t*)(buff[0]);
|
||||
uint32_t length = buff[1];
|
||||
|
||||
if(length > 64)
|
||||
{
|
||||
length = 64;
|
||||
}
|
||||
|
||||
USB_EP1Transmit(start, length);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_ERASE_PAGE:
|
||||
if(packet_length == 1)
|
||||
{
|
||||
// Not that only one byte has been received but since the PMA
|
||||
// can only be accessed word-wise, we'll have to copy two
|
||||
uint8_t buff[2];
|
||||
USB_PMAToMemory(buff, USB_BTABLE_ENTRIES[2].ADDR_RX,
|
||||
sizeof(buff));
|
||||
|
||||
unsigned int page_index = buff[0];
|
||||
if(page_index < FLASH_BOOTLOADER_PAGES)
|
||||
{
|
||||
// Do not allow erasing the bootloader
|
||||
buff[0] = FLASH_PROHIBITED;
|
||||
}
|
||||
else
|
||||
{
|
||||
buff[0] = Flash_ErasePage(page_index);
|
||||
}
|
||||
|
||||
// Reply with status byte
|
||||
USB_EP1Transmit(buff, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_PROGRAM:;
|
||||
uint32_t start;
|
||||
USB_PMAToMemory(&start, USB_BTABLE_ENTRIES[2].ADDR_RX, 4);
|
||||
uint32_t length = packet_length - 4;
|
||||
if(start >= FLASH_APPLICATION_BASE && start + length
|
||||
<= FLASH_BASE + FLASH_PAGE_BYTES * FLASH_PAGES)
|
||||
{
|
||||
// Program directly from PMA without an intermediate buffer in
|
||||
// RAM
|
||||
Flash_ProgramFromPMA(start, USB_BTABLE_ENTRIES[2].ADDR_RX + 4,
|
||||
length);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
USB_PendingCommand = CMD_NOP;
|
||||
}
|
||||
14
stm32f103c8t6-bootloader/src/usb_com.h
Normal file
14
stm32f103c8t6-bootloader/src/usb_com.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "stm32f103x6.h"
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
void USB_HandleEP2Out(void);
|
||||
|
||||
// Parses a setup packet with a vendor request type and handle the command it
|
||||
// contains. Returns false if the bootloader should exit and start the
|
||||
// application, true if the bootloader should continue execution.
|
||||
bool USB_HandleCommand(const USB_SetupPacket_t *sp);
|
||||
170
stm32f103c8t6-bootloader/src/usb_descriptors.c
Normal file
170
stm32f103c8t6-bootloader/src/usb_descriptors.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#include "usb_descriptors.h"
|
||||
|
||||
const USB_DeviceDescriptor_t USB_DeviceDescriptor =
|
||||
{
|
||||
.bLength = 18,
|
||||
.bDescriptorType = USB_DEVICE_DESCRIPTOR,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = 0xff,
|
||||
.bDeviceSubClass = 0xff,
|
||||
.bDeviceProtocol = 0x00,
|
||||
.bMaxPacketSize0 = 64,
|
||||
.idVendor = 0x16c0,
|
||||
.idProduct = 0x05dc,
|
||||
.bcdDevice = 0x0200,
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 3,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
|
||||
const USB_WholeDescriptor_t USB_ConfigurationInterfaceDescriptor =
|
||||
{
|
||||
.configuration = (USB_ConfigurationDescriptor_t)
|
||||
{
|
||||
.bLength = 9,
|
||||
.bDescriptorType = USB_CONFIGURATION_DESCRIPTOR,
|
||||
.wTotalLength = sizeof(USB_WholeDescriptor_t),
|
||||
.bNumInterfaces = 1,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 0,
|
||||
.bmAttributes = 0x80,
|
||||
.bMaxPower = 100
|
||||
},
|
||||
|
||||
.main_interface = (USB_InterfaceDescriptor_t)
|
||||
{
|
||||
.bLength = 9,
|
||||
.bDescriptorType = USB_INTERFACE_DESCRIPTOR,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = 0x00,
|
||||
.bInterfaceSubClass = 0x00,
|
||||
.bInterfaceProtocol = 0x00,
|
||||
.iInterface = 0
|
||||
},
|
||||
|
||||
// Endpoint 1: in
|
||||
.data_in_endpoint = (USB_EndpointDescriptor_t)
|
||||
{
|
||||
.bLength = sizeof(USB_EndpointDescriptor_t),
|
||||
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
|
||||
.bEndpointAddress = USB_ENDPOINT_IN | 1,
|
||||
.bmAttributes = USB_ENDPOINT_BULK | USB_ENDPOINT_NO_SYNCHRONIZATION
|
||||
| USB_ENDPOINT_DATA,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 0x01
|
||||
},
|
||||
|
||||
// Endpoint 2: out
|
||||
.data_out_endpoint = (USB_EndpointDescriptor_t)
|
||||
{
|
||||
.bLength = sizeof(USB_EndpointDescriptor_t),
|
||||
.bDescriptorType = USB_ENDPOINT_DESCRIPTOR,
|
||||
.bEndpointAddress = USB_ENDPOINT_OUT | 2,
|
||||
.bmAttributes = USB_ENDPOINT_BULK | USB_ENDPOINT_NO_SYNCHRONIZATION
|
||||
| USB_ENDPOINT_DATA,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 0x01
|
||||
},
|
||||
};
|
||||
|
||||
#define USB_STRING_LANGID 0x0409
|
||||
#define USB_STRING_VENDOR '2', '5', '1', '2', '0'
|
||||
#define USB_STRING_PRODUCT 'p', 'u', 'n', 't'
|
||||
|
||||
const uint16_t USB_StringDescriptor_LangID[] =
|
||||
USB_BUILD_STRING_DESCRIPTOR(USB_STRING_LANGID);
|
||||
const uint16_t USB_StringDescriptor_Vendor[] =
|
||||
USB_BUILD_STRING_DESCRIPTOR(USB_STRING_VENDOR);
|
||||
const uint16_t USB_StringDescriptor_Product[] =
|
||||
USB_BUILD_STRING_DESCRIPTOR(USB_STRING_PRODUCT);
|
||||
|
||||
void USB_HandleGetDescriptor(USB_DescriptorType_t descriptor_type,
|
||||
int descriptor_index, const void **reply_data, int *reply_length,
|
||||
uint8_t *reply_response)
|
||||
{
|
||||
switch(descriptor_type)
|
||||
{
|
||||
case USB_DEVICE_DESCRIPTOR:
|
||||
*reply_data = &USB_DeviceDescriptor;
|
||||
*reply_length = USB_DeviceDescriptor.bLength;
|
||||
break;
|
||||
|
||||
case USB_CONFIGURATION_DESCRIPTOR:
|
||||
*reply_data = &USB_ConfigurationInterfaceDescriptor;
|
||||
if(*reply_length < USB_ConfigurationInterfaceDescriptor
|
||||
.configuration.wTotalLength)
|
||||
{
|
||||
*reply_length = USB_ConfigurationInterfaceDescriptor
|
||||
.configuration.bLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
*reply_length = USB_ConfigurationInterfaceDescriptor
|
||||
.configuration.wTotalLength;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_STRING_DESCRIPTOR:
|
||||
switch(descriptor_index)
|
||||
{
|
||||
case 0:
|
||||
*reply_data = (uint8_t*)USB_StringDescriptor_LangID;
|
||||
*reply_length = (uint8_t)*USB_StringDescriptor_LangID;
|
||||
break;
|
||||
case 1:
|
||||
*reply_data = (uint8_t*)USB_StringDescriptor_Vendor;
|
||||
*reply_length = (uint8_t)*USB_StringDescriptor_Vendor;
|
||||
break;
|
||||
case 2:
|
||||
*reply_data = (uint8_t*)USB_StringDescriptor_Product;
|
||||
*reply_length = (uint8_t)*USB_StringDescriptor_Product;
|
||||
break;
|
||||
case 3:;
|
||||
// String descriptors are 16 bits per char
|
||||
static uint16_t buff[25];
|
||||
// The first byte is the total length in bytes, the second
|
||||
// byte is the descriptor type (3)
|
||||
buff[0] = (0x03 << 8) | sizeof(buff);
|
||||
// The unique device ID is 96 bits = 12 bytes long
|
||||
for(int i = 0; i < 12; i++)
|
||||
{
|
||||
uint8_t uid_byte = *((uint8_t*)UID_BASE + i);
|
||||
// The representation does not matter for the serial, so
|
||||
// we're using one of the first 16 letters of the
|
||||
// alphabet for each nibble
|
||||
buff[1 + 2 * i] = 'A' + (uid_byte & 0x0f);
|
||||
buff[2 + 2 * i] = 'A' + (uid_byte >> 4);
|
||||
}
|
||||
|
||||
*reply_data = (uint8_t*)buff;
|
||||
*reply_length = (uint8_t)*buff;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_INTERFACE_DESCRIPTOR:
|
||||
*reply_data = &USB_ConfigurationInterfaceDescriptor
|
||||
.main_interface;
|
||||
*reply_length = USB_ConfigurationInterfaceDescriptor
|
||||
.main_interface.bLength;
|
||||
break;
|
||||
|
||||
case USB_DEVICE_QUALIFIER_DESCRIPTOR:
|
||||
// Device is full-speed only, so it must return a request error
|
||||
*reply_response = USB_EP_TX_STALL;
|
||||
*reply_data = NULL;
|
||||
break;
|
||||
|
||||
case USB_ENDPOINT_DESCRIPTOR:
|
||||
case USB_OTHER_DESCRIPTOR:
|
||||
case USB_INTERFACE_POWER_DESCRIPTOR:
|
||||
case USB_INTERFACE_ASSOCIATION_DESCRIPTOR:
|
||||
case USB_CLASS_SPECIFIC_INTERFACE_DESCRIPTOR:
|
||||
case USB_CLASS_SPECIFIC_ENDPOINT_DESCRIPTOR:
|
||||
// Not implemented
|
||||
break;
|
||||
}
|
||||
}
|
||||
113
stm32f103c8t6-bootloader/src/usb_descriptors.h
Normal file
113
stm32f103c8t6-bootloader/src/usb_descriptors.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "stm32f103x6.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdUSB;
|
||||
uint8_t bDeviceClass;
|
||||
uint8_t bDeviceSubClass;
|
||||
uint8_t bDeviceProtocol;
|
||||
uint8_t bMaxPacketSize0;
|
||||
uint16_t idVendor;
|
||||
uint16_t idProduct;
|
||||
uint16_t bcdDevice;
|
||||
uint8_t iManufacturer;
|
||||
uint8_t iProduct;
|
||||
uint8_t iSerialNumber;
|
||||
uint8_t bNumConfigurations;
|
||||
} __attribute__((packed, aligned(1))) USB_DeviceDescriptor_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t wTotalLength;
|
||||
uint8_t bNumInterfaces;
|
||||
uint8_t bConfigurationValue;
|
||||
uint8_t iConfiguration;
|
||||
uint8_t bmAttributes;
|
||||
uint8_t bMaxPower;
|
||||
} __attribute__((packed, aligned(1))) USB_ConfigurationDescriptor_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bInterfaceNumber;
|
||||
uint8_t bAlternateSetting;
|
||||
uint8_t bNumEndpoints;
|
||||
uint8_t bInterfaceClass;
|
||||
uint8_t bInterfaceSubClass;
|
||||
uint8_t bInterfaceProtocol;
|
||||
uint8_t iInterface;
|
||||
} __attribute__((packed, aligned(1))) USB_InterfaceDescriptor_t;
|
||||
|
||||
// Endpoint direction for the bEndpointAddress field
|
||||
#define USB_ENDPOINT_OUT 0x00
|
||||
#define USB_ENDPOINT_IN 0x80
|
||||
|
||||
// Flags in bmAttributes
|
||||
#define USB_ENDPOINT_CONTROL 0x00
|
||||
#define USB_ENDPOINT_ISOCHRONOUS 0x01
|
||||
#define USB_ENDPOINT_BULK 0x02
|
||||
#define USB_ENDPOINT_INTERRUPT 0x03
|
||||
|
||||
#define USB_ENDPOINT_NO_SYNCHRONIZATION 0x00
|
||||
#define USB_ENDPOINT_ASYNCHRONOUS 0x04
|
||||
#define USB_ENDPOINT_ADAPTIVE 0x08
|
||||
#define USB_ENDPOINT_SYNCHRONOUS 0x0c
|
||||
|
||||
#define USB_ENDPOINT_DATA 0x00
|
||||
#define USB_ENDPOINT_FEEDBACK 0x10
|
||||
#define USB_ENDPOINT_IMPLICIT_FEEDBACK_DATA 0x20
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint8_t bEndpointAddress;
|
||||
uint8_t bmAttributes;
|
||||
uint16_t wMaxPacketSize;
|
||||
uint8_t bInterval;
|
||||
} __attribute__((packed, aligned(1))) USB_EndpointDescriptor_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
USB_ConfigurationDescriptor_t configuration;
|
||||
USB_InterfaceDescriptor_t main_interface;
|
||||
USB_EndpointDescriptor_t data_in_endpoint;
|
||||
USB_EndpointDescriptor_t data_out_endpoint;
|
||||
} __attribute__((packed, aligned(1))) USB_WholeDescriptor_t;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
USB_DEVICE_DESCRIPTOR = 0x01,
|
||||
USB_CONFIGURATION_DESCRIPTOR = 0x02,
|
||||
USB_STRING_DESCRIPTOR = 0x03,
|
||||
USB_INTERFACE_DESCRIPTOR = 0x04,
|
||||
USB_ENDPOINT_DESCRIPTOR = 0x05,
|
||||
USB_DEVICE_QUALIFIER_DESCRIPTOR = 0x06,
|
||||
USB_OTHER_DESCRIPTOR = 0x07,
|
||||
USB_INTERFACE_POWER_DESCRIPTOR = 0x08,
|
||||
USB_INTERFACE_ASSOCIATION_DESCRIPTOR = 0x0b,
|
||||
USB_CLASS_SPECIFIC_INTERFACE_DESCRIPTOR = 0x24,
|
||||
USB_CLASS_SPECIFIC_ENDPOINT_DESCRIPTOR = 0x25
|
||||
|
||||
} __attribute__((packed)) USB_DescriptorType_t;
|
||||
|
||||
#define USB_STRING_DESCRIPTOR_LENGTH(...) \
|
||||
(sizeof((uint16_t[]){__VA_ARGS__}) + 2)
|
||||
#define USB_BUILD_STRING_DESCRIPTOR(...) \
|
||||
{USB_STRING_DESCRIPTOR_LENGTH(__VA_ARGS__) \
|
||||
| (USB_STRING_DESCRIPTOR << 8), __VA_ARGS__}
|
||||
|
||||
|
||||
void USB_HandleGetDescriptor(USB_DescriptorType_t descriptor_type,
|
||||
int descriptor_index, const void **reply_data, int *reply_length,
|
||||
uint8_t *reply_response);
|
||||
55
stm32f103c8t6-bootloader/src/usb_util.c
Normal file
55
stm32f103c8t6-bootloader/src/usb_util.c
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
#include "usb_util.h"
|
||||
|
||||
void USB_PMAToMemory(void *mem, uint16_t offset, size_t length)
|
||||
{
|
||||
// Only words can be copied. Thus, if the length is not even, it has to be
|
||||
// incremented to ensure that the last byte is copied. This of course means
|
||||
// that the target memory area must be of even length!
|
||||
if(length & 1)
|
||||
{
|
||||
length++;
|
||||
}
|
||||
|
||||
uint8_t *dst = (uint8_t*)mem;
|
||||
|
||||
uint8_t *pma = (uint8_t*)(USB_PMA_ADDR + 2 * offset);
|
||||
for(unsigned int i = 0; i < length / 2; i++)
|
||||
{
|
||||
dst[2 * i] = *pma++;
|
||||
dst[2 * i + 1] = *pma++;
|
||||
pma += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void USB_MemoryToPMA(uint16_t offset, const void *mem, size_t length)
|
||||
{
|
||||
// Only words can be copied. Thus, if the length is not even, it has to be
|
||||
// incremented to ensure that the last byte is copied. Since the PMA buffer
|
||||
// always has even size, this is not a problem.
|
||||
if(length & 1)
|
||||
{
|
||||
length++;
|
||||
}
|
||||
|
||||
const uint8_t *src = (const uint8_t*)mem;
|
||||
|
||||
uint16_t *pma = (uint16_t*)(USB_PMA_ADDR + 2 * offset);
|
||||
for(unsigned int i = 0; i < length / 2; i++)
|
||||
{
|
||||
uint16_t tmp = src[2 * i] | (src[2 * i + 1] << 8);
|
||||
*pma++ = tmp;
|
||||
pma++;
|
||||
}
|
||||
}
|
||||
|
||||
void USB_SetEPR(volatile uint16_t *EPR, uint16_t status)
|
||||
{
|
||||
// Caution: This function does a read-modify-write and is prone to
|
||||
// unexpected behaviour when there are transactions going one, because the
|
||||
// register contents might change during the function's execution. Thus,
|
||||
// only use this function in initialisation code!
|
||||
volatile uint16_t v = *EPR;
|
||||
status ^= v & (USB_EP0R_DTOG_RX | USB_EP0R_STAT_RX |\
|
||||
USB_EP0R_DTOG_TX | USB_EP0R_STAT_TX);
|
||||
*EPR = status;
|
||||
}
|
||||
7
stm32f103c8t6-bootloader/src/usb_util.h
Normal file
7
stm32f103c8t6-bootloader/src/usb_util.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
void USB_PMAToMemory(void *mem, uint16_t offset, size_t length);
|
||||
void USB_MemoryToPMA(uint16_t offset, const void *mem, size_t length);
|
||||
void USB_SetEPR(volatile uint16_t *EPR, uint16_t status);
|
||||
10
stm32f103c8t6-bootloader/src/util.c
Normal file
10
stm32f103c8t6-bootloader/src/util.c
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "util.h"
|
||||
|
||||
void Util_Delay(unsigned int delay)
|
||||
{
|
||||
SysTick->LOAD = delay;
|
||||
SysTick->VAL = 0;
|
||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
|
||||
while(!((SysTick->CTRL) & SysTick_CTRL_COUNTFLAG_Msk));
|
||||
SysTick->CTRL = 0;
|
||||
}
|
||||
6
stm32f103c8t6-bootloader/src/util.h
Normal file
6
stm32f103c8t6-bootloader/src/util.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "stm32f103x6.h"
|
||||
|
||||
// Delay in AHB clock cycles
|
||||
void Util_Delay(unsigned int delay);
|
||||
1627
stm32f103c8t6-bootloader/third_party/core/core_cm3.h
vendored
Normal file
1627
stm32f103c8t6-bootloader/third_party/core/core_cm3.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
638
stm32f103c8t6-bootloader/third_party/core/core_cmFunc.h
vendored
Normal file
638
stm32f103c8t6-bootloader/third_party/core/core_cmFunc.h
vendored
Normal file
|
|
@ -0,0 +1,638 @@
|
|||
/**************************************************************************//**
|
||||
* @file core_cmFunc.h
|
||||
* @brief CMSIS Cortex-M Core Function Access Header File
|
||||
* @version V3.20
|
||||
* @date 25. February 2013
|
||||
*
|
||||
* @note
|
||||
*
|
||||
******************************************************************************/
|
||||
/* Copyright (c) 2009 - 2013 ARM LIMITED
|
||||
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
- 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.
|
||||
- Neither the name of ARM 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 AND CONTRIBUTORS "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 COPYRIGHT HOLDERS AND CONTRIBUTORS 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 __CORE_CMFUNC_H
|
||||
#define __CORE_CMFUNC_H
|
||||
|
||||
|
||||
/* ########################### Core Function Access ########################### */
|
||||
/** \ingroup CMSIS_Core_FunctionInterface
|
||||
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
|
||||
@{
|
||||
*/
|
||||
|
||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||
/* ARM armcc specific functions */
|
||||
|
||||
#if (__ARMCC_VERSION < 400677)
|
||||
#error "Please use ARM Compiler Toolchain V4.0.677 or later!"
|
||||
#endif
|
||||
|
||||
/* intrinsic void __enable_irq(); */
|
||||
/* intrinsic void __disable_irq(); */
|
||||
|
||||
/** \brief Get Control Register
|
||||
|
||||
This function returns the content of the Control Register.
|
||||
|
||||
\return Control Register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_CONTROL(void)
|
||||
{
|
||||
register uint32_t __regControl __ASM("control");
|
||||
return(__regControl);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Control Register
|
||||
|
||||
This function writes the given value to the Control Register.
|
||||
|
||||
\param [in] control Control Register value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_CONTROL(uint32_t control)
|
||||
{
|
||||
register uint32_t __regControl __ASM("control");
|
||||
__regControl = control;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get IPSR Register
|
||||
|
||||
This function returns the content of the IPSR Register.
|
||||
|
||||
\return IPSR Register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_IPSR(void)
|
||||
{
|
||||
register uint32_t __regIPSR __ASM("ipsr");
|
||||
return(__regIPSR);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get APSR Register
|
||||
|
||||
This function returns the content of the APSR Register.
|
||||
|
||||
\return APSR Register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_APSR(void)
|
||||
{
|
||||
register uint32_t __regAPSR __ASM("apsr");
|
||||
return(__regAPSR);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get xPSR Register
|
||||
|
||||
This function returns the content of the xPSR Register.
|
||||
|
||||
\return xPSR Register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_xPSR(void)
|
||||
{
|
||||
register uint32_t __regXPSR __ASM("xpsr");
|
||||
return(__regXPSR);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Process Stack Pointer
|
||||
|
||||
This function returns the current value of the Process Stack Pointer (PSP).
|
||||
|
||||
\return PSP Register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_PSP(void)
|
||||
{
|
||||
register uint32_t __regProcessStackPointer __ASM("psp");
|
||||
return(__regProcessStackPointer);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Process Stack Pointer
|
||||
|
||||
This function assigns the given value to the Process Stack Pointer (PSP).
|
||||
|
||||
\param [in] topOfProcStack Process Stack Pointer value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
register uint32_t __regProcessStackPointer __ASM("psp");
|
||||
__regProcessStackPointer = topOfProcStack;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Main Stack Pointer
|
||||
|
||||
This function returns the current value of the Main Stack Pointer (MSP).
|
||||
|
||||
\return MSP Register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_MSP(void)
|
||||
{
|
||||
register uint32_t __regMainStackPointer __ASM("msp");
|
||||
return(__regMainStackPointer);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Main Stack Pointer
|
||||
|
||||
This function assigns the given value to the Main Stack Pointer (MSP).
|
||||
|
||||
\param [in] topOfMainStack Main Stack Pointer value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
register uint32_t __regMainStackPointer __ASM("msp");
|
||||
__regMainStackPointer = topOfMainStack;
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Priority Mask
|
||||
|
||||
This function returns the current state of the priority mask bit from the Priority Mask Register.
|
||||
|
||||
\return Priority Mask value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_PRIMASK(void)
|
||||
{
|
||||
register uint32_t __regPriMask __ASM("primask");
|
||||
return(__regPriMask);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Priority Mask
|
||||
|
||||
This function assigns the given value to the Priority Mask Register.
|
||||
|
||||
\param [in] priMask Priority Mask
|
||||
*/
|
||||
__STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
register uint32_t __regPriMask __ASM("primask");
|
||||
__regPriMask = (priMask);
|
||||
}
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Enable FIQ
|
||||
|
||||
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
#define __enable_fault_irq __enable_fiq
|
||||
|
||||
|
||||
/** \brief Disable FIQ
|
||||
|
||||
This function disables FIQ interrupts by setting the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
#define __disable_fault_irq __disable_fiq
|
||||
|
||||
|
||||
/** \brief Get Base Priority
|
||||
|
||||
This function returns the current value of the Base Priority register.
|
||||
|
||||
\return Base Priority register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_BASEPRI(void)
|
||||
{
|
||||
register uint32_t __regBasePri __ASM("basepri");
|
||||
return(__regBasePri);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Base Priority
|
||||
|
||||
This function assigns the given value to the Base Priority register.
|
||||
|
||||
\param [in] basePri Base Priority value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_BASEPRI(uint32_t basePri)
|
||||
{
|
||||
register uint32_t __regBasePri __ASM("basepri");
|
||||
__regBasePri = (basePri & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Fault Mask
|
||||
|
||||
This function returns the current value of the Fault Mask register.
|
||||
|
||||
\return Fault Mask register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_FAULTMASK(void)
|
||||
{
|
||||
register uint32_t __regFaultMask __ASM("faultmask");
|
||||
return(__regFaultMask);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Fault Mask
|
||||
|
||||
This function assigns the given value to the Fault Mask register.
|
||||
|
||||
\param [in] faultMask Fault Mask value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
register uint32_t __regFaultMask __ASM("faultmask");
|
||||
__regFaultMask = (faultMask & (uint32_t)1);
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
#if (__CORTEX_M == 0x04)
|
||||
|
||||
/** \brief Get FPSCR
|
||||
|
||||
This function returns the current value of the Floating Point Status/Control register.
|
||||
|
||||
\return Floating Point Status/Control register value
|
||||
*/
|
||||
__STATIC_INLINE uint32_t __get_FPSCR(void)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
register uint32_t __regfpscr __ASM("fpscr");
|
||||
return(__regfpscr);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set FPSCR
|
||||
|
||||
This function assigns the given value to the Floating Point Status/Control register.
|
||||
|
||||
\param [in] fpscr Floating Point Status/Control value to set
|
||||
*/
|
||||
__STATIC_INLINE void __set_FPSCR(uint32_t fpscr)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
register uint32_t __regfpscr __ASM("fpscr");
|
||||
__regfpscr = (fpscr);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M == 0x04) */
|
||||
|
||||
|
||||
#elif defined ( __ICCARM__ ) /*------------------ ICC Compiler -------------------*/
|
||||
/* IAR iccarm specific functions */
|
||||
|
||||
#include <cmsis_iar.h>
|
||||
|
||||
|
||||
#elif defined ( __TMS470__ ) /*---------------- TI CCS Compiler ------------------*/
|
||||
/* TI CCS specific functions */
|
||||
|
||||
#include <cmsis_ccs.h>
|
||||
|
||||
|
||||
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
|
||||
/* GNU gcc specific functions */
|
||||
|
||||
/** \brief Enable IRQ Interrupts
|
||||
|
||||
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsie i" : : : "memory");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Disable IRQ Interrupts
|
||||
|
||||
This function disables IRQ interrupts by setting the I-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsid i" : : : "memory");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Control Register
|
||||
|
||||
This function returns the content of the Control Register.
|
||||
|
||||
\return Control Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, control" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Control Register
|
||||
|
||||
This function writes the given value to the Control Register.
|
||||
|
||||
\param [in] control Control Register value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CONTROL(uint32_t control)
|
||||
{
|
||||
__ASM volatile ("MSR control, %0" : : "r" (control) : "memory");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get IPSR Register
|
||||
|
||||
This function returns the content of the IPSR Register.
|
||||
|
||||
\return IPSR Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_IPSR(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, ipsr" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get APSR Register
|
||||
|
||||
This function returns the content of the APSR Register.
|
||||
|
||||
\return APSR Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_APSR(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, apsr" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get xPSR Register
|
||||
|
||||
This function returns the content of the xPSR Register.
|
||||
|
||||
\return xPSR Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, xpsr" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Process Stack Pointer
|
||||
|
||||
This function returns the current value of the Process Stack Pointer (PSP).
|
||||
|
||||
\return PSP Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void)
|
||||
{
|
||||
register uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Process Stack Pointer
|
||||
|
||||
This function assigns the given value to the Process Stack Pointer (PSP).
|
||||
|
||||
\param [in] topOfProcStack Process Stack Pointer value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)
|
||||
{
|
||||
__ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Main Stack Pointer
|
||||
|
||||
This function returns the current value of the Main Stack Pointer (MSP).
|
||||
|
||||
\return MSP Register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void)
|
||||
{
|
||||
register uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, msp\n" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Main Stack Pointer
|
||||
|
||||
This function assigns the given value to the Main Stack Pointer (MSP).
|
||||
|
||||
\param [in] topOfMainStack Main Stack Pointer value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack)
|
||||
{
|
||||
__ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Priority Mask
|
||||
|
||||
This function returns the current state of the priority mask bit from the Priority Mask Register.
|
||||
|
||||
\return Priority Mask value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PRIMASK(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, primask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Priority Mask
|
||||
|
||||
This function assigns the given value to the Priority Mask Register.
|
||||
|
||||
\param [in] priMask Priority Mask
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
|
||||
{
|
||||
__ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
|
||||
}
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Enable FIQ
|
||||
|
||||
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsie f" : : : "memory");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Disable FIQ
|
||||
|
||||
This function disables FIQ interrupts by setting the F-bit in the CPSR.
|
||||
Can only be executed in Privileged modes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void)
|
||||
{
|
||||
__ASM volatile ("cpsid f" : : : "memory");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Base Priority
|
||||
|
||||
This function returns the current value of the Base Priority register.
|
||||
|
||||
\return Base Priority register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, basepri_max" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Base Priority
|
||||
|
||||
This function assigns the given value to the Base Priority register.
|
||||
|
||||
\param [in] basePri Base Priority value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value)
|
||||
{
|
||||
__ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Get Fault Mask
|
||||
|
||||
This function returns the current value of the Fault Mask register.
|
||||
|
||||
\return Fault Mask register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set Fault Mask
|
||||
|
||||
This function assigns the given value to the Fault Mask register.
|
||||
|
||||
\param [in] faultMask Fault Mask value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask)
|
||||
{
|
||||
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory");
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
#if (__CORTEX_M == 0x04)
|
||||
|
||||
/** \brief Get FPSCR
|
||||
|
||||
This function returns the current value of the Floating Point Status/Control register.
|
||||
|
||||
\return Floating Point Status/Control register value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
uint32_t result;
|
||||
|
||||
/* Empty asm statement works as a scheduling barrier */
|
||||
__ASM volatile ("");
|
||||
__ASM volatile ("VMRS %0, fpscr" : "=r" (result) );
|
||||
__ASM volatile ("");
|
||||
return(result);
|
||||
#else
|
||||
return(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Set FPSCR
|
||||
|
||||
This function assigns the given value to the Floating Point Status/Control register.
|
||||
|
||||
\param [in] fpscr Floating Point Status/Control value to set
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr)
|
||||
{
|
||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
||||
/* Empty asm statement works as a scheduling barrier */
|
||||
__ASM volatile ("");
|
||||
__ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc");
|
||||
__ASM volatile ("");
|
||||
#else
|
||||
(void) fpscr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M == 0x04) */
|
||||
|
||||
|
||||
#elif defined ( __TASKING__ ) /*------------------ TASKING Compiler --------------*/
|
||||
/* TASKING carm specific functions */
|
||||
|
||||
/*
|
||||
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||
* Please use "carm -?i" to get an up to date list of all instrinsics,
|
||||
* Including the CMSIS ones.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/*@} end of CMSIS_Core_RegAccFunctions */
|
||||
|
||||
|
||||
#endif /* __CORE_CMFUNC_H */
|
||||
688
stm32f103c8t6-bootloader/third_party/core/core_cmInstr.h
vendored
Normal file
688
stm32f103c8t6-bootloader/third_party/core/core_cmInstr.h
vendored
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
/**************************************************************************//**
|
||||
* @file core_cmInstr.h
|
||||
* @brief CMSIS Cortex-M Core Instruction Access Header File
|
||||
* @version V3.20
|
||||
* @date 05. March 2013
|
||||
*
|
||||
* @note
|
||||
*
|
||||
******************************************************************************/
|
||||
/* Copyright (c) 2009 - 2013 ARM LIMITED
|
||||
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
- 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.
|
||||
- Neither the name of ARM 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 AND CONTRIBUTORS "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 COPYRIGHT HOLDERS AND CONTRIBUTORS 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 __CORE_CMINSTR_H
|
||||
#define __CORE_CMINSTR_H
|
||||
|
||||
|
||||
/* ########################## Core Instruction Access ######################### */
|
||||
/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface
|
||||
Access to dedicated instructions
|
||||
@{
|
||||
*/
|
||||
|
||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
||||
/* ARM armcc specific functions */
|
||||
|
||||
#if (__ARMCC_VERSION < 400677)
|
||||
#error "Please use ARM Compiler Toolchain V4.0.677 or later!"
|
||||
#endif
|
||||
|
||||
|
||||
/** \brief No Operation
|
||||
|
||||
No Operation does nothing. This instruction can be used for code alignment purposes.
|
||||
*/
|
||||
#define __NOP __nop
|
||||
|
||||
|
||||
/** \brief Wait For Interrupt
|
||||
|
||||
Wait For Interrupt is a hint instruction that suspends execution
|
||||
until one of a number of events occurs.
|
||||
*/
|
||||
#define __WFI __wfi
|
||||
|
||||
|
||||
/** \brief Wait For Event
|
||||
|
||||
Wait For Event is a hint instruction that permits the processor to enter
|
||||
a low-power state until one of a number of events occurs.
|
||||
*/
|
||||
#define __WFE __wfe
|
||||
|
||||
|
||||
/** \brief Send Event
|
||||
|
||||
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
|
||||
*/
|
||||
#define __SEV __sev
|
||||
|
||||
|
||||
/** \brief Instruction Synchronization Barrier
|
||||
|
||||
Instruction Synchronization Barrier flushes the pipeline in the processor,
|
||||
so that all instructions following the ISB are fetched from cache or
|
||||
memory, after the instruction has been completed.
|
||||
*/
|
||||
#define __ISB() __isb(0xF)
|
||||
|
||||
|
||||
/** \brief Data Synchronization Barrier
|
||||
|
||||
This function acts as a special kind of Data Memory Barrier.
|
||||
It completes when all explicit memory accesses before this instruction complete.
|
||||
*/
|
||||
#define __DSB() __dsb(0xF)
|
||||
|
||||
|
||||
/** \brief Data Memory Barrier
|
||||
|
||||
This function ensures the apparent order of the explicit memory operations before
|
||||
and after the instruction, without ensuring their completion.
|
||||
*/
|
||||
#define __DMB() __dmb(0xF)
|
||||
|
||||
|
||||
/** \brief Reverse byte order (32 bit)
|
||||
|
||||
This function reverses the byte order in integer value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
#define __REV __rev
|
||||
|
||||
|
||||
/** \brief Reverse byte order (16 bit)
|
||||
|
||||
This function reverses the byte order in two unsigned short values.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
#ifndef __NO_EMBEDDED_ASM
|
||||
__attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(uint32_t value)
|
||||
{
|
||||
rev16 r0, r0
|
||||
bx lr
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \brief Reverse byte order in signed short value
|
||||
|
||||
This function reverses the byte order in a signed short value with sign extension to integer.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
#ifndef __NO_EMBEDDED_ASM
|
||||
__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(int32_t value)
|
||||
{
|
||||
revsh r0, r0
|
||||
bx lr
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/** \brief Rotate Right in unsigned value (32 bit)
|
||||
|
||||
This function Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.
|
||||
|
||||
\param [in] value Value to rotate
|
||||
\param [in] value Number of Bits to rotate
|
||||
\return Rotated value
|
||||
*/
|
||||
#define __ROR __ror
|
||||
|
||||
|
||||
/** \brief Breakpoint
|
||||
|
||||
This function causes the processor to enter Debug state.
|
||||
Debug tools can use this to investigate system state when the instruction at a particular address is reached.
|
||||
|
||||
\param [in] value is ignored by the processor.
|
||||
If required, a debugger can use it to store additional information about the breakpoint.
|
||||
*/
|
||||
#define __BKPT(value) __breakpoint(value)
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Reverse bit order of value
|
||||
|
||||
This function reverses the bit order of the given value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
#define __RBIT __rbit
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 8 bit value.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint8_t at (*ptr)
|
||||
*/
|
||||
#define __LDREXB(ptr) ((uint8_t ) __ldrex(ptr))
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 16 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint16_t at (*ptr)
|
||||
*/
|
||||
#define __LDREXH(ptr) ((uint16_t) __ldrex(ptr))
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 32 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint32_t at (*ptr)
|
||||
*/
|
||||
#define __LDREXW(ptr) ((uint32_t ) __ldrex(ptr))
|
||||
|
||||
|
||||
/** \brief STR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive STR command for 8 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
#define __STREXB(value, ptr) __strex(value, ptr)
|
||||
|
||||
|
||||
/** \brief STR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive STR command for 16 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
#define __STREXH(value, ptr) __strex(value, ptr)
|
||||
|
||||
|
||||
/** \brief STR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive STR command for 32 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
#define __STREXW(value, ptr) __strex(value, ptr)
|
||||
|
||||
|
||||
/** \brief Remove the exclusive lock
|
||||
|
||||
This function removes the exclusive lock which is created by LDREX.
|
||||
|
||||
*/
|
||||
#define __CLREX __clrex
|
||||
|
||||
|
||||
/** \brief Signed Saturate
|
||||
|
||||
This function saturates a signed value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (1..32)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __SSAT __ssat
|
||||
|
||||
|
||||
/** \brief Unsigned Saturate
|
||||
|
||||
This function saturates an unsigned value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (0..31)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __USAT __usat
|
||||
|
||||
|
||||
/** \brief Count leading zeros
|
||||
|
||||
This function counts the number of leading zeros of a data value.
|
||||
|
||||
\param [in] value Value to count the leading zeros
|
||||
\return number of leading zeros in value
|
||||
*/
|
||||
#define __CLZ __clz
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
|
||||
#elif defined ( __ICCARM__ ) /*------------------ ICC Compiler -------------------*/
|
||||
/* IAR iccarm specific functions */
|
||||
|
||||
#include <cmsis_iar.h>
|
||||
|
||||
|
||||
#elif defined ( __TMS470__ ) /*---------------- TI CCS Compiler ------------------*/
|
||||
/* TI CCS specific functions */
|
||||
|
||||
#include <cmsis_ccs.h>
|
||||
|
||||
|
||||
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
|
||||
/* GNU gcc specific functions */
|
||||
|
||||
/* Define macros for porting to both thumb1 and thumb2.
|
||||
* For thumb1, use low register (r0-r7), specified by constrant "l"
|
||||
* Otherwise, use general registers, specified by constrant "r" */
|
||||
#if defined (__thumb__) && !defined (__thumb2__)
|
||||
#define __CMSIS_GCC_OUT_REG(r) "=l" (r)
|
||||
#define __CMSIS_GCC_USE_REG(r) "l" (r)
|
||||
#else
|
||||
#define __CMSIS_GCC_OUT_REG(r) "=r" (r)
|
||||
#define __CMSIS_GCC_USE_REG(r) "r" (r)
|
||||
#endif
|
||||
|
||||
/** \brief No Operation
|
||||
|
||||
No Operation does nothing. This instruction can be used for code alignment purposes.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __NOP(void)
|
||||
{
|
||||
__ASM volatile ("nop");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Wait For Interrupt
|
||||
|
||||
Wait For Interrupt is a hint instruction that suspends execution
|
||||
until one of a number of events occurs.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __WFI(void)
|
||||
{
|
||||
__ASM volatile ("wfi");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Wait For Event
|
||||
|
||||
Wait For Event is a hint instruction that permits the processor to enter
|
||||
a low-power state until one of a number of events occurs.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __WFE(void)
|
||||
{
|
||||
__ASM volatile ("wfe");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Send Event
|
||||
|
||||
Send Event is a hint instruction. It causes an event to be signaled to the CPU.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __SEV(void)
|
||||
{
|
||||
__ASM volatile ("sev");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Instruction Synchronization Barrier
|
||||
|
||||
Instruction Synchronization Barrier flushes the pipeline in the processor,
|
||||
so that all instructions following the ISB are fetched from cache or
|
||||
memory, after the instruction has been completed.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __ISB(void)
|
||||
{
|
||||
__ASM volatile ("isb");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Data Synchronization Barrier
|
||||
|
||||
This function acts as a special kind of Data Memory Barrier.
|
||||
It completes when all explicit memory accesses before this instruction complete.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __DSB(void)
|
||||
{
|
||||
__ASM volatile ("dsb");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Data Memory Barrier
|
||||
|
||||
This function ensures the apparent order of the explicit memory operations before
|
||||
and after the instruction, without ensuring their completion.
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __DMB(void)
|
||||
{
|
||||
__ASM volatile ("dmb");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reverse byte order (32 bit)
|
||||
|
||||
This function reverses the byte order in integer value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __REV(uint32_t value)
|
||||
{
|
||||
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
return __builtin_bswap32(value);
|
||||
#else
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
|
||||
return(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reverse byte order (16 bit)
|
||||
|
||||
This function reverses the byte order in two unsigned short values.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __REV16(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Reverse byte order in signed short value
|
||||
|
||||
This function reverses the byte order in a signed short value with sign extension to integer.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __REVSH(int32_t value)
|
||||
{
|
||||
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
|
||||
return (short)__builtin_bswap16(value);
|
||||
#else
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
|
||||
return(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** \brief Rotate Right in unsigned value (32 bit)
|
||||
|
||||
This function Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits.
|
||||
|
||||
\param [in] value Value to rotate
|
||||
\param [in] value Number of Bits to rotate
|
||||
\return Rotated value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
|
||||
{
|
||||
return (op1 >> op2) | (op1 << (32 - op2));
|
||||
}
|
||||
|
||||
|
||||
/** \brief Breakpoint
|
||||
|
||||
This function causes the processor to enter Debug state.
|
||||
Debug tools can use this to investigate system state when the instruction at a particular address is reached.
|
||||
|
||||
\param [in] value is ignored by the processor.
|
||||
If required, a debugger can use it to store additional information about the breakpoint.
|
||||
*/
|
||||
#define __BKPT(value) __ASM volatile ("bkpt "#value)
|
||||
|
||||
|
||||
#if (__CORTEX_M >= 0x03)
|
||||
|
||||
/** \brief Reverse bit order of value
|
||||
|
||||
This function reverses the bit order of the given value.
|
||||
|
||||
\param [in] value Value to reverse
|
||||
\return Reversed value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __RBIT(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 8 bit value.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint8_t at (*ptr)
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint8_t __LDREXB(volatile uint8_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
|
||||
__ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) );
|
||||
#else
|
||||
/* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not
|
||||
accepted by assembler. So has to use following less efficient pattern.
|
||||
*/
|
||||
__ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" );
|
||||
#endif
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 16 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint16_t at (*ptr)
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint16_t __LDREXH(volatile uint16_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
|
||||
__ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) );
|
||||
#else
|
||||
/* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not
|
||||
accepted by assembler. So has to use following less efficient pattern.
|
||||
*/
|
||||
__ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" );
|
||||
#endif
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief LDR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive LDR command for 32 bit values.
|
||||
|
||||
\param [in] ptr Pointer to data
|
||||
\return value of type uint32_t at (*ptr)
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __LDREXW(volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief STR Exclusive (8 bit)
|
||||
|
||||
This function performs a exclusive STR command for 8 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief STR Exclusive (16 bit)
|
||||
|
||||
This function performs a exclusive STR command for 16 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief STR Exclusive (32 bit)
|
||||
|
||||
This function performs a exclusive STR command for 32 bit values.
|
||||
|
||||
\param [in] value Value to store
|
||||
\param [in] ptr Pointer to location
|
||||
\return 0 Function succeeded
|
||||
\return 1 Function failed
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/** \brief Remove the exclusive lock
|
||||
|
||||
This function removes the exclusive lock which is created by LDREX.
|
||||
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __CLREX(void)
|
||||
{
|
||||
__ASM volatile ("clrex" ::: "memory");
|
||||
}
|
||||
|
||||
|
||||
/** \brief Signed Saturate
|
||||
|
||||
This function saturates a signed value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (1..32)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __SSAT(ARG1,ARG2) \
|
||||
({ \
|
||||
uint32_t __RES, __ARG1 = (ARG1); \
|
||||
__ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
|
||||
__RES; \
|
||||
})
|
||||
|
||||
|
||||
/** \brief Unsigned Saturate
|
||||
|
||||
This function saturates an unsigned value.
|
||||
|
||||
\param [in] value Value to be saturated
|
||||
\param [in] sat Bit position to saturate to (0..31)
|
||||
\return Saturated value
|
||||
*/
|
||||
#define __USAT(ARG1,ARG2) \
|
||||
({ \
|
||||
uint32_t __RES, __ARG1 = (ARG1); \
|
||||
__ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \
|
||||
__RES; \
|
||||
})
|
||||
|
||||
|
||||
/** \brief Count leading zeros
|
||||
|
||||
This function counts the number of leading zeros of a data value.
|
||||
|
||||
\param [in] value Value to count the leading zeros
|
||||
\return number of leading zeros in value
|
||||
*/
|
||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint8_t __CLZ(uint32_t value)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
__ASM volatile ("clz %0, %1" : "=r" (result) : "r" (value) );
|
||||
return(result);
|
||||
}
|
||||
|
||||
#endif /* (__CORTEX_M >= 0x03) */
|
||||
|
||||
|
||||
|
||||
|
||||
#elif defined ( __TASKING__ ) /*------------------ TASKING Compiler --------------*/
|
||||
/* TASKING carm specific functions */
|
||||
|
||||
/*
|
||||
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
||||
* Please use "carm -?i" to get an up to date list of all intrinsics,
|
||||
* Including the CMSIS ones.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
/*@}*/ /* end of group CMSIS_Core_InstructionInterface */
|
||||
|
||||
#endif /* __CORE_CMINSTR_H */
|
||||
36
stm32f103c8t6-bootloader/third_party/core/core_generic.h
vendored
Normal file
36
stm32f103c8t6-bootloader/third_party/core/core_generic.h
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* PackageLicenseDeclared: Apache-2.0
|
||||
* Copyright (c) 2015 ARM Limited
|
||||
*
|
||||
* 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 License 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.
|
||||
*/
|
||||
|
||||
#ifndef __CMSIS_CORE_CORE_GENERIC_H__
|
||||
#define __CMSIS_CORE_CORE_GENERIC_H__
|
||||
|
||||
#define __CMSIS_GENERIC
|
||||
#if defined(TARGET_LIKE_CORTEX_M3)
|
||||
#include "cmsis-core/core_cm3.h"
|
||||
#elif defined(TARGET_LIKE_CORTEX_M4)
|
||||
#include "cmsis-core/core_cm4.h"
|
||||
#elif defined(TARGET_LIKE_CORTEX_M0)
|
||||
#include "cmsis-core/core_cm0.h"
|
||||
#elif defined(TARGET_LIKE_CORTEX_M0PLUS)
|
||||
#include "cmsis-core/core_cm0plus.h"
|
||||
#else
|
||||
#error "Unknown platform for core_generic.h"
|
||||
#endif
|
||||
#undef __CMSIS_GENERIC
|
||||
|
||||
#endif // #ifndef __CMSIS_CORE_CORE_GENERIC_H__
|
||||
|
||||
10513
stm32f103c8t6-bootloader/third_party/device/stm32f103x6.h
vendored
Normal file
10513
stm32f103c8t6-bootloader/third_party/device/stm32f103x6.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
238
stm32f103c8t6-bootloader/third_party/device/stm32f1xx.h
vendored
Normal file
238
stm32f103c8t6-bootloader/third_party/device/stm32f1xx.h
vendored
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* @file stm32f1xx.h
|
||||
* @author MCD Application Team
|
||||
* @version V4.2.0
|
||||
* @date 31-March-2017
|
||||
* @brief CMSIS STM32F1xx Device Peripheral Access Layer Header File.
|
||||
*
|
||||
* The file is the unique include file that the application programmer
|
||||
* is using in the C source code, usually in main.c. This file contains:
|
||||
* - Configuration section that allows to select:
|
||||
* - The STM32F1xx device used in the target application
|
||||
* - To use or not the peripheral’s drivers in application code(i.e.
|
||||
* code will be based on direct access to peripheral’s registers
|
||||
* rather than drivers API), this option is controlled by
|
||||
* "#define USE_HAL_DRIVER"
|
||||
*
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
|
||||
*
|
||||
* 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 STMicroelectronics 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 AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f1xx
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef __STM32F1XX_H
|
||||
#define __STM32F1XX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/** @addtogroup Library_configuration_section
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief STM32 Family
|
||||
*/
|
||||
#if !defined (STM32F1)
|
||||
#define STM32F1
|
||||
#endif /* STM32F1 */
|
||||
|
||||
/* Uncomment the line below according to the target STM32L device used in your
|
||||
application
|
||||
*/
|
||||
|
||||
#if !defined (STM32F100xB) && !defined (STM32F100xE) && !defined (STM32F101x6) && \
|
||||
!defined (STM32F101xB) && !defined (STM32F101xE) && !defined (STM32F101xG) && !defined (STM32F102x6) && !defined (STM32F102xB) && !defined (STM32F103x6) && \
|
||||
!defined (STM32F103xB) && !defined (STM32F103xE) && !defined (STM32F103xG) && !defined (STM32F105xC) && !defined (STM32F107xC)
|
||||
/* #define STM32F100xB */ /*!< STM32F100C4, STM32F100R4, STM32F100C6, STM32F100R6, STM32F100C8, STM32F100R8, STM32F100V8, STM32F100CB, STM32F100RB and STM32F100VB */
|
||||
/* #define STM32F100xE */ /*!< STM32F100RC, STM32F100VC, STM32F100ZC, STM32F100RD, STM32F100VD, STM32F100ZD, STM32F100RE, STM32F100VE and STM32F100ZE */
|
||||
/* #define STM32F101x6 */ /*!< STM32F101C4, STM32F101R4, STM32F101T4, STM32F101C6, STM32F101R6 and STM32F101T6 Devices */
|
||||
/* #define STM32F101xB */ /*!< STM32F101C8, STM32F101R8, STM32F101T8, STM32F101V8, STM32F101CB, STM32F101RB, STM32F101TB and STM32F101VB */
|
||||
/* #define STM32F101xE */ /*!< STM32F101RC, STM32F101VC, STM32F101ZC, STM32F101RD, STM32F101VD, STM32F101ZD, STM32F101RE, STM32F101VE and STM32F101ZE */
|
||||
/* #define STM32F101xG */ /*!< STM32F101RF, STM32F101VF, STM32F101ZF, STM32F101RG, STM32F101VG and STM32F101ZG */
|
||||
/* #define STM32F102x6 */ /*!< STM32F102C4, STM32F102R4, STM32F102C6 and STM32F102R6 */
|
||||
/* #define STM32F102xB */ /*!< STM32F102C8, STM32F102R8, STM32F102CB and STM32F102RB */
|
||||
/* #define STM32F103x6 */ /*!< STM32F103C4, STM32F103R4, STM32F103T4, STM32F103C6, STM32F103R6 and STM32F103T6 */
|
||||
/* #define STM32F103xB */ /*!< STM32F103C8, STM32F103R8, STM32F103T8, STM32F103V8, STM32F103CB, STM32F103RB, STM32F103TB and STM32F103VB */
|
||||
/* #define STM32F103xE */ /*!< STM32F103RC, STM32F103VC, STM32F103ZC, STM32F103RD, STM32F103VD, STM32F103ZD, STM32F103RE, STM32F103VE and STM32F103ZE */
|
||||
/* #define STM32F103xG */ /*!< STM32F103RF, STM32F103VF, STM32F103ZF, STM32F103RG, STM32F103VG and STM32F103ZG */
|
||||
/* #define STM32F105xC */ /*!< STM32F105R8, STM32F105V8, STM32F105RB, STM32F105VB, STM32F105RC and STM32F105VC */
|
||||
/* #define STM32F107xC */ /*!< STM32F107RB, STM32F107VB, STM32F107RC and STM32F107VC */
|
||||
#endif
|
||||
|
||||
/* Tip: To avoid modifying this file each time you need to switch between these
|
||||
devices, you can define the device in your toolchain compiler preprocessor.
|
||||
*/
|
||||
|
||||
#if !defined (USE_HAL_DRIVER)
|
||||
/**
|
||||
* @brief Comment the line below if you will not use the peripherals drivers.
|
||||
In this case, these drivers will not be included and the application code will
|
||||
be based on direct access to peripherals registers
|
||||
*/
|
||||
/*#define USE_HAL_DRIVER */
|
||||
#endif /* USE_HAL_DRIVER */
|
||||
|
||||
/**
|
||||
* @brief CMSIS Device version number V4.2.0
|
||||
*/
|
||||
#define __STM32F1_CMSIS_VERSION_MAIN (0x04) /*!< [31:24] main version */
|
||||
#define __STM32F1_CMSIS_VERSION_SUB1 (0x02) /*!< [23:16] sub1 version */
|
||||
#define __STM32F1_CMSIS_VERSION_SUB2 (0x00) /*!< [15:8] sub2 version */
|
||||
#define __STM32F1_CMSIS_VERSION_RC (0x00) /*!< [7:0] release candidate */
|
||||
#define __STM32F1_CMSIS_VERSION ((__STM32F1_CMSIS_VERSION_MAIN << 24)\
|
||||
|(__STM32F1_CMSIS_VERSION_SUB1 << 16)\
|
||||
|(__STM32F1_CMSIS_VERSION_SUB2 << 8 )\
|
||||
|(__STM32F1_CMSIS_VERSION_RC))
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup Device_Included
|
||||
* @{
|
||||
*/
|
||||
|
||||
#if defined(STM32F100xB)
|
||||
#include "stm32f100xb.h"
|
||||
#elif defined(STM32F100xE)
|
||||
#include "stm32f100xe.h"
|
||||
#elif defined(STM32F101x6)
|
||||
#include "stm32f101x6.h"
|
||||
#elif defined(STM32F101xB)
|
||||
#include "stm32f101xb.h"
|
||||
#elif defined(STM32F101xE)
|
||||
#include "stm32f101xe.h"
|
||||
#elif defined(STM32F101xG)
|
||||
#include "stm32f101xg.h"
|
||||
#elif defined(STM32F102x6)
|
||||
#include "stm32f102x6.h"
|
||||
#elif defined(STM32F102xB)
|
||||
#include "stm32f102xb.h"
|
||||
#elif defined(STM32F103x6)
|
||||
#include "stm32f103x6.h"
|
||||
#elif defined(STM32F103xB)
|
||||
#include "stm32f103xb.h"
|
||||
#elif defined(STM32F103xE)
|
||||
#include "stm32f103xe.h"
|
||||
#elif defined(STM32F103xG)
|
||||
#include "stm32f103xg.h"
|
||||
#elif defined(STM32F105xC)
|
||||
#include "stm32f105xc.h"
|
||||
#elif defined(STM32F107xC)
|
||||
#include "stm32f107xc.h"
|
||||
#else
|
||||
#error "Please select first the target STM32F1xx device used in your application (in stm32f1xx.h file)"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup Exported_types
|
||||
* @{
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
RESET = 0,
|
||||
SET = !RESET
|
||||
} FlagStatus, ITStatus;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DISABLE = 0,
|
||||
ENABLE = !DISABLE
|
||||
} FunctionalState;
|
||||
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ERROR = 0,
|
||||
SUCCESS = !ERROR
|
||||
} ErrorStatus;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/** @addtogroup Exported_macros
|
||||
* @{
|
||||
*/
|
||||
#define SET_BIT(REG, BIT) ((REG) |= (BIT))
|
||||
|
||||
#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT))
|
||||
|
||||
#define READ_BIT(REG, BIT) ((REG) & (BIT))
|
||||
|
||||
#define CLEAR_REG(REG) ((REG) = (0x0))
|
||||
|
||||
#define WRITE_REG(REG, VAL) ((REG) = (VAL))
|
||||
|
||||
#define READ_REG(REG) ((REG))
|
||||
|
||||
#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))
|
||||
|
||||
#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL)))
|
||||
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#if defined (USE_HAL_DRIVER)
|
||||
#include "stm32f1xx_hal.h"
|
||||
#endif /* USE_HAL_DRIVER */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __STM32F1xx_H */
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
116
stm32f103c8t6-bootloader/third_party/device/system_stm32f1xx.h
vendored
Normal file
116
stm32f103c8t6-bootloader/third_party/device/system_stm32f1xx.h
vendored
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/**
|
||||
******************************************************************************
|
||||
* @file system_stm32f10x.h
|
||||
* @author MCD Application Team
|
||||
* @version V4.2.0
|
||||
* @date 31-March-2017
|
||||
* @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Header File.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* <h2><center>© COPYRIGHT(c) 2017 STMicroelectronics</center></h2>
|
||||
*
|
||||
* 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 STMicroelectronics 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 AND CONTRIBUTORS "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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
/** @addtogroup CMSIS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** @addtogroup stm32f10x_system
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Define to prevent recursive inclusion
|
||||
*/
|
||||
#ifndef __SYSTEM_STM32F10X_H
|
||||
#define __SYSTEM_STM32F10X_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @addtogroup STM32F10x_System_Includes
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_types
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
||||
extern const uint8_t AHBPrescTable[16U]; /*!< AHB prescalers table values */
|
||||
extern const uint8_t APBPrescTable[8U]; /*!< APB prescalers table values */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Constants
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Macros
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/** @addtogroup STM32F10x_System_Exported_Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
extern void SystemInit(void);
|
||||
extern void SystemCoreClockUpdate(void);
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /*__SYSTEM_STM32F10X_H */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|
||||
Loading…
Add table
Add a link
Reference in a new issue