历史上的今天
今天是:2024年10月16日(星期三)
2018年10月16日 | 58.外部SRAM实验
2018-10-16 来源:eefocus
一。IS62WV51216 简介
1. IS62WV51216 是 ISSI(Integrated Silicon Solution, Inc)公司生产的一颗 16 位宽 512K
(512*16,即 1M 字节)容量的 CMOS 静态内存芯片。


实验选用的芯片没有CS2引脚。
2. IS62WV51216读时序



3. IS62WV51216写时序



二。FSMC简介
1. STM32中FSMC框图

为什么VBT6不能用FSMC功能驱动SRAM?
STM32与SRAM连接必须要连接19根地址线,FSMC_A0对应的引脚为PF0,而在100脚的STM32芯片上只有A,B,C,D,E引脚,没有F引脚,所以在100脚以下的STM32芯片无法驱动SRAM。只有144个引脚的STM32芯片才可以驱动SRAM。
为什么在100个引脚的VET6的芯片上可以利用FSMC功能控制液晶屏?
因为FSMC有的地址线是在PE引脚上,而控制液晶屏只需要一根地址线,用来控制发指令还是发数据,所以在100脚的VET6上可以用FSMC功能控制液晶屏,如果要控制SRAM则地址线需要从FSMC_A0到FSMC_A18,很多都是在PF引脚上。,所以VET6不能用FSMC功能控制SRAM。
二。FSMC驱动SRAM的原理

三。NOR PSRAM外设接口

驱动SRAM使用存储块1,由4*64MB四个区组成
三。存储块1操作简介

Bank1接的是16位宽度存储器的时候,内部地址右移一位跟FSMC的地址对齐,除以2对齐
因为在STM32内部每个地址对应一个字节的数据,如果外部设备是16位宽度,那么外部设备的一个地址就代表了FSMC的2个字节。
比如 内部地址 6000 0000(0) 对应FSMC的A0=0 (A0=0的时候对应2个字节)
6000 0010(2) 对应FSMC的A0=1 (A0=1的时候对应2个字节)
6000 0100(4) 对应FSMC的A1=1,A0=0 (对应2个字节)

四。FSMC寄存器介绍

FSMC_BWTRx只有在读写时序不一致的时候才设置。
本实验中EXTMOD位设置为0,不允许读写不同的时序,因此FSMC_BWTRx寄存器不需要设置。
片选时序寄存器(FSMC_BTRx)是很重要的一个寄存器,控制访问的时序。

访问模式为模式A,因此ACCMOD设置为00. 控制FSMC只能选用模式A。

五。硬件连接

为了布线方便,IS62WV51216的地址线A0-A18并没有与FSMC的地址线A0-A18相对应,但这样不会影响使用,因为地址具有唯一性,比如写的地址是xx,读的时候地址也是xx,所以不存在任何问题,地址线可以随意乱接的。
但是数据线必须一一对应。
实验中CS接的是FSMC_NE3。
六。驱动代码讲解

//使用NOR/SRAM的 Bank1.sector3,地址位HADDR[27,26]=10
//对IS61LV25616/IS62WV25616,地址线范围为A0~A17
//对IS61LV51216/IS62WV51216,地址线范围为A0~A18
#define Bank1_SRAM3_ADDR ((u32)(0x68000000)) //NE3所在区的首地址
1. FSMC初始化函数
//初始化外部SRAM
void FSMC_SRAM_Init(void)
{
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
GPIO_InitTypeDef GPIO_InitStructure;
// 所使用的GPIO的初始化
//在使用FSMC功能中所有引脚都要设置成复用推挽输出功能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOE|RCC_APB2Periph_GPIOF| RCC_APB2Periph_GPIOG,ENABLE); //使能相应的GPIO时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE); //使能FSMC时钟
GPIO_InitStructure.GPIO_Pin = 0xFF33; //PORTD复用推挽输出 ,由于引脚很多,使用了简化的方法。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0xFF83; //PORTE复用推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0xF03F; //PORTD复用推挽输出
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 0x043F; //PORTD复用推挽输出
GPIO_Init(GPIOG, &GPIO_InitStructure);
//读写时序的设置
//控制FSMC只用到AddressSetupTime和DataSetupTime
readWriteTiming.FSMC_AddressSetupTime = 0x00; //地址建立时间(ADDSET)为1个HCLK
1/72M=14ns
readWriteTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间(ADDHLD)模式A未用到
readWriteTiming.FSMC_DataSetupTime = 0x03; //数据保持时间(DATAST)为3个HCLK
4/72M=55ns(对EM的SRAM芯片)
readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
readWriteTiming.FSMC_CLKDivision = 0x00;
readWriteTiming.FSMC_DataLatency = 0x00;
readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式A
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;// 这里我们使用NE3 ,也就对
应BTCR[4],[5]。
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
FSMC_NORSRAMInitStructure.FSMC_MemoryType=FSMC_MemoryType_SRAM; //SRAM
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//存储器数
据宽度为16bit
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; //存储器写使能
FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; // 读写使用相 同的时序
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming; //读写同样时序
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //初始化FSMC配置
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能BANK3
}
2. 连续写函数
//在指定地址开始,连续写入n个字节.
//pBuffer:字节指针
//WriteAddr:要写入的地址
//n:要写入的字节数
void FSMC_SRAM_WriteBuffer(u8* pBuffer,u32 WriteAddr,u32 n)
{
for( ; n!=0; n--)
{
*(vu8*)(Bank1_SRAM3_ADDR+WriteAddr)=*pBuffer; //把地址强制转换为u8类型
WriteAddr++;
pBuffer++;
}
}
假设WriteAddr=0,(注意:写入的地址是偶数)那么A0肯定是0
此时LB=0有效,写入的数据是D0-D7有效 ,D8-D15无效,UB=1
继续写地址1的时候,写入的地址就变成6800 0001,此时自动设置LB=1,无效,UB=0,有效,这时候高八位有效,因此数据就写入高8位地址。
UB,LB与要写入的地址的最低位有关联。
如果要写入的数据是16位,那么UB和LB都等于0.而且地址是偶数。
如果地址是奇数,要写一个16位的数据就需要分两次写入,一次写一个8位。因此如果地址是个奇数,写入一个16位的数据,速度就要减半。
3. 连续读函数
//在指定地址开始,连续读出n个字节.
//pBuffer:字节指针
//ReadAddr:要读出的起始地址
//n:要写入的字节数
void FSMC_SRAM_ReadBuffer(u8* pBuffer,u32 ReadAddr,u32 n)
{
for(;n!=0;n--)
{
*pBuffer++=*(vu8*)(Bank1_SRAM3_ADDR+ReadAddr);
ReadAddr++;
}
}
4. 测试函数
u32 testsram[250000] __attribute__((at(0X68000000)));//测试用数组,定义数组的初始绝对地址在6800 0000
//外部内存测试(最大支持1M字节内存测试)
void fsmc_sram_test(u16 x,u16 y)
{
u32 i=0;
u8 temp=0;
u8 sval=0; //在地址0读到的数据
LCD_ShowString(x,y,239,y+16,16,"Ex Memory Test: 0KB");
//每隔4K字节,写入一个数据,总共写入256个数据,刚好是1M字节
for(i=0;i<1024*1024;i+=4096)
{
FSMC_SRAM_WriteBuffer(&temp,i,1);
temp++;
}
//依次读出之前写入的数据,进行校验
for(i=0;i<1024*1024;i+=4096)
{
FSMC_SRAM_ReadBuffer(&temp,i,1);
if(i==0)sval=temp;
else if(temp<=sval)break;//后面读出的数据一定要比第一次读到的数据大.
LCD_ShowxNum(x+15*8,y,(u16)(temp-sval+1)*4,4,16,0);//显示内存容量
}
}
c语言小贴士:
__attribute__,这个是 用来指定变量或结构位域的特殊属性,该关键字后的双括弧中的内容是属性说明。
然后是at关键字,该关键字可以用来设置变量的绝对地址,也就是你可以通过这个关键字,指定某个变量处于内存里面的某个给定的地址.
综合起来,就是设置变量处于0X68000000这个地址.
在使用FSMC功能中所有引脚都要设置成复用推挽输出功能

读写时序分析

经验值 DATAST = 2才能正常工作
单位是HCLK个时钟周期
1个HCLK时钟周期为1/72M=13.8ns
DATAST位的值不能为0.(0为保留)
5. 如何对SRAM进行读写
使用指针的方法进行读写
不需要写读写函数,可以直接使用指针的方式对STM32的内存地址进行访问。
(1)首先要定义SRAM的基地址:
#defeine SRAM_BASE_ADDR (0x68000000) //基地址从0x68000000开始
#define SRAM_SIZE (1*1024*1024) //一共有1M字节
#define SRAM_END_ADDR (SRAM_BASE_ADDR + SRAM_SIZE) //SRAM结束的地址
//用#define定义宏的时候用括号是个习惯,防止以后如果有运算的时候会影响宏的运算法则。
(2)定义指针,操作单字节数据
u8 *p;
p = (u8 *)SRAM_BASE_ADDR; //把数据SRAM_BASE_ADDR强制转换成指针
*p = 0xAB; //向0x68000000地址写入0xAB
如何操作双字节数据
先定义一个16位的指针
u16 *p16;
p = (u16 *)SRAM_BASE_ADDR; //把数据SRAM_BASE_ADDR强制转换成16位指针
*p16 = 0xCDEF; //一次可以操作2个字节
如何操作浮点数
定义一个指向浮点数的指针
float *pf;
p = (float *)SRAM_BASE_ADDR; //把数据SRAM_BASE_ADDR强制转换成指向浮点数的指针
*pf = 56.35;
使用绝对地址的方式访问SRAM
u8 testValue __attribute__ ( (at (SRAM_BASE_ADDR ) ) );
把变量testValue的地址定义到0x68000000
testValue = 50;
注意:使用 __attribute__定义变量时必须定义为全局变量
否则如果使用局部变量,变量还是会被定义在内部RAM中。
下一篇:56。CAN通信基础知识介绍
史海拾趣
|
DMA传输数据64K时,目的空间每包前一部分(4K左右)是后一包的数据,后一部分是前一包的数据(60K), 比如我第i包全是2,第i+1全是3,我看到的第i+1数据如下(很有规律): 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 ...… 查看全部问答> |
|
一、正确使用变频器应注意事项 1、环境温度对变频器的使用寿命有很大的影响。环境温度每升10℃,则变频器寿命减半,所以周围环境温度及变频器散热的问题一定要解决好。 2、正确的接线及参数设置。在安装变频器之前一定要熟读其手册,掌握其用法、 ...… 查看全部问答> |
|
我相信大家都是应该先玩完单片机以后开始玩ARM的吧!~我也是这样的,但是为什么突然觉得还是单片机好玩一些,我想了一下,是因为单片机简单?不是,是因为它价格低?我不做产品,所以无所谓呀,但是就是感觉自己还是喜欢玩单片机一些,坛友们你们也 ...… 查看全部问答> |




