一、前言
虽然H743给的内部RAM已经很多了,但看到我这篇文章的朋友一定都明白:就算再慷慨的内部RAM,也有用尽的时候,所以我们要外扩RAM,这时候有两个选择,SDRAM或者SRAM,都可以用,我会用两篇博客分别带来它们两者的配置过程!
F407和H743配置大同小异,H7多出来的地方也没什么。
我就以H743+IS61WV204816BLL的配置为例:
二、配置CubeMX
首先还是惯例的配置时钟,还有电源调整器电压范围调为0(这样就能把时钟调得很高)。
然后把时钟配一下,拉到最高480M,让cubemx自动配置
照例打开串口
接下来就是配置FMC啦,SRAM就是挂在这个接口上(这个接口在F407上叫FSMC,FMC可以看作是升级版,比FSMC多些功能,还能挂SDRAM)
先是第一部分的配置:
这三点需要额外注意!!!
①首先,我们SRAM挂在这个区域,但可要注意了,这个区域里有个很容易忽视的“4x64MB”,原来这个区域又划分成了4个64MB的区域!
NE1区域:0x6000 0000 ~0x63FF FFFF
NE2区域:0x6400 0000 ~0x67FF FFFF
NE3区域:0x6800 0000 ~0x6BFF FFFF
NE4区域:0x6C00 0000 ~0x6FFF FFFF
而我们的SRAM挂在哪个NE上,要取决于SRAM的CS引脚接在STM32上的哪个引脚上,比如我的SRAM的CS引脚接在STM32H743ZIT6的PC7上,这个引脚有FMC_NE1的功能,所以我这里用的就是NE1,在CubeMX里就选择NE1。
②然后看到地址位,为什么我填的是21bit呢?因为这个SRAM是204816,这个名字表明这是一个2048K行位宽16位的SRAM,2048千行需要多少位来表示呢?2的21次方就是2048K,所以这个芯片的地址线有21bit(A0-A20),当然,这个也能在手册里看见,我啰嗦几句只是想把这个讲得更生动一些。(照例来说,如果是102416,就是20bit(A0-A19);51216就是19bit(A0-A18))
③16位宽,所以是16咯。下面也要勾上允许16位写入。
接下来是FMC配置的第二个部分,没什么好说的。
生成代码后打开MDK
三、配置MDK和程序
接下来是配置MDK和程序:
勾上微库,勾掉信息生成,关闭优化,勾上reset and run。都是基本操作了。
程序配置,我喜欢先配置串口,配置好之后编译一下看看有没有问题。
串口重定向:
int fputc(int ch, FILE *f)
{
//具体哪个串口可以更改huart1为其它串口
HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1 , 0x0f);
return ch;
}
别忘了在需要串口输出的程序上添加:
#include “stdio.h”
然后在fmc.c中添加一个测试SRAM的程序(摘自野火的例程)
/**
* @brief 测试SRAM是否正常
* @param None
* @retval 正常返回1,异常返回0
*/
uint8_t SRAM_Test(void)
{
/*写入数据计数器*/
uint32_t counter=0;
/* 8位的数据 */
uint8_t ubWritedata_8b = 0, ubReaddata_8b = 0;
/* 16位的数据 */
uint16_t uhWritedata_16b = 0, uhReaddata_16b = 0;
SRAM_INFO("正在检测SRAM,以8位、16位的方式读写sram...");
/*按8位格式读写数据,并校验*/
/* 把SRAM数据全部重置为0 ,IS62WV51216_SIZE是以8位为单位的 */
for (counter = 0x00; counter < IS62WV51216_SIZE; counter++)
{
*(__IO uint8_t*) (Bank1_SRAM4_ADDR + counter) = (uint8_t)0x0;
}
/* 向整个SRAM写入数据 8位 */
for (counter = 0; counter < IS62WV51216_SIZE; counter++)
{
*(__IO uint8_t*) (Bank1_SRAM4_ADDR + counter) = (uint8_t)(ubWritedata_8b + counter);
}
/* 读取 SRAM 数据并检测*/
for(counter = 0; counter<IS62WV51216_SIZE;counter++ )
{
ubReaddata_8b = *(__IO uint8_t*)(Bank1_SRAM4_ADDR + counter); //从该地址读出数据
if(ubReaddata_8b != (uint8_t)(ubWritedata_8b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。
{
SRAM_ERROR("8位数据读写错误!");
return 0;
}
}
/*按16位格式读写数据,并检测*/
/* 把SRAM数据全部重置为0 */
for (counter = 0x00; counter < IS62WV51216_SIZE/2; counter++)
{
*(__IO uint16_t*) (Bank1_SRAM4_ADDR + 2*counter) = (uint16_t)0x00;
}
/* 向整个SRAM写入数据 16位 */
for (counter = 0; counter < IS62WV51216_SIZE/2; counter++)
{
*(__IO uint16_t*) (Bank1_SRAM4_ADDR + 2*counter) = (uint16_t)(uhWritedata_16b + counter);
}
/* 读取 SRAM 数据并检测*/
for(counter = 0; counter<IS62WV51216_SIZE/2;counter++ )
{
uhReaddata_16b = *(__IO uint16_t*)(Bank1_SRAM4_ADDR + 2*counter); //从该地址读出数据
if(uhReaddata_16b != (uint16_t)(uhWritedata_16b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。
{
SRAM_ERROR("16位数据读写错误!");
return 0;
}
}
SRAM_INFO("SRAM读写测试正常!");
/*检测正常,return 1 */
return 1;
}
然后在fmc.h中前后分别添加两段代码
段前:
/* USER CODE BEGIN Includes */
#include "stdio.h"
//地址线范围为A0~A19
#define Bank1_SRAM1_ADDR ((uint32_t)(0x60000000))
#define IS62WV51216_SIZE 0x200000 //1024*16/2bits = 0x200000 ,2M字节
/* USER CODE END Includes */
段后:
/* USER CODE BEGIN Prototypes */
/*信息输出*/
#define SRAM_DEBUG_ON 1
#define SRAM_INFO(fmt,arg...) printf("<<-SRAM-INFO->> "fmt"\n",##arg)
#define SRAM_ERROR(fmt,arg...) printf("<<-SRAM-ERROR->> "fmt"\n",##arg)
#define SRAM_DEBUG(fmt,arg...) do{\
if(SRAM_DEBUG_ON)\
printf("<<-SRAM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
}while(0)
uint8_t SRAM_Test(void);
/* USER CODE END Prototypes */
在main.c中添加引用SRAM检测函数对SRAM进行检测,并用串口打印出检测结果。
printf("SRAM配置实例");
printf ( "\r\n扩展SRAM写入/读取测试开始\r\n" );
if(SRAM_Test()==1)
{
printf("测试成功");
}
else
{
printf("测试失败");
}
编译下载,结果成功!