ZYNQ PS 基于 AXI_IIC 的 EEPROM 读写

embedded/2024/11/26 18:25:12/

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;
}
 

调试的话就跟

//补一下上周没写滴~


http://www.ppmy.cn/embedded/140685.html

相关文章

CASAIM与新疆大学达成全自动化光学测量技术合作,加速推进智能制造现代产业学院建设

近年来&#xff0c;教育部、工业和信息化部联合发布了《现代产业学院建设指南(试行)》&#xff0c;旨在培养适应和引领现代产业发展的高素质应用型、复合型、创新型人才。这一政策背景为智能制造现代产业学院的建设提供了有力支持。 随着“中国制造2025”战略的深入实施&#…

Nginx防御机制

文章目录 1.访问控制1.1基于 IP 的访问限制1.2基于用户认证的访问控制 2.防止 DDoS 攻击2.1连接数限制2.2请求速率限制 3.缓存机制3.1内容缓存 4.安全协议与加密4.1SSL/TLS 加密4.2HTTP/2 支持 5.防 SQL 注入和 XSS 攻击5.1输入验证与过滤 6.防盗链6.1基于 Nginx 的防盗链配置方…

KMeans实验(以鸢尾花为例)

KMeans实验是一个经典的聚类分析实验&#xff0c;它利用KMeans算法将数据集中的样本分成K个簇&#xff0c;使得同一簇内的样本尽可能相似&#xff0c;而不同簇的样本尽可能不同。以下是以常用数据集&#xff08;如鸢尾花数据集&#xff09;为例的KMeans实验详细过程和内容&…

基于FPGA(现场可编程门阵列)的SD NAND图片显示系统是一个复杂的项目,它涉及硬件设计、FPGA编程、SD卡接口、NAND闪存控制以及图像显示等多个方面

文章目录 0、前言 1、目标 2、图片的预处理 3、SD NAND的预处理 4、FPGA实现 4.1、详细设计 4.2、仿真 4.3、实验结果 前言 在上一篇文章《基于FPGA的SD卡的数据读写实现&#xff08;SD NAND FLASH&#xff09;》中&#xff0c;我们了解到了SD NAND Flash的相关知识&am…

Flink学习连载第二篇-使用flink编写WordCount(多种情况演示)

使用Flink编写代码&#xff0c;步骤非常固定&#xff0c;大概分为以下几步&#xff0c;只要牢牢抓住步骤&#xff0c;基本轻松拿下&#xff1a; 1. env-准备环境 2. source-加载数据 3. transformation-数据处理转换 4. sink-数据输出 5. execute-执行 DataStream API开发 //n…

基于YOLOv8深度学习的智慧课堂教师上课行为检测系统研究与实现(PyQt5界面+数据集+训练代码)

随着人工智能技术的迅猛发展&#xff0c;智能课堂行为分析逐渐成为提高教学质量和提升教学效率的关键工具之一。在现代教学环境中&#xff0c;能够实时了解教师的课堂表现和行为&#xff0c;对于促进互动式教学和个性化辅导具有重要意义。传统的课堂行为分析依赖于人工观测&…

python oa服务器巡检报告脚本的重构和修改(适应数盾OTP)有空再去改

Two-Step Vertification required&#xff1a; Please enter the mobile app OTPverification code: 01.因为巡检的服务器要双因子认证登录&#xff0c;也就是登录堡垒机时还要输入验证码。这对我的巡检查服务器的工作带来了不便。它的机制是每一次登录&#xff0c;算一次会话…

conda下载与pip下载的区别

一、conda下载与pip下载的区别 最重要是依赖关系&#xff1a; pip安装包时&#xff0c;尽管也对当前包的依赖做检查&#xff0c;但是并不保证当前环境的所有包的所有依赖关系都同时满足。 当某个环境所安装的包越来越多&#xff0c;产生冲突的可能性就越来越大。conda会检查当…