标题:
【晒FRAM铁电存储器样片】+MB85RC64芯片读写测试(IO模拟IIC总线—STM32平台)
[打印本页]
作者:
fengye5340
时间:
2014-8-4 21:21
标题:
【晒FRAM铁电存储器样片】+MB85RC64芯片读写测试(IO模拟IIC总线—STM32平台)
本帖最后由 fengye5340 于 2014-8-6 22:13 编辑
一
硬件准备
在深入了解了富士通
FRAM
的特性后,这次来进行
MB85RC64FRAM
的详细测试。测试平台采用
STM32
开发板,其芯片型号是
:STM32F103VBT6,
这个是一个中等容量的
FLASH
芯片,和准备项目应用的芯片
STM32F103VCT6
在软件和代码是兼容的,方便了程序的修改和移植。
在开始全面测试之前,需要准备好硬件资源,这里借助
STM32F0DISCOVERY
上的
ST-LINKV2
作为仿真调试器,采用自制的
CH341USB
转串口芯片作为串口调试终端的连接器。一个功能比较完备的
STM32F103VBT6
开发板。为了实现
MB85RC64 FRAM
芯片的稳定测试,找了一个半成品板子(没有采用万用板连线方式,焊接后线会比较乱),见下图。
焊好四根通信线
后来发现该板子没有上拉电阻,接到开发板上必须得找一个带上拉电阻的端口,麻烦。于是,又换了一个带有上拉电阻的计数器板子,这个板子的外观如下
焊上四根通信线
原理图:
这样相当于为
MB85RC64 FRAM
做好了一个成品模块,直接接入
STM32
的
IO
口就可以了。
因为
STM32
硬件
IIC
总线代码不太稳定,这里采用
IO
模拟
IIC
总线的方式,只需要两个
IO
端口即可,查看了一下板子,通常用
PB6/PB7
端口已经被板子其它
IIC
器件占据,这里我们修改端口
IO
为
PC6--SDA/PC7—SCL
。连线图如下所示。
作者:
fengye5340
时间:
2014-8-4 21:42
A
底层驱动代码实现
底层驱动主要是用
IO
端口模拟出
IIC
总线的通信时序,这个比较简单,从
51
时代就开始模拟
IC
总线,这个没有什么难度,代码如下:
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include <stdio.h>
#include <string.h>
#include "stm32f10x_conf.h"
#include "system_stm32f10x.h"
#include "I2C_103VCT6.H"
/* 类型定义 typedef-----------------------------------------------------------*/
/* 预定义字符 ------------------------------------------------------------*/
/* 宏定义 -------------------------------------------------------------*/
// 对I2C数据总线进行操作。
//===========================================================
// PC7--SCL
// PC6--SDA
#define I2C_PRORT GPIOC
#define I2C_PORT_CLK RCC_APB2Periph_GPIOC
#define I2C_SDA_PIN GPIO_Pin_6
#define I2C_SCL_PIN GPIO_Pin_7
#define I2C_SDA_H GPIO_SetBits(I2C_PRORT, I2C_SDA_PIN)
#define I2C_SDA_L GPIO_ResetBits(I2C_PRORT, I2C_SDA_PIN)
#define I2C_SDA_VAL GPIO_ReadInputDataBit(I2C_PRORT,I2C_SDA_PIN)
#define I2C_SCL_H GPIO_SetBits(I2C_PRORT, I2C_SCL_PIN )
#define I2C_SCL_L GPIO_ResetBits(I2C_PRORT, I2C_SCL_PIN
/* 变量定义 ---------------------------------------------------------*/
extern void Delay_Us(__IO uint32_t nCount);
/*******************************************************************************
* 函数名称: I2C_Gpio_Config();
* 功能描述: 设置I2C引脚,用软件模拟的方法实现I2C功能
* 输入参数: void
* 返回参数: 无
********************************************************************************/
void I2C_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure ;
RCC_APB2PeriphClockCmd(I2C_PORT_CLK ,ENABLE);
//配置I2C_SCL/I2C_SDA引脚
GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN |I2C_SCL_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_PRORT, &GPIO_InitStructure);
GPIO_SetBits(I2C_PRORT, I2C_SDA_PIN |I2C_SCL_PIN );
}
/*******************************************************************************
* 函数名称: I2C_SDA_OUT();
* 功能描述: 设置SDA端口为输出模式
* 输入参数: void
* 返回参数: 无
********************************************************************************/
void I2C_SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_PRORT, &GPIO_InitStructure);
}
/*******************************************************************************
* 函数名称: I2C_SDA_IN();
* 功能描述: 设置SDA端口为输入模式
* 输入参数: void
* 返回参数: 无
********************************************************************************/
void I2C_SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_PRORT, &GPIO_InitStructure);
}
/*******************************************************************************
* 函数名称: I2C_Start();
* 功能描述: 开始条件
* 输入参数: void
* 返回参数: 无
********************************************************************************/
void I2C_Start(void)
{
I2C_SDA_OUT();
I2C_SDA_H ;
I2C_SCL_H ;
Delay_Us(4);
I2C_SDA_L; //START:when CLK is high,DATA change form high to low
Delay_Us(4);
I2C_SCL_L ;//钳住I2C总线,准备发送或接收数据
Delay_Us(4);
}
/*******************************************************************************
* 函数名称: I2C_Stop();
* 功能描述: 停止条件
* 输入参数: void
* 返回参数: 无
********************************************************************************/
void I2C_Stop(void)
{
I2C_SDA_OUT();
//I2C_SCL_L ;
I2C_SDA_L; //STOP:when CLK is high DATA change form low to high
Delay_Us(4);
I2C_SCL_H ;
Delay_Us(4);
I2C_SDA_H ; //发送I2C总线结束信号
Delay_Us(4);
}
/*******************************************************************************
* 函数名称: I2C_Wait_Ack();
* 功能描述: 检查从机的应答操作
* 输入参数: 无
* 返回参数: 从机是否有应答:1--失败,0--成功
********************************************************************************/
unsigned char I2C_Wait_Ack(void)
{
unsigned char utemp ;
I2C_SDA_H ;
Delay_Us(2);
I2C_SCL_H ;
Delay_Us(2);
I2C_SDA_IN(); //SDA设置为输入
utemp = I2C_SDA_VAL;
Delay_Us(2);
I2C_SCL_L ;
Delay_Us(2);
I2C_SDA_OUT();
if( utemp) return 1 ;
else return 0 ;
}
/*******************************************************************************
* 函数名称: I2C_Ack();
* 功能描述: 产生I2C的主机应答操作
* 输入参数: 无
* 返回参数: 无
********************************************************************************/
void I2C_Ack(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_L;
Delay_Us(2);
I2C_SCL_H ;
Delay_Us(2);
I2C_SCL_L;
//I2C_SDA_H;
}
/*******************************************************************************
* 函数名称: I2C_NAck();
* 功能描述: 不产生I2C的主机应答操作
* 输入参数: 无
* 返回参数: 无
********************************************************************************/
void I2C_NAck(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_H;
Delay_Us(2);
I2C_SCL_H ;
Delay_Us(2);
I2C_SCL_L;
}
/*******************************************************************************
* 函数名称: I2C_Write_1();
* 功能描述: 向IIC总线发送一个1
* 输入参数: 无
* 返回参数: 无
********************************************************************************/
void I2C_Write_1(void)
{
I2C_SDA_H;
Delay_Us(2);
I2C_SCL_H ;
Delay_Us(2);
I2C_SCL_L;
Delay_Us(2);
}
/*******************************************************************************
* 函数名称: I2C_Write_0();
* 功能描述: 向IIC总线发送一个0
* 输入参数: 无
* 返回参数: 无
********************************************************************************/
void I2C_Write_0(void)
{
I2C_SDA_L;
Delay_Us(2);
I2C_SCL_H ;
Delay_Us(2);
I2C_SCL_L;
Delay_Us(2);
}
作者:
fengye5340
时间:
2014-8-4 21:44
/*******************************************************************************
* 函数名称: I2C_Send_Byte();
* 功能描述: 向IIC总线发送一个字节的数据
* 输入参数: ucData--发送的数据
* 返回参数: 无
********************************************************************************/
void I2C_Send_Byte(unsigned char ucData)
{
unsigned char i;
//I2C_SDA_OUT();
//I2C_SCL_L;
for(i = 8;i > 0;i--)
{
if( ucData & 0x80) I2C_Write_1();
else I2C_Write_0();
Delay_Us(2);
ucData <<= 1;
}
I2C_SDA_H;
Delay_Us(2);
}
/*******************************************************************************
* 函数名称: I2C_Send_Byte();
* 功能描述: 向IIC总线发送N个字节的数据
* 输入参数: pbuffer--指向发送数据存放首地址
n--数据的个数
* 返回参数: 发送是否成功的标志:0--成功,1--失败
********************************************************************************/
unsigned char I2C_Send_NByte(unsigned char * pbuffer, unsigned char n)
{
unsigned char i;
for(i = 0;i < n;i++)
{
I2C_Send_Byte(* pbuffer);
if(I2C_Wait_Ack()==0)
{
pbuffer++;
}
else
{
I2C_Stop();
return 1;
}
}
I2C_Stop();
return 0;
}
/*******************************************************************************
* 函数名称: I2C_Read_Byte();
* 功能描述: 从IIC总线读取一个字节
* 输入参数: 无
* 返回参数: 读取的数据
********************************************************************************/
unsigned char I2C_Read_Byte(void)
{
unsigned char uData =0x00;
unsigned char utemp,i;
for(i = 8;i > 0;i--)
{
I2C_SDA_H;
Delay_Us(2);
I2C_SCL_H ;
Delay_Us(2);
I2C_SDA_IN(); //SDA设置为输入
Delay_Us(2);
utemp = I2C_SDA_VAL;
uData <<= 1;
if(utemp) uData |= 0x01;
Delay_Us(2);
I2C_SCL_L;
Delay_Us(2);
I2C_SDA_OUT();
}
I2C_SDA_H;
Delay_Us(2);
return( uData );
}
/*******************************************************************************
* 函数名称: I2C_Read_NByte();
* 功能描述: 从IIC总线读取N个字节的数据
* 输入参数: pbuffer--指向发送数据存放首地址
n--数据的个数
* 返回参数: 读取的数据
********************************************************************************/
void I2C_Read_NByte(unsigned char * pbuffer, unsigned char n)
{
unsigned char i;
for(i = 0;i < n;i++)
{
pbuffer[i] = I2C_Read_Byte();
if( i < (n-1)) I2C_Ack(); //应答
else I2C_NAck(); //无应答
}
I2C_Stop();
}
/********************************************************************************
函数名称:Delay()
功 能:延时函数
参 数:无
返 回 值:无
*********************************************************************************/
void Delay(__IO uint32_t nCount)
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
/********************************************************************************
函数名称:Delay_Us()
功 能:软件延时微秒级函数
参 数:无
返 回 值:无
*********************************************************************************/
void Delay_Us(__IO uint32_t nCount)
{
/* 10uS延迟=>10.8uS,100uS延迟=>104uS*/
while (nCount != 0)
{
nCount--;
Delay(350);
}
}
/********************************************************************************
函数名称:Delay_Ms()
功 能:软件延时豪秒级函数
参 数:无
返 回 值:无
*********************************************************************************/
void Delay_Ms(__IO uint32_t nCount)
{
/* 10uS延迟=>10.8uS,100uS延迟=>104uS*/
while (nCount != 0)
{
nCount--;
Delay(35000);
}
}
作者:
fengye5340
时间:
2014-8-4 21:47
B
应用层驱动代码实现
这个代码可以不经修改,直接应用到任何硬件平台中,主要实现
FRAM
器件的读写函数。为了兼容
EERPOM
器件,这里函数名称沿用原来的,没有重新命名和优化,因为
MB85RC64
兼容
AT24C64EERPOM
的。
extern void Delay_Ms(__IO uint32_t nCount);
extern void Delay_Us(__IO uint32_t nCount);
#define Device_Address 0xA0 //24CXX的设备地址
/*******************************************************************************
* 函数名称:
EEPROM_Read_Byte
()
* 功能描述: 从24CXX的指定地址读取1个字节的数据
* 输入参数: dataaddress--数据读取的地址
* 返回参数: 读取的数据
********************************************************************************/
unsigned char EEPROM_Read_Byte(unsigned char dataaddress)
{
unsigned char temp;
I2C_Start(); // 起始条件
I2C_Send_Byte(Device_Address); // 向从器件发送设备地址
if(I2C_Wait_Ack()==0) // 如果有从器件应答
I2C_Send_Byte(dataaddress); // 发送数据地址
else
return 0;
if(I2C_Wait_Ack()==0)
{
I2C_Start(); // 起始条件
I2C_Send_Byte((Device_Address|0x01));
}
else
return 0;
if(I2C_Wait_Ack()==0)
temp = I2C_Read_Byte();
else
return 0;
I2C_NAck();
I2C_Stop();
return temp;
}
/*******************************************************************************
* 函数名称:
EEPROM_Read_NByte
()
* 功能描述: 从24CXX的指定地址读取N个字节的数据
* 输入参数: pbuffer--指向保存数据地址的指针
n--读取数据的个数
dataaddress--数据读取的首地址
* 返回参数: 读取结果:0--成功,1--失败
********************************************************************************/
unsigned char EEPROM_Read_NByte( unsigned char *pbuffer, unsigned char n, unsigned char dataaddress )
{
I2C_Start(); // 起始条件
I2C_Send_Byte(Device_Address); // 向从器件发送设备地址
if(I2C_Wait_Ack()==0) // 如果有从器件应答
I2C_Send_Byte(dataaddress); // 发送数据地址
else
return 1;
if(I2C_Wait_Ack()==0)
{
I2C_Start(); // 起始条件
I2C_Send_Byte((Device_Address|0x01));
}
else
return 1;
if(I2C_Wait_Ack()==0)
I2C_Read_NByte(pbuffer, n);
else
return 1;
return 0;
}
/*******************************************************************************
* 函数名称:
EEPROM_Write_Byte
();
* 功能描述: 向24CXX的指定地址中写入1个字节的数据
* 输入参数: wdata--写入的数据
dataaddress--数据读取的首地址
* 返回参数: 写入结果:0--成功,1--失败
********************************************************************************/
unsigned char EEPROM_Write_Byte( unsigned char dataaddress, unsigned char wdata )
{
I2C_Start(); // 起始条件
I2C_Send_Byte(Device_Address); // 向从器件发送设备地址
if(I2C_Wait_Ack()==0) // 如果有从器件应答
I2C_Send_Byte(dataaddress); // 发送数据地址
else
return 1;
if(I2C_Wait_Ack()==0) // 如果从器件应答
I2C_Send_Byte(wdata); // 发送要写入的数据
else
return 1 ;
if(I2C_Wait_Ack()==0) // 如果从器件应答
I2C_Stop(); // 如果从器件应答 ,发送停止条件
else
return 1;
Delay_Ms(10); //等待EEPROM完成内部写入
return 0 ;
}
/*******************************************************************************
* 函数名称:
EEPROM_Write_NByte
();
* 功能描述: 向24CXX的指定地址中写入1个字节的数据
* 输入参数: dataaddress--数据读取的地址
* 返回参数: 写入结果:0--成功,1--失败
********************************************************************************/
unsigned char EEPROM_Write_NByte( unsigned char *pbuffer, unsigned char n, unsigned char dataaddress )
{
unsigned char temp;
I2C_Start(); // 起始条件
I2C_Send_Byte(Device_Address); // 向从器件发送设备地址
if(I2C_Wait_Ack()==0) // 如果有从器件应答
I2C_Send_Byte(dataaddress); // 发送数据地址
else
return 1;
if(I2C_Wait_Ack()==0) // 如果从器件应答
temp = I2C_Send_NByte(pbuffer, n);
else
return 1;
Delay_Ms(10); //等待EEPROM完成内部写入
if(temp==0) return 0;
else return 1;
}
这应用层的四个函数可以满足大部分应用需求,在测试环节会用到。
作者:
fengye5340
时间:
2014-8-4 21:55
本帖最后由 fengye5340 于 2014-8-6 22:19 编辑
三、读写测试:
1
、编程器读写测试
在使用之前,先用自制的编程器,对
MB85RC64
进行了读写测试,如下图:
因为编程器上位机软件里面没有实现
MB85RC64
这个型号,这里选择
AT24C64
芯片型号,可以看到芯片整片读取时间为
2.78S,
擦写时间:
2.90S
,如果是小容量的话,读写是比较快一些的。
2
多字节缓冲区读写测试
在项目应用中,
FRAM
多字节缓冲区读写主要用于特定字符,测试记录等内容的存储操作。
先来测试多字节读写函数,这里定义了两个缓冲区,
E_buf[16]
和
W_buf[16]
,
内容见截图:
利用
EEPROM_Write_NByte
函数将
E_buf[16]
的内容写入地址
0x20
开始的
16
个地址中,然后利用
EEPROM_Read_NByte
将地址
0x20
开始的
16
个字节再读取出来,打印到串口助手上显示,并进行对照。结果如下:
通过串口助手显示的数据正确无误!为了保险起见,又将
MB85RC64
的存储数据用编程器读出来看看。
看到这样的结果,验证了读写函数的正确性。
现在反过来验证一下,先用编程器编辑一部分烧写数据,然后烧录到
MB85RC64
里面,然后再用多字节读函数
EEPROM_Read_NByte
读取,然后打印到串口助手看看:
烧录的数据如下:
读函数代码:
这里读取
0x00
开始的
255
个字节,也就是
0XFE
处结束。串口助手显示内容截图:
读出来的和通过编程器烧录的数据时一样的!可以进行下一下步了。
作者:
fengye5340
时间:
2014-8-4 21:59
本帖最后由 fengye5340 于 2014-8-6 22:23 编辑
3
单字节缓冲区读写测试
在项目应用中,
FRAM
单字节读写应用范围更广,主要用于触摸屏校准标记,
ADC
校准标记,触摸屏密码设定、程序运行状态储存、各项系统参数存储,掉电数据存储等功能实现。
在这里先简单测试一下,在实际应用中再做详细介绍
,
修改原来的缓冲区
W_buf[16]
内容为相等字符,然后利用循环单个写入
0XA0
起始的
16
个地址中,然后分别读写
0X
A0
和
0XB0
起始的
16
个地址的字符
串口助手显示字符结果:
、
这里读取了两个
16
字节,第一个是
0XA0-0XAF,
可以看到结果是一样的。
0XB0-0XBF
的内容是上次通过编程器烧录的,
结果也是正确的,有了这些测试基础,可以进行应用性测试了。一个器件要保证稳定性应用,必须要做大量的测试才行。
四、总结:
通过上面的详细测试过程,
MB85RC64FRAM
和
EEPROM
完全兼容,且能够发挥自己的优势,下面计划把它应用到一个硬度计的项目中,随样机做更多稳定性测试。
作者:
fengye5340
时间:
2014-8-5 14:24
发帖子上去,现在看不到图片了,不知道如何解决这个问题!
作者:
fengye5340
时间:
2014-8-6 22:25
终于可以显示图片了
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0