C Programming for Embedded System

Introduction

Now for embedded system development people are using operating system to add more features and at the same time reduce the development time of a complex system. This article gives a simple & understandable overview of scheduling technique of embedded system programming for beginners and intermediate programmers. I am considering “C” as the programming language and an application running in a dedicated hardware/device without operating system. The binary output (*.bin file) can be directly running from the device after Power on. In this case, the time scheduling is an important part of system development. We should ensure that the right task should execute at the right time.

What is Embedded System?

An embedded system is some combination of computer hardware and software, either fixed in capability or programmable - it is specifically designed for a particular kind of application device. Or in short we can say, an embedded system is a special-purpose computer system designed to perform one or a few dedicated functions.

All embedded systems need not be a real time system. Real Time systems are those in which timeliness is as important as the correctness of the outputs. Performance estimation and reduction are crucial in real time system. By definition, we can say a real time system is a system that must satisfy explicit (bounded) response time constraints or risk severe consequences, including failure.

Embedded system plays an important part in our daily lives. Most of the people around the globe are highly dependent on different types of gadgets like mobile phones, iPods and many more. The embedded systems used in industrial machines, automobiles, medical equipment, airplanes, and vending machines have to be real time.

I thought of sharing my experience in Embedded systems. This is my first ever article on CodeProject, so I am expecting your valuable feedback and suggestions for betterment.

Background

People are using operating system (RTOS) for complex devices to make it more flexible, add more features and minimize the development time. But it will increase the cost of the device for a small application. So for small application firmware development without operating system is very much popular.

Time scheduling is an important aspect of real-time system. Real time software are executed in response to external events. This event may be periodic, in which case an appropriate scheduling of events and related task is required to guarantee performance. The scheduling strategy also depends on scheduling facilities that the chosen RTOS offers. This article emphasis on the event based technique when there was no operating system running in the device.

Scheduling

Two kinds of scheduling techniques are used in Real-Time system:

  1. Static Scheduling
  2. Dynamic Scheduling

Static Scheduling

This involves analyzing the tasks statically and determining their timing properties. This timing property can be used to create a fixed scheduling table, according to which tasks will be dispatched for execution at run time. Thus the order of execution of the task is fixed, and it is assumed that their execution time is also fixed.

Round-Robin Scheduling

Round Robin scheduling by Time Slicing is one of the ways to achieve static scheduling. Round robin is one of the simplest and most widely used scheduling algorithms; in which a small unit of time known as time slice is defined. Schedulers go around the queue of ready-to-run processes and allocate a time slice to each such process.

Scheduling with Priority

Priority indicates the urgency or importance assigned to a task. There are two approaches of scheduling based on priority based execution – when the processor is idle, the ready task with the highest priority is chosen for execution; once chosen, the task is run to completion.

Pre-Emptive Scheduling

Preemptive Priority based execution is when the processor is idle, the ready task with highest priority is chosen for execution; at any time, the execution of a task can be preempted if a task of higher priority becomes ready. Thus, at all times, the processor is idle or executing the ready task with the highest priority.

Dynamic Scheduling

Another kind of scheduling mechanism is known as Dynamic Scheduling – In this case, a real-time program requires a sequence of decisions to be taken during execution of the assignment of resource to transactions. Here each decision must be taken without prior knowledge of the needs of future tasks. Dynamic scheduling is not in the scope of this article, so I am not discussing it in detail here. Perhaps we can discuss it in another article.

Code Snippet

Let us take a example of a Master-Slave communication system. Master system is connected to n number of slave systems over serial port (RS 485 network) in multi-drop architecture. Figure 1 shows the typical configuration of this system. Here only one system can talk at a time and others are in listen mode. The Master controls the communication.

Main Routine

Collapse | Copy Code

void main(void)
{
    /* Initialise all register of processor and the peripheral devices */
    InitMain();

    /* Register the event handler */
    RegisterTask(MainEventHandler);

    RegisterTask(CheckDataIntegrity);
    ..............

    /* Turn on all the leds for 1 sec as lamp test */
    TurnOnLed(LED, 1000);

    /* Call the application event manager - no return */
    EventManager();
}

In the above case, the RegisterTast() and EventManager() are two important functions. For any application, we have number of tasks and a function represents the entry point of a task, like 'CheckDataIntegrity' . When a device receives a complete data packet, it goes for data checking. RegisterTask() function creates a link-list of function pointers where each node represents a single task. Here I have passed the function pointer MainEventHandler or CheckDataIntegrity as an argument.

Main.h should have the following lines:

Collapse | Copy Code

/* Application event handler function pointer */
typedef void (*tEventHandler)(unsigned short *);

/* Link-list definition */
typedef struct TaskRecord
{
    tEventHandler EventHandler;
    struct TaskRecord *pNext;
}tTaskRecord;

static tTaskRecord *mpTaskList = NULL;

Here mpTaskList represents a link-list of function pointers. Considering each node of link list as a entry point of a task, this will execute one by one in EventManager() function. Below is the definition of RegisterTask() function which adds the function pointer into the link-list.

Collapse | Copy Code

void RegisterTask(tEventHandler EventHandlerFunc)
{
    tTaskRecord *pNewTask;

    /* Create a new task record */
    pNewTask = malloc(sizeof(tTaskRecord));
    if(pNewTask != NULL)
    {
        /* Assign the event handler function to the task */
        pNewTask->EventHandler = EventHandlerFunc;
        pNewTask->pNext = NULL;

        if(mpTaskList == NULL)
        {
            /* Store the address of the first task in the task list */
            mpTaskList = pNewTask;
        }
        else
        {
            /* Move to the last task in the list */
            mpActiveTask = mpTaskList;
            while(mpActiveTask->pNext != NULL)
            {
                mpActiveTask = mpActiveTask->pNext;
            }

            /* Add the new task to the end of the list */
            mpActiveTask->pNext = pNewTask;
        }
    }
}

For this type of application, after initialization there should be an infinite loop for continuous execution. The function EventManager() at the end of the main which is nothing but a infinite loop always checks for active tasks or events. If any event occurs, then it passes that event flag as an argument of the function which is already added into the mpTaskList. So EventManager() function calls MainEventHandler() function with eventID as an argument. MainEventHandler will check the eventId and do the necessary action or execute the corresponding code. Here the event should be unique for each event-handler function, i.e. two event-handler functions should not check the same eventID.

Definition of EventManager Function

Collapse | Copy Code

void EventManager(void)
{
    unsigned short AllEvents;
    tTaskRecord pActiveTask

    /* No return */
    while(1)
    {
        /* Read application events */
        AllEvents = mEventID;

        /* Process any application events */
        pActiveTask = mpTaskList;
        while((AllEvents != 0) && (pActiveTask != NULL))
        {
            if(pActiveTask->EventHandler != NULL)
            {
                /* Call the task's event handler function */
                (mpActiveTask->EventHandler)(&AllEvents);

                /* Read application events */
                AllEvents = mEventID;
            }

            /* Move to the next event handler */
            pActiveTask = pActiveTask->pNext;
        }
    }
}

Event can be generated from interrupt service routine or by checking the status of an input pin in polling mode. SerialReceiveISR function generates an event after receiving the complete packet. Since the variable mEventID is modified in the interrupt service routine, it is recommended to disable interrupt while reading.

Collapse | Copy Code

#pragma interrupt_level 0
void interrupt IService(void)
{
    /* Receive bit is set when a byte is received */
    if(Receivebit == 1)
    {
        SerialReceiveISR()
    }
    ...........
    /* code for other interrupt */
}

SerialReceiveISR Function

Collapse | Copy Code

#pragma inline SerialReceiveISR
void SerialReceiveISR(void)
{
    static char RxMsgDataCount;

    /* If a framing or overrun error occurs then clear the error */
    if(Error == 1)
    {
        /* Indicate a problem was seen */
        mEventID = mEventID | ATTENTION_REQ_FLG;
    }
    else if( RxMsgCount == DataLength)
    {
        /* Packet receive complete */
        mEventID = mEventID | DATA_RECEIVE_COMPLETE;
    }
    else
    {
        /* Store data in memory */
        Store(RxByte);
        RxMsgCount++;
    }
}

Here ATTENTION_REQ_FLAG & DATA_RECEIVE_COMPLETE flags are two bits of a Global variable mEventID, which is 16 bits and each bit triggers the corresponding event when set.

Collapse | Copy Code

#define ATTENTION_REQ_FLAG  0x0008
#define DATA_RECEIVE_COMPLETE  0x0001

When the flag is set, the EventManager will call all the registered functions with the eventID as argument.

Collapse | Copy Code

void MainEventHandler(unsigned short *Event)
{
    if(*Event & DATA_RECEIVE_COMPLETE)
    {
        /* Do the corresponding action */
        .........
        /* Reset the flag */
        *Event &= ~DATA_RECEIVE_COMPLETE;
    }
}

Now we can change the variable type to increase the number of flags. If you want to generate multiple number of events, then use a structure rather than a single variable.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

时间: 2025-01-21 19:36:42

C Programming for Embedded System的相关文章

What is an Embedded System?

What is an Embedded System? Most people don't realise that the most common form of computer in use today is by far the embedded computer. In fact, 98% of computing devices are embedded in all kinds of electronic equipment and machines. Computers are

Serial Port Programming on Linux(转载)

This is a tutorial on how to program the Serial Ports on your Linux box.Serial Ports are nice little interfaces on the PC which helps you to interface your embedded system projects using a minimum number of wires.In this tutorial we will write a smal

Embedded Linux 技术与概念解析

引言 Embedded Linux技术基于开放源码的资源,并且已经是当今最重要的嵌入式应用技术之一.Embedded Linux是烧录在目标装置上的系统,1个Embedded Linux系统包含Linux kernel与 root filesystem 2大部分,Embedded Linux系统到底包含哪些组成要素构成,本文将由概念的层面进行解析. 本文 由于目前的目标装置,都必须嵌入极为复杂的功能,所以嵌入式操作系统(Embedded system)成为嵌入式系统不可或缺的要素.由于嵌入式系统

第 1 章 Developer & Programming language

1.1. System programming language A System programming language is usually used to mean "a language for system programming": that is, a language designed for writing system software as distinct from application software. http://en.wikipedia.org/w

TCL通讯上海产品创新中心职位推荐

对于以下岗位如有感兴趣的同学请将简历发送至vincent.song@tcl.com,我们的HR将会及时与您取得联系! 以下是紧急招聘职位信息: 紧急/Emergency Position Android集成工程师 Android Integration Engineer Job Description Android smartphone is in fact a very complex system, which include typically an AP (Application Pr

uboot2011.09源代码ReadMe译文

# # (C) Copyright 2000 - 2011 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. #查看建立这个工程的文件列表人 # #这个程序是自由软件,你可以重新分配它或者修改它在GNU通用公共许可证以由自由软件基#金会发布:第二版或者任何之后的版本. #本程序是分布在希望它是有用的,但没有任何保证:甚至没有隐含保证. #查看 GNU通用公共许可证对于更多的细节. #你应该收到一份GNU通用公共许可证随着这个程序:如果

《例说8051:单片机程序设计案例教程》——1-3 8051的开发流程与工具

1-3 8051的开发流程与工具 8051系统的开发流程与一般单片机的开发流程类似,其基本开发流程可分为软件与硬件两部分,而这两部分是并行开发.在硬件开发方面,主要是设计原型电路板(prototype),也就是目标板(target board).在软件开发方面,则是编写源程序(可使用C语言或汇编语言).再经过编译.汇编成为可执行代码,然后进行排错/仿真.当完成软件设计后,即可应用在线仿真器(In-Circuit Emulator,ICE),下载该可执行代码,然后在目标板上进行在线仿真.若软.硬件

Pervasive Java

Pervasive Java   引言          进入正文之前,先来点废话.          这要从那部追随我近20个月之久的Nokia 3350说起.在去年5月的某一天,就在我上公汽的那一刹那,它被迫离开了我.后来买了一部N3100,就是经常可以在公汽和校园里见到的很多人在用的那种.它是彩屏的,可以支持java游戏,准确的说它采用了Nokia S40平台,可以支持MIDP 1.0.后来买了根COM口的数据线,从PC下载些图片和铃声,然后是游戏和应用软件.期间,我一直有一个想法,就是给

数字转人民币大写算法的使用例子

闲来无事,一时心血来潮,写了个数字转人民币大写的例子.其中主要的难点是"0"在不同位置,处理的方式有所不同. 这里考虑的是整数位为最多12位,小数位2位的通用数字.也就是最小值0.00,最大值为999999999999.99. 从左往右看,首先数字在整数部第4位,第8位与第12位为"0"时,不应转化为大写"零".而在小数部的第2位也不应为零. 再者,若是某处数字为"0",那么如果其前一位也是"0"的话,则同