Обзор безопасных микроконтроллеров 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 для отдельных автомобильных систем

Типовое распределение требований к уровню 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 исполнения

Реализация Lockstep исполнения

Не менее важным для соответствия требованиям ISO26262 является механизм ECC, обеспечивающий детектирование и/или исправление ошибок. В частности, у микроконтроллеров Flagchip используется механизм SECDED. Также важные регистры имеют трехкратную избыточность, что даёт возможность продолжить работу при повреждении одной копии. За счет этого реализуется принцип мажоритарности.

Обычно к требованиям ISO26262 относится мониторинг тактовых сигналов (CMU/CCS), критичных напряжений питания и температуры, так как они являются важными для работы MCU в целом, и могут приводить к «странным» недетектируемым событиям.

Рассмотрим подробно отладочные платы на основе безопасных микроконтроллеров FC4150 и FC7300.

Отладочная плата на FC4150

FC4150 Demo Board V2

FC4150 Demo Board V2

На плате установлен микроконтроллер с наибольшим количеством периферийных устройств и встроенным Flash — FC4150F2MBS1P144T1A.

Состав микроконтроллера FC4150

Состав микроконтроллера 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

FC7300 Demo Board

В этом микроконтроллере установлено 3 ядра: два D-Core LS M7 и один B-Core M7 по терминологии Flagchip. D-Core LS — это как раз безопасные Lockstep ядра. B-Core — обычное M7.

Состав микроконтроллера FC7300

Состав микроконтроллера 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

Окно FC_IDE с демо-примером Led Blink

Сразу хочу заметить, что мы получили в своё распоряжение версию SDK 1.2.1, поэтому всё нижеследующее относится в первую очередь к ней. В SDK встречаются ошибки, связанные с регистром в именовании файлов, что намекает на использование авторами Windows. Впрочем, всё это легко исправляется.

SDK выглядит довольно традиционно — примеры использования различных драйверов и шаблон для сборки проекта. К сожалению, Flagchip не делится библиотеками для работы с HSM, которые поставляются пресобранными в директориях _gcc_libs / _iar_libsсоответственно. Также пресобранными поставляется библиотека для работы со встроенной Flash-памятью, которая, впрочем, представляет набор обёрток для функций из ROM, которые описаны в Reference Manual.

Структура директорий SDK_FC4150

Структура директорий 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.

© Habrahabr.ru