自学内容网 自学内容网

ZYNQ PS 基于 AXI_IIC 的 EEPROM 读写

REVIEW

关于 PS I2C读写EEPROM已经简单的实现过:

ZYNQ PS 基于I2C的EEPROM读写-CSDN博客

1. 今日摸鱼任务

使用 AXI IIC 核搭建的 IIC 控制器读取 EDA 拓展板上的EEPROM 芯片。
数据经由 I2C 接口写入和读出 EEPROM芯片,并对比写入和读出的值,将错误个数和对比结果通过开发板 PS 侧调试接口打印出来。

小梅哥教材:

03_【裸机教程】基于C编程的Zynq裸机程序设计与应用教程v2.4.5.pdf

第九章 基于AXI_I2C的EEPROM读写

2. AXI_IIC

AXI4-Lite 接口:该接口为 AXI4-Lite 从接口,用于访问 AXI IIC 寄存器
中断控制:该模块从 AXI IIC 获取中断状态并向主机生成中断。
寄存器接口:用户可以通过 AXI4-lite 接口访问寄存器,该模块包含控制和状态寄存器。
                      它还提供了访问 TX FIFO 和 RX FIFO 的选项。
动态主机:该模块动态控制 IIC 模块的模式。 当开始位和停止位写入发送 FIFO 时,该模块工作。
软复位:该模块允许用户使用软件复位模块。
IIC 控制:该模块包含控制 IIC 接口的状态机。
                它与 Dynamic Master 模块相连以将 IP 核配置为主或从模式。
中断控制:该模块根据中断使能寄存器设置,为各种条件生成中断。
动态 IIC 控制逻辑:动态控制器逻辑为 AXI IIC 控制器提供了一个易于使用的接口。
                                动态逻辑仅支持主模式和 7 位寻址。
ACZ702 开发板上芯片速度等级为 -1,因此输出给 AXI-Lite 接口的时钟最大为 120MHz

3. Block Design

4.  AXI_IIC

AXI_IIC.h

#ifndef __AXI_IIC_H__
#define __AXI_IIC_H__

#include "xiic.h"
#define REG8 8
#define REG16 16

extern XIic AXI_IIC0;


void AXI_IIC_Init(XIic *InstPtr, uint16_t DeviceId);
void AXI_IIC_Write_Reg(XIic *InstPtr,uint8_t SlaveID,uint8_t RegBIT, uint16_t reg, uint8_t dat);
uint8_t AXI_IIC_Read_Reg(XIic *InstPtr,uint8_t SlaveID,uint8_t RegBIT, uint16_t reg);
void AXI_IIC_SeqWrite_Reg(XIic *InstPtr,uint8_t SlaveID,uint8_t RegBIT, uint16_t reg, uint8_t *send_dat, uint32_t send_len);
void AXI_IIC_SeqRead_Reg(XIic *InstPtr,uint8_t SlaveID, uint8_t RegBIT, uint16_t reg,uint8_t *recv_data, uint32_t recv_len);
#endif

AXI_IIC.c

#include "AXI_IIC.h"

XIic AXI_IIC0;//例化IIC设备

/*********************************************************************
**  @brief    初始化AXI IIC设备
**  @param    InstPtr IIC设备实例化对象
**  Sample usage:    AXI_IIC_Init(&AXI_IIC0,XPAR_IIC_0_DEVICE_ID);//初始化AXI_IIC0
**  注:IIC频率在图形化界面的AXI IIC IP核中配置,默认为100K
***********************************************************************/
void AXI_IIC_Init(XIic *InstPtr, uint16_t DeviceId)
{
    XIic_Config *ConfigPtr;    //指向配置数据的指针
    //初始化IIC驱动程序
    ConfigPtr = XIic_LookupConfig(DeviceId);
    XIic_CfgInitialize(InstPtr, ConfigPtr,ConfigPtr->BaseAddress);
}

/************************************************************************************************************
**  @brief    写入一个字节数据到I2C设备指定寄存器地址
**  @param    InstPtr IIC设备实例化对象
**  @param    SlaveID    从机地址(7位地址)
**  @param    RegBIT    从机寄存器位数:REG8(8位)REG16(16位)
**  @param    reg        从机寄存器地址(8位或16位)
**  @param    Data    要写入的数据
**    Sample usage:    AXI_IIC_Write_Reg(&AXI_IIC0,0x12,REG8,0x34, 6);//写入数据6到0x34地址,从机地址0x12
************************************************************************************************************/
void AXI_IIC_Write_Reg(XIic *InstPtr,uint8_t SlaveID,uint8_t RegBIT, uint16_t reg, uint8_t dat)
{
    uint8_t Byte = 0;
    uint8_t WR_Buffer[3];
    if(RegBIT== REG16)
    {
        WR_Buffer[0] = reg>>8;
        WR_Buffer[1] = reg&0x00FF;
        WR_Buffer[2] = dat;
    }
    else if(RegBIT== REG8)
    {
        WR_Buffer[0] = reg;
        WR_Buffer[1] = dat;
    }


    //发送数据
    if(RegBIT== REG16)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, 3,XIIC_STOP);
        }while(Byte < 3);
    }
    else if(RegBIT== REG8)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, 2,XIIC_STOP);
        }while(Byte < 2);
    }
}
/************************************************************************************************************
**  @brief    读取I2C设备指定地址寄存器的数据
**  @param    InstPtr IIC设备实例化对象
**  @param    SlaveID    从机地址(7位地址)
**  @param    RegBIT    从机寄存器位数:REG8(8位)REG16(16位)
**  @param    reg        从机寄存器地址
**  @return            要读取的数据
**  Sample usage:    uint8_t value = AXI_IIC_Read_Reg(&AXI_IIC0,0x12,REG8,0x34);//从机设备地址为0x12,读取从机寄存器地址为0x34的数据
************************************************************************************************************/
uint8_t AXI_IIC_Read_Reg(XIic *InstPtr,uint8_t SlaveID,uint8_t RegBIT,uint16_t reg)
{
    uint8_t Byte = 0;
    uint8_t RD_Buffer[1],WR_Buffer[2];

    if(RegBIT== REG16)
    {
        WR_Buffer[0] = reg>>8;
        WR_Buffer[1] = reg&0x00FF;
    }
    else if(RegBIT== REG8)
    {
        WR_Buffer[0] = reg;
    }

    //发送数据
    if(RegBIT== REG16)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, 2,XIIC_STOP);
        }while(Byte<2);
    }
    else if(RegBIT== REG8)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, 1,XIIC_STOP);
        }while(Byte<1);
    }

    //接收数据
    do
    {
        Byte = XIic_Recv(InstPtr->BaseAddress, SlaveID,RD_Buffer, 1,XIIC_STOP);
    }while(Byte<1);

    return RD_Buffer[0];//返回读取到的值
}

/************************************************************************************************************
**  @brief    连续写入多个字节数据到I2C设备指定寄存器地址
**  @param    InstPtr IIC设备实例化对象
**  @param    SlaveID    从机地址(7位地址)
**  @param    RegBIT    从机寄存器位数:REG8(8位)REG16(16位)
**  @param    reg        从机寄存器地址(8位或16位)
**  @param    send_dat    要写入的数据
**  @param    send_len    写入数据的长度
**    Sample usage:    AXI_IIC_SeqWrite_Reg(&AXI_IIC0,0x12,REG8,0x34,send_dat,6);//将数组send_dat里的6个数据连续写入0x12设备的0x34到0x39寄存器
************************************************************************************************************/
void AXI_IIC_SeqWrite_Reg(XIic *InstPtr,uint8_t SlaveID,uint8_t RegBIT, uint16_t reg, uint8_t *send_dat, uint32_t send_len)
{
    uint32_t Byte = 0;
    uint8_t WR_Buffer[send_len+2];
    if(RegBIT == REG16)
    {
        WR_Buffer[0] = reg>>8;        //取高八位
        WR_Buffer[1] = reg&0x00FF;    //取低八位

        memcpy(WR_Buffer+2,send_dat,send_len);
    }
    else if(RegBIT == REG8)
    {
        WR_Buffer[0] = reg;

        memcpy(WR_Buffer+1,send_dat,send_len);
    }
    
    //发送数据
    if(RegBIT== REG16)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, send_len + 2,XIIC_STOP);
        }while(Byte < (send_len + 2));
    }
    else if(RegBIT== REG8)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, send_len + 1,XIIC_STOP);
        }while(Byte < (send_len + 1));
    }
}
/************************************************************************************************************
**  @brief    连续读取多个字节数据到I2C设备指定寄存器地址
**  @param    InstPtr IIC设备实例化对象
**  @param    SlaveID    从机地址(7位地址)
**  @param    RegBIT    从机寄存器位数:REG8(8位)REG16(16位)
**  @param    reg        从机寄存器地址(8位或16位)
**  @param    recv_data    将读取的数据存放在数组recv_data里
**  @param    recv_len    读取数据的长度
**    Sample usage:    AXI_IIC_SeqRead_Reg(&AXI_IIC0,0x12,REG8,0x34,recv_data,6);//将0x12设备的0x34到0x39寄存器里的数据读取到数组send_dat里,长度为6
************************************************************************************************************/
void AXI_IIC_SeqRead_Reg(XIic *InstPtr,uint8_t SlaveID, uint8_t RegBIT, uint16_t reg,uint8_t *recv_data, uint32_t recv_len)
{
    uint32_t Byte = 0;
    uint8_t WR_Buffer[2];

    if(RegBIT== REG16)
    {
        WR_Buffer[0] = reg>>8;
        WR_Buffer[1] = reg&0x00FF;
    }
    else if(RegBIT== REG8)
    {
        WR_Buffer[0] = reg;
    }

    //发送数据
    if(RegBIT== REG16)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, 2,XIIC_STOP);
        }while(Byte<2);
    }
    else if(RegBIT== REG8)
    {
        do
        {
            Byte = XIic_Send(InstPtr->BaseAddress,SlaveID,WR_Buffer, 1,XIIC_STOP);
        }while(Byte<1);
    }

    //接收数据
    do
    {
        Byte = XIic_Recv(InstPtr->BaseAddress, SlaveID,recv_data, recv_len,XIIC_STOP);
    }while(Byte<recv_len);
}
 

5. main.c

#include <stdio.h>
#include <stdint.h>
#include "xparameters.h"
#include "AXI_IIC.h"
#include "sleep.h"

#define SEND_PACK_SIZE 32 //EEPROM 最多只能连续写一页数据(32byte)
#define data_len SEND_PACK_SIZE+5
int main(void)
{
    u8 Write_Data[data_len];
    u8 Read_Data[SEND_PACK_SIZE];
    u16 i;
    u16 Error_Cnt=0;
    AXI_IIC_Init(&AXI_IIC0,XPAR_IIC_0_DEVICE_ID);
    //将数据 0~31 放入数组 Write_Data 里
    for(i=0;i<data_len;i++)
    {
        Write_Data[i]=i;
    }
    //将 0~31 写入 EEPROM 的第一页 0~31 地址里
    AXI_IIC_SeqWrite_Reg(&AXI_IIC0,0x50,REG16,0x0080,Write_Data,data_len);
    usleep(100000);
    //读取 EEPROM 的第一页 0~31 地址里的数据,存放在 Read_Data 数组里
    AXI_IIC_SeqRead_Reg(&AXI_IIC0, 0x50,REG16,0x0080,Read_Data,SEND_PACK_SIZE);
    //对比 Write_Data 与 Read_Data 是否一致
    for(i=0;i<SEND_PACK_SIZE;i++)
    {
        if(Write_Data[i] != Read_Data[i])
        {
            printf("Write_Data[ %d] =  %d Read_Data[ %d]= %d !\n",i , Write_Data[i], i ,Read_Data[i]);
            Error_Cnt++;//记录错误数据个数
        }
    }
    printf("Error = %d !\n",Error_Cnt);
    if(Error_Cnt == 0)
        printf("Write EEPROM successful !!!\n");
    else
        printf("Write EEPROM failed !!!\n");
    return 0;
}
 

调试的话就跟

//补一下上周没写滴~


原文地址:https://blog.csdn.net/hhh123987_/article/details/143944040

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!