Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OMAPL多核异构通信驱动AD9833-Notify组件demo #34

Open
carloscn opened this issue Apr 11, 2022 · 0 comments
Open

OMAPL多核异构通信驱动AD9833-Notify组件demo #34

carloscn opened this issue Apr 11, 2022 · 0 comments

Comments

@carloscn
Copy link
Owner

#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='https://player.youku.com/embed/XMzY1MjUwNDI0OA==' 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/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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant