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

#OMAPL多核異構通訊驅動AD9833-Notify組件demophp

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

要作一個什麼實驗?

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

那麼ARM的Linux端首選Qt,DSP端的程序使用SYSLINK/BIOS實施操做系統,IPC通信組件使用Notify。api

視頻預覽:app

<iframe height=498 width=510 src='http://player.youku.com/embed/XMzY1MjUwNDI0OA==' frameborder=0 'allowfullscreen'></iframe>ide

多核通訊工程目錄結構

幾個文件,arm,dsp,run,shared,還有makefile文件,makefile文件本身要會修改。函數

DSP端程序

DSP端程序對於用戶來說ad9833_dev.c ad9833_server.c main.c 三個主要的文件,post

  • ad9833_dev.c 爲AD9833底層驅動,負責寫時序,寫參數的
  • ad9833_server.c 至關於以太網scoket通訊因子,負責進行多核通訊和調用dev中的api的
  • main.c 爲dspbios啓動,初始化操做。

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

AD9833底層驅動-ad9833_dev.c

咱們這裏給出接口函數目錄,具體實現不給出:this

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/1sxjQaalhhtNcIBGKPlnxmg 密碼: 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.

相關文章
相關標籤/搜索