• 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( &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...
    " );
    	while( ! self->quit ){
    		uint32_t cmd	=	ad9833_server_wait_command( self );
    		ad9833_server_handle_command( self, cmd );
    	}
    
    	printf( "ad9833 server is stopped!
    " );
    
    }
    
    
    
    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 
    " );
    	}
    	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()
    ");
        Error_init(&eb);
        ad9833_handle 	=	ad9833_dev_new();
        task = Task_create(taskFxn, NULL, &eb);
        if (task == NULL) {
            System_printf("Task_create() failed!
    ");
            BIOS_exit(0);
        }
    
        BIOS_start();    /* does not return */
        return(0);
    }
    
    Void taskFxn(UArg a0, UArg a1)
    {
        System_printf("enter taskFxn()
    ");
        printf("Hello sysbios.
    ");
        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()
    ");
    }
    
    

    到此我们就完成了对于多核通信的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!
    ");
            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
    ");
            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.

  • 相关阅读:
    2.6
    2.5
    2.4
    2.3
    2.2
    2.1
    条件查询
    项目办公自动化工具-文件夹照片批量插入word&#183;
    suffer根据CGCS2000坐标利用散点图生成奥维坐标
    案例应用:给照片文件夹里照片按日期排序后引用表格的照片名称批量重命名(源码)
  • 原文地址:https://www.cnblogs.com/sigma0/p/9155134.html
Copyright © 2020-2023  润新知