为什么需要四线串行访问23LC1024?
在“单片机片外RAM,串行的
”中减少了对Microchip公司的SPI接口RAM芯片:23LC1024的读写测试。但是在STC8G1K08但潘辰的SPI接口驱动下,访问对其进行一次字节的读写操作,大概需要消耗20微妙的的时间,这使得在高速、高精度采集应用中跟不上数据的采集。
为了提高对其的访问速度,可以采用以下的方式:
- 使用其四线串行模式(SQI)的方式进行访问;
- 尽量使用序列读写方式,而不是每次完成完整的命令+地址+数据的腹泻方式
下面为了配合AD7606八通道AD采集模块测试
中数据的采集,首先测试23LC1024在STC8G1K08操作下访问速度
本文实验中的工程文件可以在下面资源中下载:
实验电路设计
AD工程文件目录:
AD\Test\2020\TestAD7606STC\TestAD7606STC8G.SchDoc
1. 原理图
电路板设计中采用了STC8G1K08 TSOP20封装的芯片。核心板上集成了23LC1024串行接口的RAM,对于AD7606的接口是通过ADI10芯接口连接。
▲ 原理图
2. PCB
设计电路PCB版图,适宜使用单面PCB板制作实验电路。
▲ 快速制版后的实验电路板
3. 硬件调试
软件开发所在的目录:
C51\STC\Test\2020\testAD76068G1K\TestAD76068G.uvproj
置STC8G1K08的硬件选项配置如下:
▲ 单片机硬件选项配置
主要性能测试
1. 测试单个字节读写的时间
测试标准写入函数在执行过程中,LC1024的CS的波形:
LC1024ByteWrite(0, 0, 0xff, 0xf)
写入时间为2us,CS的波形如下图所示:
▲ CS波形,时间为2.03us
读出的时间也是2.0us,
LC1024ByteRead(0x0, 0x0, 0xff)
下面是在读的时候,CLK, SO1的波形。
▲ CLK,SD1的波形
2. 连续字节读写
使用连续字节读写的方式读取多组字节。下面是读取连续10个字节。所需要的时间为8.57us。
LC1024ReadBegin(0x0, 0x0, 0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024WriteByte(0x0);
LC1024ReadWriteEnd();
▲ 连续读取十个字节所需要的时间
如果仅仅执行读取起始和结束的语句:
LC1024ReadBegin(0x0, 0x0, 0x0);
LC1024ReadWriteEnd();
所小号的时间为2us。这说明读取单个字节的时间大约为 左右。
这个速度与博文“扩展32KRAM的STC8H8K信号采集版
”中,通过并口扩展RAM的一次读写时间0.532us的速度基本相当了。
通过这个时间可以说明,使用SQI(串行四线制)在连续读写的情况下可以达到与并口扩展RAM相当的速度。
即使是单个读写所消耗的2us的时间,也比在博文“单片机片外RAM,串行的
”中读取单个字节所消耗19.2us将近快了10倍左右。
▲ 通电进行调试
▲ 测量读写信号波形
函数程序模块
相关LC1024读取的程序模块如下。
其中致的说明的是,在LC1024的初始化函数中,调用了LC1024Reset命令,就保证了LC1024成功进入SQI模式。
- LC1024访问函数头文件:
/*
**==============================================================================
** LC1024L4.H: -- by Dr. ZhuoQing, 2020-05-04
**
** Description:
**
**==============================================================================
*/
#ifndef __LC1024L4__
#define __LC1024L4__
//------------------------------------------------------------------------------
#ifdef LC1024L4_GLOBALS
#define LC1024L4_EXT
#else
#define LC1024L4_EXT extern
#endif // LC1024L4_GLOBALS
//------------------------------------------------------------------------------
//==============================================================================
#define LC1024_CS 1, 5
#define LC1024_CLK 1, 4
#define LC1024_SO0 1, 0
#define LC1024_SO1 1, 1
#define LC1024_SO2 1, 2
#define LC1024_SO3 1, 3
#define LC1024_CLK_PULSE ON(LC1024_CLK),_nop_(),OFF(LC1024_CLK)
#define LC1024_SO_OUT (P1M1 &= 0xf0, P1M0|=0xf)
#define LC1024_SO_IN (P1M1 |= 0xf, P1M0 &= 0xf0)
//------------------------------------------------------------------------------
void LC1024L4Init(void);
//------------------------------------------------------------------------------
#define LC1024_READ 0x03 // Read data from memory areray beginning at selected address
#define LC1024_WRITE 0x02 // Write data to memory array beginning at selected address
#define LC1024_EDIO 0x3B // Enter Dual I/O access(Enter SDI bus mode)
#define LC1024_EQIO 0x38 // Enter Quad I/O access
#define LC1024_RSTIO 0xFF // Reset Dual and Quad I/O access
#define LC1024_RDMR 0x05 // Read Mode register
#define LC1024_WRMR 0x1 // Write Mode register
#define LONG_3(w) ((unsigned char)(w >> 24))
#define LONG_2(w) ((unsigned char)(w >> 16))
#define LONG_1(w) ((unsigned char)(w >> 8))
#define LONG_0(w) ((unsigned char)w)
//------------------------------------------------------------------------------
void LC1024Reset(void);
void LC1024EQIEnter(void);
void LC1024EQIExit(void);
//------------------------------------------------------------------------------
unsigned char LC1024ByteRead(unsigned char ucAdd2, unsigned char ucAdd1, unsigned char ucAdd0);
void LC1024ByteWrite(unsigned char ucAdd2, unsigned char ucAdd1,
unsigned char ucAdd0, unsigned char ucByte);
//------------------------------------------------------------------------------
void LC1024ReadBegin(unsigned char ucAdd2, unsigned char ucAdd1, unsigned char ucAdd0);
void LC1024WriteBegin(unsigned char ucAdd2, unsigned char ucAdd1, unsigned char ucAdd0);
unsigned char LC1024ReadByte(void);
void LC1024WriteByte(unsigned char ucByte);
void LC1024ReadWriteEnd(void);
//------------------------------------------------------------------------------
unsigned char LC1024ReadMode(void);
void LC1024WriteMode(unsigned char ucMode);
//==============================================================================
// END OF THE FILE : LC1024L4.H
//------------------------------------------------------------------------------
#endif // __LC1024L4__
- LC1024的C语言程序。
/*
**==============================================================================
** LC1024L4.C: -- by Dr. ZhuoQing, 2020-05-04
**
**==============================================================================
*/
//------------------------------------------------------------------------------
#define LC1024L4_GLOBALS 1 // Define the global variables
#include "LC1024L4.H"
#include "C51BASIC.H"
#include "STC8G.H"
#include "INTRINS.H"
//------------------------------------------------------------------------------
void LC1024L4Init(void) {
PM_PP(LC1024_CS);
PM_PP(LC1024_CLK);
ON(LC1024_CS);
OFF(LC1024_CLK);
LC1024_SO_IN;
LC1024Reset();
LC1024EQIEnter();
}
//------------------------------------------------------------------------------
void LC1024EQIEnter(void) {
unsigned char i, ucMask, ucByte;
ucByte = LC1024_EQIO;
ucMask = 0x80;
LC1024_SO_IN;
PM_PP(LC1024_SO0);
OFF(LC1024_CS);
for(i = 0; i < 8; i ++) {
if(ucByte & ucMask) ON(LC1024_SO0);
else OFF(LC1024_SO0);
ucMask >>= 1;
LC1024_CLK_PULSE;
}
LC1024_SO_IN;
ON(LC1024_CS);
}
void LC1024EQIExit(void) {
LC1024_SO_OUT;
P1 |= 0xf;
OFF(LC1024_CS);
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
LC1024_SO_IN;
ON(LC1024_CS);
}
//------------------------------------------------------------------------------
unsigned char LC1024ByteRead(unsigned char ucAdd2, unsigned char ucAdd1, unsigned char ucAdd0) {
unsigned char ucRet;
LC1024_SO_OUT;
OFF(LC1024_CS);
P1 &= 0xf0;
LC1024_CLK_PULSE;
P1 |= 0x3;
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 & 0xf);
LC1024_CLK_PULSE;
LC1024_SO_IN;
LC1024_CLK_PULSE; // Dummy byte
LC1024_CLK_PULSE;
ON(LC1024_CLK);
ucRet = (P1 << 4);
OFF(LC1024_CLK);
ON(LC1024_CLK);
ucRet |= (P1 & 0xf);
OFF(LC1024_CLK);
ON(LC1024_CS);
return ucRet;
}
//------------------------------------------------------------------------------
void LC1024ByteWrite(unsigned char ucAdd2, unsigned char ucAdd1,
unsigned char ucAdd0, unsigned char ucByte) {
LC1024_SO_OUT;
OFF(LC1024_CS);
P1 &= 0xf0;
LC1024_CLK_PULSE;
P1 |= 0x2;
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucByte >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucByte & 0xf);
LC1024_CLK_PULSE;
LC1024_SO_IN;
ON(LC1024_CS);
}
//------------------------------------------------------------------------------
unsigned char LC1024ReadMode(void) {
unsigned char ucRet;
OFF(LC1024_CS);
LC1024_SO_OUT;
P1 &= 0xf0;
LC1024_CLK_PULSE;
P1 |= 0x5;
LC1024_CLK_PULSE;
LC1024_SO_IN;
ON(LC1024_CLK);
ucRet = (P1 << 4);
OFF(LC1024_CLK);
ON(LC1024_CLK);
ucRet |= (P1 & 0xf);
OFF(LC1024_CLK);
ON(LC1024_CS);
return ucRet;
}
//------------------------------------------------------------------------------
void LC1024ReadBegin(unsigned char ucAdd2, unsigned char ucAdd1, unsigned char ucAdd0) {
LC1024_SO_OUT;
OFF(LC1024_CS);
P1 &= 0xf0;
LC1024_CLK_PULSE;
P1 |= 0x3;
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 & 0xf);
LC1024_CLK_PULSE;
LC1024_SO_IN;
LC1024_CLK_PULSE; // Dummy byte
LC1024_CLK_PULSE;
}
//------------------------------------------------------------------------------
void LC1024WriteBegin(unsigned char ucAdd2, unsigned char ucAdd1, unsigned char ucAdd0) {
LC1024_SO_OUT;
OFF(LC1024_CS);
P1 &= 0xf0;
LC1024_CLK_PULSE;
P1 |= 0x2;
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd2 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd1 & 0xf);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucAdd0 & 0xf);
LC1024_CLK_PULSE;
}
unsigned char LC1024ReadByte(void) {
unsigned char ucRet;
ON(LC1024_CLK);
ucRet = (P1 << 4);
OFF(LC1024_CLK);
ON(LC1024_CLK);
ucRet |= (P1 & 0xf);
OFF(LC1024_CLK);
return ucRet;
}
void LC1024WriteByte(unsigned char ucByte) {
P1 &= 0xf0;
P1 |= (ucByte >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucByte & 0xf);
LC1024_CLK_PULSE;
}
//------------------------------------------------------------------------------
void LC1024ReadWriteEnd(void) {
LC1024_SO_IN;
ON(LC1024_CS);
}
//------------------------------------------------------------------------------
void LC1024WriteMode(unsigned char ucMode) {
LC1024_SO_OUT;
OFF(LC1024_CS);
P1 &= 0xf0;
LC1024_CLK_PULSE;
P1 |= 0x5;
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucMode >> 4);
LC1024_CLK_PULSE;
P1 &= 0xf0;
P1 |= (ucMode & 0xf);
LC1024_CLK_PULSE;
ON(LC1024_CS);
LC1024_SO_IN;
}
//------------------------------------------------------------------------------
void LC1024Reset(void) {
LC1024_SO_OUT;
P1 |= 0xf;
OFF(LC1024_CS);
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
LC1024_CLK_PULSE;
ON(LC1024_CS);
LC1024_SO_IN;
}
//==============================================================================
// END OF THE FILE : LC1024L4.C
//------------------------------------------------------------------------------