我正在为基于STM32F103的ARM微控制器开发一些软件(与GCC一起编写)。我的一些用户希望能够使用同一芯片的不同版本(有更多RAM)的相同二进制文件,所以我需要一种方法来找出我在运行时有多少RAM。
有一个地址(0x1FFFF7E0)包含闪存大小,但似乎没有一个地址包含RAM大小!
最明显的解决方案是运行内存地址,检查哪些地址是可读/可写的,但当从内存地址太高(我不知道如何恢复)时,我尝试了这个和芯片HardFaults。
有什么办法能解决这个问题吗?理想情况下,我会进行实验,因为一些芯片(比如我现在使用的STM32F103RCT6 )看起来实际有64 48的内存,尽管数据表显示它们有48 48。例如,0x1FFFF7E0寄存器报告了256 is的可用闪存,尽管512 is是可用的。
看起来我可以在CCR寄存器中设置BFHFNMIGN位,然后尝试从软件中断中访问内存,但是我不知道如何在GCC+STM32中调用或创建一个软件中断。
发布于 2014-05-08 16:46:39
是的,我终于在ST论坛上的用户的帮助下解决了这个问题。
首先,您需要启用BusFault IRQ:
SCB->SHCSR |= SCB_SHCSR_BUSFAULTENA;
然后,您需要定义一个BusFault处理程序,它将使程序计数器增加2,以便跳过违规指令(赌它实际上是2字节指令):
__attribute__ ((naked)) void BusFault_Handler(void) {
/* NAKED function so we can be sure that SP is correct when we
* run our asm code below */
// DO NOT clear the busfault active flag - it causes a hard fault!
/* Instead, we must increase the value of the PC, so that when we
* return, we don't return to the same instruction.
*
* Registers are stacked as follows: r0,r1,r2,r3,r12,lr,pc,xPSR
* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/Babedgea.html
*
* So we want PC - the 6th down * 4 bytes = 24
*
* Then we add 2 - which IS DANGEROUS because we're assuming that the op
* is 2 bytes, but it COULD be 4.
*/
__asm__(
"ldr r0, [sp, #24]\n" // load the PC
"add r0, #2\n" // increase by 2 - dangerous, see above
"str r0, [sp, #24]\n" // save the PC back
"bx lr\n" // Return (function is naked so we must do this explicitly)
);
}现在--最后--我们可以尝试从任意的内存位置读取。如果错误,则调用BusFault处理程序,但我们跳过读或写指令,就好像它不在那里一样。
这意味着写到一个内存位置,然后再读回来相对容易--如果你得到了同样的东西,你就知道它是有效的(你只需要确保你的代码不会因为str和ldr都是空操作而被愚弄)。
发布于 2017-04-10 23:59:22
我发现,通过设置FAULTMASK位(禁用所有中断和故障处理程序),同时设置BFHFNMIGN位,可以探测访问地址是否会在不引发异常的情况下生成总线故障。不引发异常的好处意味着您不必编写异常处理程序。下面的示例是一个执行探测的C函数:
/**
* @brief Probe an address to see if can be read without generating a bus fault
* @details This function must be called with the processor in privileged mode.
* It:
* - Clear any previous indication of a bus fault in the BFARV bit
* - Temporarily sets the processor to Ignore Bus Faults with all interrupts and fault handlers disabled
* - Attempt to read from read_address, ignoring the result
* - Checks to see if the read caused a bus fault, by checking the BFARV bit is set
* - Re-enables Bus Faults and all interrupts and fault handlers
* @param[in] read_address The address to try reading a byte from
* @return Returns true if no bus fault occurred reading from read_address, or false if a bus fault occurred.
*/
bool read_probe (volatile const char *read_address)
{
bool address_readable = true;
/* Clear any existing indication of a bus fault - BFARV is write one to clear */
HWREG (NVIC_FAULT_STAT) |= NVIC_FAULT_STAT_BFARV;
HWREG (NVIC_CFG_CTRL) |= NVIC_CFG_CTRL_BFHFNMIGN;
asm volatile (" CPSID f;");
*read_address;
if ((HWREG (NVIC_FAULT_STAT) & NVIC_FAULT_STAT_BFARV) != 0)
{
address_readable = false;
}
asm volatile (" CPSIE f;");
HWREG (NVIC_CFG_CTRL) &= ~NVIC_CFG_CTRL_BFHFNMIGN;
return address_readable;
}该代码是为德州仪器ARM编译器编写的,使用德州仪器TivaWare软件进行注册定义,并在基于Cortex-M4F的TM4C设备上进行测试。理论上,它应该在其他的Cortex-M3或Cortex-M4设备上工作。
发布于 2019-05-03 21:27:54
在具有不同SRAM大小的MCU上运行相同二进制程序的一个相关问题是,堆栈指针(SP)在重置时以0的值初始化。通常,在构建程序时,编译器/启动文件/链接器脚本将SRAM顶部的值(适当地对齐)放置在0位置。因此,当您的二进制文件放在具有更多SRAM的机器上时,堆栈现在不再位于SRAM的顶部。如果要利用更大的SRAM大小,程序必须将堆栈重新定位到SRAM的真正顶部。
https://stackoverflow.com/questions/23411824
复制相似问题