TI drv2667压电触觉电机驱动芯片开发

本文详细介绍了使用TI的DRV2667芯片进行触觉电机反馈的开发过程。首先,概述了芯片的接口和内存映射,包括I2C通信接口、震动电机接口以及Page0和Page1~Page8的内存布局。接着,解析了关键的控制寄存器和波形序列寄存器,并提供了配置电压、幅度、频率等参数的方法。通过逻辑分析仪验证了I2C通信的正确性,并展示了如何编写和封装C接口函数以控制芯片工作。最后,给出了配置文件和启动震动的示例代码,便于实际项目应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.前言

        最近遇到一个项目需要触觉电机的反馈,项目组选了TI的drv2667芯片+震动电机的方案,其中drv2667芯片的接口交给我开发,因为期间上网搜索发现这款芯片除了芯片手册,其他的开发资料很少,都是靠芯片手册完成开发的,把我对芯片的理解和开发的简单流程整理了一下。

1.芯片介绍

1.1芯片接口

        下图为芯片的接口图,其中(SDA,SCL)I2C为与主机的通信接口,(DOUT+,OUT-)Piezo Actuator就是震动电机,其他引脚就是外围电路。

1.2芯片内存映射        

        芯片的内存地址映射图如下,drv2667共有2048+256 RAM,共分为Page0和Page1~Page8共9页,其中每页的8bit寻址共256个地址。Page0预留为控制寄存器,包含了所有的状态和控制操作,Page1~Page8用来存储需要合成的震动频谱。其中每个Page的0xFF地址page register用来对PageX进行切换。

 

 Page0控制寄存器的寄存器功能如下:

简单说几个要用到的:

地址0x1用来选择控制的方式,数字OR模拟;控制的电压25,50,100,125V,bit2选择控制的方式,数字OR模拟;bit0~1选择控制的电压25,50,100,125V,

 

 地址0x2的bit0选择是否启动震动,

 

         地址0x3~0xA用来设置要播放的波形,需要播放哪个page的波形,直接写入寄存器即可,如果需要在某个波形停止,写0即可,如果所有地址数据都不为0,播放完波形7后结束。

如: addr3[2],addr4[3], addr5[0] ,中括号代表地址内的数据

        表示地址0x2的bit0写入1启动后,先播放Page2的合成频谱,再播放Page3的合成频谱,在addr5遇到0后结束。

         下图为Page1~Page8的2048bytes RAM空间的分布。RAM的起始位置包含了一个头部区域用于配置Page的一些信息。其中地址0x00,存放头部的结束地址,占了一个字节,所以地址0x00的大小为N*5+1,结束地址为N*5, N为需要配置的Page的数量。

         头部区域的其他区域为Page配置,每个Page需要5个字节的配置信息,分别为起始地址2个字节,结束地址2个字节,重复次数1个字节。地址高字节的bit2~bit0表示配置的Page编号。起始地址高字节的bit7用来设置模式。

 

         当mode模式为0时,直接从Ram读取波形,按照奈奎斯特频率输出(这种模式我没使用和测试),当mode模式为1时,为合成波形,开始地址起每4个字节为合成频率的参数,分别为幅度、频率、循环次数、斜坡时间。如果需要多个合成波形,PageX的结束地址为head结束地址+4*N个波形,每个波形需要4个参数,每个参数一个字节。

Amplitude :幅度的公式为   峰值电压 = amplitude(输入数值) / 255 x 全波峰值电压,即255表示全幅度,128表示半幅度,0表示没有幅度。 
Frequency:合成正弦波 (Hz) = 7.8125 x frequency (输入数值)
Number of Cycles:波形的循环次数。所有循环波形的持续时间(ms) = 1000 x # of cycles(输入数值) / (7.8125 x frequency(输入数值) )
Envelope: 正弦波爬坡时间

2.调试过程

        用到的工具主要是逻辑分析仪,先对单片机的IIC输出进行了查看,在逻辑分析仪能看到波形后,证明单片机运行正常。读取drv2667的寄存器,读取了0x1寄存器,返回了0x38,证明和drv2667的通信是正常的。写波形文件,运行,振动。振动后调节不同的参数,查看振动的效果。

最后按照项目要求封装了.c .h的接口文件使用。

int drv2667Config(uint8 vpp, uint8 amp, uint32 freq, uint32 playTime, uint32 silentTime, uint8 repeatCnt)//配置电压,幅度,频率,震动时间,静默时间,重复次数

下图为封装函数的使用效果示意:

 

3.提交的文件

编写的接口文件txDrv2667.c

/* ========================================
 *
 * author: tx 
 * date:    2022.3.3
 * function: 
 *      drv2667Init() //初始化,主要是初始化IIC
 *      int drv2667Config(uint8 vpp, uint8 amp, uint32 freq, uint32 playTime, uint32 silentTime, uint8 repeatCnt)//配置电压,幅度,频率,震动时间,静默时间,重复次数
 *      int drv2667ConfigDefault(void)///配置2667的参数默认值
 *      drv2667Start() //启动震动
*  use example:
        头文件包含
        #include "txDrv2667.h"//drv2667
    
        int main()
        {
            //drv2667初始化
            drv2667Init();
            //drv2667Config(uint8 vpp电压, uint8 amp幅值, uint32 freq频率hz, uint32 playTime震动时间ms, uint32 silentTime停止时间ms, uint8 repeatCnt重复次数);
            drv2667Config(DRV2667_50_VPP_GAIN, 255, 256, 500, 1000, 5);
            //drv2667启动震动
            drv2667Start();
        }
 *
 * ========================================
*/
#include <project.h>
#include "txDrv2667.h"//drv2667

/* I2C Slave address to communicate with */
#define I2C_SLAVE_ADDR      (0x59u)

/* Contol registers */
#define DRV2667_STATUS	0x00
#define DRV2667_CTRL_1	0x01
#define DRV2667_CTRL_2	0x02
/* Waveform sequencer */
#define DRV2667_WV_SEQ_0	0x03
#define DRV2667_WV_SEQ_1	0x04
#define DRV2667_WV_SEQ_2	0x05
#define DRV2667_WV_SEQ_3	0x06
#define DRV2667_WV_SEQ_4	0x07
#define DRV2667_WV_SEQ_5	0x08
#define DRV2667_WV_SEQ_6	0x09
#define DRV2667_WV_SEQ_7	0x0A
#define DRV2667_FIFO		0x0B
#define DRV2667_PAGE		0xFF
#define DRV2667_MAX_REG		DRV2667_PAGE
#define DRV2667_PAGE_0		0x00
#define DRV2667_PAGE_1		0x01
#define DRV2667_PAGE_2		0x02
#define DRV2667_PAGE_3		0x03
#define DRV2667_PAGE_4		0x04
#define DRV2667_PAGE_5		0x05
#define DRV2667_PAGE_6		0x06
#define DRV2667_PAGE_7		0x07
#define DRV2667_PAGE_8		0x08
/* RAM fields */
#define DRV2667_RAM_HDR_SZ	0x0
/* RAM Header addresses */
#define DRV2667_RAM_START_HI	0x01
#define DRV2667_RAM_START_LO	0x02
#define DRV2667_RAM_STOP_HI		0x03
#define DRV2667_RAM_STOP_LO		0x04
#define DRV2667_RAM_REPEAT_CT	0x05
/* RAM data addresses */
#define DRV2667_RAM_AMP		0x06
#define DRV2667_RAM_FREQ	0x07
#define DRV2667_RAM_DURATION	0x08
#define DRV2667_RAM_ENVELOPE	0x09

/* Control 2 Register */
#define DRV2667_GO			(1 << 0)
#define DRV2667_STANDBY		(1 << 6)
#define DRV2667_DEV_RST		(1 << 7)
/* RAM Envelope settings */
#define DRV2667_NO_ENV			0x00
#define DRV2667_32_MS_ENV		0x01
#define DRV2667_64_MS_ENV		0x02
#define DRV2667_96_MS_ENV		0x03
#define DRV2667_128_MS_ENV		0x04
#define DRV2667_160_MS_ENV		0x05
#define DRV2667_192_MS_ENV		0x06
#define DRV2667_224_MS_ENV		0x07
#define DRV2667_256_MS_ENV		0x08
#define DRV2667_512_MS_ENV		0x09
#define DRV2667_768_MS_ENV		0x0a
#define DRV2667_1024_MS_ENV		0x0b
#define DRV2667_1280_MS_ENV		0x0c
#define DRV2667_1536_MS_ENV		0x0d
#define DRV2667_1792_MS_ENV		0x0e
#define DRV2667_2048_MS_ENV		0x0f

/*
二维数组int a[2][3]={ {80,75,92}, {61,65,71}};
定义了一个 2 行 3 列的二维数组,共有 3×2=6 个元素,数组名为 a,即:
a[0][0], a[0][1], a[0][2
a[1][0], a[1][1], a[1][2]*/
//配置寄存器Typical Usage Examples size=34
static uint8 configArray[][2]={
//Control,page0
0xFF,0x00,//0 Set page register to control space
0x02,0x00,//1 Take device out of standby mode
//0x01,0x00,//Set to lowest gain, 25 VPP maximum
0x01,0x03,//2 Set to lowest gain, 100v VPP maximum
0x03,0x01,//3 Set sequencer to play waveform ID #1
0x04,0x00,//4 End of sequence
//Header,page1
0xFF,0x01,//5 Set memory to page 1
0x00,0x05,//6 Header size –1
0x01,0x80,//7 Start address upper byte, also indicates Mode 3
0x02,0x06,//8 Start address lower byte
0x03,0x00,//9 Stop address upper byte
//0x04,0x09,//10 Stop address lower byte,只执行data0如果需要波形,可以加4个字节,顺序执行
0x04,0x0d,//Stop address lower byte 执行data0 data1
0x05,0x01,//11 Repeat count, play waveform once
//0x05,0x0a,//Repeat count, play waveform once
//Data0,page1 4个字节,分别为幅度、频率、循环次数,
0x06,0xFF,//12 幅度,Amplitude for waveform ID #1, full-scale, 50 VPP at gain = 0, FFH full,80H half
0x07,0x20,//13 频率(高频有声音), Frequency for waveform ID #1, 195 Hz,Sinusoid frequency (Hz) = 7.8125 x frequency  
0x08,0x1,//14 循环次数(0时不动作),Duration for waveform ID #1, play 5 cycles,Duration (ms) = 1000 x # of cycles / (7.8125 x frequency)
0x09,0x00,//15 Envelope for waveform ID #1, ramp up = no envelope, ramp down = no envelope
//Data1,page1 4个字节,分别为幅度、频率、循环次数,
0x0a,0x0,//16 Amplitude for waveform ID #1, full-scale, 50 VPP at gain = 0,幅度0
0x0b,0xd,//17 Frequency for waveform ID #1, 195 Hz,Sinusoid frequency (Hz) = 7.8125 x frequency,配置为10ms
0x0c,0x1,//18 Duration for waveform ID #1, play 5 cycles,Duration (ms) = 1000 x # of cycles / (7.8125 x frequency)
0x0d,0x00,//19 Envelope for waveform ID #1, ramp up = no envelope, ramp down = no envelope
//Contol,page0
0xFF,0x00,//20 Set page register to control space
//0x02,0x01//Set GO bit (execute waveform sequence)
};
//默认寄存器,初始化寄存器为默认值
static const uint8 configDefaultArray[][2]={
//Control,page0
0xFF,0x00,//Set page register to control space
0x02,0x00,//Take device out of standby mode
0x01,0x03,//Set to lowest gain, 100v VPP maximum
0x03,0x01,//Set sequencer to play waveform ID #1
0x04,0x00,//End of sequence
//Header,page1
0xFF,0x01,//Set memory to page 1
0x00,0x05,//Header size –1
0x01,0x80,//Start address upper byte, also indicates Mode 3
0x02,0x06,//Start address lower byte
0x03,0x00,//Stop address upper byte
0x04,0x0d,//Stop address lower byte
0x05,0x01,//Repeat count, play waveform once
//data0
0x06,0xFF,//幅度,Amplitude for waveform ID #1, full-scale, 50 VPP at gain = 0, FFH full,80H half
0x07,0x20,//频率(高频有声音), Frequency for waveform ID #1, 195 Hz,Sinusoid frequency (Hz) = 7.8125 x frequency  
0x08,0x1,//循环次数(0时不动作),Duration for waveform ID #1, play 5 cycles,Duration (ms) = 1000 x # of cycles / (7.8125 x frequency)
0x09,0x00,//Envelope for waveform ID #1, ramp up = no envelope, ramp down = no envelope
//data1
0x0a,0x0,//Amplitude for waveform ID #1, full-scale, 50 VPP at gain = 0,幅度0
0x0b,0xd,//Frequency for waveform ID #1, 195 Hz,Sinusoid frequency (Hz) = 7.8125 x frequency
0x0c,0x1,//Duration for waveform ID #1, play 5 cycles,Duration (ms) = 1000 x # of cycles / (7.8125 x frequency)
0x0d,0x00,//Envelope for waveform ID #1, ramp up = no envelope, ramp down = no envelope
//Contol,page0
0xFF,0x00,//Set page register to control space
};

#define VAL_MIN_LIMIT0(x)   x<0?0:x         //限定最小值0
#define VAL_MAX_LIMIT255(x) x>255?255:x     //限定最大值255

extern uint32 I2CM_I2CMasterStatus(void);//获取IIC状态 I2CM_I2C_MSTAT_WR_CMPLT(Write complete), I2CM_I2C_MSTAT_ERR_XFER(Error during transfer)
extern uint32 I2CM_I2CMasterWriteBuf(uint32 slaveAddress, uint8 * wrData, uint32 cnt, uint32 mode);//IIC写缓存数据

///drv2667Init初始化,连接IIC
void drv2667Init(void)
{
    /* Start the I2C Master */
    I2CM_Start();
}

///文件内函数,向IIC写数据,等待传送完成,判断传输状态
static int drv2667WriteBuf(uint8 * wrData, uint32 cnt)
{
    I2CM_I2CMasterClearStatus();
        
    /* Start I2C write and check status*/
    if(I2CM_I2C_MSTR_NO_ERROR == I2CM_I2CMasterWriteBuf(I2C_SLAVE_ADDR,
                                    wrData, cnt,
                                    I2CM_I2C_MODE_COMPLETE_XFER))
    {
        /*If I2C write started without errors, 
        / wait until I2C Master completes write transfer 
        */
        while (0u == (I2CM_I2CMasterStatus() & I2CM_I2C_MSTAT_WR_CMPLT))
        {
            ; /* Wait */
        }
        
        /* Display transfer status */
        if (0u == (I2CM_I2CMasterStatus() & I2CM_I2C_MSTAT_ERR_XFER))
        {
            return I2CM_I2C_MSTR_NO_ERROR;
        }
    }
    
    return I2CM_I2C_MSTR_ERR_BUS_ERR;
}

///配置2667的参数
/*
    输入参数:vpp    #define DRV2667_25_VPP_GAIN		0x00
                    #define DRV2667_50_VPP_GAIN		0x01
                    #define DRV2667_75_VPP_GAIN		0x02
                    #define DRV2667_100_VPP_GAIN	0x03
            amp 振幅,0~255,0最小,128一半50%,255最大100%
            freq 频率 0~2000Hz,
            playTime 震动时间 ms,相当于占空比高电平
            silentTime 静默时间 ms,相当于占空比低电平
            repeatCnt 重复次数,高低电平相当于一个周期,这个可以更改重复的周期
*/
int drv2667Config(uint8 vpp, uint8 amp, uint32 freq, uint32 playTime, uint32 silentTime, uint8 repeatCnt)
{
    uint8 iicSndBuf[2] = {0};//iic发送缓存
    uint8 i = 0;//循环轮询
    uint8 len = sizeof(configArray);//计算配置寄存器的长度

    //①计算传递的参数
    //计算vpp电压
    configArray[2][1] = vpp;
    //计算重复次数
    configArray[11][1] = VAL_MAX_LIMIT255(repeatCnt);
    //计算幅度
    configArray[12][1] = VAL_MAX_LIMIT255(amp);
    //计算频率Sinusoid frequency (Hz) = 7.8125 x frequency;
    configArray[13][1] = VAL_MAX_LIMIT255(freq/8);
    //计算震动时间;Duration (ms) = 1000 x # of cycles / (7.8125 x frequency)
    configArray[14][1] = VAL_MAX_LIMIT255(freq*playTime/1000);
    //计算静默时间ms,设置了data1频率100hz,10ms
    configArray[16][1] = 0;//幅度0
    configArray[17][1] = 0xd;//配置为频率100hz,单次10ms
    configArray[18][1] = VAL_MAX_LIMIT255(silentTime/10);//循环0次
    //循环配置传递的参数
    for(i=0;i<len/2;i++)
    {
        /* Initialize buffer with packet */
        iicSndBuf[0] = configArray[i][0];
        iicSndBuf[1] = configArray[i][1];
        //write buf to 2667
        drv2667WriteBuf(iicSndBuf, sizeof(iicSndBuf));
        //delay 1ms
        CyDelay(1); 
    }
    
    return 0;
}

///配置2667的参数默认值
int drv2667ConfigDefault(void)
{
    uint8 iicSndBuf[2] = {0};//iic发送缓存
    uint8 i = 0;//循环轮询
    uint8 len = sizeof(configArray);//计算配置寄存器的长度
    
    //复制传递默认的参数
    for(i=0;i<len/2;i++)
    {
        configArray[i][0] = configDefaultArray[i][0];
        configArray[i][1] = configDefaultArray[i][1];
    }
    //配置传递的参数
    for(i=0;i<len/2;i++)
    {
        /* Initialize buffer with packet */
        iicSndBuf[0] = configArray[i][0];
        iicSndBuf[1] = configArray[i][1];
        //write buf to 2667
        drv2667WriteBuf(iicSndBuf, sizeof(iicSndBuf));
        //delay 1ms
        CyDelay(1); 
    }
    
    return 0;
}
///启动一次震动
void drv2667Start(void)
{
    uint8 iicSndBuf[2] = {0x2,0x1};//iic发送缓存 Set GO bit (execute waveform sequence)
    //write buf to 2667
    drv2667WriteBuf(iicSndBuf, sizeof(iicSndBuf));
}

/* [] END OF FILE */

 

编写的接口文件txDrv2667.h

/* ========================================
 *
 * author: tx 
 * date:    2022.3.3
 *
 * ========================================
*/
#if !defined(_TX_DRV2667_H)
#define _TX_DRV2667_H
#include <project.h>

    
/* Control 1 Register */
#define DRV2667_25_VPP_GAIN		0x00
#define DRV2667_50_VPP_GAIN		0x01
#define DRV2667_75_VPP_GAIN		0x02
#define DRV2667_100_VPP_GAIN	0x03
#define DRV2667_DIGITAL_IN		0xfc
#define DRV2667_ANALOG_IN		(1 << 2)
    
/*function*/
///drv2667Init初始化,连接IIC
extern void drv2667Init(void);

///配置2667的参数
/*
    输入参数:vpp    #define DRV2667_25_VPP_GAIN		0x00
                    #define DRV2667_50_VPP_GAIN		0x01
                    #define DRV2667_75_VPP_GAIN		0x02
                    #define DRV2667_100_VPP_GAIN	0x03
            amp 振幅,0~255,0最小,128一半50%,255最大100%
            freq 频率 0~2000Hz,
            playTime 震动时间 ms,相当于占空比高电平
            silentTime 静默时间 ms,相当于占空比低电平
            repeatCnt 重复次数,高低电平相当于一个周期,这个可以更改重复的周期
*/
extern int drv2667Config(uint8 vpp, uint8 amp, uint32 freq, uint32 playTime, uint32 silentTime, uint8 repeatCnt);

///配置2667的参数默认值
extern int drv2667ConfigDefault(void);

///启动一次震动
extern void drv2667Start(void);
#endif
/* [] END OF FILE */

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值