Boot code for AT32F421

RT-890
Silvano Seva 2023-12-18 08:12:49 +01:00
rodzic 20a7a842b5
commit d8e22e0b11
5 zmienionych plików z 549 dodań i 0 usunięć

Wyświetl plik

@ -0,0 +1,11 @@
#ifndef ARCH_REGISTERS_IMPL_H
#define ARCH_REGISTERS_IMPL_H
#include "at32f421.h"
#include "core_cm4.h"
#include "system_at32f421.h"
#define RCC_SYNC() //Workaround for a bug in stm32f42x
#endif //ARCH_REGISTERS_IMPL_H

Wyświetl plik

@ -0,0 +1,69 @@
/***************************************************************************
* Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO, *
* Federico Terraneo *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
/***********************************************************************
* bsp.cpp Part of the Miosix Embedded OS.
* Board support package, this file initializes hardware.
************************************************************************/
#include <interfaces/bsp.h>
#include <kernel/kernel.h>
#include <kernel/sync.h>
namespace miosix
{
//
// Initialization
//
void IRQbspInit()
{
CRM->ahben |= (1 << 17) // Enable GPIOA
| (1 << 18) // Enable GPIOB
| (1 << 19) // Enable GPIOC
| (1 << 22); // Enable GPIOF
// Configure SysTick
SysTick->LOAD = SystemCoreClock / miosix::TICK_FREQ;
}
void bspInit2()
{
}
//
// Shutdown and reboot
//
void shutdown()
{
reboot();
}
void reboot()
{
disableInterrupts();
miosix_private::IRQsystemReboot();
}
} //namespace miosix

Wyświetl plik

@ -0,0 +1,61 @@
/***************************************************************************
* Copyright (C) 2023 by Silvano Seva IU2KWO *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#include <stdio.h>
#include <reent.h>
#include <filesystem/file_access.h>
using namespace std;
#ifdef __cplusplus
extern "C" {
#endif
/**
* \internal
* _write_r, write to a file
*/
int _write_r(struct _reent *ptr, int fd, const void *buf, size_t cnt)
{
(void) ptr;
(void) fd;
(void) buf;
(void) cnt;
/* If fd is not stdout or stderr */
ptr->_errno = EBADF;
return -1;
}
/**
* \internal
* _read_r, read from a file.
*/
int _read_r(struct _reent *ptr, int fd, void *buf, size_t cnt)
{
(void) ptr;
(void) fd;
(void) buf;
(void) cnt;
ptr->_errno = EBADF;
return -1;
}
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,243 @@
/***************************************************************************
* Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, *
* Niccolò Izzo IU2KIN *
* Frederik Saraci IU2NRO *
* Silvano Seva IU2KWO, *
* Federico Terraneo *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
/*
* startup.cpp
* STM32 C++ startup.
* NOTE: for stm32f4 devices ONLY.
* Supports interrupt handlers in C++ without extern "C"
* Developed by Terraneo Federico, based on ST startup code.
* Additionally modified to boot Miosix.
*/
#include "interfaces/arch_registers.h"
#include "kernel/stage_2_boot.h"
#include "core/interrupts.h" //For the unexpected interrupt call
#include <string.h>
/**
* Called by Reset_Handler, performs initialization and calls main.
* Never returns.
*/
void program_startup() __attribute__((noreturn));
void program_startup()
{
//Cortex M3 core appears to get out of reset with interrupts already enabled
__disable_irq();
//SystemInit() is called *before* initializing .data and zeroing .bss
//Despite all startup files provided by ST do the opposite, there are three
//good reasons to do so:
//First, the CMSIS specifications say that SystemInit() must not access
//global variables, so it is actually possible to call it before
//Second, when running Miosix with the xram linker scripts .data and .bss
//are placed in the external RAM, so we *must* call SystemInit(), which
//enables xram, before touching .data and .bss
//Third, this is a performance improvement since the loops that initialize
//.data and zeros .bss now run with the CPU at full speed instead of 8MHz
SystemInit();
//These are defined in the linker script
extern unsigned char _etext asm("_etext");
extern unsigned char _data asm("_data");
extern unsigned char _edata asm("_edata");
extern unsigned char _bss_start asm("_bss_start");
extern unsigned char _bss_end asm("_bss_end");
//Initialize .data section, clear .bss section
unsigned char *etext=&_etext;
unsigned char *data=&_data;
unsigned char *edata=&_edata;
unsigned char *bss_start=&_bss_start;
unsigned char *bss_end=&_bss_end;
memcpy(data, etext, edata-data);
memset(bss_start, 0, bss_end-bss_start);
//Move on to stage 2
_init();
//If main returns, reboot
NVIC_SystemReset();
for(;;) ;
}
/**
* Reset handler, called by hardware immediately after reset
*/
void Reset_Handler() __attribute__((__interrupt__, noreturn));
void Reset_Handler()
{
/*
* Initialize process stack and switch to it.
* This is required for booting Miosix, a small portion of the top of the
* heap area will be used as stack until the first thread starts. After,
* this stack will be abandoned and the process stack will point to the
* current thread's stack.
*/
asm volatile("ldr r0, =_heap_end \n\t"
"msr psp, r0 \n\t"
"movw r0, #2 \n\n" //Privileged, process stack
"msr control, r0 \n\t"
"isb \n\t":::"r0");
program_startup();
}
/**
* All unused interrupts call this function.
*/
extern "C" void Default_Handler()
{
unexpectedInterrupt();
}
//System handlers
void /*__attribute__((weak))*/ Reset_Handler(); //These interrupts are not
void /*__attribute__((weak))*/ NMI_Handler(); //weak because they are
void /*__attribute__((weak))*/ HardFault_Handler(); //surely defined by Miosix
void /*__attribute__((weak))*/ MemManage_Handler();
void /*__attribute__((weak))*/ BusFault_Handler();
void /*__attribute__((weak))*/ UsageFault_Handler();
void /*__attribute__((weak))*/ SVC_Handler();
void /*__attribute__((weak))*/ DebugMon_Handler();
void /*__attribute__((weak))*/ PendSV_Handler();
void /*__attribute__((weak))*/ SysTick_Handler();
//Interrupt handlers
void __attribute__((weak)) WWDT_IRQHandler();
void __attribute__((weak)) PVM_IRQHandler();
void __attribute__((weak)) ERTC_IRQHandler();
void __attribute__((weak)) FLASH_IRQHandler();
void __attribute__((weak)) CRM_IRQHandler();
void __attribute__((weak)) EXINT1_0_IRQHandler();
void __attribute__((weak)) EXINT3_2_IRQHandler();
void __attribute__((weak)) EXINT15_4_IRQHandler();
void __attribute__((weak)) DMA1_Channel1_IRQHandler();
void __attribute__((weak)) DMA1_Channel3_2_IRQHandler();
void __attribute__((weak)) DMA1_Channel5_4_IRQHandler();
void __attribute__((weak)) ADC1_CMP_IRQHandler();
void __attribute__((weak)) TMR1_BRK_OVF_TRG_HALL_IRQHandler();
void __attribute__((weak)) TMR1_CH_IRQHandler();
void __attribute__((weak)) TMR3_GLOBAL_IRQHandler();
void __attribute__((weak)) TMR6_GLOBAL_IRQHandler();
void __attribute__((weak)) TMR14_GLOBAL_IRQHandler();
void __attribute__((weak)) TMR15_GLOBAL_IRQHandler();
void __attribute__((weak)) TMR16_GLOBAL_IRQHandler();
void __attribute__((weak)) TMR17_GLOBAL_IRQHandler();
void __attribute__((weak)) I2C1_EVT_IRQHandler();
void __attribute__((weak)) I2C2_EVT_IRQHandler();
void __attribute__((weak)) SPI1_IRQHandler();
void __attribute__((weak)) SPI2_IRQHandler();
void __attribute__((weak)) USART1_IRQHandler();
void __attribute__((weak)) USART2_IRQHandler();
void __attribute__((weak)) I2C1_ERR_IRQHandler();
void __attribute__((weak)) I2C2_ERR_IRQHandler();
//Stack top, defined in the linker script
extern char _main_stack_top asm("_main_stack_top");
//Interrupt vectors, must be placed @ address 0x00000000
//The extern declaration is required otherwise g++ optimizes it out
extern void (* const __Vectors[])();
void (* const __Vectors[])() __attribute__ ((section(".isr_vector"))) =
{
reinterpret_cast<void (*)()>(&_main_stack_top),/* Stack pointer*/
Reset_Handler,
NMI_Handler,
HardFault_Handler,
MemManage_Handler,
BusFault_Handler,
UsageFault_Handler,
0,
0,
0,
0,
SVC_Handler,
DebugMon_Handler,
0,
PendSV_Handler,
SysTick_Handler,
WWDT_IRQHandler, /* Window Watchdog Timer */
PVM_IRQHandler, /* PVM through EXINT Line detect */
ERTC_IRQHandler, /* ERTC */
FLASH_IRQHandler, /* Flash */
CRM_IRQHandler, /* CRM */
EXINT1_0_IRQHandler, /* EXINT Line 1 & 0 */
EXINT3_2_IRQHandler, /* EXINT Line 3 & 2 */
EXINT15_4_IRQHandler, /* EXINT Line 15 ~ 4 */
0, /* Reserved */
DMA1_Channel1_IRQHandler, /* DMA1 Channel 1 */
DMA1_Channel3_2_IRQHandler, /* DMA1 Channel 3 & 2 */
DMA1_Channel5_4_IRQHandler, /* DMA1 Channel 5 & 4 */
ADC1_CMP_IRQHandler, /* ADC1 & Comparator */
TMR1_BRK_OVF_TRG_HALL_IRQHandler, /* TMR1 brake overflow trigger and hall */
TMR1_CH_IRQHandler, /* TMR1 channel */
0, /* Reserved */
TMR3_GLOBAL_IRQHandler, /* TMR3 */
TMR6_GLOBAL_IRQHandler, /* TMR6 */
0, /* Reserved */
TMR14_GLOBAL_IRQHandler, /* TMR14 */
TMR15_GLOBAL_IRQHandler, /* TMR15 */
TMR16_GLOBAL_IRQHandler, /* TMR16 */
TMR17_GLOBAL_IRQHandler, /* TMR17 */
I2C1_EVT_IRQHandler, /* I2C1 Event */
I2C2_EVT_IRQHandler, /* I2C2 Event */
SPI1_IRQHandler, /* SPI1 */
SPI2_IRQHandler, /* SPI2 */
USART1_IRQHandler, /* USART1 */
USART2_IRQHandler, /* USART2 */
0, /* Reserved */
0, /* Reserved */
0, /* Reserved */
I2C1_ERR_IRQHandler, /* I2C1 Error */
0, /* Reserved */
I2C2_ERR_IRQHandler /* I2C2 Error */
};
#pragma weak WWDT_IRQHandler = Default_Handler
#pragma weak PVM_IRQHandler = Default_Handler
#pragma weak ERTC_IRQHandler = Default_Handler
#pragma weak FLASH_IRQHandler = Default_Handler
#pragma weak CRM_IRQHandler = Default_Handler
#pragma weak EXINT1_0_IRQHandler = Default_Handler
#pragma weak EXINT3_2_IRQHandler = Default_Handler
#pragma weak EXINT15_4_IRQHandler = Default_Handler
#pragma weak DMA1_Channel1_IRQHandler = Default_Handler
#pragma weak DMA1_Channel3_2_IRQHandler = Default_Handler
#pragma weak DMA1_Channel5_4_IRQHandler = Default_Handler
#pragma weak ADC1_CMP_IRQHandler = Default_Handler
#pragma weak TMR1_BRK_OVF_TRG_HALL_IRQHandler = Default_Handler
#pragma weak TMR1_CH_IRQHandler = Default_Handler
#pragma weak TMR3_GLOBAL_IRQHandler = Default_Handler
#pragma weak TMR6_GLOBAL_IRQHandler = Default_Handler
#pragma weak TMR14_GLOBAL_IRQHandler = Default_Handler
#pragma weak TMR15_GLOBAL_IRQHandler = Default_Handler
#pragma weak TMR16_GLOBAL_IRQHandler = Default_Handler
#pragma weak TMR17_GLOBAL_IRQHandler = Default_Handler
#pragma weak I2C1_EVT_IRQHandler = Default_Handler
#pragma weak I2C2_EVT_IRQHandler = Default_Handler
#pragma weak SPI1_IRQHandler = Default_Handler
#pragma weak SPI2_IRQHandler = Default_Handler
#pragma weak USART1_IRQHandler = Default_Handler
#pragma weak USART2_IRQHandler = Default_Handler
#pragma weak I2C1_ERR_IRQHandler = Default_Handler
#pragma weak I2C2_ERR_IRQHandler = Default_Handler

Wyświetl plik

@ -0,0 +1,165 @@
/*
* C++ enabled linker script
* Developed by TFT: Terraneo Federico Technologies
* Optimized for use with the Miosix kernel
*/
/*
* This linker script puts:
* - read only data and code (.text, .rodata, .eh_*) in flash
* - stacks, heap and sections .data and .bss in the internal ram
* - the external ram (if available) is not used.
*/
/*
* The main stack is used for interrupt handling by the kernel.
*
* *** Readme ***
* This linker script places the main stack (used by the kernel for interrupts)
* at the bottom of the ram, instead of the top. This is done for two reasons:
*
* - as an optimization for microcontrollers with little ram memory. In fact
* the implementation of malloc from newlib requests memory to the OS in 4KB
* block (except the first block that can be smaller). This is probably done
* for compatibility with OSes with an MMU and paged memory. To see why this
* is bad, consider a microcontroller with 8KB of ram: when malloc finishes
* up the first 4KB it will call _sbrk_r asking for a 4KB block, but this will
* fail because the top part of the ram is used by the main stack. As a
* result, the top part of the memory will not be used by malloc, even if
* available (and it is nearly *half* the ram on an 8KB mcu). By placing the
* main stack at the bottom of the ram, the upper 4KB block will be entirely
* free and available as heap space.
*
* - In case of main stack overflow the cpu will fault because access to memory
* before the beginning of the ram faults. Instead with the default stack
* placement the main stack will silently collide with the heap.
* Note: if increasing the main stack size also increase the ORIGIN value in
* the MEMORY definitions below accordingly.
*/
_main_stack_size = 0x00000200; /* main stack = 512Bytes */
_main_stack_top = 0x20000000 + _main_stack_size;
ASSERT(_main_stack_size % 8 == 0, "MAIN stack size error");
_heap_end = 0x20004000; /* end of available ram */
/* identify the Entry Point */
ENTRY(_Z13Reset_Handlerv)
/* specify the memory areas */
MEMORY
{
flash(rx) : ORIGIN = 0x08001400, LENGTH = 59K
ram(wx) : ORIGIN = 0x20000200, LENGTH = 16K - 0x200
}
/* now define the output sections */
SECTIONS
{
. = 0;
/* .text section: code goes to flash */
.text :
{
/* Startup code must go at address 0 */
KEEP(*(.isr_vector))
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
/* these sections for thumb interwork? */
*(.glue_7)
*(.glue_7t)
/* these sections for C++? */
*(.gcc_except_table)
*(.gcc_except_table.*)
*(.ARM.extab*)
*(.gnu.linkonce.armextab.*)
. = ALIGN(4);
/* .rodata: constant data */
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
/* C++ Static constructors/destructors (eabi) */
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__miosix_init_array_start = .;
KEEP (*(SORT(.miosix_init_array.*)))
KEEP (*(.miosix_init_array))
__miosix_init_array_end = .;
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
/* C++ Static constructors/destructors (elf) */
. = ALIGN(4);
_ctor_start = .;
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
_ctor_end = .;
. = ALIGN(4);
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
} > flash
/* .ARM.exidx is sorted, so has to go in its own output section. */
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > flash
__exidx_end = .;
/* .data section: global variables go to ram, but also store a copy to
flash to initialize them */
.data : ALIGN(8)
{
_data = .;
*(.data)
*(.data.*)
*(.gnu.linkonce.d.*)
. = ALIGN(8);
_edata = .;
} > ram AT > flash
_etext = LOADADDR(.data);
/* .bss section: uninitialized global variables go to ram */
_bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(.gnu.linkonce.b.*)
. = ALIGN(8);
} > ram
_bss_end = .;
_end = .;
PROVIDE(end = .);
}