Обзор безопасных микроконтроллеров Flagchip для автомобильной электроники
В предыдущих статьях мы уже немного касались темы требований функциональной безопасности для автомобильной электроники. Очевидно, что отказ автомобильной электронной системы ABS или ECU может привести к тяжёлым последствиям. Для автомобильной электрики/электроники был разработан стандарт ISO26262, который, в частности, содержит требования по отказу и надёжности. По этому стандарту, все устройства делятся на 4 уровня по требованиям, которые приведены в таблице ниже.
Таблица из стандарта IS26262 с detection rate для SPF/LF и FIT
ASIL-A | ASIL-B | ASIL-C | ASIL-D | |
SPF Metric | Not applicable | > 90% | > 97% | > 99% |
LF Metric | Not applicable | > 60% | > 80% | > 90% |
Failure rate | 10–6 / hour | 10–7 / hour | 10–7 / hour | 10–8 / hour |
FIT | < 1000 | < 100 | < 100 | < 10 |
Типовое распределение требований к уровню ASIL для отдельных автомобильных систем
В этой статье мы будем рассматривать один из основных управляющих элементов для построения подобных систем, а именно, микроконтроллер.
По статистике, ряд электронных устройств для автомобиля строится на микроконтроллерах общего применения, таких как STM32, ESP32 и других. Они подробно документированы, поддерживаются опытными разработчиков, но не слишком подходят для ответственного автомобильного применения.
Также ряд производителей выпускает микроконтроллеры, специально предназначенные для автомобильного сегмента. Микросхемы, которые применяются в автомобилях, должны соответствовать квалификации AEC-Q100 и иметь набор документов, связанных с функциональной безопасностью. В частности Safety Manual, в котором изложены требования к дизайну железу и софту, а также расписаны конкретные Safety Mechanisms.
К сожалению, в связи с текущей геополитической ситуацией, популярные микроконтроллеры, удовлетворяющие требованиям ISO26262, стали практически недоступны. При этом отечественная микроэлектронная промышленность только набирает обороты в производстве безопасных автомобильных микроконтроллеров.
В результате поисков доступных альтернатив мы вышли на китайского производителя Flagchip as Flagship, контроллеры которого обладают достаточно неплохими характеристиками и Safety Mechanisms для реализации автомобильных ECU с уровнем до ASIL-D при доступности для российского рынка.
Сейчас в линейке компании Flagchip есть два микроконтроллера серии Raptor (FC4150) и Rex (FC7300), характеристики которых показаны в таблице:
FC4150x | FC7300x | |
Core | 1x Cortex-M4 150MHz | Up to 6x Cortex-M7 300MHz with Lockstep capabilities |
RAM | Up to 256 KB with SECDED | Up to 512 KB with SECDED |
Flash | 512KB / 2MB with SECDED | 4 / 8 MB with SECDED |
Analog | ||
ADC | Up to 2 12bit SAR with up to 32 channel per module | Up to 2 12bit SAR with up to 32 channel per module |
CMP | Up to 3 comparators with 8bit DAC | Up to 3 comparators with 8bit DAC |
Communication | ||
UART | Up to 6 with LIN | Up to 18 with LIN |
SPI | Up to 4 with ½/4 lane Master/Slave | up to 8 with ½/4 lane with Master/Slave |
I2S | Up to 2 | - |
Network | 1 MII/RMII (Only in 2MB version) | 1 MII/RMII/RGMII |
CAN | Up to 6 with 3 CAN-FD | Up to 10 with CAN-FD |
Safety | ||
ASIL Level | Up to ASIL-B | Up to ASIL-D |
Safety Mechanism | ECC, 4x CMU, ISM, MAP, AFCB, CRC, WDOG, EIM, ERM, FWM, BIST | Lockstep, Triple critical registers, ECC, CMU, FCSMU, PMC, AFCB, CRC, WDOG, EIM, ERM, LBIST, MBIST |
Operational Conditions | ||
Voltage Range, V | 3.0 — 5.5 | 3.0 — 5.5 |
Temperature range | -40 — +125 | -40 — +125 |
Package | LQFP 64/100/144/176 | LQFP 144/176, MAPBGA 320 |
Обычно требования к электронному устройству разделяются на программные и аппаратные. Рассмотрим требования к аппаратной части MCU SEooC и отдельно остановимся на реализованных Safety Mechanisms.
Механизм HW redundancy является одним из критичных для реализации электронных блоков с уровнем ASIL-D. В отношении вычислительных ядер этот механизм реализуется через избыточность — добавление N ядер, выполняющих одинаковые операции параллельно. При отличии в результатах операции генерируется сигнал Fault. Для ASIL-D является достаточным 2 ядра в режиме Lockstep — оба ядра работают на одной тактовой частоте с одинаковыми входными данными. Наглядно это показано на рисунке ниже:
Реализация Lockstep исполнения
Не менее важным для соответствия требованиям ISO26262 является механизм ECC, обеспечивающий детектирование и/или исправление ошибок. В частности, у микроконтроллеров Flagchip используется механизм SECDED. Также важные регистры имеют трехкратную избыточность, что даёт возможность продолжить работу при повреждении одной копии. За счет этого реализуется принцип мажоритарности.
Обычно к требованиям ISO26262 относится мониторинг тактовых сигналов (CMU/CCS), критичных напряжений питания и температуры, так как они являются важными для работы MCU в целом, и могут приводить к «странным» недетектируемым событиям.
Рассмотрим подробно отладочные платы на основе безопасных микроконтроллеров FC4150 и FC7300.
Отладочная плата на FC4150
FC4150 Demo Board V2
На плате установлен микроконтроллер с наибольшим количеством периферийных устройств и встроенным Flash — FC4150F2MBS1P144T1A.
Состав микроконтроллера FC4150
Также на плате присутствует довольно большой набор периферийных устройств:
Количество | Функция | Компонент | Комментарий |
1 | CAN | NXP TJA1042T/3 | |
1 | CAN | NXP TJA1043T / Infineon TLE6251 | С поддержкой Wake / Error detection |
2 | LIN | NXP TJA1021T/20 | |
1 | EEPROM | BL24C64A-PARC | |
2 | Potentiometer | ||
3 | Blue Leds | ||
2 | RGB Leds | ||
4 | User Keys | ||
1 | SPI Flash | Gigadevice GD25Q32CSIGR | Разделяют общие пины, выбор производится перепайкой 0 омных резисторов на плате. |
1 | 100Base-TX | Motorcomm YT8512H | |
1 | 100Base-T1 | Motorcomm YT8010A |
Для подключения отладчика используется стандартный для ARM 20pin JTAG разъём с выведенными на него интерфейсами отладки JTAG и SWD.
Также на плате присутствуют 3 PLD разъёма с большим количеством User GPIO. Даже по маркировке на плате MOTOR1/MOTOR2 понятно, что они предназначены для управления BLDC моторами, что, впрочем, не мешает подключить на них что-то другое.
Также во Flash записана тестовая программа от производителя, которая при запуске пытается поднять линк на Ethernet порту и отправляет сообщения в UART.
Отладочная плата на FC7300
На плате установлен довольно мощный FC7300F8MDT2A320T1A в BGA корпусе.
FC7300 Demo Board
В этом микроконтроллере установлено 3 ядра: два D-Core LS M7 и один B-Core M7 по терминологии Flagchip. D-Core LS — это как раз безопасные Lockstep ядра. B-Core — обычное M7.
Состав микроконтроллера FC7300
Количество | Функция | Компонент | Комментарий |
5 | CAN | NXP TJA1042T/3 | |
1 | CAN | NXP TJA1043T / Infineon TLE6251 | С поддержкой Wake / Error detection |
4 | LIN | NXP TJA1021T/20 | |
1 | EEPROM | FM24C256EA1SO | |
2 | Потенциометр | ||
3 | Blue LED | ||
1 | RGB LED | ||
4 | Кнопки пользователя | ||
1 | SPI Flash | Gigadevice GD25Q32ESIGR | |
1 | 1000Base-TX | Motorcomm YT8531SH / Realtek RTL8211FS-CG | |
1 | 1000Base-T1 | Semidrive JL3113 | SGMII YT8531/RTL8211 |
Сборка прошивки для моргания светодиодами
Производитель вместе с SDK распространяет свою среду разработки FC IDE на базе opensource Eclipse:
Окно FC_IDE с демо-примером Led Blink
Сразу хочу заметить, что мы получили в своё распоряжение версию SDK 1.2.1, поэтому всё нижеследующее относится в первую очередь к ней. В SDK встречаются ошибки, связанные с регистром в именовании файлов, что намекает на использование авторами Windows. Впрочем, всё это легко исправляется.
SDK выглядит довольно традиционно — примеры использования различных драйверов и шаблон для сборки проекта. К сожалению, Flagchip не делится библиотеками для работы с HSM, которые поставляются пресобранными в директориях _gcc_libs
/ _iar_libs
соответственно. Также пресобранными поставляется библиотека для работы со встроенной Flash-памятью, которая, впрочем, представляет набор обёрток для функций из ROM, которые описаны в Reference Manual.
Структура директорий SDK_FC4150
Также производитель поставляет MCAL библиотеки, но они доступны от производителя только за отдельную плату.
Как легко можно заметить, сборка проектов предполагается в IAR, Keil или FC_SDK (среда от Flagchip на базе Eclipse + GCC), но мы планируем использовать для сборки make + GCC, то требуется небольшая доработка до приемлемого состояния. Нам понадобится arm-none-eabi-
версию gcc.
В примерах разработчики подключают в файлы проекта ./Inlclude/_driver_header.h
, включающие в себя inlcude нужных драйверов из ./Driver/include
, которые включают в себя include из ./HwA/Include
, которые включают в себя ./Device/fc/fc4xxx_.h,
содержащие уже конкретные структуры и дефайны.
./Template/Sources/main.c
мы не будем использовать, напишем свой, который будет конфигурировать клоки и мигать светодиодами:
main.c
#inlcude "_driver_header.h"
#define SOSC_CLOCK_DFT 32000U
#define FOSC_CLOCK_DFT 24000000U
#define USED_PCC_NUMBER 3U
static void Bsp_SCG_Init(void);
static void Bsp_PCC_Init(void);
int main(void)
{
Bsp_CLOCK_Init();
Bsp_Port_Gpio_Init();
while (true)
{
Bsp_Gpio_Toggle();
delay(1000U);
}
return 0;
}
void Bsp_Port_Gpio_Init(void)
{
PORT_InitType tInitStruct = {0};
/* LED0: PortC 30: MUX = GPIO output */
tInitStruct.u32PortPins = PORT_PIN_30;
tInitStruct.uPortPinMux.u32PortPinMode = PORT_GPIO_MODE;
tInitStruct.ePortGpioDir = PORT_GPIO_OUT;
tInitStruct.ePortGpioLevel = PORT_GPIO_HIGH;
PORT_InitPins(PORT_C, &tInitStruct);
/* LED1: PortD 4: MUX = GPIO output */
tInitStruct.u32PortPins = PORT_PIN_4;
PORT_InitPins(PORT_D, &tInitStruct);
/* LED2: PortB 28: MUX = GPIO output */
tInitStruct.u32PortPins = PORT_PIN_28;
PORT_InitPins(PORT_B, &tInitStruct);
}
void Bsp_Gpio_Toggle(void)
{
GPIO_Toggle(PORT_C, PORT_PIN_30);
GPIO_Toggle(PORT_D, PORT_PIN_4);
GPIO_Toggle(PORT_B, PORT_PIN_28);
}
static PCC_ClkCtrlType BSP_PCC_Config[USED_PCC_NUMBER] =
{
{PCC_CLK_PORTB, true, PCC_CLKGATE_SRC_OFF, PCC_CLK_DIV_BY1},
{PCC_CLK_PORTC, true, PCC_CLKGATE_SRC_OFF, PCC_CLK_DIV_BY1},
{PCC_CLK_PORTD, true, PCC_CLKGATE_SRC_OFF, PCC_CLK_DIV_BY1},
};
static void Bsp_SCG_Init(void)
{
SCG_FoscType tFoscCfg = {0};
SCG_SoscType tSoscCfg = {0};
SCG_FircType tFircCfg = {0};
SCG_SircType tSircCfg = {0};
SCG_Pll0Type tPll0Cfg = {0};
SCG_ClockCtrlType tClockCtrlCfg;
SCG_InitClockSrcStatus();
/* initialize SIRC setting */
tSircCfg.bLock = false;
tSircCfg.bLpen = false;
tSircCfg.bSten = false;
tSircCfg.eDivH = SCG_ASYNCCLOCKDIV_BY1;
tSircCfg.eDivM = SCG_ASYNCCLOCKDIV_BY4;
SCG_SetSIRC(&tSircCfg);
/* initialize SOSC setting */
tSoscCfg.bBypass = false;
tSoscCfg.bEnable = true;
tSoscCfg.bLock = false;
tSoscCfg.u32XtalFreq = SOSC_CLOCK_DFT;
SCG_SetSOSC(&tSoscCfg);
/* initialize FOSC setting */
tFoscCfg.bBypass = false;
tFoscCfg.bEnable = true;
tFoscCfg.bLock = false;
tFoscCfg.eDivH = SCG_ASYNCCLOCKDIV_BY1;
tFoscCfg.eDivM = SCG_ASYNCCLOCKDIV_BY4;
tFoscCfg.eDivL = SCG_ASYNCCLOCKDIV_BY8;
tFoscCfg.u32XtalFreq = FOSC_CLOCK_DFT;
SCG_SetFOSC(&tFoscCfg);
/* initialize PLL0 clock frequency setting */
/* input frequency as FOSC, currently on board is 24Mhz
pre-divider is 4, multiplier is 50.
output clock is 24/4*50/2=150Mhz */
tPll0Cfg.bLock = false;
tPll0Cfg.bEnable = true;
tPll0Cfg.bCm = true;
tPll0Cfg.bCmre = true;
tPll0Cfg.bSten = true;
tPll0Cfg.eSrc = SCG_PLL0SOURCE_FOSC;
tPll0Cfg.eDivH = SCG_ASYNCCLOCKDIV_BY1;
tPll0Cfg.eDivM = SCG_ASYNCCLOCKDIV_BY2;
tPll0Cfg.ePrediv = SCG_PLL0PREDIV_BY4;
tPll0Cfg.eMult = SCG_PLL0MULTIPLY_BY50;
SCG_SetPLL0(&tPll0Cfg);
tClockCtrlCfg.bSysClkMonitor = true;
tClockCtrlCfg.eSrc = SCG_CLOCK_SRC_PLL0;
tClockCtrlCfg.eClkOutSrc = SCG_CLOCKOUT_SRC_SIRC;
tClockCtrlCfg.eDivCore = SCG_CLOCK_DIV_BY1;
tClockCtrlCfg.eDivBus = SCG_CLOCK_DIV_BY4;
tClockCtrlCfg.eDivSlow = SCG_CLOCK_DIV_BY8;
tClockCtrlCfg.eNvmClkSrc = SCG_NVMCLK_SRC_FIRC;
SCG_SetClkCtrl(&tClockCtrlCfg);
SCG_SetClkOut(&tClockCtrlCfg);
/* initialize FIRC setting */
tFircCfg.eDivH = SCG_ASYNCCLOCKDIV_BY1;
tFircCfg.eDivM = SCG_ASYNCCLOCKDIV_BY4;
tFircCfg.bEnable = true;
tFircCfg.bLock = false;
SCG_SetFIRC(&tFircCfg);
}
static void Bsp_PCC_Init(void)
{
uint8_t i;
PCC_InitClockSrcStatus();
for (i = 0U; i < USED_PCC_NUMBER; i++)
{
PCC_SetPcc(&BSP_PCC_Config[i]);
}
}
void Bsp_CLOCK_Init(void)
{
Bsp_SCG_Init();
Bsp_PCC_Init();
}
Для сборки нам понадобятся Startup_FC4150.S
и скрипт линкера FC4150_2M_ram.ld
, которые мы можем позаимствовать из проекта, который генерируется FC_IDE или любого примера. Тут следует обратить внимание, что файл имеет расширение .S
и содержит в себе директивы препроцессора, поэтому собирать его надо gcc.
Startup_FC4150.S
/******************************************
this startup is only adapt to flagchip FC100 with FC IDE
Author: Beatfan
******************************************/
.syntax unified
.arch armv7-m
/**************************************************************/
/******************** set vector table ***********************/
.section .isr_vector
.align 2
.globl __isr_vector
/* vector table */
__isr_vector:
.long __StackTop /* Top of Stack */
.long Reset_Handler /* Reset Handler */
.long NMI_Handler /* NMI Handler */
.long HardFault_Handler /* Hard Fault Handler */
.long MemManage_Handler /* MPU Fault Handler */
.long BusFault_Handler /* Bus Fault Handler */
.long UsageFault_Handler /* Usage Fault Handler */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long 0 /* Reserved */
.long SVC_Handler /* SVCall Handler */
.long DebugMon_Handler /* Debug Monitor Handler */
.long 0 /* Reserved */
.long PendSV_Handler /* PendSV Handler */
.long SysTick_Handler /* SysTick Handler */
/* External Interrupts*/
.long DMA0_IRQHandler /* DMA channel 0 transfer complete */
.long DMA1_IRQHandler /* DMA channel 1 transfer complete */
.long DMA2_IRQHandler /* DMA channel 2 transfer complete */
.long DMA3_IRQHandler /* DMA channel 3 transfer complete */
.long DMA4_IRQHandler /* DMA channel 4 transfer complete */
.long DMA5_IRQHandler /* DMA channel 5 transfer complete */
.long DMA6_IRQHandler /* DMA channel 6 transfer complete */
.long DMA7_IRQHandler /* DMA channel 7 transfer complete */
.long DMA8_IRQHandler /* DMA channel 8 transfer complete */
.long DMA9_IRQHandler /* DMA channel 9 transfer complete */
.long DMA10_IRQHandler /* DMA channel 10 transfer complete */
.long DMA11_IRQHandler /* DMA channel 11 transfer complete */
.long DMA12_IRQHandler /* DMA channel 12 transfer complete */
.long DMA13_IRQHandler /* DMA channel 13 transfer complete */
.long DMA14_IRQHandler /* DMA channel 14 transfer complete */
.long DMA15_IRQHandler /* DMA channel 15 transfer complete */
.long DMA_Error_IRQHandler /* DMA error interrupt channels 0-15 */
.long MCM_IRQHandler /* FPU sources */
.long FC_IRQHandler /* FC Command complete */
.long LVD_LVW_IRQHandler /* PMC Low voltage detect interrupt */
.long WDOG0_IRQHandler /* interrupt request out before wdg reset out */
.long WDOG1_IRQHandler /* interrupt request out before wdg reset out */
.long FWM_IRQHandler /* FWM output as interrupt */
.long RCM_IRQHandler /* RCM Asynchronous Interrupt */
.long FCIIC0_IRQHandler /* FCIIC0 Interrupt */
.long FCIIC1_IRQHandler /* FCIIC1 Interrupt */
.long FCSPI0_IRQHandler /* FCSPI0 Interrupt */
.long FCSPI1_IRQHandler /* FCSPI1 Interrupt */
.long FCSPI2_IRQHandler /* FCSPI2 Interrupt */
.long FCUART0_RxTx_IRQHandler /* FCUART0 Transmit / Receive Interrupt */
.long FCUART1_RxTx_IRQHandler /* FCUART1 Transmit / Receive Interrupt */
.long FCUART2_RxTx_IRQHandler /* FCUART2 Transmit / Receive Interrupt */
.long ADC0_IRQHandler /* ADC0 interrupt request. */
.long ADC1_IRQHandler /* ADC1 interrupt request. */
.long CMP0_IRQHandler /* CMP0 interrupt request */
.long CMP1_IRQHandler /* CMP1 interrupt request */
.long CMP2_IRQHandler /* CMP2 interrupt request */
.long ERM_fault_IRQHandler /* ERM single/double bit error correction */
.long INTM_IRQHandler /* INTM alarm interrupt */
.long RTC_IRQHandler /* RTC alarm interrupt */
.long RTC_Seconds_IRQHandler /* RTC seconds interrupt */
.long FCPIT0_IRQHandler /* FCPIT0 interrupt */
.long PTIMER0_IRQHandler /* PTIMER0 interrupt */
.long PTIMER1_IRQHandler /* PTIMER1 interrupt */
.long I2S0_IRQHandler /* I2S0 Interrupt */
.long I2S1_IRQHandler /* I2S1 Interrupt */
.long SCG_IRQHandler /* SCG bus interrupt request */
.long AONTIMER_IRQHandler /* AONTIMER interrupt request */
.long PORTA_IRQHandler /* Port A pin detect interrupt */
.long PORTB_IRQHandler /* Port B pin detect interrupt */
.long PORTC_IRQHandler /* Port C pin detect interrupt */
.long PORTD_IRQHandler /* Port D pin detect interrupt */
.long PORTE_IRQHandler /* Port E pin detect interrupt */
.long SWI_IRQHandler /* Software interrupt */
.long QSPI_IRQHandler /* QSPI All interrupts ORed output */
.long RESERVED_55_IRQHandler /* Reserved */
.long RESERVED_56_IRQHandler /* Reserved */
.long RESERVED_57_IRQHandler /* Reserved */
.long RESERVED_58_IRQHandler /* Reserved */
.long RESERVED_59_IRQHandler /* Reserved */
.long CAN0_IRQHandler /* CAN0 Interrupt */
.long CAN1_IRQHandler /* CAN1 Interrupt */
.long CAN2_IRQHandler /* CAN2 Interrupt */
.long CAN3_IRQHandler /* Reserved */
.long CAN4_IRQHandler /* Reserved */
.long CAN5_IRQHandler /* Reserved */
.long FTU0_IRQHandler /* FTU0 all source interrupt */
.long FTU1_IRQHandler /* FTU1 all source interrupt */
.long FTU2_IRQHandler /* FTU2 all source interrupt */
.long FTU3_IRQHandler /* FTU3 all source interrupt */
.long FTU4_IRQHandler /* FTU4 all source interrupt */
.long FTU5_IRQHandler /* FTU5 all source interrupt */
.long FTU6_IRQHandler /* FTU6 all source interrupt */
.long FTU7_IRQHandler /* FTU7 all source interrupt */
.long HSM0_IRQHandler /* Crypto interrupt */
.long TSTAMP0_IRQHandler /* TimerStamp0 interrupt */
.long RESERVED_75_IRQHandler /* Cordic Accelator interrupt */
.long CMU0_IRQHandler /* CMU0 interrupt */
.long CMU1_IRQHandler /* CMU1 interrupt */
.long CMU2_IRQHandler /* CMU2 interrupt */
.long CMU3_IRQHandler /* CMU3 interrupt */
.long ISM0_IRQHandler
.long FCSPI3_IRQHandler /* FCSPI3 Interrupt */
.long FCUART3_RxTx_IRQHandler /* FCUART3 Transmit / Receive Interrupt */
.long FCUART4_RxTx_IRQHandler /* FCUART4 Transmit / Receive Interrupt */
.long FCUART5_RxTx_IRQHandler /* FCUART5 Transmit / Receive Interrupt */
.long TSTAMP1_IRQHandler /* TimerStamp1 interrupt */
.long TMU0_IRQHandler /* Temperature sensor monitor interrupt */
.long ENET_Tx0_IRQHandler /* ENET 1588 Timer Interrupt - synchronous */
.long ENET_Tx1_IRQHandler /* ENET Data transfer done */
.long ENET_Rx0_IRQHandler /* ENET Receive Buffer Done for Ring/Queue 0 */
.long ENET_Rx1_IRQHandler /* ENET Receive Buffer Done for Ring/Queue 0 */
.long ENET_System_IRQHandler /* ENET Payload receive error.*/
.long DefaultISR /* 163 */
.long DefaultISR /* 164 */
.long DefaultISR /* 165 */
.long DefaultISR /* 166 */
.long DefaultISR /* 167 */
.long DefaultISR /* 168 */
.long DefaultISR /* 169 */
.long DefaultISR /* 170 */
.long DefaultISR /* 171 */
.long DefaultISR /* 172 */
.long DefaultISR /* 173 */
.long DefaultISR /* 174 */
.long DefaultISR /* 175 */
.long DefaultISR /* 176 */
.long DefaultISR /* 177 */
.long DefaultISR /* 178 */
.long DefaultISR /* 179 */
.long DefaultISR /* 180 */
.long DefaultISR /* 181 */
.long DefaultISR /* 182 */
.long DefaultISR /* 183 */
.long DefaultISR /* 184 */
.long DefaultISR /* 185 */
.long DefaultISR /* 186 */
.long DefaultISR /* 187 */
.long DefaultISR /* 188 */
.long DefaultISR /* 189 */
.long DefaultISR /* 190 */
.long DefaultISR /* 191 */
.long DefaultISR /* 192 */
.long DefaultISR /* 193 */
.long DefaultISR /* 194 */
.long DefaultISR /* 195 */
.long DefaultISR /* 196 */
.long DefaultISR /* 197 */
.long DefaultISR /* 198 */
.long DefaultISR /* 199 */
.long DefaultISR /* 200 */
.long DefaultISR /* 201 */
.long DefaultISR /* 202 */
.long DefaultISR /* 203 */
.long DefaultISR /* 204 */
.long DefaultISR /* 205 */
.long DefaultISR /* 206 */
.long DefaultISR /* 207 */
.long DefaultISR /* 208 */
.long DefaultISR /* 209 */
.long DefaultISR /* 210 */
.long DefaultISR /* 211 */
.long DefaultISR /* 212 */
.long DefaultISR /* 213 */
.long DefaultISR /* 214 */
.long DefaultISR /* 215 */
.long DefaultISR /* 216 */
.long DefaultISR /* 217 */
.long DefaultISR /* 218 */
.long DefaultISR /* 219 */
.long DefaultISR /* 220 */
.long DefaultISR /* 221 */
.long DefaultISR /* 222 */
.long DefaultISR /* 223 */
.long DefaultISR /* 224 */
.long DefaultISR /* 225 */
.long DefaultISR /* 226 */
.long DefaultISR /* 227 */
.long DefaultISR /* 228 */
.long DefaultISR /* 229 */
.long DefaultISR /* 230 */
.long DefaultISR /* 231 */
.long DefaultISR /* 232 */
.long DefaultISR /* 233 */
.long DefaultISR /* 234 */
.long DefaultISR /* 235 */
.long DefaultISR /* 236 */
.long DefaultISR /* 237 */
.long DefaultISR /* 238 */
.long DefaultISR /* 239 */
.long DefaultISR /* 240 */
.long DefaultISR /* 241 */
.long DefaultISR /* 242 */
.long DefaultISR /* 243 */
.long DefaultISR /* 244 */
.long DefaultISR /* 245 */
.long DefaultISR /* 246 */
.long DefaultISR /* 247 */
.long DefaultISR /* 248 */
.long DefaultISR /* 249 */
.long DefaultISR /* 250 */
.long DefaultISR /* 251 */
.long DefaultISR /* 252 */
.long DefaultISR /* 253 */
.long DefaultISR /* 254 */
.long 0xFFFFFFFF /* Reserved for user TRIM value */
.size __isr_vector, . - __isr_vector
/**************************************************************/
/************************ set other ***************************/
.text
.thumb
/* Reset Handler */
.thumb_func
.align 2
.globl Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
cpsid i /* Mask interrupts */
/* Init the rest of the registers */
ldr r1,=0
ldr r2,=0
ldr r3,=0
ldr r4,=0
ldr r5,=0
ldr r6,=0
ldr r7,=0
mov r8,r7
mov r9,r7
mov r10,r7
mov r11,r7
mov r12,r7
/* lock SEC */
ldr r0,=0x4001400C
ldr r1,=0x000000AA
str r1,[r0,#0]
/* disable all wdog*/
ldr r0,=0x40052000
ldr r1,=0x2920
str r1,[r0,#0]
ldr r0,=0x40052008
ldr r1,=0xF000
str r1,[r0,#0]
ldr r0,=0x40053000
ldr r1,=0x2920
str r1,[r0,#0]
ldr r0,=0x40053008
ldr r1,=0xF000
str r1,[r0,#0]
/* clear RTC interrupt */
ldr r0,=0x400650f4;
ldr r1,=0x40000000;
str r1,[r0,#0]
ldr r0,=0x4003d000;
ldr r1,=0xFFFFFFFF;
str r1,[r0,#0]
ldr r0,=0x400650f4;
ldr r1,=0x00000000;
str r1,[r0,#0]
/* Initialize the stack pointer */
ldr r0,=__StackTop
mov sp,r0 /* sp=r13 */
/* ########################################################################################### */
/* ##################################### RAM Operation ##################################### */
/* if start from flash, do ram initial */
#ifdef START_FROM_FLASH
/***************** Clear All RAM ******************/
/* Clear RAM_U. */
ldr r2, =__RAM_L_START__
ldr r4, =__RAM_L_END__
movs r3, #0
b LoopFillZero_RAM_L
.align 2
FillZero_RAM_L:
str r3, [r2]
adds r2, r2, #4
LoopFillZero_RAM_L:
cmp r2, r4
bcc FillZero_RAM_L
/* Clear RAM_U. */
ldr r2, =__RAM_U_START__
ldr r4, =__RAM_U_END__
movs r3, #0
b LoopFillZero_RAM_U
.align 2
FillZero_RAM_U:
str r3, [r2]
adds r2, r2, #4
LoopFillZero_RAM_U:
cmp r2, r4
bcc FillZero_RAM_U
#endif
/***************** Clear Stack ******************/
/* Clear Stack. */
ldr r2, =__StackLimit
ldr r4, =__StackTop
movs r3, #0
b LoopFillZero_STACK
.align 2
FillZero_STACK:
str r3, [r2]
adds r2, r2, #4
LoopFillZero_STACK:
cmp r2, r4
bcc FillZero_STACK
/*************** copy data initial value from Flash *********************/
/* Loop to copy data from read only memory to RAM. The ranges
* of copy from/to are specified by following symbols evaluated in
* linker script.
* __etext: End of code section, i.e., begin of data sections to copy from.
* __data_start__/__data_end__: RAM address range that data should be
* copied to. Both must be aligned to 4 bytes boundary. */
ldr r1, =__etext
ldr r2, =__data_start__
ldr r3, =__data_end__
.align 2
.flash_to_ram_loop:
cmp r2, r3
ittt lt
ldrlt r0, [r1], #4
strlt r0, [r2], #4
blt .flash_to_ram_loop
/*************** copy data initial value from Flash *********************/
/* initial bss data to RAM. The ranges
* are specified by following symbols evaluated in
* linker script.
* __bss_start__/__bss_end__: RAM address range that data should be
* copied to. Both must be aligned to 4 bytes boundary. */
ldr r2, =__bss_start__
ldr r3, =__bss_end__
.align 2
.bss_ram_loop:
cmp r2, r3
ittt lt
ldrlt r0, =0
strlt r0, [r2], #4
blt .bss_ram_loop
ldr r1, =__interrupts_start__
ldr r2, =__interrupts_ram_start__
ldr r3, =__interrupts_ram_end__
.align 2
.vector_copy:
cmp r2, r3
ittt lt
ldrlt r0, [r1], #4
strlt r0, [r2], #4
blt .vector_copy
/* ##################################### RAM Operation ##################################### */
/* ########################################################################################### */
/* initial interrupt table to RAM */
ldr r0,=IntMgr_Init
blx r0
cpsie i /* Unmask interrupts */
bl main
JumpToSelf:
b JumpToSelf
.pool
.size Reset_Handler, . - Reset_Handler
.align 1
.thumb_func
.weak DefaultISR
.type DefaultISR, %function
DefaultISR:
b DefaultISR
.size DefaultISR, . - DefaultISR
/* Macro to define default handlers. Default handler
* will be weak symbol and just dead loops. They can be
* overwritten by other handlers */
.macro def_irq_handler handler_name
.weak \handler_name
.set \handler_name, DefaultISR
.endm
/* Exception Handlers */
def_irq_handler NMI_Handler
def_irq_handler HardFault_Handler
def_irq_handler MemManage_Handler
def_irq_handler BusFault_Handler
def_irq_handler UsageFault_Handler
def_irq_handler SVC_Handler
def_irq_handler DebugMon_Handler
def_irq_handler PendSV_Handler
def_irq_handler SysTick_Handler
def_irq_handler DMA0_IRQHandler
def_irq_handler DMA1_IRQHandler
def_irq_handler DMA2_IRQHandler
def_irq_handler DMA3_IRQHandler
def_irq_handler DMA4_IRQHandler
def_irq_handler DMA5_IRQHandler
def_irq_handler DMA6_IRQHandler
def_irq_handler DMA7_IRQHandler
def_irq_handler DMA8_IRQHandler
def_irq_handler DMA9_IRQHandler
def_irq_handler DMA10_IRQHandler
def_irq_handler DMA11_IRQHandler
def_irq_handler DMA12_IRQHandler
def_irq_handler DMA13_IRQHandler
def_irq_handler DMA14_IRQHandler
def_irq_handler DMA15_IRQHandler
def_irq_handler DMA_Error_IRQHandler
def_irq_handler MCM_IRQHandler
def_irq_handler FC_IRQHandler
def_irq_handler LVD_LVW_IRQHandler
def_irq_handler WDOG0_IRQHandler
def_irq_handler WDOG1_IRQHandler
def_irq_handler FWM_IRQHandler
def_irq_handler RCM_IRQHandler
def_irq_handler FCIIC0_IRQHandler
def_irq_handler FCIIC1_IRQHandler
def_irq_handler FCSPI0_IRQHandler
def_irq_handler FCSPI1_IRQHandler
def_irq_handler FCSPI2_IRQHandler
def_irq_handler FCUART0_RxTx_IRQHandler
def_irq_handler FCUART1_RxTx_IRQHandler
def_irq_handler FCUART2_RxTx_IRQHandler
def_irq_handler ADC0_IRQHandler
def_irq_handler ADC1_IRQHandler
def_irq_handler CMP0_IRQHandler
def_irq_handler CMP1_IRQHandler
def_irq_handler CMP2_IRQHandler
def_irq_handler ERM_fault_IRQHandler
def_irq_handler INTM_IRQHandler
def_irq_handler RTC_IRQHandler
def_irq_handler RTC_Seconds_IRQHandler
def_irq_handler FCPIT0_IRQHandler
def_irq_handler PTIMER0_IRQHandler
def_irq_handler PTIMER1_IRQHandler
def_irq_handler I2S0_IRQHandler
def_irq_handler I2S1_IRQHandler
def_irq_handler SCG_IRQHandler
def_irq_handler AONTIMER_IRQHandler
def_irq_handler PORTA_IRQHandler
def_irq_handler PORTB_IRQHandler
def_irq_handler PORTC_IRQHandler
def_irq_handler PORTD_IRQHandler
def_irq_handler PORTE_IRQHandler
def_irq_handler SWI_IRQHandler
def_irq_handler QSPI_IRQHandler
def_irq_handler RESERVED_55_IRQHandler
def_irq_handler RESERVED_56_IRQHandler
def_irq_handler RESERVED_57_IRQHandler
def_irq_handler RESERVED_58_IRQHandler
def_irq_handler RESERVED_59_IRQHandler
def_irq_handler CAN0_IRQHandler
def_irq_handler CAN1_IRQHandler
def_irq_handler CAN2_IRQHandler
def_irq_handler CAN3_IRQHandler
def_irq_handler CAN4_IRQHandler
def_irq_handler CAN5_IRQHandler
def_irq_handler FTU0_IRQHandler
def_irq_handler FTU1_IRQHandler
def_irq_handler FTU2_IRQHandler
def_irq_handler FTU3_IRQHandler
def_irq_handler FTU4_IRQHandler
def_irq_handler FTU5_IRQHandler
def_irq_handler FTU6_IRQHandler
def_irq_handler FTU7_IRQHandler
def_irq_handler HSM0_IRQHandler
def_irq_handler TSTAMP0_IRQHandler
def_irq_handler RESERVED_75_IRQHandler
def_irq_handler CMU0_IRQHandler
def_irq_handler CMU1_IRQHandler
def_irq_handler CMU2_IRQHandler
def_irq_handler CMU3_IRQHandler
def_irq_handler ISM0_IRQHandler
def_irq_handler FCSPI3_IRQHandler
def_irq_handler FCUART3_RxTx_IRQHandler
def_irq_handler FCUART4_RxTx_IRQHandler
def_irq_handler FCUART5_RxTx_IRQHandler
def_irq_handler TSTAMP1_IRQHandler
def_irq_handler TMU0_IRQHandler
def_irq_handler ENET_Tx0_IRQHandler
def_irq_handler ENET_Tx1_IRQHandler
def_irq_handler ENET_Rx0_IRQHandler
def_irq_handler ENET_Rx1_IRQHandler
def_irq_handler ENET_System_IRQHandler
.end
FC4150_2M_ram.ld
/* Linker script to place sections and symbol values. Should be used together
* with other linker script that defines memory regions FLASH and RAM.
* It references following symbols, which must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines following symbols, which code can use without definition:
* __exidx_start
* __exidx_end
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
*/
/* Entry Point */
ENTRY(Reset_Handler)
__RAM_VECTOR_TABLE_SIZE = 0x0400;
HEAP_SIZE = 0x400;
STACK_SIZE = 0x400;
/* Specify the memory areas */
MEMORY
{
/* Flash */
FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 2M
/* SRAM_L */
RAM_L (RW) : ORIGIN = 0x02000000, LENGTH = 64K
/* SRAM_U */
RAM_U (RW) : ORIGIN = 0x20000000, LENGTH = 192K
}
/* Define output sections */
SECTIONS
{
/* The program code and other data goes into internal flash */
.text :
{
. = ALIGN(1024); /* VTOR must be align to 1K */
__VECTOR_TABLE = .;
__interrupts_start__ = .;
. = ALIGN(4);
KEEP(*(.isr_vector))
__interrupts_end__ = .;
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.init) /* section used in crti.o files */
*(.fini) /* section used in crti.o files */
*(.eh_frame) /* section used in crtbegin.o files */
. = ALIGN(4);
} > RAM_U
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
__exidx_end = .;
__etext = .;
.interrupts_ram :
{
. = ALIGN(1024); /* VTOR must be align to 1K */
__VECTOR_RAM = .;
__RAM_START = .;
__interrupts_ram_start__ = .; /* Create a global symbol at data start. */
*(.m_interrupts_ram) /* This is a user defined section. */
. += __RAM_VECTOR_TABLE_SIZE;
. = ALIGN(4);
__interrupts_ram_end__ = .; /* Define a global symbol at data end. */
} > RAM_L
.data : AT (__etext)
{
__data_start__ = .;
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM_U
.bss :
{
__bss_start__ = .;
*(.bss*)
*(COMMON)
__bss_end__ = .;
} > RAM_U
.heap :
{
. = ALIGN(8);
__HeapBegin = .;
_end = .;
end = _end;
. += HEAP_SIZE;
. = ALIGN(8);
__HeapLimit = .;
} > RAM_L
.stack_dummy :
{
. = ALIGN(8);
__StackLimit = .;
. += STACK_SIZE;
. = ALIGN(8);
__StackTop = .;
} > RAM_L
__RAM_L_START__ = ORIGIN(RAM_L);
__RAM_L_END__ = ORIGIN(RAM_L)+LENGTH(RAM_L)-1;
__RAM_U_START__ = ORIGIN(RAM_U);
__RAM_U_END__ = ORIGIN(RAM_U)+LENGTH(RAM_U)-1;
.ARM.attributes 0 : { *(.ARM.attributes) }
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with STACK")
}
После сборки всех объектных файлов, линкуем их с использованием скрипта линкера FC4150_2M_ram.ld
, в котором код секции text / rodata / init располагается в SRAM с адреса 0×20000000.
Заливаем код в SRAM, записываем в регистры PC и SP значения по смещению +0 и +4 соответственно и продолжаем выполнение.
openocd -f /usr/share/openocd/scripts/interface/jlink.cfg -f ./openocd/fc4150.cfg -c "init" -c "reset halt" -c "load_image out/main.elf" -c "reg pc [mdw 0x20000004]" -c "reg sp [mdw 0x20000000]" -c "resume"
Запускаем openocd и наблюдаем за миганием светодиодов на плате.
Демонстрация работы
Заключение
Flagchip производит безопасные микроконтроллеры, которые доступны в РФ и подходят для для применения в автомобильной промышленности. Это особенно актуально в текущей ситуации, когда многие компании прекратили поставки собственных микроконтроллеров на наш рынок.
С помощью отладочных плат на базе безопасных микроконтроллеров Flagchip можно достаточно хорошо изучить и опробовать возможности данных чипов и убедиться в возможности сборки на них собственных приложений.
Применение данных микроконтроллеров может существенно повысить надежность и безопасность устройств автомобильной электроники с учетом их соответствия требованиям ISO-26262.