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( ¶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