小模块例程:i2c_at24cxx - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

i2c读写eeprom(官方例程)

  • mb_zynq_periph_test
  • 我们用了2个AXI IIC,分别读写z7nano上面的eeprom(at24c32),和我的扩展板上的eeprom(at24c02)
  • 使用的是官方的demo例程。需要说明的是,官方的demo例程是可以work的,但需要做一些修改,因为:at24c32的dev地址是0x50, mem地址是16bit, pagesize=32;at24c02的dev地址是0x51, mem地址是8bit,pagesize=8
  • 因此,官方例程修改如下: 对于at24c32
/************************** Constant Definitions *****************************/

/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define IIC_DEVICE_ID			XPAR_IIC_1_DEVICE_ID
#define INTC_DEVICE_ID			XPAR_INTC_0_DEVICE_ID
#define IIC_INTR_ID			XPAR_INTC_0_IIC_1_VEC_ID

/*
 * The following constant defines the address of the IIC Slave device on the
 * IIC bus. Note that since the address is only 7 bits, this constant is the
 * address divided by 2.
 * The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML510/
 * ML501/ML505/ML507/ML510 boards is 0x50. The 7 bit IIC Slave address of the
 * IIC EEPROM on the ML605/SP601/SP605 boards is 0x54.
 * Please refer the User Guide's of the respective boards for further
 * information about the IIC slave address of IIC EEPROM's.
 */
#define EEPROM_ADDRESS		0x50	/* 0xA0 as an 8 bit number. */

/*
 * The page size determines how much data should be written at a time.
 * The ML310/ML300 board supports a page size of 32 and 16.
 * The write function should be called with this as a maximum byte count.
 */
#define PAGE_SIZE		16

/*
 * The Starting address in the IIC EEPROM on which this test is performed.
 */
#define EEPROM_TEST_START_ADDRESS   128

/**************************** Type Definitions *******************************/

/*
 * The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the
 * address pointer in the on board EEPROM is 2 bytes.
 * The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should
 * be u8 as the address pointer in the on board EEPROM is 1 bytes.
 */
typedef u16 AddressType;

对于at24c02,修改如下:

/************************** Constant Definitions *****************************/

/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define IIC_DEVICE_ID			XPAR_IIC_0_DEVICE_ID
#define INTC_DEVICE_ID			XPAR_INTC_0_DEVICE_ID
#define IIC_INTR_ID			XPAR_INTC_0_IIC_0_VEC_ID

/*
 * The following constant defines the address of the IIC Slave device on the
 * IIC bus. Note that since the address is only 7 bits, this constant is the
 * address divided by 2.
 * The 7 bit IIC Slave address of the IIC EEPROM on the ML300/ML310/ML403/ML510/
 * ML501/ML505/ML507/ML510 boards is 0x50. The 7 bit IIC Slave address of the
 * IIC EEPROM on the ML605/SP601/SP605 boards is 0x54.
 * Please refer the User Guide's of the respective boards for further
 * information about the IIC slave address of IIC EEPROM's.
 */
#define EEPROM_ADDRESS		0x51	/* 0xA0 as an 8 bit number. */

/*
 * The page size determines how much data should be written at a time.
 * The ML310/ML300 board supports a page size of 32 and 16.
 * The write function should be called with this as a maximum byte count.
 */
#define PAGE_SIZE		8

/*
 * The Starting address in the IIC EEPROM on which this test is performed.
 */
#define EEPROM_TEST_START_ADDRESS   128

/**************************** Type Definitions *******************************/

/*
 * The AddressType for ML300/ML310/ML410/ML510 boards should be u16 as the
 * address pointer in the on board EEPROM is 2 bytes.
 * The AddressType for ML403/ML501/ML505/ML507/ML605/SP601/SP605 boards should
 * be u8 as the address pointer in the on board EEPROM is 1 bytes.
 */
typedef u8 AddressType;

运行结果

image image image

i2c读写eeprom(小梅哥例程,用的是zynq核,可以直接在microblaze核上运行。程序是完全兼容的。)

  • 注意条件与前面的一样,需要注意AT24C02和AT24C32的设备地址,mem地址位宽,以及pagesize的差异
  • AXI IIC这个IP本身不需要初始化,直接就可以使用。所以用在mb核上,直接可以进入读写
  • 库函数请参考Code部分的ACZ702_Lib\AXI_IIC at24c02程序
/**
  *****************************************************************************
  * 					使用AXI IIC IP核读写EEEPROM
  *****************************************************************************
  *
  * @File    : main.c
  * @By      : Sun
  * @Version : V1.1
  * @Date    : 2022 / 06 / 13
  *
  *****************************************************************************
**/
#include "COMMON.h"
#include "AXI_IIC.h"

#define SEND_PACK_SIZE 8 //AT24C02 EEPROM最多只能连续写一页数据(8byte)

int main(void)
{
	uint8_t Write_Data[SEND_PACK_SIZE];
	uint8_t Read_Data[SEND_PACK_SIZE];
	uint16_t i;
	uint16_t Error_Cnt=0;

	AXI_IIC_Init(&AXI_IIC0,XPAR_IIC_0_DEVICE_ID);	//初始化设备Iic,时钟频率为100kHz

	//将数据0~31放入数组Write_Data里
	for(i=0;i<SEND_PACK_SIZE;i++)
	{
		Write_Data[i]=i;
	}

	//将0~31写入EEPROM的第一页0~31地址里
	AXI_IIC_SeqWrite_Reg(&AXI_IIC0,0x51,REG8, 0x00,Write_Data,SEND_PACK_SIZE);

	usleep(100000);

	//读取EEPROM的第一页0~31地址里的数据,存放在Read_Data数组里
	AXI_IIC_SeqRead_Reg(&AXI_IIC0, 0x51,REG8, 0x00,Read_Data,SEND_PACK_SIZE);

	//对比Write_Data与Read_Data是否一致
	for(i=0;i<SEND_PACK_SIZE;i++)
	{
		if(Write_Data[i] != Read_Data[i])
		{
			Error_Cnt++;//记录错误数据个数
		}
	}

	printf("Error = %d !\n",Error_Cnt);//打印错误数据的个数,全对则为0,代表试验成功
	if(Error_Cnt == 0)
		printf("Write EEPROM successful !!!\n");
	else
		printf("Write EEPROM failed !!!\n");

	return 0;
}

at24c32程序

/**
  *****************************************************************************
  * 					使用AXI IIC IP核读写EEEPROM
  *****************************************************************************
  *
  * @File    : main.c
  * @By      : Sun
  * @Version : V1.1
  * @Date    : 2022 / 06 / 13
  *
  *****************************************************************************
**/
#include "COMMON.h"
#include "AXI_IIC.h"

#define SEND_PACK_SIZE 32 //EEPROM最多只能连续写一页数据(32byte)

int main(void)
{
	uint8_t Write_Data[SEND_PACK_SIZE];
	uint8_t Read_Data[SEND_PACK_SIZE];
	uint16_t i;
	uint16_t Error_Cnt=0;

	AXI_IIC_Init(&AXI_IIC0,XPAR_IIC_1_DEVICE_ID);	//初始化设备Iic,时钟频率为100kHz

	//将数据0~31放入数组Write_Data里
	for(i=0;i<SEND_PACK_SIZE;i++)
	{
		Write_Data[i]=i;
	}

	//将0~31写入EEPROM的第一页0~31地址里
	AXI_IIC_SeqWrite_Reg(&AXI_IIC0,0x50,REG16, 0x00,Write_Data,SEND_PACK_SIZE);

	usleep(100000);

	//读取EEPROM的第一页0~31地址里的数据,存放在Read_Data数组里
	AXI_IIC_SeqRead_Reg(&AXI_IIC0, 0x50,REG16, 0x00,Read_Data,SEND_PACK_SIZE);

	//对比Write_Data与Read_Data是否一致
	for(i=0;i<SEND_PACK_SIZE;i++)
	{
		if(Write_Data[i] != Read_Data[i])
		{
			Error_Cnt++;//记录错误数据个数
		}
	}

	printf("Error = %d !\n",Error_Cnt);//打印错误数据的个数,全对则为0,代表试验成功
	if(Error_Cnt == 0)
		printf("Write EEPROM successful !!!\n");
	else
		printf("Write EEPROM failed !!!\n");

	return 0;
}

补充说明

小梅哥的程序,编译后比较大,达到66kB,超过了我们给microblaze分配的64kB的空间。我们将ld文件中的部分section放到了ddr中。

  • 看框图,microblaze的DP通过zynq的GP0接口可以访问到ddr/ocm。因此数据是可以访问到ddr的,但是指令不能访问到ddr。
  • 实际的测试结果是:将.bss/.heap/.stack分配到ddr中可以运行,而如果将.text分配到ddr中则不能运行,因为.text需要取指令。进一步的测试表明,除了.text/.init/.fini外,其余的都可以放到ddr中,如下图所示。也就是说,只有.text/.init/.fini是跟取指令有关系的。

image image image image