Have the usb code physically separate from the main/application code

with large number of updates to the linker script (nokeep.ld)

The first 2KByte is dedicated for vector table, usb driver, usb desc
tables, hardfault, dummy handler, and firmware update routines.  There
is currently ~700Bytes of free space in that first 2KB.  Should be
plenty of space for firmware update routines and other advanced future
features.

The 070RB has 2KByte pages, and 070C6 has 1KB pages, which is the
smallest erase granularity size.  So we can't really have anything
smaller than 2KByte on the RB.  This leaves 30Kbyte for the
main/application code on the C6 which should be more than enough.

That 30KByte starts with the reset handler fixed to 0x0800_0800 because
we don't want to have to update the vector table.

After the reset handler is the usbFunctionWrite, then Setup routines
which the usb driver calls for incoming/outgoing data.  These need to be
in first 64KByte of flash as a 16bit pointer is kept in usb_buff RAM.
Write was put first as it's less likely to change, with Setup following
which is quite large due to all the inlining that's happening inside it
thanks to the compiler.

Perhaps these function locations could be kept at a fixed location.  Or
we could make a 'vector table' of our own just before the reset handler.
This may speed things up a bit, but for now it works.  Also like the
ability to change these pointers which may be useful for the next update
as the firmware update code will effectively need it's own Setup/Write
functions.  So the current pointers can just be updated to call them
instead, and restore originals/new ones through reset.?

This leaves 96KByte of unused flash on the 070RB, don't have any plans
for this yet.  Perhaps future updates for all the connectors and
features will require it.

Also added definition for fast ram functions to .data section.  Got that
working but not sure when it may be needed..
This commit is contained in:
Paul XPS 2018-11-28 16:01:58 -06:00
parent e3d0ec434e
commit a8a4e7e1e2
10 changed files with 169 additions and 50 deletions

View File

@ -11,14 +11,18 @@ MEMORY
/* $0000 0000 128KB of flash/sram depending on BOOT */
/* $0002 0000 ~128MB of system reserved */
/* $0800 0000 always flash size depends on part */
/* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K */ /* 0x20000 128K */
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* 0x20000 128K */
/* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K */ /* 0x20000 128K 070RB */
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* 0x08000 32K 070C6 */
/* FLASH0 (rx) : ORIGIN = 0x08000000, LENGTH = 2K */ /* 0x0800 2K vectors, usb, firmware update, etc */
/* FLASH1 (rx) : ORIGIN = 0x08000800, LENGTH = 30K */ /* 0x7800 30K reset, main, & application code */
/* FLASH2 (rx) : ORIGIN = 0x08008000, LENGTH = 96K */ /* RB ONLY 0x18000 96K */
/* $0802 0000 ~384MB of system reserved */
/* $1FFF C800 12KB of system memory (bootloader and etc) */
/* $1FFF C400 13KB of system memory (bootloader and etc) 070C6 */
/* $1FFF C800 12KB of system memory (bootloader and etc) 070RB */
/* $1FFF F800 2KB of option bytes */
/* $2000 0000 always SRAM size depends on part */
/* RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K */ /* 0x04000 16K */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 6K /* 0x04000 16K */
/* RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K */ /* 0x04000 16K 070RB */
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 6K /* 0x01800 6K 070C6 */
/* $2000 4000 ~512MB of system reserved */
/* $4000 0000 128KB of APB perif regs & reserved */
/* $4002 0000 17KB of AHB1 perif regs & reserved */
@ -65,7 +69,36 @@ SECTIONS
{
.text :
{
/* First 2KByte of flash EXCLUDES all application & main code */
/* start with vector table */
KEEP(*(.isr_vector))
/* then USB code & desc tables */
*(.usb_driver)
*(.usb_desc)
/* hardfault & dummy handlers */
*(.hardfault)
/* put firmware update code at end of first 2KByte
* should allow for easier updating of that code alone
* by the application code if desired */
*(.fw_update)
. = 0x0800; /*update the location counter to the 3rd KByte */
/* reset handler fixed to 0x08000800
* that way the vector table should always be accurate */
*(.reset_handler)
/* usbFunctionSetup & usbFunctionWrite must be in first 64KByte of flash
* make Write first, and Setup last since Write is less likely to change
* or maybe we just want to make them fixed addresses and avoid use of usb_buff
* function pointers, possible future TODO for speedup? */
*(.usbFuncWrite)
*(.usbFuncSetup)
/* then everything else (application code) follows */
*(.text*)
*(.init)
@ -168,6 +201,12 @@ SECTIONS
*(.fini_array)
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
*(.fastrun) /*Placing functions in .fastrun section in RAM */
/* This kind of breaks arm-none-eabi-size look at .map file __data_end__ for actual data size*/
/* Really size is just combining text & data together */
*(.jcr)
. = ALIGN(4);
/* All data end */

View File

@ -122,7 +122,12 @@ __isr_vector:
.size __isr_vector, . - __isr_vector
.text
//;.text
//;want to move this to a fixed flash location so the lower
//;vector/usb section of flash doesn't need to be updated for
//;main/application firmware updates.
//;want the reset handler to always reside @ 0x08000800
.section .reset_handler
.thumb
.thumb_func
.align 1
@ -268,6 +273,9 @@ Reset_Handler:
.pool
.size Reset_Handler, . - Reset_Handler
//;want the default handler to be in same space as hardfault
.section .hardfault
.align 1
.thumb_func
.weak Default_Handler

View File

@ -46,10 +46,10 @@
USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) {
#endif
#ifdef STM_CORE
#define NOINLINE __attribute__ ((section (".text"), noinline, noclone))
//NOINLINE should keep these functions at beinging of flash (.text)
#define USBSETUP __attribute__ ((section (".usbFuncSetup"), noinline, noclone))
//noinline should keep these functions at beinging of flash (.text)
//they need to be in the first 64KByte which is non issue with C6, but could prob with RB
NOINLINE uint16_t usbFunctionSetup(uint8_t data[8]) {
USBSETUP uint16_t usbFunctionSetup(uint8_t data[8]) {
#endif
@ -279,7 +279,10 @@ USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) {
#endif
#ifdef STM_CORE
NOINLINE uint8_t usbFunctionWrite(uint8_t *data, uint8_t len) {
#define USBWRITE __attribute__ ((section (".usbFuncWrite"), noinline, noclone))
//noinline should keep these functions at beinging of flash (.text)
//they need to be in the first 64KByte which is non issue with C6, but could prob with RB
USBWRITE uint8_t usbFunctionWrite(uint8_t *data, uint8_t len) {
#endif
//defined and controled by buffer.c

View File

@ -0,0 +1,17 @@
#include "fwupdate.h"
FWUPDATE void erase_main()
{
//usb driver & this code resisdes in first 2KByte of last (0x0800_0800)
//The smaller STMF070C6 has 32KByte of flash, and larger STMF070RB has 128KByte
//C6 flash is split into 1KB pages
//RB flash is split into 2KB pages
//So the C6 must leave first two pages alone, and RB only the first page
//But they're both leaving the first 2KByte untouched
//And erasing the 30KByte that follows
//For now we're ignoring the extra 96KByte of additional flash that the RB contains
while(1){
}
}

View File

@ -0,0 +1,15 @@
#ifndef _fwupdate_h
#define _fwupdate_h
//include target chip port definition library files
#include <stm32f0xx.h>
//#define FWUPDATE __attribute__ ((section (".fw_update")))
#define FWUPDATE __attribute__ ((section (".fw_update"), noinline, noclone))
void erase_main();
#endif

View File

@ -0,0 +1,37 @@
//want this to be in first 2KByte of USB boot space so the handler should typically be present
#define HARDFAULT __attribute__ ((section (".hardfault")))
HARDFAULT void HardFault_Handler(void)
{
//TODO test out this function
//should retrieve PC of the instruction that follows whatever caused the hardfault
//This didn't work for me earlier bc the stack itself was broke
// asm(
// "movs r0, #4 \n"
// "movs r1, lr \n"
// "tst r0, r1 \n"
// "beq _MSP \n"
// "mrs r0, psp \n"
// "b _HALT \n"
// "_MSP: \n"
// " mrs r0, msp \n"
// "_HALT: \n"
// " ldr r1, [r0,#20] \n"
// //" bkpt #0 \n"
// );
asm(
"ldr r0, dead\n"
"b loop\n"
//"bkpt\n"
".p2align 2\n"
"dead:\n"
".word 0xDEAD0123\n" //MSP for bootloader
"loop:\n"
);
while (1) {
}
}

View File

@ -1,29 +1,6 @@
#include "stm_init.h"
void HardFault_Handler(void)
{
//TODO test out this function
//should retrieve PC of the instruction that follows whatever caused the hardfault
//This didn't work for me earlier bc the stack itself was broke
// asm(
// "movs r0, #4 \n"
// "movs r1, lr \n"
// "tst r0, r1 \n"
// "beq _MSP \n"
// "mrs r0, psp \n"
// "b _HALT \n"
// "_MSP: \n"
// " mrs r0, msp \n"
// "_HALT: \n"
// " ldr r1, [r0,#20] \n"
// //" bkpt #0 \n"
// );
while (1) {
}
}
/* stm32f0x2 devices have HSI48 available which isn't on stm32f0x0 devices
* I'm primarily targetting f070 devices which will require external xtal

View File

@ -1,6 +1,8 @@
#ifndef _usb_descriptors_h
#define _usb_descriptors_h
#define USBDESC __attribute__ ((section (".usb_desc")))
/* Contains all the device, configuration, interface, endpoint, and string descriptor definitions
* The excellent breakdown of the USB standard and field comments have been copy pasted from the
* almighty documentation "USB in a Nutshell" article by BeyondLogic:
@ -19,7 +21,7 @@
#define DESC_TYPE_ENDPOINT 0x05
#define DEVICE_DESC_LEN 18
const uint8_t device_desc[DEVICE_DESC_LEN] = {
USBDESC const uint8_t device_desc[DEVICE_DESC_LEN] = {
// 0 bLength 1 Number Size of the Descriptor in Bytes (18 bytes)
DEVICE_DESC_LEN,
// 1 bDescriptorType 1 Constant Device Descriptor (0x01)
@ -93,7 +95,7 @@ const uint8_t device_desc[DEVICE_DESC_LEN] = {
//NOTE: current table broken if total is greater 255 bytes!!!
#define CONFIG_TOTAL_LEN (CONFIG_DESC_LEN + INTERFACE_DESC_LEN + ENDPOINT_DESC_LEN)
#define wTotalLength 2 //offset of wTotalLength in descriptor array
const uint8_t config_desc[CONFIG_TOTAL_LEN] = {
USBDESC const uint8_t config_desc[CONFIG_TOTAL_LEN] = {
// Off Field Size Value Description
// 0 bLength 1 Number Size of Descriptor in Bytes
CONFIG_DESC_LEN,
@ -224,7 +226,7 @@ const uint8_t config_desc[CONFIG_TOTAL_LEN] = {
// Universal Serial Bus Language Identifiers (LANGIDs) version 1.0
//
#define STRING0_DESC_LEN 4
const uint8_t string0_desc[STRING0_DESC_LEN] = {
USBDESC const uint8_t string0_desc[STRING0_DESC_LEN] = {
// Off Field Size Value Description
// 0 bLength 1 Number Size of Descriptor in Bytes
STRING0_DESC_LEN,
@ -255,7 +257,7 @@ const uint8_t string0_desc[STRING0_DESC_LEN] = {
//Defining string arrays as uint16_t effectively makes the strings UTF-16 as required
#define BYTES_PER_HWORD 2
#define STRING1_DESC_LEN (21*BYTES_PER_HWORD) //characters plus 1 for bLength & bDescriptorType
const uint16_t string1_desc[STRING1_DESC_LEN] = {
USBDESC const uint16_t string1_desc[STRING1_DESC_LEN] = {
// 0 bLength 1 Number Size of Descriptor in Bytes
// 1 bDescriptorType 1 Constant String Descriptor (0x03)
((uint16_t)DESC_TYPE_STRING<<8 | STRING1_DESC_LEN),
@ -263,7 +265,7 @@ const uint16_t string1_desc[STRING1_DESC_LEN] = {
'I','n','f','i','n','i','t','e','N','e','s','L','i','v','e','s','.','c','o','m'};
#define STRING2_DESC_LEN (15*BYTES_PER_HWORD) //characters plus 1 for bLength & bDescriptorType
const uint16_t string2_desc[STRING2_DESC_LEN] = {
USBDESC const uint16_t string2_desc[STRING2_DESC_LEN] = {
// 0 bLength 1 Number Size of Descriptor in Bytes
// 1 bDescriptorType 1 Constant String Descriptor (0x03)
((uint16_t)DESC_TYPE_STRING<<8 | STRING2_DESC_LEN),

View File

@ -6,7 +6,7 @@
//since usb drivers don't use any .data nor .bss space
//static int log = 0;
void usb_reset_recovery(){
USBDRIVER void usb_reset_recovery(){
// USB->CNTR |= USB_CNTR_FRES;
// USB->CNTR &= ~USB_CNTR_FRES;
@ -165,7 +165,7 @@ void usb_reset_recovery(){
//uint16_t volatile (* const usb_buff)[512] = (void*)USB_PMAADDR;
//this was suggestion by: http://a3f.at/articles/register-syntax-sugar
//which errors on compilation due to assigning of type array
uint16_t volatile (* const usb_buff) = (void*)USB_PMAADDR;
USBDRIVER uint16_t volatile (* const usb_buff) = (void*)USB_PMAADDR;
//static uint16_t num_bytes_req;
@ -207,7 +207,7 @@ uint16_t volatile (* const usb_buff) = (void*)USB_PMAADDR;
//#define TSSOP20 //defined when using TSSOP-20 part to get PA11/12 alternate mapping to the pins
//prereq: USB block's clock must be initialized prior to calling
void init_usb()
USBDRIVER void init_usb()
{
//initialize the clock
@ -433,7 +433,7 @@ void init_usb()
//currently hardcoded for EP0 only
//num_bytes_sending, num_bytes_xfrd, and *usbMsgPtr must be initialized prior to entry
static void control_xfr_in(){
USBDRIVER static void control_xfr_in(){
//determine if have data remaining to be sent
// We should never get to this point, if we did there was an error and should prob send STALL
@ -570,7 +570,7 @@ static void control_xfr_in(){
//return number of bytes expected
static uint16_t standard_req_out( usbRequest_t *spacket ){
USBDRIVER static uint16_t standard_req_out( usbRequest_t *spacket ){
switch ( spacket->bRequest ) {
@ -614,7 +614,7 @@ static uint16_t standard_req_out( usbRequest_t *spacket ){
}
static uint16_t standard_req_in( usbRequest_t *spacket ){
USBDRIVER static uint16_t standard_req_in( usbRequest_t *spacket ){
switch ( spacket->bRequest ) {
@ -694,7 +694,7 @@ static uint16_t standard_req_in( usbRequest_t *spacket ){
//USB IRQ handler calls this function after recieving a control setup packet
//function is responsible for preparing follow on data/status transfers to complete control xfr
//must set everything up for control_xfr_in/out functions to be called during data packets
static void control_xfr_init( usbRequest_t *spacket ) {
USBDRIVER static void control_xfr_init( usbRequest_t *spacket ) {
//determine number of requested data payload bytes
num_bytes_req = spacket->wLength;
@ -748,15 +748,29 @@ static void control_xfr_init( usbRequest_t *spacket ) {
//to do this the usb code can't directly call application code (usbFunction Setup/Write)
//need the application code to tell the usb code where the functions are using variables
//call the usbFunctionSetup function with some function pointer magic
typedef uint16_t (*pFunction)(uint8_t data[8]);
pFunction JumpToApplication;
JumpToApplication = (uint16_t (*)(uint8_t data[8])) ((0x08000000)); //base of flash
//application main makes the following assignment at powerup
//usbfuncsetup = (uint32_t) &usbFunctionSetup; //should only assign lower 16bits
JumpToApplication += usbfuncsetup;
//but this is where we need to snoop on the setup packet to determine
//if it's a firmware update packet
// if (fwupdate logic) {
// //send this packet to the firmware updater
// erase_main();
// }
// else { //normal setup packet send to application code
JumpToApplication = (uint16_t (*)(uint8_t data[8])) ((0x08000000)); //base of flash
//application main makes the following assignment at powerup
//usbfuncsetup = (uint32_t) &usbFunctionSetup; //should only assign lower 16bits
JumpToApplication += usbfuncsetup;
// }
//perform the actual jump/call
num_bytes_sending = JumpToApplication( (uint8_t*) spacket );
}
@ -866,7 +880,7 @@ static void control_xfr_init( usbRequest_t *spacket ) {
//USB interrupt status register (USB_ISTR)
//This register contains the status of all the interrupt sources allowing application
//software to determine, which events caused an interrupt request.
void USB_IRQHandler(void)
USBDRIVER void USB_IRQHandler(void)
{
//communications between application code & USB to prevent direct calls

View File

@ -5,6 +5,13 @@
//include target chip port definition library files
#include <stm32f0xx.h>
#include "fwupdate.h"
#define USBDRIVER __attribute__ ((section (".usb_driver")))
//let the compiler perform inline optization, it'll keep code smaller
//this code is all exactly where we want it anyway and separate from
//application code, so inlining is not just okay, it's good!
//#define USBDRIVER __attribute__ ((section (".usb_boot"), noinline, noclone))
//clear RX interrupt
//set tx field to keep from accidentally clearing //mask out toggle feilds making them zero //clear rx bit removing active interrupt