从开始移植ecos到stm32开发板以来,“程序运行过程中时不时跑飞或死掉,或者一加载就死掉”的问题一直令我头痛和百思不得其“姐”。如下图:程序一加载就死掉了。
程序运行过程中跑飞的现象类似,也是出现这种类似信息:$T050f:00800068;0d:e80f0d68;#98$T050f……
今天在编写按键程序时,频繁出现,是时把它解决了。功夫不负有心人,终于定位问题为外扩的SRAM时序不正确导致的,重新配置下SRAM的FSMC时序就解决了。
问题定位
首先,排除是否自己编写的程序有问题。经过反复试验,保证了自己编写的程序无问题,确定了不是自己编写的程序有问题。
在http://velep.com/archives/600.html一文中,曾经说到,直接下载bin格式程序到内存时,下载到内存中的数据居然有问题。redboot中使用xmodem协议的load命令应当是没有问题的,因为这是官方的代码,经过无数人的验证,如果有问题,早就暴露出来并修正了。所以,我开始怀疑是不是sram有问题了。
sram时序配置
既然怀疑SRAM有问题,所以找了个开发板光盘中有使用外扩SRAM的例程,把例程中SRAM的配置与ecos中SRAM配置进行了对比。先看下开发板例程中SRAM的配置代码(Ex021—I2S录音和回放例程(WM8978),bsp_sram.c文件):
void SRAM_Init(void) { FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure; FSMC_NORSRAMTimingInitTypeDef p; GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOG | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF, ENABLE); /* 配置SRAM数据线 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(GPIOE, &GPIO_InitStructure); /* 配置SRAM 地址线 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_Init(GPIOF, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5; GPIO_Init(GPIOG, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13; GPIO_Init(GPIOD, &GPIO_InitStructure); /* 配置 NOE 和 NWE */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 |GPIO_Pin_5; GPIO_Init(GPIOD, &GPIO_InitStructure); /* 配置 NE3 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_Init(GPIOG, &GPIO_InitStructure); /* 配置 NBL0, NBL1 */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1; GPIO_Init(GPIOE, &GPIO_InitStructure); /* 配置FSMC */ p.FSMC_AddressSetupTime = 0; p.FSMC_AddressHoldTime = 0; p.FSMC_DataSetupTime = 3; /* 根据SRAM的最大速度进行调整 */ p.FSMC_BusTurnAroundDuration = 0; p.FSMC_CLKDivision = 0; p.FSMC_DataLatency = 0; p.FSMC_AccessMode = FSMC_AccessMode_A; FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3; FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low; 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 = &p; FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p; FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); /*!< Enable FSMC Bank1_SRAM Bank */ FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); }
上面代码中,主要看下配置FSMC这段代码,参考:STM32F10xxx参考手册_cn.pdf 文档的19.5.6节内容,形成FSMC的配置字如下:
- BCR3寄存器配置字:0x00001011;
- BTR3寄存器配置字:0x00000300
现看下ecos中SRAM的FSMC配置字(基于我移植的模板,stm32f10xxx_misc.c文件hal_system_init()函数中):
// Set up FSMC NOR/SRAM bank 3 for SRAM HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FSMC_BCR3, 0x00001011 ); HAL_WRITE_UINT32( base+CYGHWR_HAL_STM32_FSMC_BTR3, 0x00000200 );
我们看到BTR3寄存器的配置字,两者有差异:BTR3寄存器的bit[15:8]域即数据保持时间不一样,开发板例程配置的是3个HCLK周期,而ecos中是2HCLK周期,且开发板例程配置中有明显说明:数据保持时间,根据SRAM的最大速度进行调整。
肯定的是,开始板例程是正确的。把ecos中SRAM的FSMC BTR3寄存器配置字调整为与开发板例程的一样,然后重新编译出redboot再烧写到内部flash中。这时使用redboot load命令load到内存中的程序运行稳定,不再出现:程序运行过程中时不时跑飞或死掉以及程序一加载就死掉的问题。
原因分析
安富莱开发板使用的SRAM器件与ST官方STM3210E_EVAL评估板使用的SRAM器件不一样。为了省成本,开发板使用了更为便宜但也更为慢速的SRAM器件,如下描述: