DSP28377D控制MCP4661数字电位器

前言

注意:本程序中IIC搭载了6块MCP4661,通过A2、A1、A0来区别硬件地址(上电时地址自动锁存)。
需区别正常命令读写和高压命令的读写,高压命令需硬件操作HVC的电平。

1. MCP4661基本

具体引脚图和设备框图如下(后续知识点见下文):
在这里插入图片描述
在这里插入图片描述
MCP4661内部结构包含两个完全独立的数字电位器通道,通讯模式为IIC存储为EEPROM、带雨刮锁、上电后滑动端初始值放在存储器中,数据宽度8位, 257 步分辨率调节。

2.MCP4661具体驱动

接下来将介绍如何使用28377d对MCP4661进行驱动

2.1 IIC初始化

GPIO初始化
GPIO配置为IIC_A、使能上拉、异步输入(避免输入同步器引入延迟)。IIC是开漏协议,GPIO配置后I2C功能会自动配置为开漏输出。

  // I2C_A引脚配置
    GpioCtrlRegs.GPDGMUX1.bit.GPIO104 = 0;
    GpioCtrlRegs.GPDMUX1.bit.GPIO104 = 1;//SDA_A
    GpioCtrlRegs.GPDPUD.bit.GPIO104 = 0;
    GpioCtrlRegs.GPDQSEL1.bit.GPIO104 = 3;

    GpioCtrlRegs.GPDGMUX1.bit.GPIO105 = 0;
    GpioCtrlRegs.GPDMUX1.bit.GPIO105 = 1; //SCL_A
    GpioCtrlRegs.GPDPUD.bit.GPIO105 = 0;
    GpioCtrlRegs.GPDQSEL1.bit.GPIO105 = 3;

IIC初始化
1、复位模块:配置IIC前必须复位,确保从已知状态开始;
2、配置预分频寄存器, I2C模块时钟 = SYSCLKOUT / (I2CPSC + 1),系统时钟200MHz,IIC工作时钟计算可得为20MHz;
3、配置SCL高低电平时间, SCL频率 = I2C模块时钟 / (I2CCLKL + I2CCLKH + 6),代入公式可得SCL频率 = 20MHz / 200 =100kHz,100kHz为标准模式,高低电平对称,占空比50%;
4、禁止所用中断,防止配置过程中产生意外中断;
5、开启发送就绪中断(当发送数据寄存器为空,可以写入新的发送数据时触发以提高传输效率)、无应答中断(当从设备没有返回应答信号(NACK)时触发);
6、禁用FIFO,采用单字节模式,一次处理一个字节,每个字节传输完成产生中断;
7、使能I2C模块,模块开始工作,可以响应起始条件;

//I2C初始化代码
void I2CA_Init(void)
{
    // 复位并禁止I2C_A模块
    I2caRegs.I2CMDR.bit.IRS = 0;
    // 配置I2C模块输入时钟的预分频值
    I2caRegs.I2CPSC.all = 9;
    // 配置通讯的时钟频率
    I2caRegs.I2CCLKL = 97;
    // 配置通讯的时钟频率
    I2caRegs.I2CCLKH = 97;
    // 禁止I2C中断
    I2caRegs.I2CIER.all = 0x00;
    // 使能中断
    I2caRegs.I2CIER.all = 0x24;
    // 禁止I2C模块的FIFO模式
    I2caRegs.I2CFFTX.all = 0x0000;
    // 使能I2C_A模块
    I2caRegs.I2CMDR.bit.IRS = 1;
}

2.2 状态检查函数

1、检查发送数据寄存器是否就绪,当XRDY位为1时,表示发送数据寄存器(I2CDXR)已空,可以写入新的数据;当XRDY=0时,表示发送数据寄存器忙,不能写入
2、检查接收数据寄存器是否就绪,当RRDY位为1时,表示接收数据寄存器(I2CDRR)中有新的数据可以读取;当RRDY=0时,表示接收数据寄存器为空,没有新数据

// 获取I2C发送数据准备状态
uint16_t I2C_xrdy(void)
{
    uint16_t t;
    t = I2caRegs.I2CSTR.bit.XRDY;
    return t;
}

// 获取I2C读取数据准备状态
uint16_t I2C_rrdy(void)
{
    uint16_t t;
    t = I2caRegs.I2CSTR.bit.RRDY;
    return t;
}

2.3 MCP4661驱动函数

2.3.1 IIC写入时序

1.对易失性内存的单次写入
1、IIC起始信号S;
2、控制字节:前4位为MCP4661的固定设备类型标识,中间3位A2 A1 A0为设备地址,由芯片引脚决定;最后1位0为写操作位(1为读,0为写)具体含义见下图;
3、从机应答位
4、命令字节(包含寄存器地址和命令),AD3-AD0需操作寄存器地址,C1-C0命令操作位,D9-D8位数据的最高两位,具体含义见下图;
5、从机应答和IIC停止信号。
2.连续写入
当写入易失性wiper寄存器(地址00h、01h、04h)或TCON寄存器时,可连续写入:
重复写入命令字节和写入数据
在这里插入图片描述
从设备地址根据A2、A1、A0的逻辑电平来决定的,IIC总线最多挂在8个数字电位器。
在这里插入图片描述
命令字节详情如下
在这里插入图片描述
寄存器地址详细控制命令如下表所示

在这里插入图片描述
DSP28377具体写入数据流程
1、检查总线是否繁忙,如果总线忙,立即返回错误
2、等待发送寄存器就绪,轮询等待发送寄存器(I2CDXR)为空**
3、配置IIC相关参数**
目标从设备7位地址(硬件自动将7位地址左移一位,加上R/W位)对应控制字节;
设置IIC传输字节数,number+1,所加的1为寄存器地址字节;
将寄存器地址写入数据发送寄存器(I2CDXR)对应寄存器+控制命令字节;
配置IIC工作模式并启动传输,0x6E20的二进制:0110 1110 0010 0000;
主机发送模式、自动产生起始和停止条件、7位从机地址、标准I2C格式、8位数据、传输number+1个字节
4、循环写入数据,等待发送寄存器准备就绪,写入数据若未产生应答位,返回错误
向内部寄存器里面写具体值(0-255对应265步分辨)。

数据位配置详情
15-1400 保留
131 = FREE (自由运行,仿真时不停止)
121 = STT (发送起始条件)
111 = STP (发送停止条件) ← 传输结束后自动发送停止
101 = MST (主机模式)
91 = TRX (发送模式)
80 =XA (7位地址模式)
70 = RM (禁用重复模式)
60 = DLB (禁用数字回环)
51 = IRS (I2C模块使能)
40 = STB (禁用起始字节模式)
30 = FDF (标准I2C格式)
2-0000 = BC[2:0] (8位数据)
uint16_t WriteData(uint16_t *Wdata, uint16_t RomAddress, uint16_t number, uint16_t IcAddr)
{
    uint16_t i;
    if(I2caRegs.I2CSTR.bit.BB == 1)
        return I2C_BUS_BUSY_ERROR;
    while(!I2C_xrdy());
    I2caRegs.I2CSAR.all = IcAddr;
    I2caRegs.I2CCNT = number+1;
    I2caRegs.I2CDXR.all = RomAddress;
    I2caRegs.I2CMDR.all = 0x6E20;
    for(i=0; i<number; i++)
    {
        while(!I2C_xrdy());
        I2caRegs.I2CDXR.all = *Wdata;
        Wdata++;
        if(I2caRegs.I2CSTR.bit.NACK == 1)
            return I2C_BUS_BUSY_ERROR;
    }
    return I2C_SUCCESS;
}
2.3.2 IIC读取时序

连续读取从上次访问的地址开始
起始条件(S)
控制字节:0101A2A1A0 1(读命令)
从机应答(A)
数据字节
主机非应答(A̅)表示结束
停止条件(P)
随机地址读取需要在读取数据前写入寄存器地址+命令再读数据
控制字节后两位为11为读取命令
在这里插入图片描述
DSP28377具体读取数据流程
1、检查总线忙状态
2、采用随机读取,发送寄存器地址
设置从机地址
只发送1个字节(寄存器地址)
要读取的寄存器地址
启动传输,I2CMDR配置为0x6620(0110 0110 0010 0000)
主机模式、自动产生起始条件、不发送停止条件、发送模式、I2C模块使能
3、检查NACK
4、延迟50us,等待从机处理
5、重新启动传输并读取数据

I2CMDR配置为0x6C20(0110 1100 0010 0000),进入接受模式,读取number个字节.
6、检查NACK
7、循环读取number个字节
每次等待接收数据就绪(RRDY)、读取数据寄存器(I2CDRR)、存储到RamAddr指向的地址

//数据读取函数
uint16_t ReadData(uint16_t *RamAddr, uint16_t RomAddress, uint16_t number, uint16_t IcAddr)
{
    uint16_t i,Temp;

    if(I2caRegs.I2CSTR.bit.BB == 1)
        return I2C_BUS_BUSY_ERROR;

    while(!I2C_xrdy());
    I2caRegs.I2CSAR.all = IcAddr;
    I2caRegs.I2CCNT = 1;
    I2caRegs.I2CDXR.all = RomAddress;
    I2caRegs.I2CMDR.all = 0x6620;
    if(I2caRegs.I2CSTR.bit.NACK == 1)
        return I2C_BUS_BUSY_ERROR;
    DELAY_US(50);
    while(!I2C_xrdy());
    I2caRegs.I2CSAR.all = IcAddr;
    I2caRegs.I2CCNT = number;
    I2caRegs.I2CMDR.all = 0x6C20;
    if(I2caRegs.I2CSTR.bit.NACK == 1)
        return I2C_BUS_BUSY_ERROR;
    for(i=0; i<number; i++)
    {
        while(!I2C_rrdy());
        Temp = I2caRegs.I2CDRR.all;
        if(I2caRegs.I2CSTR.bit.NACK == 1)
            return I2C_BUS_BUSY_ERROR;
        *RamAddr = Temp;
        RamAddr++;
    }
    return I2C_SUCCESS;
}

硬件配置了6路MCP4661,需要读取6路数字电位器里的值,地址从0x28-0x2D
0xC(00001100)即表示为读取 Volatile Wiper0的数据,读取2个字节数据
0X1C(00011100)即表示读取Volatile Wiper1的数据,读取2个字节数据

//具体应用程序
case 20:
        if((*(r_buf+1)==0)&&(*(r_buf+2)==12))
        {
            sdata[0] = 20;
            for(i=0; i<6; i++)
            {
                icaddr = 0x28 + i;
                ReadData(&datofRegister[i*4], 0xC, 2, icaddr);
                DELAY_US(500);
                ReadData(&datofRegister[i*4+2], 0x1C, 2, icaddr);
                DELAY_US(500);
            }
            for(i=0;i<24;i++)
                sdata[i+1] = datofRegister[i];
            dynpack_print(1,sdata,50,512,NULL,NULL);
        }
        break;

数字电位器解锁与锁定(针对非遗失性存储)
HVC高压命令:与A0进行复用,用于指示命令或命令序列处于高压模式,通常
HVC引脚电压大于8.5时,MCP4661处于高压模式,高压命令允许启用或禁用设备的WiperLock技术和写保护功能。

解锁命令(01)
0x24= 0010 0100b Wiper Lock 0 Disable
0x34= 0011 0100b Wiper Lock 1 Disable

锁定命令(10)
0x28= 0010 1000b Wiper Lock 0 Enable
0x38= 0011 1000b Wiper Lock 0 Enable
在这里插入图片描述

该程序前面为功能码(需联系上下文就不阐述了)
采用WriteData函数向icaddr写入1个寄存器数据即可。
通过GPIO口来控制HVC的高低电平
当GPIO100 = 0时HVC2为高电平,GPIO100 = 1时HVC2为低电平
当GPIO101=1时HVC1为高电平,GPIO101 = 0时HVC1为低电平
当锁定/或解锁完成后,配置GPIO退出高压模式
在这里插入图片描述

  // 功能码22:锁定/解锁数字电位器芯片
    case 22:
        if(*(r_buf+2)==12)
        {
            if(*(r_buf+1)==0)
            {
                datofRegister[0] = 0x24;
                datofRegister[1] = 0x34;
            }
            else
            {
                datofRegister[0] = 0x28;
                datofRegister[1] = 0x38;
            }
            GpioDataRegs.GPDCLEAR.bit.GPIO100 = 1;
            GpioDataRegs.GPDSET.bit.GPIO101 = 1;
            DELAY_US(500);
            for(i=0;i<6;i++)
            {
                icaddr = 0x28 + i;
                WriteData(&datofRegister[2],datofRegister[0],0,icaddr);
                DELAY_US(500);
                WriteData(&datofRegister[2],datofRegister[1],0,icaddr);
                DELAY_US(500);
            }
            GpioDataRegs.GPDSET.bit.GPIO100 = 1;
            GpioDataRegs.GPDCLEAR.bit.GPIO101 = 1;
        }
        break;

3.其他

MCP4661的wiper(滑动端)位置会从非易失性寄存器(地址02h/03h)加载保存的值。如果非易失性寄存器未被编程,则加载默至默认值的中间刻度。
地址0与高压命令(HVC)功能复用。因此,A0的状态会在MCP4XXX的上电复位/欠压复位(POR/BOR)事件上锁存

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐