Zynq Linux 使用 SPI EEPROM(AT25M02)


参考文章

  1. Xilinx Wiki/Linux/Linux Drivers/SPI Zynq driver
  2. Xilinx Wiki/Linux/Linux Drivers/Linux SPI Driver
  3. SPI EEPROM

一、AT25M02介绍

AT25M02 提供 2,097,152 位串行电可擦和可编程只读存储器(EEPROM),组织为262,144字,每个8位。 该设备经过了优化,适用于许多低功率和低压操作必不可少的工业和商业应用。 该器件可用于节省空间的8引线SOIC和8球WLCSP封装。 所有的封装工作在1.7V到5.5V或2.5V到5.5V。

• SPI Serial EEPROM 2 Mbits (262,144 x 8)
• Supports SPI Modes 0 (0,0) and 3 (1,1):
– Data sheet describes mode 0 operation
• 5 MHz Clock Rate (5V)
• 256‑Byte Page Mode
• 24‑bit address

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、Vivado工程说明

AT25M02 连接到 PS 端的 SPI_0 上:
在这里插入图片描述

三、设备树配置

在 spi 节点中添加 eeprom 节点,根据 芯片手册 和 驱动程序 drivers/misc/eeprom/at25.c 配置设备树如下:

&spi0 {
	is-decoded-cs = <0>;
	num-cs = <1>;
	status = "okay";
	
	eeprom: eeprom-at25m02@0 {
        compatible = "atmel,at25";
        spi-max-frequency = <5000000>;//5MHz
        reg = <0>;
		//在 drivers/misc/eeprom/at25.c 和 include/linux/spi/eeprom.h 中定义
        at25,addr-mode = <4>;//address bits: 24 bit
        at25,page-size = <256>;//Page: 256 Byte
        at25,byte-len = <262144>;//262144 bytes(2-Mbit)
	};
};

说明:

  • 使用现有驱动程序 "atmel,at25"
  • SPI EEPROM 最大时钟频率 5MHz
  • AT25M02寻址 24 bits ,对应驱动中 mode 为 4
  • AT25M02页大小 256 Bytes
  • AT25M02总大小 262144 bytes

驱动程序如下:

drivers/misc/eeprom/at25.c 中解析设备树程序如下:

static const struct of_device_id at25_of_match[] = {
	{ .compatible = "atmel,at25", },
	{ }
};
static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
	u32 val;

	memset(chip, 0, sizeof(*chip));
	strncpy(chip->name, "at25", sizeof(chip->name));

	if (device_property_read_u32(dev, "size", &val) == 0 ||
	    device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
		chip->byte_len = val;
	} else {
		dev_err(dev, "Error: missing \"size\" property\n");
		return -ENODEV;
	}

	if (device_property_read_u32(dev, "pagesize", &val) == 0 ||
	    device_property_read_u32(dev, "at25,page-size", &val) == 0) {
		chip->page_size = (u16)val;
	} else {
		dev_err(dev, "Error: missing \"pagesize\" property\n");
		return -ENODEV;
	}

	if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) {
		chip->flags = (u16)val;
	} else {
		if (device_property_read_u32(dev, "address-width", &val)) {
			dev_err(dev,
				"Error: missing \"address-width\" property\n");
			return -ENODEV;
		}
		switch (val) {
		case 9:
			chip->flags |= EE_INSTR_BIT3_IS_ADDR;
			/* fall through */
		case 8:
			chip->flags |= EE_ADDR1;
			break;
		case 16:
			chip->flags |= EE_ADDR2;
			break;
		case 24:
			chip->flags |= EE_ADDR3;
			break;
		default:
			dev_err(dev,
				"Error: bad \"address-width\" property: %u\n",
				val);
			return -ENODEV;
		}
		if (device_property_present(dev, "read-only"))
			chip->flags |= EE_READONLY;
	}
	return 0;
}

include/linux/spi/eeprom.h:

struct spi_eeprom {
	u32		byte_len;
	char		name[10];
	u16		page_size;		/* for writes */
	u16		flags;
#define	EE_ADDR1	0x0001			/*  8 bit addrs */
#define	EE_ADDR2	0x0002			/* 16 bit addrs */
#define	EE_ADDR3	0x0004			/* 24 bit addrs */
#define	EE_READONLY	0x0008			/* disallow writes */

	/*
	 * Certain EEPROMS have a size that is larger than the number of address
	 * bytes would allow (e.g. like M95040 from ST that has 512 Byte size
	 * but uses only one address byte (A0 to A7) for addressing.) For
	 * the extra address bit (A8, A16 or A24) bit 3 of the instruction byte
	 * is used. This instruction bit is normally defined as don't care for
	 * other AT25 like chips.
	 */
#define EE_INSTR_BIT3_IS_ADDR	0x0010

	void *context;
};

四、测试程序

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define SPI_EEPROM_PATH "/sys/bus/spi/devices/spi1.0/eeprom"


int eeprom_read(const int fd, const uint32_t offset, void *dev_to_buf, const uint32_t size)
{
	lseek(fd, offset, SEEK_SET);
	return (read(fd, dev_to_buf, size));
}

int eeprom_write(const int fd, const uint32_t offset, const void *buf_to_dev, const uint32_t size)
{
	lseek(fd, offset, SEEK_SET);
	return (write(fd, buf_to_dev, size));
}

int eeprom_open()
{    
	int fd = 0;
	fd = open(SPI_EEPROM_PATH, O_RDWR);
	if(fd < 0) {
		printf("%s: SPI EEPROM device open failed\n", __func__);
		return -1;
	}
	
	return fd;
}

void eeprom_close(const int fd)
{
	close(fd);
}


int main()
{
	int size;
	char sbuf[] = "Hi,this is an eeprom test.";
	char rbuf[64];
	int len;
	int fd;

	len = sizeof(sbuf);
	fd = eeprom_open();
	size = eeprom_write(fd, 0, sbuf, len);
	if(size != len) {
		printf("EEPROM Write Error\n");
		return -1;
	} else {
		printf("\tWrite EEPROM: %s\n", sbuf);
	}
	size = eeprom_read(fd, 0, rbuf, len);
	if(size != len) {
		printf("EEPROM Read Error\n");
		return -1;
	} else {
		printf("\tRead EEPROM: %s\n", rbuf);
	}
	eeprom_close(fd);

	return 0;
}

五、测试

  1. 查看spi总线下设备:
    ls /sys/bus/spi/devices/spi1.0/
    
    在这里插入图片描述
  2. 运行测试程序
    在这里插入图片描述
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值