2012年8月12日 星期日

新工作一年感想

一句話:突飛猛進。

工作量大,新技術不斷出現。部門人口暴增三倍。
所以就沒有多少時間寫文章了。

一邊工作,一邊找人。只是,人難找。
找嵌入式系統的人,都是做手機,不想來碰硬體。
找單晶片的人,不懂RTOS。
找馬達控制的人,幾乎沒有工作經驗。
找影像處理的人,不幸的目前無空缺。
有合的真的不多。



簡單多工3.1版


Bee用第3版發展到程式大了,使用的Task數目一多,整個反應時間就慢了。
但有不少Task其實作用時間很短,且工作量很低。
所以就加入了暫時性的工作。
其實考量了可以使用暫時性工作可以用,大部分都是暫時性工作的使用機會高。
這樣就不會一下子增加太多的工作數目,可以保持掃描率,反應不會太慢。

只是暫時性工作要除錯完成再改為暫時性管理方式。因為TaskID一直變的話是不好追蹤的。

新增程式功能說明:

#define MIN_FREE_NUM    3
設定從那一個ID數往後找

unsigned char Get_Temp_Task(void (*p_func)(void));
設定暫時性工作,傳入啟動函式,回傳可用的TaskID。
若回傳為0xFF,則是無空的Task可用。

void Task_Retire(void);
暫時性工作結束

unsigned char Check_Task_Free(unsigned char TaskID);
看工作是否為空閒,主要是用來檢查暫時性工作是否結束。


整體程式:
#include "mt.h"
#define TASK_NUM        4
#define MIN_FREE_NUM    3
extern void SimInit(void);
extern void OS_ENTER_CRITICAL(void);
extern void OS_EXIT_CRITICAL(void);

#define INIT_DEVICE()        SimInit()
#define DIS_INTR()            OS_ENTER_CRITICAL()
#define ENA_INTR()            OS_EXIT_CRITICAL()
// O.S function declaim
void Dummy(void);
unsigned char FuncID;
volatile unsigned char Task_State[TASK_NUM];
unsigned short Task_Delay_Count[TASK_NUM];
void (*TaskFunc[TASK_NUM])(void);

// O.S functions
void InitSystem(void)
{
    extern void Task1(void);
    extern void Task2(void);
    extern void Task3(void);
    unsigned char i;

    FuncID = 0;
    for ( i= 0; i< TASK_NUM ; i++)
    {
        Task_State[i] = TASK_RUNNING;
        Task_Delay_Count[i] = 0;
        TaskFunc[i] = Dummy;
    }
    TaskFunc[0] = Task1;
    TaskFunc[1] = Task2;
    TaskFunc[2] = Task3;
}

void Sleep_Next(void (*p_func)(void))
{
    TaskFunc[FuncID] = p_func;
    Task_State[FuncID] = TASK_WAIT;
}

void WakeUp(unsigned char n)
{
    Task_State[n] = TASK_RUNNING;
}

void Task_Set_Next(void (*p_func)(void))
{
    TaskFunc[FuncID]=p_func;
}

void Dummy(void)
{
    Sleep_Next(Dummy);
}

void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void))
{
    if (! n ) n = 1;
    TaskFunc[FuncID] = p_func;
    Task_Delay_Count[FuncID] = n;
    Task_State[FuncID] = TASK_DELAY;
}

void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void))
{
    if (! n ) n = 1;
    TaskFunc[FuncID] = p_func;
    Task_Delay_Count[FuncID] = n;
    Task_State[FuncID] = TASK_SKIP;
}

unsigned char Get_Temp_Task(void (*p_func)(void))
{
    int i = MIN_FREE_NUM;
    while(i < TASK_NUM )
    {
        if( TaskFunc[i] == Dummy )
        {
            TaskFunc[i] = p_func;
            return i;
        }
        i++;
    }
    return 0xff;
}

void Task_Retire(void)
{
    Sleep_Next(Dummy);
}

unsigned char Check_Task_Free(unsigned char TaskID)
{
    return ( TaskFunc[TaskID] == Dummy )? 1: 0;
}

// O.S functions end

// main loop
void main(void)
{
    INIT_DEVICE();
    InitSystem();
    while (1)
    {
        switch (Task_State[FuncID])
        {
        case TASK_RUNNING :
            TaskFunc[FuncID]();
            break;
        case TASK_SKIP :
            if ( Task_Delay_Count[FuncID] )
            {
                Task_Delay_Count[FuncID]--;
                if (! Task_Delay_Count[FuncID]) WakeUp(FuncID);
            }
            break;
        default:
            break;
        }
        if ( ++FuncID >= TASK_NUM ) FuncID = 0;
    }
}

void TimeTick(void)  // This is timer interrupt
{
    unsigned char i;

    for ( i=0; i< TASK_NUM; i++)
    {
        if ( Task_State[i] == TASK_DELAY )
        {
            if ( Task_Delay_Count[i] )
            {
                Task_Delay_Count[i]--;
                if (! Task_Delay_Count[i]) WakeUp(i);
            }
        }
    }
}



開頭檔內容:
void Sleep_Next(void (*p_func)(void));
void WakeUp(unsigned char n);
void Task_Set_Next(void (*p_func)(void));
void Task_Delay_Ms_Next(unsigned int n, void (*p_func)(void));
void Task_Set_Skip_Next(unsigned int n, void (*p_func)(void));
unsigned char Get_Temp_Task(void (*p_func)(void));
void Task_Retire(void);
unsigned char Check_Task_Free(unsigned char TaskID);

//  Task State
#define        TASK_RUNNING  0
#define        TASK_SKIP     1
#define        TASK_DELAY    2
#define        TASK_WAIT     3

// O.S. Macro
#define     SET_TASK(id,p_func)     {TaskFunc[id]=p_func;}
#define     SET_STATE(id,state)     {Task_State[id]=state;}
#define     SET_DELAY(id,n)         {Task_Delay_Count[id]=n;}

// Time Constant
#define     SKIP_CYCLE_TIME_US      (0.083)
#define     SKIP_US(x)              ((int)((x)*(1.0/SKIP_CYCLE_TIME_US)))


測試程式:
#include < stdio.h >
#include "mt.h"

unsigned char temp_count;
void TempTask(void)
{
    printf("T");
    temp_count++;
    if(temp_count < 10)
    {
        Task_Set_Skip_Next(SKIP_US(500),TempTask);
    }
    else
    {
        Task_Retire();
    }
}

void Task1(void)
{
    unsigned char task_handle;
  
    printf("G");
    temp_count = 0;
    task_handle = Get_Temp_Task(TempTask);
    WakeUp(task_handle);
    Task_Delay_Ms_Next(10,Task1);
}

void Task2(void)
{
    printf("z");
    Task_Delay_Ms_Next(1,Task2);
}

void Task3(void)
{
    printf(".");
    Task_Set_Skip_Next(SKIP_US(1000),Task3);
}


測試結果:



2012年8月5日 星期日

Cortex-M3 : 遇到HardFault該如何處理

寫Config週邊時最常遇到的是,週邊不動,不然就是HardFault。

若是發展中的程式,還知道現在正在加入的是那一個功能。

但拿到的是舊程式,出現HardFault就糟了,因為從那裏產生的都不知。

其實沒有如此糟,只要去看堆疊內容就行了。

SP+24的位置,就是產生HardFault的位址,一般會是標準函式庫。
就可以查出是那一個呼叫弄錯了。

另外SP+20則是Link Register的內容,可以進一步告知前一個呼叫函式位置。
往前追就可以看到是那一個應用程式弄錯了。

不過大概要會組合語言的人才會知道怎麼回事,原理不多說了。