OMAPL多核异构通信驱动AD9833-Notify组件demo
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='' frameborder=0 'allowfullscreen'>
多核通信工程目录结构
几个文件,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( ¶ms ); params.mode = Semaphore_Mode_COUNTING; Semaphore_construct(&server->sem_obj,0,¶ms); 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
源程序: 链接: 密码: ya8g
参考文献
[1] ti/wiki, , 19 July 2014, at 13:36
[2] ti/wiki, , 2015 [3] ti/wiki, , 24 July 2014, at 09:26.