打印

SPI读写FM25L256出错

[复制链接]
1992|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cjseng|  楼主 | 2017-4-17 02:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
折腾好几天了,用SPI1读写FM25L256,用SPI接口读写或者1模拟SPI接口,都会出错。SPI底层读写程序用来读写FLASH一切正常,连续读写2M字节都没出错。
以下是测试代码,用4个变量来记录连续读写32K字节出错的次数,发现每读一次,出错计数值都不一样。
//测试EEPROM
void Test_EEPROM()
{
u16 i;
u8 temp;       

Count_Err_EEPROM_1=0;
Count_Err_EEPROM_2=0;
for(i=0;i<32768;i++)
{
  SPI_EEPROM_ByteWrite(i, i&0xff);
        temp=SPI_EEPROM_ByteRead(i);
        if(temp!=(i&0xff))
        {       
   Count_Err_EEPROM_1++;                 
        }
}

for(i=0;i<32768;i++)
{
  temp=SPI_EEPROM_ByteRead(i);
        if(temp!=(i&0xff)) Count_Err_EEPROM_2++;
}
  for(i=0;i<32768;i++)
{
  temp=SPI_EEPROM_ByteRead(i);
        if(temp!=(i&0xff)) Count_Err_EEPROM_3++;
}
  for(i=0;i<32768;i++)
{
  temp=SPI_EEPROM_ByteRead(i);
        if(temp!=(i&0xff)) Count_Err_EEPROM_4++;
}
}       


相关帖子

沙发
cjseng|  楼主 | 2017-4-17 02:22 | 只看该作者
本帖最后由 cjseng 于 2017-4-17 02:25 编辑

出错记录(以下数字均为16进制数),冒号前为写入的数字,后面为读出的数字,都是错了一位,均为bit7或者bit2出错,其它位正常。
67:27
3F:BF
75:71
65:61
85:81
95:91
A5:A1
45:41
65:61
D5:55
E5:65
A5:25
C5:45
........

使用特权

评论回复
板凳
dltshuiyu| | 2017-4-17 09:00 | 只看该作者
1.没用过该芯片。是否可从检忙方面入手,连续写应该都是要检忙吧;
2.i&0xff,i是2字节,本身就会产生0xff的数据。i为0xff,0x1ff,0x2ff...写入到dataflash的也将会是0xff

使用特权

评论回复
地板
Prry| | 2017-4-17 10:22 | 只看该作者
cjseng 发表于 2017-4-17 02:22
出错记录(以下数字均为16进制数),冒号前为写入的数字,后面为读出的数字,都是错了一位,均为bit7或者bi ...

单片机常用的总线如i2c、spi、uart等,将其硬件抽象层分离,相关外设在其抽象层上的应用函数接口调用。这样的好处是 :
1、外设的驱动方便移植到任何单片机;
2、外设总线方便移植到其他单片机,只需更改部分寄存器配置;
3、总线调试OK后,调试新的外设程序时,不用重重复复调试总线的程序。
比如:spi总线和eeprom设备分离,假如我这个spi总线要挂其他spi设备(传感器、ADC等),那不需重新写一次总线程序。假设换了一家公司,用了不同单片机,这个eeprom程序可以方便移植到任何单片机。
4、附上25系列(spi)接口eeprom驱动程序,spi函数做了封装,只需调用相关抽象层接口即可,程序方便移植到任何单片机,只需修改相应spi底层接口。没记错的话FM25LXX兼容25系列(spi)的EEPROM,FM24Lxx兼容24系列(i2c)的EEPROM。
//头文件
#ifndef _25XX_H_
#define        _25XX_H_

//25xx register
#define                REG_READ_COMMAND                0X03
#define                REG_WRITE_COMMAND                0X02
#define                REG_WRITE_ENABLE                0X06
#define                REG_WRITE_DISABLE                0X04
#define                REG_READ_STATUS                        0X05
#define                REG_WRITE_STATUS                0X01

//extern function
extern void ee_25xx_init(void);
extern void ee_25xx_write_bytes(uint16_t write_addr, uint8_t *write_buff, uint16_t write_bytes);
extern void ee_25xx_read_bytes(uint16_t read_addr,uint8_t *read_buff,uint16_t read_bytes);
       
#endif

//源文件
#include         "main.h"
#include        "spi.h"
#include  "25xx.h"

//module variable
#define                EE25XX_PAGE_SIZE        64                                //25aa256
struct st_spi_device        ee_25xx_spi_dev;

//module function
static uint8_t ee_25xx_wait_busy(void);

//
void ee_25xx_init(void)
{
                SPI_InitTypeDef  SPI_InitStructure;
                GPIO_InitTypeDef GPIO_InitStructure;
        
                RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO,ENABLE);

                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
                GPIO_Init(GPIOB, &GPIO_InitStructure);
        
                //SPI2 cs
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                                                                                //ÍÆÍìÊä³ö
                GPIO_Init(GPIOB, &GPIO_InitStructure);
                GPIO_SetBits(GPIOB, GPIO_Pin_12);
        
                SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;        //È«Ë«¹¤
                SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                                                                                                //Ö÷ģʽ
                SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                                                                          //data_width                                                
                SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
                SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
                SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                                                                                          
                SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32; //spiʱÖÓ£¬¸ù¾ÝÆ÷¼þËÙ¶ÈÉèÖÃ
                SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                                                                        //¸ßλÔÚÇ°
                SPI_InitStructure.SPI_CRCPolynomial = 7;
                SPI_Init(SPI2, &SPI_InitStructure);
                        
                //device init
                ee_25xx_spi_dev.cs_io.GPIOx = GPIOB;
                ee_25xx_spi_dev.cs_io.GPIO_Pin = GPIO_Pin_12;
                ee_25xx_spi_dev.data_width = 8;
                ee_25xx_spi_dev.SPI = SPI2;
               
                SPI_Cmd(SPI2, ENABLE);                                       
}

//
void ee_25xx_write_enable(uint8_t select)
{
                spi_send(&ee_25xx_spi_dev,&select,1);
}

//
void ee_25xx_write_byte(uint16_t write_addr,uint8_t write_data)
{
                uint8_t send_buff[3];
        
                ee_25xx_write_enable(REG_WRITE_ENABLE);
                send_buff[0] = REG_WRITE_COMMAND;
                send_buff[1] = (write_addr>>8)&0xff;
                send_buff[2] = write_addr&0xff;
                spi_send_then_send(&ee_25xx_spi_dev,send_buff,3,&write_data,1);
                ee_25xx_write_enable(REG_WRITE_DISABLE);
}

/**
  * @brief  25xx write page
  * @param  address,buff,size.write_size is not more than device page size,such as 64 bytes for 25aa256.
  * @retval None
  */
void ee_25xx_write_page(uint16_t write_addr,uint8_t *write_page_buff,uint8_t write_size)
{
                uint8_t send_buff[3];
        
                ee_25xx_write_enable(REG_WRITE_ENABLE);
                send_buff[0] = REG_WRITE_COMMAND;
                send_buff[1] = (write_addr>>8)&0xff;
                send_buff[2] = write_addr&0xff;
                spi_send_then_send(&ee_25xx_spi_dev,send_buff,3,write_page_buff,write_size);
                ee_25xx_write_enable(REG_WRITE_DISABLE);
}

//
void ee_25xx_write_bytes(uint16_t write_addr, uint8_t *write_buff, uint16_t write_bytes)
{
                uint8_t   write_current_bytes,page_offset;
                uint16_t  write_remain,write_current_addr;
                uint8_t         *pbuff;
        
                //ee_25xx_write_enable(REG_WRITE_ENABLE);
                pbuff                                        = write_buff;                        //²»ÒªÖ±½ÓʹÓÃÐβμÆË㣬ÌرðÊÇÖ¸Õë²Ù×÷
                write_remain  = write_bytes;
                write_current_addr = write_addr;
                while(write_remain > 0)
                {
                                page_offset = write_current_addr % EE25XX_PAGE_SIZE;                //Á¬Ðøҳд´óС£¬25aa256Ϊ64×Ö½Ú
                                write_current_bytes   = write_remain > (EE25XX_PAGE_SIZE - page_offset) ? (EE25XX_PAGE_SIZE - page_offset) : write_remain;
                                ee_25xx_write_page(write_current_addr,pbuff, write_current_bytes);
                                write_remain   = write_remain - write_current_bytes;
                                if(write_remain > 0)
                                {
                                                pbuff = pbuff + EE25XX_PAGE_SIZE - page_offset;
                                                write_current_addr  =  write_current_addr + EE25XX_PAGE_SIZE - page_offset;
                                                //Delayms(5);
                                                ee_25xx_wait_busy();//wait free,¸ù¾ÝcpuʱÖÓ¼ÆËãʱ¼ä
                                }
                }
                //ee_25xx_write_enable(REG_WRITE_DISABLE);
}

//
void ee_25xx_read_bytes(uint16_t read_addr,uint8_t *read_buff,uint16_t read_bytes)
{
                uint8_t send_buff[3];
        
                send_buff[0] = REG_READ_COMMAND;
                send_buff[1] = (read_addr>>8)&0xff;
                send_buff[2] = read_addr&0xff;
                spi_send_then_recv(&ee_25xx_spi_dev,send_buff,3,read_buff,read_bytes);
}

//
void ee_25xx_write_status(uint8_t write_data)
{
                u8 send_buff[2];
        
                send_buff[0] = REG_WRITE_STATUS;
                send_buff[1] = write_data;
                spi_send(&ee_25xx_spi_dev,send_buff,2);
}

//
uint8_t ee_25xx_read_status(void)
{
                uint8_t read_status = 0,send_buff[1];
        
                send_buff[0] = REG_READ_STATUS;
                spi_send_then_recv(&ee_25xx_spi_dev,send_buff,1,&read_status,1);
        
                return read_status;
}

//
static uint8_t ee_25xx_wait_busy(void)
{
                uint32_t i;
        
                i = 0xFFFFF;
                while (i--);
               
                return 0;
}

//test
void ee_25xx_test(void)
{
                uint8_t write_buff[255] = {0},read_buff[255] = {0},i;
               
                for(i = 0;i < 0xff;i++)
                                write_buff = i;
                ee_25xx_read_bytes(255,read_buff,255);
                ee_25xx_write_bytes(255,write_buff,255);
                memset(read_buff,0,255);
                ee_25xx_read_bytes(255,read_buff,255);
                for(i = 0;i < 0xff;i++)
                                write_buff = 255-i;
                i=ee_25xx_read_status();
                ee_25xx_write_bytes(255,write_buff,255);
                ee_25xx_read_bytes(255,read_buff,255);
               
}

使用特权

评论回复
5
cjseng|  楼主 | 2017-4-17 10:41 | 只看该作者
dltshuiyu 发表于 2017-4-17 09:00
1.没用过该芯片。是否可从检忙方面入手,连续写应该都是要检忙吧;
2.i&0xff,i是2字节,本身就会产生0xff的 ...

谢谢!
1.这个芯片是铁电EEPROM,无需等待,无需检查忙信号,以总线速度实时写入的。
2.我的程序的本意是,依次写入0x00-0xff,然后循环,直到写满32K字节。

使用特权

评论回复
6
cjseng|  楼主 | 2017-4-17 10:44 | 只看该作者
Prry 发表于 2017-4-17 10:22
单片机常用的总线如i2c、spi、uart等,将其硬件抽象层分离,相关外设在其抽象层上的应用函数接口调用。这 ...

谢谢!
不过我用的这颗芯片,不需要页写,可以一次写入任意字节的数据,直到写到最后一个字节又翻转到0x0000地址。
其它的代码跟你这个几乎就是一样了。

使用特权

评论回复
7
Prry| | 2017-4-17 16:52 | 只看该作者
cjseng 发表于 2017-4-17 10:44
谢谢!
不过我用的这颗芯片,不需要页写,可以一次写入任意字节的数据,直到写到最后一个字节又翻转到0x0 ...

这片东西可以任意写?FRAM读写速度是很快,但也需要页写吧?但从它的数据手册里面确实没有提到页写功能;我使用的FM24Lxx系列的FRAM是需要页写的,跟普通EEPROM一样,只是不需要忙检测或页写延时。

使用特权

评论回复
8
Prry| | 2017-4-17 20:52 | 只看该作者
cjseng 发表于 2017-4-17 10:44
谢谢!
不过我用的这颗芯片,不需要页写,可以一次写入任意字节的数据,直到写到最后一个字节又翻转到0x0 ...

注意spi时钟相位(4种模式),spi速率。

使用特权

评论回复
9
cjseng|  楼主 | 2017-4-17 21:44 | 只看该作者
Prry 发表于 2017-4-17 20:52
注意spi时钟相位(4种模式),spi速率。

模式0和3都试过了,结果一样的,这个芯片支持0和3模式,SPI速率从4-256都试过了,一个样

使用特权

评论回复
10
cjseng|  楼主 | 2017-4-17 21:52 | 只看该作者
Prry 发表于 2017-4-17 16:52
这片东西可以任意写?FRAM读写速度是很快,但也需要页写吧?但从它的数据手册里面确实没有提到页写功能; ...


为什么我看到的datasheet上都说不需要页缓冲区?
我用的是RAMTRON公司的铁电

使用特权

评论回复
11
dalarang| | 2017-4-17 21:59 | 只看该作者
这个问题我也遇上过,后来确认是FM25W256本身的问题,换个供应商买了一批铁电换上去就好了。
当时进了100颗,有50多颗会读取出错,还专门写了个程序来测试。

FM25.rar

1.72 KB

使用特权

评论回复
12
cjseng|  楼主 | 2017-4-17 22:35 | 只看该作者
dalarang 发表于 2017-4-17 21:59
这个问题我也遇上过,后来确认是FM25W256本身的问题,换个供应商买了一批铁电换上去就好了。
当时进了100颗 ...

我买了富士通的铁电,还没到货,到时候试试。

使用特权

评论回复
13
cjseng|  楼主 | 2017-4-18 15:50 | 只看该作者
临时换成FM24L256了,一切正常,连续写32K字节,没有出错,只是写入速度不如SPI接口的。还在等富士通的芯片来测试。

使用特权

评论回复
14
cjseng|  楼主 | 2017-4-18 16:41 | 只看该作者
收到MB85RS256,换上后,一切正常,连续读写32K,不再出错了。看来真是买到假芯片了。

使用特权

评论回复
评论
专注于嵌入式 2023-4-24 16:42 回复TA
我也遇到了,奶奶,重买芯片 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

63

主题

4242

帖子

46

粉丝