AS5045B/AS5145 零位编程 OTP

因为项目需要修改零位,最终没有采用硬件SPI,发现OTP操作需要用到芯片手册中特定的时序,于是采用IO模拟的方法。

下图是芯片的寄存器,蛋疼的是根据官方手册和例程,知道这款芯片需要对寄存器所有位进行操作,所以需要先读一遍寄存器,再把零位数据Z11-Z0依次写入。AMS公司有别的芯片,可以通过spi选择寄存器对某些功能进行改写。

有关SSI通信的还有另一种,AS5045不带B的,那个貌似只需要直接写16位命令即可,比较方便,没有实际动手尝试过。

对芯片进行写/编程操作分4块步骤。

例如启动编程操作是CS先要在上升沿,CS拉低,PDIO引脚拉高,CLK拉低;然后CS拉高,再延迟一段时间,拉低,处于下降沿。CLK再拉高,再接着进入下降沿拉低。信号的延时可以自己把握,只要按照手册时间要求范围即可。不一定像官方那样,每一步都要延时,有几个可以同时进行。

当时打的草稿hh。

打的草稿
标题

零位编程代码的话就是根据官方给的例程直接修改即可。

void initPPTRIM()
{
  PDIO_SetDigitalOutput();
  PDIO_SetLow();
}

void clkPulses(unsigned char num)
{
  unsigned char i;
  for (i = 0; i < num; i++)
  {
    CLK_SetHigh(); DELAY_microseconds(PPTRIMDelay);
    CLK_SetLow(); DELAY_microseconds(PPTRIMDelay);
  }
}

void setupCondition() {
  SPI_CS_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  PDIO_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  SPI_CS_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  SPI_CS_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetLow();
  DELAY_microseconds(PPTRIMDelay);
}

void exitCondition() {
  PDIO_SetDigitalOutput();
  DELAY_microseconds(PPTRIMDelay);
  SPI_CS_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  SPI_CS_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  PDIO_SetLow();
  DELAY_microseconds(PPTRIMDelay);
}

void operationModeLoad()
{
  PDIO_SetLow();
  DELAY_microseconds(1);
  SPI_CS_SetHigh();
  DELAY_microseconds(1);
  clkPulses(4);
}

void operationModeRead()
{
  PDIO_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  SPI_CS_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  clkPulses(1);
  PDIO_SetDigitalInput();
}

void operationModeWrite()
{
  SPI_CS_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  clkPulses(3);
}

void operationModeProg()
{
  CLK_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  SPI_CS_SetHigh();
  DELAY_microseconds(PPTRIMDelay);
  CLK_SetLow();
  DELAY_microseconds(PPTRIMDelay);
  clkPulses(4);
}

unsigned char reversebits(unsigned char val) // Endian switch
{
  unsigned char i = 0, result = 0;
  while (i < 8)
  {
    result += (val << i) & 0x80;
    if (i < 7) result = result >> 1;
    i++;
  }
  return result;
}

void pptrimLoad(unsigned char num_bits)
{
  setupCondition();
  operationModeLoad();
  clkPulses(num_bits);
  exitCondition();
}

void pptrimRead(unsigned char *buff, unsigned char num_bits)
{
  unsigned char current_byte = 0;
  unsigned char current_bit = 0;
  unsigned char temp = 0;
  if (!num_bits) return;
  current_byte = num_bits >> 3;
  current_bit = num_bits & ~0x07;
  setupCondition();
  operationModeRead();
  clkPulses(1); // position the first bit to read
  //-- read OTP Data --
  temp = 0;
  temp += PDIO_GetValue();
  for (current_bit = num_bits; current_bit; current_bit--)
  {
    if (((current_bit - 1) & 0x07) == 0)
    {
      buff[current_bit >> 3] = temp;
      temp = 0;
    }
    if (current_bit)
    {
      temp <<= 1;
      CLK_SetHigh();
      DELAY_microseconds(2);
      temp += PDIO_GetValue();
      CLK_SetLow();
      DELAY_microseconds(2);
    }
  }
  exitCondition();
}

void pptrimWrite(unsigned char *buff, unsigned char num_bits)
{
  unsigned char *current_byte;
  unsigned char current_bit = 0;
  unsigned char temp = 0;
  current_byte = buff + ((num_bits - 1) >> 3);
  temp = *current_byte;
  if (num_bits % 8)
    temp <<= 8 - (num_bits % 8);
  setupCondition();
  operationModeWrite();
  //-- send OTP Data
  for (current_bit = num_bits; current_bit; current_bit--)
  {
    if (temp & 0x80)
      PDIO_SetHigh();
    else
      PDIO_SetLow();
    DELAY_microseconds(1);
    CLK_SetHigh();
    DELAY_microseconds(2);// delay, tzapp=2us(typ.)
    CLK_SetLow();
    DELAY_microseconds(PPTRIMDelay);
    temp <<= 1;
    if (((current_bit - 1) & 0x07) == 0)
    {
      temp = *(--current_byte);
    }
  }
  PDIO_SetHigh();
  DELAY_microseconds(1);
  clkPulses(1); // data latched
  // END OTP-Write
  exitCondition();
}

/*********读绝对角度值****************/
/*IO模拟SPI*/
uint16_t Sim_Read_AS5045()
{
    uint16_t out=0;
    uint8_t i;
    out=0;        
    SPI_CS_SetHigh(); 
    CLK_SetHigh(); 
    SPI_CS_SetLow();         //数据输出DO从变为高电平并启动读取操作
    DELAY_microseconds(5);
    
    CLK_SetLow();         //数据在CLK第一个下降沿锁存至输出移位寄存器中
    DELAY_microseconds(5);
    for(i=0;i<15;i++)     //循环取15位信息
    {
        out=out<<1;
        CLK_SetHigh();
       //每个CLK上升沿移出一位数据
        DELAY_microseconds(2);
        out|=DO_GetValue();
        DELAY_microseconds(2);
        CLK_SetLow();
        DELAY_microseconds(2);
    }

    DELAY_microseconds(2);
    SPI_CS_SetHigh();
    CLK_SetHigh();
    DELAY_microseconds(1);
    return (out);
}
 
uint16_t Sim_Angle_Dout()
{
    Read_Magnetic_Field();
    AS5045.Dat=Sim_Read_AS5045();
    AS5045.OCF= (AS5045.Dat>>2) & 0x01;
    AS5045.COF= (AS5045.Dat>>1) & 0x01;
    AS5045.LIN= AS5045.Dat& 0x01;
    AS5045.AngleDigtal= (AS5045.Dat >> 3);
    
    return AS5045.AngleDigtal;
}

uint16_t Angle =0;

void AS5045_Dat()
{
    Angle=Sim_Angle_Dout()*0.00879*10;
    AS5045.Ang_L=Angle;
    AS5045.Ang_H=Angle>>8;
}

void WriteZero()
{
    unsigned char ZeroTemp,PPTrimBuffer[7];
    Sim_Angle_Dout();
     if(AS5045.OCF&&AS5045.COF==0&&AS5045.LIN==0)
    {  
        // Step 1: Read the 18 bit SSI value from the AS5145 (AS5140 uses 16 bit)
        AS5045.AngleDigtal= (Sim_Read_AS5045() >> 3);

        // Step 2: Read the 54 PPTRIM OTP bits from the AS5145
        pptrimRead(PPTrimBuffer, 54);

        // Step 3: Write the actual angle to the zero position field of the OTP bits
        ZeroTemp = AS5045.AngleDigtal>>8;
        ZeroTemp = reversebits(ZeroTemp);
        PPTrimBuffer[4] = ZeroTemp;

        ZeroTemp = (uint8_t)AS5045.AngleDigtal;
        ZeroTemp = reversebits(ZeroTemp);
        PPTrimBuffer[5] = ZeroTemp;

        // Step 4: Write back the 54 PPTRIM OTP bits containing the Zero position (which isthe actual angle) to the AS5145
        pptrimWrite(PPTrimBuffer, 54);
        DELAY_milliseconds(10);
         // Step 5: Read the new angle. Must be 0 (+-1, if the mechanics is not very stable)
        AS5045_Dat();
     }

}

关于零位编程,发送指令后会将当前读到的角度值设为零位,再次读取角度值,该角度为0。<br>

重复读当前零位值可能会出现原来设定前的值或0,旋转磁铁后不会出现此情况,每次设备上电只能进行一次零位编程,不可重复发送零位编程的命令,掉电后写零数据丢失。

工程下载地址:https://gitee.com/ling0yi/as5045-b-as5145

版权声明:本文为CSDN博主「随风飘零翼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zy19981110/article/details/122879098

生成海报
点赞 0

随风飘零翼

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

RT-Thread Studio移植LAN8720A驱动

RTT网络协议栈驱动移植(霸天虎) 1、新建工程 ​ 工程路径不含中文路径名,工程名用纯英文不含任何符号。 2、用CubeMx配置板子外设 2.1、配置时钟 ​ 按照自己板子配置相应时钟。

ESP8266 无限重启踩坑

最近做了一个电子墨水屏万年历,在移植屏幕代码时遇到了esp8266无限软复位的问题,如果你的串口打印是以下图片所示,那么恭喜你问题解决了。 造成软复位的原因是因为,程序里有死循环&#xf

Lin总线通信在STM32作为主机代码以及从机程序

距离上次做资料准备已经过去六天了。最近在学车,上周末就没有开电脑。这周开始进行了Lin通信的代码整理,目前是可以正常通信的了,采用的是增强型校验方式。后期再进一步跟进研究。。。更新一博,留

4路红外循迹模块使用教程

4路红外循迹模块使用教程 个人原创博客:点击浏览模块详细信息: 工作电压:DC 3.3V~5V 工作电流:尽量选择1A以上电源供电 工作温度:-10℃~50℃ 安装孔