1. 程式人生 > >OMAPL多核異構通訊驅動AD9833波形發生器-Notify元件

OMAPL多核異構通訊驅動AD9833波形發生器-Notify元件

OMAPL多核異構通訊驅動AD9833-Notify元件demo

OMAPL多核通訊有三個主要機制,Notify,MessageQ,RegionShare;這裡主要利用了Notify機制進行通訊控制。

要做一個什麼實驗?

簡單的說,ARM跑一個介面上面有一些按鈕,DSP負責驅動AD9833產生正弦、方波和三角波,寫入頻率資訊。這個實驗結構是一個經典的單向的傳輸結構,由使用者觸發ARM跑的介面上的按鈕,發出訊息通知DSP,DSP控制AD9833產生波形,寫入頻率字等資訊。

那麼ARM的Linux端首選Qt,DSP端的程式使用SYSLINK/BIOS實施作業系統,IPC通訊元件使用Notify。

視訊預覽:

多核通訊工程目錄結構


幾個檔案,arm,dsp,run,shared,還有makefile檔案,makefile檔案自己要會修改。

DSP端程式

DSP端程式**對於使用者來講**ad9833_dev.c ad9833_server.c main.c 三個主要的檔案,
* ad9833_dev.c 為AD9833底層驅動,負責寫時序,寫引數的
* ad9833_server.c 相當於乙太網scoket通訊因子,負責進行多核通訊和呼叫dev中的api的
* main.c 為dspbios啟動,初始化操作。

環境搭建正確之後,最核心的就是這三個東西,對還有個makefile要配置正確。我在環境除錯的時間花的比開發時間多的多,最重要的就是要環境配置正確,庫啊,路徑啊,這類的。

AD9833底層驅動-ad9833_dev.c

我們這裡給出介面函式目錄,具體實現不給出:

enum ad9833_wavetype_t{
    SIN,SQU,TRI
};

struct ad9833_hw_t {

    uint16 clk;
    uint16 sdi;
    uint16 fsy;
};
// AD9833結構體表述
typedef struct ad9833_t {

    struct ad9833_hw_t hw;
    struct ad9833_t *self;
    enum ad9833_wavetype_t wave_type;

    u16 delay;

    void
(*write_reg)( struct ad9833_t *self, u16 reg_value); void (*init_device)( struct ad9833_t *self ); void (*set_wave_freq)( struct ad9833_t *self , float freqs_data); void (*set_wave_type)( struct ad9833_t *self, enum ad9833_wavetype_t wave_type ); void (*set_wave_phase)( struct ad9833_t *self, u16 phase ); void (*set_wave_para)( struct ad9833_t *self, u32 freqs_data, u16 phase, enum ad9833_wavetype_t wave_type ); } AD9833; // 函式列表 void ad9833_set_para( struct ad9833_t *self,u32 freqs_data, u16 phase, enum ad9833_wavetype_t wave_type ); void ad9833_device_init( struct ad9833_t *self ); void ad9833_write_reg( struct ad9833_t *self, uint16_t data ); void ad9833_delay( struct ad9833_t *self ); void ad9833_gpio_init( void ); void ad9833_set_wave_type( struct ad9833_t *self, enum ad9833_wavetype_t wave_type ); void ad9833_set_phase( struct ad9833_t *self, uint16_t phase ); void ad9833_set_freq( struct ad9833_t *self, float freq ); void ad9833_dev_destroy( AD9833 *dev ); void ad9833_dev_new();

AD9833的驅動,按照手冊進行編輯,然後封裝成這個樣子,這裡一定需要有的函式是:
* ad9833_dev_new()
* ad9833_dev_destroy()

這兩個函式需要在ad9833_server裡面執行。
AD9833這塊就不多說了,我們主要來說多核通訊這塊的知識。

IPC之Notify機制-ad9833_server.c

結構體建立

ad9833_server結構體的建立:

typedef struct ad9833_server_t {
    // 3個id
    uint8_t host_id;        
    uint8_t line_id;
    uint8_t event_id;
    // 連線狀態
    bool connected;
    bool quit;
    // 訊號量的機制
    Semaphore_Struct sem_obj;
    Semaphore_Handle sem;
    uint32_t payload;
    // 底層裝置,ad9833_dev.c的驅動結構體
    AD9833 *dev;
} AD9833_SERVER ;

* 3個ID
host id: 在BIOS裡面有設定
line_id,event_id: 在shared資料夾內有個SystemCfg.h裡面定義了這兩個ID

/* ti.ipc.Notify system configuration */
#define SystemCfg_LineId        0
#define SystemCfg_EventId       7

* 訊號量

l提供對共享資源的的互斥訪問,最多直接64個獨立的訊號量,訊號量請求方式
——直接方式
——間接方式
——混合方式
l不分大小端
l訊號量的原子操作
l鎖存模式(訊號量被使用時)
l排隊等待訊號量
l獲取訊號量時產生中斷
l支援訊號量狀態檢測
l錯誤檢測和錯誤中斷

通過以上閱讀就可以知道訊號量是做什麼的了。

* 底層裝置
需要通過server結構體的例項化對AD9833實行操控。

服務函式

Notify必不可少的幾個函式:
* 事件註冊函式:static void ad9833_server_on_event(**uint16_t proc_id, uint16_t line_id, uint32_t event_id, UArg arg, uint32_t payloa**)
* 事件銷燬函式:void ad9833_server_destroy(AD9833_SERVER *server)
* 執行函式: void ad9833_server_run(AD9833_SERVER *server)
* 命令接收函式: static uint32_t ad9833_server_wait_command(AD9833_SERVER *server)
* 命令執行函式:static void ad9833_server_handle_command(AD9833_SERVER *server, uint32_t cmd)

基本上有了這些函式之後,就可以完成對於Notify服務函式的處理:

Ad9833Server    *ad9833_server_new( uint16_t host_id, uint16_t line_id, uint32_t event_id )
{
    Ad9833Server    *server = ( Ad9833Server * )calloc(1,sizeof( Ad9833Server ));
    server->host_id         =   host_id;
    server->line_id         =   line_id;
    server->event_id            =   event_id;
    server->quit            =   false;
    server->connected       =   false;

    server->dev             =   ad9833_dev_new();
    Semaphore_Params    params;
    Semaphore_Params_init( &params );
    params.mode             =   Semaphore_Mode_COUNTING;
    Semaphore_construct(&server->sem_obj,0,&params);
    server->sem = Semaphore_handle(&server->sem_obj);

    if( Notify_registerEvent( \
        server->host_id, \
        server->line_id, \
        server->event_id, \
        ad9833_server_start_event, \
        (UArg)server ) < 0 ) {
        printf( "fail to register event in %d:%d(line:event)", server->line_id, server->event_id );
    }

    return server;
}

static void ad9833_server_start_event( uint16_t proc_id, uint16_t line_id, uint32_t event_id, UArg arg, uint32_t payload )
{
    Ad9833Server    *server     =   (Ad9833Server *)arg;

    Notify_disableEvent( server->host_id, server->line_id, server->event_id );
    //ASSERT( server->payload == APP_CMD_NULL );
    server->payload =   payload;
    Semaphore_post( server->sem );
}

void    ad9833_server_destroy( Ad9833Server *self )
{
    if( !self ) return;
    Notify_unregisterEvent( self->host_id, self->line_id, self->event_id, ad9833_server_start_event, (UArg)self );
    Semaphore_destruct(&self->sem_obj);
    ad9833_dev_destroy(self->dev);
    free(self);

}

void    ad9833_server_run( Ad9833Server *self )
{
    //ASSERT(self);
    printf( "ad9833_server running...\n" );
    while( ! self->quit ){
        uint32_t cmd    =   ad9833_server_wait_command( self );
        ad9833_server_handle_command( self, cmd );
    }

    printf( "ad9833 server is stopped!\n" );

}

static uint32_t ad9833_server_wait_command( Ad9833Server *self )
{
    Semaphore_pend( self->sem, BIOS_WAIT_FOREVER );
    uint32_t cmd = self->payload;
    self->payload   =   APP_CMD_NULL;
    Notify_enableEvent( self->host_id, self->line_id, self->event_id );

    return cmd;
}
static uint32_t ad9833_server_wait_command( Ad9833Server *self )
{
    Semaphore_pend( self->sem, BIOS_WAIT_FOREVER );
    uint32_t cmd = self->payload;
    self->payload   =   APP_CMD_NULL;
    Notify_enableEvent( self->host_id, self->line_id, self->event_id );

    return cmd;
}

static void ad9833_server_handle_command( Ad9833Server *self, uint32_t cmd )
{
    if( !self->connected && cmd != APP_CMD_CONNECTED ) {
        printf( "disconnect client \n" );
    }
    switch( cmd ) {

    case APP_CMD_CONNECTED:
        //ASSERT(! self->connected);
        //LOG_DEBUG("led client had connected");
        self->connected = true;
        break;

    case APP_CMD_DISCONNECTED:
        //ASSERT( self->connected );

        self->connected =   false;
        self->quit  = true;

        break;

    case    APP_CMD_SETSINE:

        self->dev->set_wave_type( self->dev, SIN );

        break;

    case    APP_CMD_SETSEQ:

        self->dev->set_wave_type( self->dev, SQU );

        break;

    case    APP_CMD_SETTRI:

        self->dev->set_wave_type( self->dev, TRI );

        break;

    case    APP_CMD_SETFREQ_UP:

        self->dev->set_wave_freq( self->dev, current_freq += 10 );
        if( current_freq > 50000 ) {
            current_freq = 50000;
        }
        break;

    case    APP_CMD_SETPHASE_UP:

        self->dev->set_wave_phase( self->dev, current_phase += 1 );
        if( current_phase > 360 ) {
            current_phase = 360;
        }

        break;

    case    APP_CMD_SETFREQ_DOWN:

        self->dev->set_wave_freq( self->dev, current_freq -= 10 );
        if( current_freq < 10 ) {
            current_freq = 10;
        }

        break;
    case    APP_CMD_SETPHASE_DOWN:

        self->dev->set_wave_phase( self->dev, current_phase -= 1 );
        if( current_phase < 1 ) {
            current_phase = 0;
        }
    }
}

SYSBIOS啟動服務

AD9833  *ad9833_handle;

Int main()
{ 
    Task_Handle task;
    Error_Block eb;
    System_printf("enter main()\n");
    Error_init(&eb);
    ad9833_handle   =   ad9833_dev_new();
    task = Task_create(taskFxn, NULL, &eb);
    if (task == NULL) {
        System_printf("Task_create() failed!\n");
        BIOS_exit(0);
    }

    BIOS_start();    /* does not return */
    return(0);
}

Void taskFxn(UArg a0, UArg a1)
{
    System_printf("enter taskFxn()\n");
    printf("Hello sysbios.\n");
    ad9833_handle->set_wave_para( ad9833_handle, 5000, 0, SIN );


    Task_sleep(1500);
    ad9833_handle->set_wave_type( ad9833_handle, SQU );
    Task_sleep(1500);
    ad9833_handle->set_wave_type( ad9833_handle, TRI );
    Task_sleep(1500);
    ad9833_handle->set_wave_freq( ad9833_handle, 1000.0f );
    System_printf("exit taskFxn()\n");
}

到此我們就完成了對於多核通訊的Notify DSP端程式。

ARM端Qt程式

在ARM端有Qt程式,Qt主程式中對syslink的初始化,需要註冊幾個事件:

    SysLink_setup();
    this->m_slave_id    =   MultiProc_getId("DSP");

    if( Ipc_control(this->m_slave_id, Ipc_CONTROLCMD_LOADCALLBACK, NULL ) < 0) {
        LOG_ERROR("load callback failed");
    }

    if( Ipc_control(this->m_slave_id, Ipc_CONTROLCMD_STARTCALLBACK, NULL ) < 0 ) {
        LOG_ERROR("start callback failed");
    }

    m_dev   =   new ad9833_client( this->m_slave_id, SystemCfg_LineId, SystemCfg_EventId );
    if( ! this->m_dev->connect() ) {
        LOG_ERROR("failed to connect to led server");
    }else {
        LOG_DEBUG("connect to led server");
    }

需要建立服務函式:

#include "ad9833_client.h"
#include "ti/syslink/Std.h"
#include "ti/ipc/Notify.h"
#include "unistd.h"
#include "log.h"

ad9833_client::ad9833_client(uint16_t slave_id, uint16_t line_id, uint16_t event_id )
    : m_slave_id(slave_id),m_line_id(line_id),m_event_id(event_id)
{

}

ad9833_client::~ad9833_client() {

}

bool    ad9833_client::connect() {
    int status;

    do {
        LOG_DEBUG("try to connect!\n");
        status = Notify_sendEvent( this->m_slave_id,  \
                                   this->m_line_id,   \
                                   this->m_event_id,  \
                                   APP_CMD_CONNECTED, \
                                   TRUE );
        if( status != Notify_E_EVTNOTREGISTERED ) {
            usleep(100);
        }
    }while( status == Notify_E_EVTNOTREGISTERED );

    if( status != Notify_S_SUCCESS ) {
        LOG_ERROR("failed to send connect command\n");
        return false;
    }

    LOG_DEBUG("send connected command");
    return true;
}

bool    ad9833_client::send_cmd( uint16_t cmd )
{
    int status = Notify_sendEvent( this->m_slave_id, \
                                   this->m_line_id,  \
                                   this->m_event_id, \
                                   cmd,              \
                                   TRUE);
    if( status < 0 ) {
        LOG_DEBUG("fail to send command: %d", cmd);
        return false;
    }
    LOG_DEBUG("send command: %d", cmd);
    return true;
}

bool    ad9833_client::disconnect()
{
    LOG_DEBUG("disconnect with server");
    return this->send_cmd(APP_CMD_DISCONNECTED);
}

bool    ad9833_client::set_freq_down()
{
    LOG_DEBUG("set freq down with server");
    return this->send_cmd(APP_CMD_SETFREQ_DOWN);
}

bool    ad9833_client::set_freq_up()
{
    LOG_DEBUG("set freq up with server");
    return this->send_cmd(APP_CMD_SETFREQ_UP);
}

bool    ad9833_client::set_phase_down()
{
    LOG_DEBUG("set phase down with server");
    return this->send_cmd(APP_CMD_SETPHASE_DOWN);
}

bool    ad9833_client::set_phase_up()
{
    LOG_DEBUG("set phase up with server");
    return this->send_cmd(APP_CMD_SETPHASE_UP);
}
bool    ad9833_client::set_wave_type(WAVE_TYPE type)
{
    if( type == SIN ) {
        LOG_DEBUG("set wave type is sine");
        this->send_cmd( APP_CMD_SETSINE );
    }else if( type == SQU ) {
        LOG_DEBUG("set wave type is squ");
        this->send_cmd( APP_CMD_SETSEQ );
    }else {
        LOG_DEBUG("set wave type is tri");
        this->send_cmd( APP_CMD_SETTRI );
    }
}

#ifndef AD9833_CLIENT_H
#define AD9833_CLIENT_H
#include "stdint.h"
#include "app_common.h"

typedef enum wave_type_t { SIN=0,SQU,TRI } WAVE_TYPE;

class ad9833_client
{
public:
    explicit ad9833_client( uint16_t  slave_id, uint16_t line_id, uint16_t event_id  );
    ~ad9833_client();

    bool    connect();
    bool    disconnect();


    bool    set_wave_type( WAVE_TYPE type );
    bool    set_freq_up();
    bool    set_freq_down();
    bool    set_phase_up();
    bool    set_phase_down();

private:

    bool    send_cmd( uint16_t cmd );

private:

    uint16_t    m_slave_id;
    uint16_t    m_line_id;
    uint16_t    m_event_id;

};

#endif // AD9833_CLIENT_H

參考文獻