Introduction to Embedded System Platform

My definition of the embedded system platform is very simple: the environment in which the cause program of electronic products can be developed smoothly, including;

  • System software and drivers
  • Hardware platform
  • Development environment (compiler, debugging and download tools)
  • Emulator
  • Programming specification

Therefore, there is usually a "system platform group" in the embedded software development team, and their main tasks are:

  • System architecture design and implementation
  • Design and Implementation of Embedded Operating System
  • API design and implementation
  • Memory usage configuration (standardize the memory address range that a module or program can use)
  • Development environment design
  • Simulator design and implementation
  • System integration (integration of drivers, system programs, subsystems, library functions and applications)

  • Version production

1. System architecture design

<img src=" https://cdn.jsdelivr.net/gh/Leon1023/leon_pics/img/20201115105212.png "alt="Embedded system platform architecture diagram" style="zoom:80%;" />

(1) Before system architecture design: product specifications need to be clear

  1. Hardware specifications:
    • CPU speed: Determine the CPU speed according to the complexity of the application or algorithm;
    • Memory capacity: According to the size of the program, static space, and dynamic space;
    • Peripheral equipment performance:
  2. Product characteristics: use environment, sales area, target user group and application characteristics, scope, etc.
  3. The communication interface between the driver, system, subsystem and application layers.
  4. Whether to use an object-oriented design system
  5. Manpower and progress
  6. Quality requirements
  7. Real-time requirements
  8. Multitasking requirements
  9. Power supply, scalability, portability and other requirements

(2) Expression of system architecture: block diagram or UML

Example block diagram:

<img src=" https://cdn.jsdelivr.net/gh/Leon1023/leon_pics/img/20201115110613.png "alt="System architecture diagram example" style="zoom:80%;" />

A box corresponds to a work package, and each box can be further subdivided into smaller block diagrams, so that a work list can be generated. When designing the system architecture, we must pay attention to the following principles: API must be simple and clear; low coupling between program modules; the design scope should include unit testing and stress testing of each module; use the callback idea to allow applications to be embedded in system modules. Next, each of these boxes will be further introduced:

  • Hardware layer

This layer has two things: real hardware and simulator. The first one is a good understanding, that is, the hardware on which our program really runs. The simulator is a PC-based program that can simulate the behavior of real hardware indiscriminately, and is generally more expensive.

  • Driver layer

This layer is completely related to the hardware. In addition to realizing the function of driving peripheral devices, it also has to provide APIs that can be called by other program modules. The driver can shield all hardware features, and the upper application only needs to use the API provided by it to call the hardware device, so the driver layer is also called the hardware abstraction level (HAL).

  • Operating system layer

    ​ The OS used in embedded systems is generally called RTOS, and its functions are generally simple. Common ones are Linux, uclinux, ucOS, WinCE, etc. The reason for dividing the operating system into two parts is that the simulator must additionally simulate hardware-related functions, while the hardware-independent parts only need a set of programs.

    • Hardware related parts

    ​ The hardware-related functions include: multitasking, interrupt control, real-time clock RTC and timers.

    • Parts that have nothing to do with hardware

    ​ The hardware-related functions include: inter-process communication, synchronization mechanism, dynamic memory function, etc.

  • Graphics function library, GUI subsystem

    ​ If the product has a screen for interaction, it must provide a simple window system. GUI uses graphics function library (point, line, surface) to realize image display, and at the same time, it must have the function of processing font display.

  • Other subsystems

    ​ Network communication protocol, decompression library function, file system and other functional modules.

  • Application layer

All the layers mentioned above are system functions, except that they have nothing to do with hardware, but are general functions. But if some similar functions can be used as a dedicated module library in a certain field, it is also very beneficial for software reuse.

    • Exclusive function library functions based on product characteristics: extract many shareable modules into library functions.
    • Application layer: A program that uses the APIs provided by the above layers to implement product functions

Of course, UML can also be used to describe such an architecture. It provides a variety of diagrams to express the system from different perspectives:

View Graphics
User model view User Case Diagram
Structural model view Class Diagram
Behavioral model view Sequence Diagram (Sequence Diagram) and Collaboration Diagram (Collaboration Diagram); State Diagram (State Diagram); Activity Diagram (Activity Diagram)
Implementation model view Component Diagram
Environmental model view Deployment Diagram

(3) Data flow

<img src="https://cdn.jsdelivr.net/gh/Leon1023/leon_pics/img/20201115132618.png" style="zoom:80%;" />

  • Two input sources : the state of the peripheral device changes, and the system obtains input data through two methods: "polling" or "interrupt".
  • Trigger the driver : if the system adopts the polling method, the driver is triggered by the supervisory program; if the interrupt method is adopted, the corresponding interrupt handler (ISR) will be executed.
  • ISR judges the change of the hardware state, and transmits the message to the system layer at the same time. You can set global variables, message queues, etc.
  • The system will have an infinite loop. The job of the loop is to check or wait for the arrival of new hardware events. If there is, it will be processed, if not, it will enter idle mode.
while(1)
{
    os_MSG new_msg;
    if(os_get_msg(&new_msg))
    {
        //在消息队列中有新的消息,则处理新的消息
        os_process_msg(&new_msg);   
    }
    else
    {
        //没有新消息到达,则进入待机模式(idle mode)
        //当有新的消息到达时,系统会自动离开待机模式,并继续执行该循环语句
        drv_enter_idle_mode();
    }
}
  • The system layer decides whether to send the message to the application. The communication method can be: the application registers a callback function to the hardware event to be processed, and when it occurs within this time, the system will automatically execute the event processing function of the application.

(4) Reusability and portability

When designing the program, pay attention to separate the hardware-related and hardware-independent modules. Because hardware-independent modules can be reused in other projects, the portability and reusability of hardware-related modules are generally low. In the embedded field, hardware-related and hardware-independent modules are clearly distinguished at the design stage, and only public APIs can be used to communicate between modules. E.g:

<img src=" https://cdn.jsdelivr.net/gh/Leon1023/leon_pics/img/20201115135222.png "alt="Two levels of driver" style="zoom:80%;" />

(5) Scalability and adjustability

In embedded systems, a configuration file is usually sys_config.hused to define some macros, and then conditional compilation is used to select the modules that the system needs to include. E.g:

/************************************************
 File Name :sys_config.h
 Function: 通过定义合适的宏,去编译包含特定模块的程序
 ************************************************/

//常数定义
//
#define _HW_CONFIG_FALSE    0
#define _HW_CONFIG_TRUE     1

#define KME_MODEL_A         1
#define KME_MODEL_B         2
#define KME_MODEL_C         3

//定义产品名称
//
#define PRODUCT_NAME        KME_MODEL_B

//定义系统是否支持某些硬件的驱动程序
//
#define HW_MUSIC_MP3_SUPPORT    _HW_CONFIG_FALSE
#define HW_MR_SENSOR_SUPPORT    _HW_CONFIG_FALSE
#define HW_REMOTE_CONTROLLER_SUPPORT    _HW_CONFIG_FALSE
#define HW_SD_CARD_SUPPORT      _HW_CONFIG_FALSE

//定义LCD相关属性
//
#if (PRODUCT_NAME == KEM_MODEL_A)
    //产品2的LCD分辨率为160x160
    //
    #define LCD_RESOLUTION_WIDTH    160
    #define LCD_RESOLUTION_HEIGHT   160
#else
    #define LCD_RESOLUTION_WIDTH    160
    #define LCD_RESOLUTION_HEIGHT   240
#endif

#define LCD_LCD_COLOR_LEVEL         8
#define WITH_TOUCH_PANEL            _HW_CONFIG_TRUE

//定义相同是否支持某些子系统
//
#define SYS_TCPIP_SUPPORT           _HW_CONFIG_FALSE
#define SYS_FAT32_SUPPORT           _HW_CONFIG_FALSE
/*******************************************
 File Name :my_function.c
 Function:条件式编译范例
 ******************************************/

#include <sys_config.h>

void my_function(void)
{
    #ifdef(PRODUCT_NAME == KEM_MODEL_B)
        //和产品B有关的程序段
        //
        product_B();
   #else
        //这段程序给产品B之外的产品使用
        //
        not_product_B();
    #endif

    #if(HW_MUSIC_MP3_SUPPORT == _HW_CONFIG_TRUE)
        //和播放MP3有关的程序段
        //
        play_mp3();
    #else
        // 系统不支持MP3时采用这段程序
        //
        do_nothing();
    #endif
}

These adjustable system configurations should be formulated as early as possible in the design phase, and they must be managed in a unified manner, and the meaning of each configuration must be clearly defined, as the person responsible for the system architecture designer follows. Each configuration must be an absolutely independent module. When it is added to the system, it will not affect other program modules.

2. API and programming style design

After the design work of the system architecture and module planning is finished, each module will be handed over to the program developers for detailed design. At this time, someone must formulate the writing style of the system program and the application program!

(1) System programming style

System programs also have many style limitations, but they are not so strong overall. For example, the message-dispatcher in the aforementioned data flow architecture diagram is a product-related system module. Different products may have different requirements, but the basic program architecture should be the same. From the sample code in the design file Or pseudo code to get examples.

// sample code of message dispatcher
// - forever loop
//
void os_message_dispatcher(void)
{
    struct os_msg   new_msg;
    struct os_event new_event;
    while(1)
    {
        //取得新的消息
        //
        if(os_get_msg(&new_msg) == TRUE)
        {
            //driver层送来新的消息
            //
            new_event = os_preprocess_message(&new_msg);
            if(new_event == NULL)
                continue;   //事件已经处理,无须再网上传递
            if(new_evnet.owner != NULL)
            {
                //将事件传递给指定的应用程序或对象
                //
                os_send_sys_event(&new_event);
            }
            else
            {
                //处理新事件,方法视具体产品而定
                //1. 送给current/active AP
                //2. 送给所有的AP或对象,由其自己决定
                //
                os_process_new_event(&new_event);
            }
        }
        else
        {
            //暂时没有硬件信息,让系统进入待机模式
            //
            os_enter_idle_mode();
        }
    }
}

Therefore, when using this system to develop a product, you can directly use this example to modify it. In addition to providing examples in the system design documents, a system programming style may also be specified, which is based on the system architecture and design concepts. For example, when the system adopts a structure-oriented thinking, all modules should show the characteristic of "processing information as the main". The following is a typical program style for structural system modules:

// 系统模块程序风格规范
//重要原则:
//      声明这个模块中处理各种信息的静态函数(类似对象的method)
//      1. 这些函数只有这个模块会调用
//      2.每种信息有其专用的处理函数
//
static int xxx_msg_1_processor(struct message * new_msg);
static int xxx_msg_2_processor(struct message * new_msg);
static int xxx_msg_3_processor(struct message * new_msg);
static int xxx_msg_default_processor(struct message * new_msg);

/****************************************************
foo模块信息处理程序:foo_module_basic_message_processor
****************************************************/
int foo_module_basic_message_processor(struct message * new_msg)
{
    int msg_type = new_msg->message_type;

    switch(msg_type)
    {
        case MSG_TYPE_001:
            return xxx_msg_1_processor(new_msg);
        case MSG_TYPE_002:
            return xxx_msg_2_processor(new_msg);
        case MSG_TYPE_003:
            return xxx_msg_3_processor(new_msg);
        default:
            xxx_msg_default_processor(new_msg);       
    }
    return MSG_PASS;    //继续让其它模块处理这个消息
}
/*************************************************
foo模块信息1处理程序:foo_msg_1_processor
*************************************************/
static int foo_msg_1_processor(struct message * new_msg)
{
    //处理第一种类信息的程序代码
    //
    ...
    //已处理完毕,系统无须再将此信息送给其它模块
    return MSG_PROCESSED;
}
...

(2) Application style

The idea of ​​application programming style specification is relatively simple. There are two points to be emphasized here:

  • Formulate restrictions that should be paid attention to when writing applications, and require application programmers to comply. Such as the life cycle of the program, the resources used, etc.
  • If the application is designed with an object-oriented approach, but due to compiler limitations or performance considerations, only C language can be used for development, there will be some specifications or suggestions. I will describe it in detail in a dedicated article.

(3)API

A good API document should include:

  • Function description and scope of use of the module
  • Data structure and constant description
  • Explanation of the function, parameter and return value of each function
  • Enough examples
  • Notes and restrictions
  • related functions

E.g:

image-20201115222915437

3. Embedded operating system

Embedded operating systems include uC/OS, Embedded Linux, uCLinux, FreeRTOS, Android, etc. Most embedded operating systems are real-time operating systems, and they have the following characteristics:

  • High portability (Portable)
  • ROMable: Usually small embedded systems do not have the idea of ​​disk devices and file systems, so the system must be directly executable in ROM.
  • Adjustability (Scalable) and reorganization (Configurable)
  • Multi-Tasking and task management
  • Adjustable task scheduling algorithm (Scheduling Algorithm)
  • Task (Threads) synchronization mechanism: semaphore, Mutex, etc.
  • Inter-Task communication mechanism (IPC): message queue, mail box
  • Interrupt mechanism
  • Memory management
  • Resource management

The core task of the operating system is still task scheduling. Some embedded systems include a debugging subsystem, which can communicate with the PC program during execution, execute debugging commands or send debugging information.

(1) Task architecture of embedded system

Let’s take a product with only one main task as an example. Because the customer has a need to save power, when the main task has nothing to do, the system will sleep on its own and give control to the idle task with a lower priority, which is the responsibility of the idle task. Put the CPU into sleep mode.

When a hardware event occurs, its ISR will transfer the hardware event to the message queue of the main task. At this time, the CPU will wake up from sleep mode, the idle task will continue to execute, and then the main task will be awakened (Wakeup). Because the priority of the main task is higher, the system will transfer the CPU usage rights to the main task. The main task can handle the new hardware events. After processing, it goes back to sleep, and the system then transfers control to the idle task to enter standby mode.

The following figure illustrates the interaction diagram of task and ISR in the system and the actual pseudo code:

Diagram of the interaction between task and ISR in the system

The interaction between task and ISR in the system

image-20201115232240415

(2) Precautions for multi-task programming

A. Multitasking system execution process

Multitasking system execution flow chart

B. Timing of task scheduling

​ If it is determined to adopt a multi-tasking system, the scheduling algorithm must be determined in the design stage, and before the actual coding, each program developer must know the system scheduling algorithm. Because the programming method or synchronization mechanism used by different algorithms is different.

The three common timings that require task scheduling are:

  • At the end of the boot phase, the system must select the first task to be executed
  • System functions related to scheduling (sleep, delay, wakeup-task, wait_event, etc.)
  • After a hardware interrupt occurs, the ISR is executed.

C. Features of RTOS multitasking system

  • Multitasking system = tasks for multiple users + scheduler
  • Task execution point (enter point): a C language function
  • Active Task: Function + Context.
  • The system will store information control blocks (Task-Control-Block) of various tasks in several linked lists (lists), and the scheduler will perform scheduling according to these control blocks. As shown below:

Task-Control-Block List

D. Common scheduling algorithms for RTOS multitasking systems

Common scheduling algorithms

Before deciding which scheduling algorithm to choose, it is necessary to consider whether the task is preemptive and whether the execution sequence and execution time of the task are determinative.

E. Precautions for RTOS multitasking system

1. Choose a suitable scheduling algorithm and try to eliminate the uncertainty of the execution order between tasks;

2. Pay attention to the protection of critical section (Critical section);

Unlike Linux or Windows, it distinguishes between user mode and kernel mode, and each application has its own address space and does not interfere with each other. In an RTOS, all programs share the address space, and they may affect each other if they are not careful. Coupled with random interrupt effects, the execution sequence of the program cannot be accurately predicted. For this reason, the system must provide a protection mechanism for shared variables or a certain program segment.

Among them, prohibition of interrupts is one of the most effective protection mechanisms, but frequent prohibition of interrupts will also lead to a decrease in system real-time performance. To this end, the system provides mechanisms such as Mutex and Semaphore. But use them to prevent deadlock (deadlock) and starvation (starvation). Through modularization, reducing the complexity of the system and reducing the opportunities for variable sharing (the number of critical sections) is the king!

With the development of embedded systems nowadays, Linux is generally used as a platform for embedded systems with complex functions, so how to port the original RTOS programs to Linux? One method is to let multiple tasks on RTOS be executed in a process with Linux. Make the core function of the product can run normally on Linux, and then if you want to add extended functions, you can add process to realize it in Linux.

4. Source Tree design and program style specification

The source tree is used to standardize the structure of the source code of the entire system and decide which code file is placed in which directory. The general principle is to make the directory structure of the system program easy to use in other projects, that is, to satisfy portability. Basically, we must distinguish between hardware-related , hardware-related , product-related , and product-related . The figure below is an example:

Source Tree example

image-20201116222259912

  • Programming Style Convention (Programming Style Convention)

    ​ The so-called program style specifications not only make naming specifications, but also specify at least what information should be included in the program code and the precautions for program writing.

    • File description
    • Author and date
    • Edit resume
    • Use special conspicuous symbols to distinguish paragraphs
    • Each function must specify the purpose, the meaning of each parameter, and the meaning of the return value
    • The purpose of each global variable
    • The meaning of each element in the data structure
    • Write more comments
    • Neatly indented (use tabs instead of spaces)
    • If the for, while, and nested if statements are too long, there must be an annotation at the end of the curly brace to explain the content of the loop or judgment.
    • Don't be stingy with blank lines
    • The size of a program file is controlled at 1000-2000 lines, and the number of lines of a function is controlled at about 50 lines (one page).

    The following is an example:

// os_message_queue.c
//
/***********************************************************
程序名称:os_message_queue.c
所在目录:library/os
项目名称:Typhoon 2020
创建者  :S202001(工号)Leon George
程序用途:。。。。。。。。
版权声明:Copyright (C) KME S/W Co.Ltd. All Right Reserved
维护信息:2020/11/1  created by Leon George
         2020/11/7  Add new API - emptyQueue() by Leon George
。。。
*************************************************************/

/************************************
    INCLUDE FILE
*************************************/
#include <system_config.h>
#include <os\os_message_queue.h>

/************************************
    CONSTANT Definition
*************************************/
//常数名称的所有字母大写
//只会在本文件中用到的常数不必定义在.h文件中
//常数的详细用途解释。。。
#define OS_MSGQ_MAX_ENTRY_NO    20
。。。

/************************************
    数据结构与数据类型定义
*************************************/
//一般数据结构定义在.h文件中,除非它是静态的
//数据结构的详细用途
//
struct messageQueue
{
    //详细解释各组成元素的用途与约束
    struct message mQueue[OS_MSGO_MAX_ENTRY_NO];

    //使用时的注意事项:initial Value must be 0
    short mqFront;
    short mqRear;
}

/************************************
    Global Variable Definition
*************************************/
//“p"表示pointer
//全局变量:首字母大写
//全局变量的详细用途解释
//
struct messageQueue * pSystemMessageQueue = NULL;

/************************************
    静态函数声明
*************************************/
//静态函数不会声明在.h文件中
//静态函数的用途、参数、返回值解释
//
static void os_msgq_internal_func(...);

//用特殊显眼的符号区分程序段落
/************************************
FUNCTION NAME:os_msgq_initMessageQueue
函数用途:。。。
参数描述:。。。
返回值描述:。。。
特殊算法:。。。
注意事项:。。。
*************************************/
short os_msgq_initMessageQueue(struct messageQueue *newMQueue)
{
    //局部变量定义,尽量描述其用途
    //“p”表示指针
    //局部变量首字母小写
    struct messageQueue *pnew_MQueue = NULL;
    int i;
    if(newMQueue != NULL)
    {
        //如果又用到任何特殊技巧,一定要写明
        ...
        for(i=0; i < OS_MSGQ_MAX_ENTRY_NO; i++)
        {
            ...
        }//程序中的缩进必须整齐
    }//如果内容太长,要在结尾说明该语句内容
}
...
//end of program - os_message_queue.c
  • Header file specification (header file)

    A good header file should meet the requirement that the module can be used in its program only by looking at the header file of the module .

    • Requirements for all program documents

    • Avoid repeated definitions caused by repeated include.

    • #ifndef XXX_OS_MSG_QUEUE_H
      #define XXX_OS_MSG_QUEUE_H
      //XXX_OS_MSG_QUEUE_H是一个在其它地方不会用到或定义
      。。。实际内容
      #endif
    • Constants and macro definitions must clearly describe their purpose
    • When defining data structures (struct, union, enum) and data types (typedef), you must specify their meaning
    • The header file should only contain declarations of functions or variables, not definitions. Do not implement functions or define variables in the .h file

Coding style

There are many static testing tools that can help us review the code. For example, the C language compiler comes with a static code testing tool, and the detected problems will be pointed out with "Warning" and "error" respectively. In addition, in the embedded field, there are static code testing rules specifically for embedded C programming. The most popular one is MISRA C , which defines 21 types of 141 rules, which are divided into mandatory rules ( Required) and recommended rules (Advisory). Many embedded static test tools will contain this rule set, such as PC-Lint, LDRA Testbed, LogiScope/Rule-Check, etc.

Guess you like

Origin blog.51cto.com/14592069/2556460