Using Keil uVison 4 on Windows 7 I have a c project for stm32f105 that is showing very strange behaviour. I checked it up with a debugger, and after several hours error chasing I localized the error to comming from an already tested in other projects function. Which looked like that:
uint8_t can_add_filter_mask(can_t* this, uint32_t id, uint32_t id_mask, can_frm_type_t type, can_frm_type_t type_mask)
{
CAN_FilterInitTypeDef filt;
/* Empty filter available? */
if(this->filter_len >= 14)
{
return FALSE;
}
/* Select filter number */
if(this->canx == CAN1)
filt.CAN_FilterNumber = this->filter_len + 0;
else
filt.CAN_FilterNumber = this->filter_len + 14;
this->filter_len++;
...
//filt is read
CAN_FilterInit(&filt);
}
It was so that the structure filt is not changed after any of the assigments! Then I changed the dissassembly and it's the following (I'm sorry that it's a bit long):
108: uint8_t can_add_filter_mask(can_t* this, uint32_t id, uint32_t id_mask, can_frm_type_t type, can_frm_type_t type_mask)
0x08001B22 BD70 POP {r4-r6,pc}
109: {
110: CAN_FilterInitTypeDef filt;
111:
112: /* Empty filter available? */
0x08001B24 E92D41FF PUSH {r0-r8,lr}
0x08001B28 4604 MOV r4,r0
0x08001B2A 460D MOV r5,r1
0x08001B2C 4690 MOV r8,r2
0x08001B2E 461E MOV r6,r3
0x08001B30 9F0A LDR r7,[sp,#0x28]
113: if(this->filter_len >= 14)
114: {
0x08001B32 7C20 LDRB r0,[r4,#0x10]
0x08001B34 280E CMP r0,#0x0E
0x08001B36 DB03 BLT 0x08001B40
115: return FALSE;
0x08001B38 2000 MOVS r0,#0x00
151: }
152:
153: /******************************************************************************/
154: void can_clr_filter(can_t* this)
0x08001B3A B004 ADD sp,sp,#0x10
0x08001B3C E8BD81F0 POP {r4-r8,pc}
119: if(this->canx == CAN1)
0x08001B40 4970 LDR r1,[pc,#448] ; #0x08001D04
0x08001B42 6820 LDR r0,[r4,#0x00]
0x08001B44 4288 CMP r0,r1
0x08001B46 D103 BNE 0x08001B50
120: filt.CAN_FilterNumber = this->filter_len + 0;
121: else
0x08001B48 7C20 LDRB r0,[r4,#0x10]
0x08001B4A F88D000A STRB r0,[sp,#0x0A]
0x08001B4E E004 B 0x08001B5A
122: filt.CAN_FilterNumber = this->filter_len + 14;
0x08001B50 7C20 LDRB r0,[r4,#0x10]
0x08001B52 300E ADDS r0,r0,#0x0E
0x08001B54 B2C0 UXTB r0,r0
0x08001B56 F88D000A STRB r0,[sp,#0x0A]
123: this->filter_len++;
124:
125: /* Select mask mode */
0x08001B5A 7C20 LDRB r0,[r4,#0x10]
0x08001B5C 1C40 ADDS r0,r0,#1
0x08001B5E 7420 STRB r0,[r4,#0x10]
I'm not an assembly expert, neither an ARM expert, but I have been programing a bit on assembly and to me it doesn't look bad. What I noticed that was a bit strange was that in between was part of another function can_clr_filter, so it looked like the compiler was reusing some code, though any optimizations are turned off. The interesting part was that when I checked the address of the filt.CAN_FilterNumber variable, it changed after the line
0x08001B36 DB03 BLT 0x08001B40
from address 0x20002262 to address 0x20002252. So all changes were applied just somewhere else in the memory!! The problem has dissapear after I had declared the variable as static, though it's a mistery to me what actually happened... How could it be that a local variable is relocated to another address by the instruction BLT? Or could the uVision debugger show the wrong reference value by watching the &filt.CAN_FilterNumber?
Because you did no post the whole function from this fragment I can only guess:
There are only assignments to the local variable, but it is not used anywhere in your program and it is probably removed from the generated code.
Don't look for errors in the compiler. They are quite good and I have not found any (I am a very active coder). Always when someone says : "this is disassembly listing, the compiler is wrong", the mistake is done somewhere by the asker. Forget about disassembly when you debug your program. You just waste you time.
The problem was in the uVision: http://www.keil.com/support/docs/2824.htm.
uVision is doing some additional optimization so watching local variables is not reliable.
Related
hi i am using an APM32F003 with Keil uVision compiler.
is a little known microcontroller but compatible with STM32.
I would like to write functions in RAM for different purposes.
I don't want to use the linker attribute to assign the function in ram,
but I want to copy a written one in flash and transfer it in RAM in run-time.
below the code I am trying to write but for now it is not working.
I think it's not possible in this way right?
static volatile uint8_t m_buffer_ram[100];
void flash_function()
{
/* Example */
LED2_ON();
}
void flash_function_end()
{
}
void call_function_in_ram()
{
uint32_t size = (uint32_t) flash_function_end - (uint32_t) flash_function;
/* clone function in RAM */
for (uint32_t i = 0; i < size; i++)
m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
__disable_irq();
/* cast buffer to function pointer */
void(*func_ptr)(void) = (void(*)(void)) (&m_buffer_ram);
/* call function in ram */
func_ptr();
__enable_irq();
}
Eugene asked if your function is relocatable. This is very important. I have had issues in the past wherein I copied a function from flash to RAM, and the compiler used an absolute address in the "flash" based function. Therefore the code which was running in RAM jumped back into the flash. This is just one example of what might go wrong with moving code which is not relocatable.
If you have a debugger that can disassemble and also step through the compiled code for you, that would be ideal.
Note also "the busybee" pointed out that code which is adjacent in source code does is not guaranteed to be adjacent in the compiled binary, so your method of finding the size of the code is not reliable.
You can look in the map file to determine the size of the function.
I agree with the comment that you would be better off learning to have the linker do the work for you.
None of what I am saying here is new; I am just reinforcing the comments made above.
CODE
static volatile uint8_t m_buffer_ram[200];
static uint32_t m_function_size;
void flash_function(void)
{
LED2_ON();
}
void flash_function_end(void)
{
}
void test(void)
{
m_function_size = (uint32_t) flash_function_end - (uint32_t) flash_function;
/* clone function in RAM */
for (uint16_t i = 0; i < m_function_size; i++)
m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
__disable_irq();
/* cast buffer to function pointer, +1 Thumb Code */
void(*func_ptr)(void) = (void(*)(void)) (&m_buffer_ram[1]);
/* call function in ram */
func_ptr();
__enable_irq();
}
MAP
Image Symbol Table
Symbol Name Value Ov Type Size Object(Section)
Local Symbols
.....
m_function_size 0x20000024 Data 4 test.o(.data)
m_buffer_ram 0x200001f0 Data 200 test.o(.bss)
Global Symbols
.....
flash_function 0x00000399 Thumb Code 12 test.o(i.flash_function)
flash_function_end 0x000003a9 Thumb Code 2 test.o(i.flash_function_end)
Memory Map of the image
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
.....
0x00000398 0x00000398 0x00000010 Code RO 355 i.flash_function test.o
0x000003a8 0x000003a8 0x00000002 Code RO 356 i.flash_function_end test.o
DISASSEMBLE
.....
30: m_function_size = (uint32_t) flash_function_end - (uint32_t) flash_function;
31:
0x00000462 480D LDR r0,[pc,#52] ; #0x00000498
0x00000464 4A0D LDR r2,[pc,#52] ; #0x0000049C
0x00000466 4C0E LDR r4,[pc,#56] ; #0x000004A0
0x00000468 1A81 SUBS r1,r0,r2
0x0000046A 6021 STR r1,[r4,#0x00]
32: for (uint16_t i = 0; i < m_function_size; i++)
0x0000046C 2000 MOVS r0,#0x00
33: m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
34:
0x0000046E 4B0D LDR r3,[pc,#52] ; #0x000004A4
0x00000470 2900 CMP r1,#0x00
0x00000472 D905 BLS 0x00000480
33: m_buffer_ram[i] = (((uint8_t*)&flash_function)[i]);
0x00000474 5C15 LDRB r5,[r2,r0]
0x00000476 541D STRB r5,[r3,r0]
32: for (uint16_t i = 0; i < m_function_size; i++)
0x00000478 1C40 ADDS r0,r0,#1
0x0000047A B280 UXTH r0,r0
32: for (uint16_t i = 0; i < m_function_size; i++)
0x0000047C 4288 CMP r0,r1
0x0000047E D3F9 BCC 0x00000474
35: __disable_irq();
36:
0x00000480 B672 CPSID I
37: void(*func_ptr)(void) = (void(*)(void)) (&m_buffer_ram[1]);
0x00000482 1C5B ADDS r3,r3,#1
38: func_ptr();
39:
0x00000484 4798 BLX r3
40: __enable_irq();
41:
0x00000486 B662 CPSIE I
I report all the information that I was able to recover.
I added a shift for the Thumb Code; the calculation of the function size coincides with the MAP file
my doubt is that in debug the pointer cannot jump to a point of the RAM .. for this reason I activate a led to see if (flashing code and run) this turns on without debugging.
as reported below, the read values coincide
(0x000003a8)flash_function_end - (0x00000398)flash_function = 0x10
(0x20000024)m_function_size = 0x10
func_ptr = 0x200001f1;
I'm working on a dual-core Cortex-R52 ARM chip, with an instance of FreeRTOS running in each core (AMP), and using ICCARM (IAR) as my compiler.
I need to ensure that CPU1 initialize some tasks, in order to pass their handler to CPU0 through the shared memory, but both cores are executed at the same time, which creates a problem in the scenario where CPU0 gets to using the supposedly passed handler, that wasn't created yet by CPU1.
A solution I tried, was creating a volatile variable pdSTART at a dedicated address space, which keeps CPU0 looping as long as its equal to 0:
#pragma location = 0x100F900C
__no_init volatile uint8_t pdSTART;
while (pdSTART == 0)
{
vTaskDelay(10 / portTICK_PERIOD_MS);
}
As expected the generated assembly was as follows:
vTaskDelay(10 / portTICK_PERIOD_MS);
0xc3a: 0x200a MOVS R0, #10 ; 0xa
0xc3c: 0xf000 0xf93c BL vTaskDelay ; 0xeb8
while (pdSTART == 0)
0xc40: 0x7b28 LDRB R0, [R5, #0xc]
0xc42: 0x2800 CMP R0, #0
0xc44: 0xd0f9 BEQ.N 0xc3a
With register R5 containing the address 0x100F9000.
Using the debugger I made sure CPU0 reaches the while condition first and gets in the loop, I then made CPU1 change the value of pdSTART, which I confirmed on the memory map
pdSTART:
0x100f'900c: 0x0000'0001 DC32 VECTOR_RBLOCK$$Base
And yet the condition on CPU0 remains false and pdSTART is never updated, both the memory map and "Watch" window of the debugger show the variable updated.
I tried explicitly writing a read from the address of pdSTART:
void func(void)
{
asm volatile ("" : : "r" (*(uint8_t *)0x100F900C));
}
But the generated assembly was the same as the while condition.
Is the old value of pdSTART saved into some kind of stack or cache? is there a way to forcefully update it?
Thank you.
I am new to IAR and Embedded Programming. I was debugging the following C code, and found that R0 gets to hold the address of counter1 through ??main_0, while R1 gets to hold address of counter2 through [PC,#0x20]. This is completely understandable, but I cannot get why it was assigned to R0 to use LDR Rd, -label while R1 used LDR Rd, [PC+Offset] and what is the difference between the two approaches?
I only knew about literal pools after searching but It didn't answer my question. In addition, where did ??main_0 get defined in the first place?
int counter1=1;
int counter2=1;
int main()
{
int *ptr;
int *ptr2;
ptr=&counter1;
ptr2=&counter2;
++(*ptr);
++(*ptr2);
++counter2;
return 0;
}
??main_0 is not "defined" as such, it's just an auto-generated label for the address used here so that when reading the disassembly you don't have to remember that address 0x8c is that counter pointer. In fact it would make sense to have the other counter pointer as ??main_1 and I'm not sure why it shows the bare [PC, #0x20] instead. As you can see on page 144/145 of the IAR assembly reference, those two forms are just different interpretations of the same machine code. If the disassembler decides to assign a label to an address, it can show the label form, otherwise the offset form.
The machine code of the first instruction is 48 07, which means LDR.N R0, [PC, #0x1C]. The interpretation as ??main_0 (and the assignment of a label ??main_0 to address 0x8c in the first place) is just something the disassembler decided to do. You cannot know what the original assembly source (if it even exists and the compiler didn't directly compile to machine code) looked like and whether it used a label there or not.
////// EDIT: SOLVED, read solution below
I'm trying to use the fpu with the stm32f4Discovery board, programmed with Keil 4 (free version) but, when trying to use it, enters in an infinite loop.
I don't know exactly why, I'm using a very simple code in C and the debugger:
#include "stm32f4_discovery.h"
#include <stdio.h>
float a = 1.332, b = 2.994;
int main(void)
{
printf("Hola");
printf("%f",a*b);
return(0);
}
Here is the results from the debugger: nothing in printf viewer and infinite loop because of "Hard Fault exception occurs" (image here, imgur)
Without line printf("%f",a*b) the debugger shows perfectly "Hola" and ends the program.
I've been searching a possible solution in google since I used this board for a project in university months ago, but anyone knows how to fix it.
I know I can disable fpu and use libraries but that's not the point...
Thank you for your help
/////////////// SOLUTION
I had to change the code in startup_stm32f4xx.s and the function SystemInit() from system_stm32f4xx.c
In startup_stm32f4xx.s, search for the Reset Handler, the code should look like this, but the part below ";FPU settings" is mostly not in the original:
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
;FPU settings
LDR R0, =0xE000ED88 ; Enable CP10,CP11
LDR R1,[R0]
ORR R1,R1,#(0xF << 20)
STR R1,[R0]
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
And then add in system_stm32f4xx.c, function SystemInit(void), this lines:
void SystemInit(void)
{
/* FPU settings ------------------------------------------------------------*/
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
#endif
The debugger will show now the operation result in printf viewer. I don't really know if it's using FPU, but I will test it tomorrow (should be faster now).
Source here
I am writing the boot-up code for an ARM CPU. There is no internal RAM, but there is 1GB of DDRAM connected to the CPU, which is not directly accessible before initialisation. The code is stored in flash, initialises RAM, then copies itself and the data segment to RAM and continue execution there. My program is:
#define REG_BASE_BOOTUP 0xD0000000
#define INTER_REGS_BASE REG_BASE_BOOTUP
#define SDRAM_FTDLL_REG_DEFAULT_LEFT 0x887000
#define DRAM_BASE 0x0
#define SDRAM_FTDLL_CONFIG_LEFT_REG (DRAM_BASE+ 0x1484)
... //a lot of registers
void sdram_init() __attribute__((section(".text_sdram_init")));
void ram_init()
{
static volatile unsigned int* const sdram_ftdll_config_left_reg = (unsigned int*)(INTER_REGS_BASE + SDRAM_FTDLL_CONFIG_LEFT_REG);
... //a lot of registers assignments
*sdram_ftdll_config_left_reg = SDRAM_FTDLL_REG_DEFAULT_LEFT;
}
At the moment my program is not working correctly because the register values end up being linked to RAM, and at the moment the program tries to access them only the flash is usable.
How could I change my linker script or my program so that those values have their address in flash? Is there a way I can have those values in the text segment?
And actually are those defined values global or static data when they are declared at file scope?
Edit:
The object file is linked with the following linker script:
MEMORY
{
RAM (rw) : ORIGIN = 0x00001000, LENGTH = 12M-4K
ROM (rx) : ORIGIN = 0x007f1000, LENGTH = 60K
VECTOR (rx) : ORIGIN = 0x007f0000, LENGTH = 4K
}
SECTIONS
{
.startup :
{
KEEP((.text.vectors))
sdram_init.o(.sdram_init)
} > VECTOR
...
}
Disassembly from the register assignment:
*sdram_ftdll_config_left_reg = SDRAM_FTDLL_REG_DEFAULT_LEFT;
7f0068: e59f3204 ldr r3, [pc, #516] ; 7f0274 <sdram_init+0x254>
7f006c: e5932000 ldr r2, [r3]
7f0070: e59f3200 ldr r3, [pc, #512] ; 7f0278 <sdram_init+0x258>
7f0074: e5823000 str r3, [r2]
...
7f0274: 007f2304 .word 0x007f2304
7f0278: 00887000 .word 0x00887000
To answer your question directly -- #defined values are not stored in the program anywhere (besides possibly in debug sections). Macros are expanded at compile time as if you'd typed them out in the function, something like:
*((unsigned int *) 0xd0010000) = 0x800f800f;
The values do end up in the text segment, as part of your compiled code.
What's much more likely here is that there's something else you're doing wrong. Off the top of my head, my first guess would be that your stack isn't initialized properly, or is located in a memory region that isn't available yet.
There are a few options to solve this problem.
Use PC relative data access.
Use a custom linker script.
Use assembler.
Use PC relative data access
The trouble you have with this method is you must know details of how the compiler will generate code. #define register1 (volatile unsigned int *)0xd0010000UL is that this is being stored as a static variable which is loaded from the linked SDRAM address.
7f0068: ldr r3, [pc, #516] ; 7f0274 <sdram_init+0x254>
7f006c: ldr r2, [r3] ; !! This is a problem !!
7f0070: ldr r3, [pc, #512] ; 7f0278 <sdram_init+0x258>
7f0074: str r3, [r2]
...
7f0274: .word 0x007f2304 ; !! This memory doesn't exist.
7f0278: .word 0x00887000
You must do this,
void ram_init()
{
/* NO 'static', you can not do that. */
/* static */ volatile unsigned int* const sdram_reg =
(unsigned int*)(INTER_REGS_BASE + SDRAM_FTDLL_CONFIG_LEFT_REG);
*sdram_ftdll_config_left_reg = SDRAM_FTDLL_REG_DEFAULT_LEFT;
}
Or you may prefer to implement this in assembler as it is probably pretty obtuse as to what you can and can't do here. The main effect of the above C code is that every thing is calculated or PC relative. If you opt not to use a linker script, this must be the case. As Duskwuff points out, you also can have stack issues. If you have no ETB memory, etc, that you can use as a temporary stack then it probably best to code this in assembler.
Linker script
See gnu linker map... and many other question on using a linker script in this case. If you want specifics, you need to give actual addresses use by the processor. With this option you can annotate your function to specify which section it will live in. For instance,
void ram_init() __attribute__((section("FLASH")));
In this case, you would use the Gnu Linkers MEMORY statement and AT statements to put this code at the flash address where you desire it to run from.
Use assembler
Assembler gives you full control over memory use. You can garentee that no stack is used, that no non-PC relative code is generated and it will probably be faster to boot. Here is some table driven ARM assembler I have used for the case you describe, initializing an SDRAM controller.
/* Macro for table of register writes. */
.macro DCDGEN,type,addr,data
.long \type
.long \addr
.long \data
.endm
.set FTDLL_CONFIG_LEFT, 0xD0001484
sdram_init:
DCDGEN 4, FTDLL_CONFIG_LEFT, 0x887000
1:
init_sdram_bank:
adr r0,sdram_init
adr r1,1b
1:
/* Delay. */
mov r5,#0x100
2: subs r5,r5,#1
bne 2b
ldmia r0!, {r2,r3,r4} /* Load DCD entry. */
cmp r2,#1 /* byte? */
streqb r4,[r3] /* Store byte... */
strne r4,[r3] /* Store word. */
cmp r0,r1 /* table done? */
blo 1b
bx lr
/* Dump literal pool. */
.ltorg
Assembler has many benefits. You can also clear the bss section and setup the stack with simple routines. There are many on the Internet and I think you can probably code one yourself. The gnu ld script is also beneficial with assembler as you can ensure that sections like bss are aligned and a multiple of 4,8,etc. so that the clearing routine doesn't need special cases. Also, you will have to copy the code from flash to SDRAM after it is initialized. This is a fairly expensive/long running task and you can speed it up with some short assembler.