1. 程式人生 > >TMS320C6474學習總結(五)----DSP/BIOS自帶例程 mailbox exampe 詳解

TMS320C6474學習總結(五)----DSP/BIOS自帶例程 mailbox exampe 詳解

附上例程的主程式:

 
#include <std.h>

#include <log.h>
#include <mbx.h>
#include <tsk.h>

#include "mailboxcfg.h"


#define NUMMSGS         3       /* number of messages */

#define TIMEOUT         10

typedef struct MsgObj {
    Int         id;             /* writer task id */
    Char        val;            /* message value */
} MsgObj, *Msg;


Void reader(Void);
Void writer(Arg id_arg);

/*
 *  ======== main ========
 */
Void main()
{
    /* Does nothing */
}

/*
 *  ======== reader ========
 */
Void reader(Void)
{
    MsgObj      msg;
    Int         i;

    for (i=0; ;i++) {

        /* wait for mailbox to be posted by writer() */
        if (MBX_pend(&mbx, &msg, TIMEOUT) == 0) {
            LOG_printf(&trace, "timeout expired for MBX_pend()");
            break;
        }

        /* print value */
        LOG_printf(&trace, "read '%c' from (%d).", msg.val, msg.id);
    }
    LOG_printf(&trace, "reader done.");
}

/*
 *  ======== writer ========
 */
Void writer(Arg id_arg)
{
    MsgObj      msg;
    Int         i;
    Int id =    ArgToInt (id_arg);

    for (i=0; i < NUMMSGS; i++) {
        /* fill in value */
        msg.id = id;
        msg.val = i % NUMMSGS + (Int)('a');

        /* enqueue message */
        MBX_post(&mbx, &msg, TIMEOUT);
       
        LOG_printf(&trace, "(%d) writing '%c' ...", id, (Int)msg.val);

        /* what happens if you call TSK_yield() here? */
        // TSK_yield();
    }

   // LOG_printf(&trace, "writer (%d) done.", id);
}

程式建立了四個任務,一個 reader 任務,三個 writer 任務,三個 writer 任務呼叫的是同一個任務函式 writer(),但傳遞的函式引數是不同的,分別是0,1,2;四個任務的優先順序是一樣的,任務建立順序是:reader->writer0->writer1->writer2。郵箱大小為8位元組,2個字的長度。

程式執行結果如下:

下面我們就來分析下這個demo是如何得到上述結果的:首先我們要清楚程式執行的順序是怎樣的,在這裡我簡單畫一個程式的流程圖。

        程式在執行完main()函式後,最先執行的是reader()函式,在執行MBX_pend函式時發現郵箱內為空,故此任務被阻塞,只有等到系統呼叫MBX_post函式後才可以繼續執行。這時候程式就執行到writer0任務了,writer0任務是往郵箱裡寫資料,由於郵箱的長度是2個位元組,所以寫入兩個位元組後,郵箱已滿,任務切換至reader任務,就是打印出郵箱內的內容,同時清空郵箱內的資料。接著MBX_pend又被阻塞,繼續執行writer0任務,writer0剩下的任務只能往郵箱裡再寫入一個位元組,所以writer1任務被啟動,此時郵箱又滿了,故切換任務至reader讀取資料。按照這種演示的步驟,推理出來的結果與真實輸出的結果是不同的,那麼問題出在哪裡呢?

        我在查閱了一些前輩的資料後終於明白mailbox有一個自己的任務佇列,在這裡借用前輩們一個生動的例子來說明下:

        假設有ABC三隊人在排隊買票,每隊3人,分別叫A1A2A3B1B2B3C1C2C3.他們在售票大廳外面的廣場排隊,售票大廳有一個門,要進大廳的人,必須在門前排成一隊,然後才能進去.從各自的隊伍排到門口的隊伍,按照ABC的順序,門口的隊伍每隊只能有一人.大廳裡面有2個視窗在賣票,如果兩個視窗都有人在買,那麼後面的人只能排在門口,不能進大廳.只有當在兩個視窗買票的人都離開後,排在後面的前兩個人才能進大廳.進入大廳的人,如果自己的隊伍還有人,必須通知下一個人過來排隊.那麼看一下買票和排隊的順序.一開始A1A2到門口,大廳空,兩人進去,通知A3過來排隊
        A3到門口,裡面滿了,在門口排隊,A隊已經一人在門外,就輪到B隊了B1到門口排隊,排在A3後面,B組結束,輪到C隊,C1排到B1後面,C隊結束.現在開始第一輪賣票,A1A2買完走人,大門可以進人,A3進大廳,因為A隊沒人了,不用通知,接著B1進入大廳,順便通知B隊的B2過來排隊,B2只能排在C1後面.
        大廳又滿,禁止進人,開始賣票,A3B1買完走人.大門開,C1進門,通知C2過來排隊,C2排在B2後面,B2進門,通知B3來排隊,B3排在C2後邊.大廳滿,開始賣票,C1B2買完走人.大廳空,門開,C2進,通知C3,C3排在B3後邊,B3進大廳,B隊沒人,不用通知,大廳滿,開始賣票,C2B3買完走人,大廳空,門開,C3進,後邊沒人,不用通知,由於所有隊都排完,大廳雖然沒滿,也開始賣票,C3買完走人.賣票的人等了一會,發現沒人來買了,就關門回家了.買票的順序就是A1A2A3B1 C1B2 C2B3 C3,再和tsk和mbx類比,三個tsk就是ABC三條隊伍,每次要post一個數據,就是來門口排隊,而門口的隊伍就是mbx的任務佇列,只有mbx中的內容被讀完,才會依次啟動任務佇列中的任務。

        按照這個例子的意思我畫了個示意圖:

        我通過修改郵箱大小以及每個任務寫入郵箱位元組數的大小,做了一些測試,發現當郵箱數目小於任務的數目時,上述理論是正確的,但是一旦郵箱數目超過任務數目時,任務在排隊時就會出現相同任務排在一個隊伍中,就與上述理論發生了衝突,也就無法知曉此時的任務佇列是怎樣的了,MBX_pend 和 MBX_post函式都是TI提供的API介面函式,閉源的結果是我們並不清楚其函式內部是如何來進行任務佇列設定的,所以這部分內容還是有待研究的。