OMAPL多核异构通信驱动AD9833Notify组件demo

32次阅读

共计 9661 个字符,预计需要花费 25 分钟才能阅读完成。

OMAPL 多核通信有三个主要机制,Notify,MessageQ,RegionShare; 这里主要利用了 Notify 机制进行通信控制。

要做一个什么实验?

简单的说,ARM 跑一个界面上面有一些按钮,DSP 负责驱动 AD9833 产生正弦、方波和三角波,写入频率信息。这个实验结构是一个经典的单向的传输结构,由用户触发 ARM 跑的界面上的按钮,发出消息通知 DSP,DSP 控制 AD9833 产生波形,写入频率字等信息。

那么 ARM 的 Linux 端首选 Qt,DSP 端的程序使用 SYSLINK/BIOS 实施操作系统,IPC 通讯组件使用 Notify。

视频预览:

<iframe height=498 width=510 src=’http://player.youku.com/embed…’ frameborder=0 ‘allowfullscreen’></iframe>

多核通信工程目录结构


几个文件,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

源程序:链接: https://pan.baidu.com/s/1sxjQ… 密码: ya8g

参考文献

[1] ti/wiki, IPC Users Guide/Notify Module, 19 July 2014, at 13:36
[2] ti/wiki, IPC API-Notify.h File Reference 3.40.00.06, 2015
[3] ti/wiki, SysLink UserGuide/Notify, 24 July 2014, at 09:26.

正文完
 0