5
\$\begingroup\$

I hope my title is correct terminologicaly. I am working(learning) with STM32F4 discovery board, which has an STM32F407VGTx microcontroller on it. I really try to find the answers in the reference manual, but sometimes it is really hard to find even where to look. Maybe because of the fact that it is 1700+ pages long...

So, here the situation, during my tests(C code, compiler is arm-none-eabi-size), I realized that, I can write any value to peripheral registers, for example to GPIOD registers. But using same code (to write to an address), I am not able to write to, for example, 0x58(0x00000058 indeed) address. In case of peripheral registers, document clearly states which registers/bits are write enabled, which ones read-only with notations like 'r', 'rw'. However, for the address 0x58, I couldn't find the reason why I cannot write to it.

Any guidance, or explanation would be appreciated, thanks.


update:

Counter-question: Why should you be able to write to that address? Is something mapped to that? – Marcus Müller

OK, it is a bit interesting. I was just started to learn about external interrupts, and I want to do everything(thus including external interrupts) at register level, during my learning. So, that's why I did not use any functions from HAL, SPL, or CMSIS and also none of those files are present in the project directory. I kind of managed it, so I had EXTI pending register firing up correctly, but I could not manage to find a way to link a callback function to the interrupt which will define the process I want to be executed in case of the interrupt. Inspecting NVIC table(page 372) from the reference manual, revealed that each interrupt is related with a memory address on the last column. So, I thought, maybe, just an idea, those locations will contain the memory address(pointer) to the interrupt handler functions. So, I then thought to define a function and then write the address of that function into the 0x58 memory location. So that, when the interrupt comes, the microcontroller will look at 0x58, which will redirect it to location of the function of interest.

Yes, this update could have been a whole another question by itself. Sorry for the mess. I think the question can be answered without this story, but, a comment made me to also append this...

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Counter-question: Why should you be able to write to that address? Is something mapped to that? \$\endgroup\$ Commented Jun 17, 2020 at 8:11
  • \$\begingroup\$ @MarcusMüller it is a little bit interesting why I needed mysef to be able to write to that address, it was just a hypotetical thing in my mind, and I would probably see that it wasn't like I thought, if I could manage to write to that address. Let me append the story to my answer, and when I'm done, I will notify you. \$\endgroup\$
    – muyustan
    Commented Jun 17, 2020 at 8:13
  • \$\begingroup\$ I don't know whether the story matters much, the question is whether there's something you can write to mapped to that address \$\endgroup\$ Commented Jun 17, 2020 at 8:17
  • 1
    \$\begingroup\$ ok, I assumed you know why I cannot write to there and asking a rethorical question. If that's not the case, I think my update won't give much information to you on "Is something mapped to that" because it will explain why I thought, intend to write something to that memory address. As I said, I don't exactly know is that region containing 0x58 somewhere I should be able to write something or not. I could totally be talking about nonsense things, but my update will make it clear at least why I came up with the idea of writing to that address in first place. \$\endgroup\$
    – muyustan
    Commented Jun 17, 2020 at 8:21

4 Answers 4

4
\$\begingroup\$

You need to have a look at the processor's memory configuration. The Cortex-M4 implements the ARMv7-M architecture. Here's a grab of the top half of the memory map (annoyingly this is split over two pages in the M4's reference manual).

enter image description here

As you can see, the area 0x00000000 - 0x1FFFFFFF is allocated to Code. The STM implementation will not include an accessible path on the system AHB bus to that area, hence you cannot write to that address.

\$\endgroup\$
2
  • \$\begingroup\$ oh, ok, so that region is some kind of a hard drive of our usual computers, after the C code is compiled and converted to binary code, it will be loaded into that region, and the microcontroller will read instructions from there. Am I at least close to the point? \$\endgroup\$
    – muyustan
    Commented Jun 17, 2020 at 8:43
  • 1
    \$\begingroup\$ The linker is used to specify the areas of memory, and their attributes. Have a look at this, it might help keil.com/support/man/docs/armlink/armlink_pge1406297881263.htm It can be a confusing topic, but part of the fun of using micros rather than full systems :) \$\endgroup\$
    – awjlogan
    Commented Jun 17, 2020 at 9:05
3
\$\begingroup\$

Possibly, the vector table is relocated; there's a register that stores the "0" address of that table, and that can be adjusted. That's actually a pretty handy feature: it allows you to set up a interrupt handler table anywhere in RAM, and then with one write to VTOR (which is at address 0x08, I think), you can switch over to that new table.

See p.218 of the stm32f4 programming manual.

\$\endgroup\$
19
  • 1
    \$\begingroup\$ let me try myself that whether I got you correct or not. So, 0x00000058 and its surrounding are not allowed to me to modify, let's say 0x50000000 address is OK to work with. Then I write 0x50000000 to VTOR. Now NVIC table starts from that address. Then, if I write the address of my interrupt handler function to 0x50000058 I would achieve what I intended? I will try it now, meantime waiting for your comment. Thanks for the answer btw. \$\endgroup\$
    – muyustan
    Commented Jun 17, 2020 at 10:13
  • 1
    \$\begingroup\$ @muyustan You have to copy the entire vector table, otherwise other irq's fail. And usually you can change 0x58, during flash programming. \$\endgroup\$
    – Jeroen3
    Commented Jun 17, 2020 at 13:04
  • 2
    \$\begingroup\$ @muyustan I think you're doing well. Modern microcontrollers are incredibly complex computers. It's not possible to understand everything within a weak :) Keep going! \$\endgroup\$ Commented Jun 17, 2020 at 14:13
  • 1
    \$\begingroup\$ you can't! a) you don't have the full 32 bit address space, as you noticed yourself(0x00000080 to 0x3FFFFF80), so the upper bits aren't useful, and b) when you read the paragraph above the table, you see that the lower bits are impossible to choose, either. \$\endgroup\$ Commented Jun 17, 2020 at 19:13
  • 2
    \$\begingroup\$ Another thing: just as you wouldn't try to program your PC without an operating system (you'd go insane initializing stuff before you can use it – and then figuring out how to keep things running), you really don't use such microcontrollers without their HALs. In most cases, these HALs are really "zero-cost abstractions", as in that they'd just be giving your register addresses names to work with, or allow you to call a function in manufacturer ROM to write to flash instead of you having to implement the same function. I agree, it's great for learning how a processor works what you're doing, \$\endgroup\$ Commented Jun 18, 2020 at 9:01
3
\$\begingroup\$

So, I thought, maybe, just an idea, those locations will contain the memory address(pointer) to the interrupt handler functions.

That's how it works. There is also VTOR, as Marcus described. However, simple projects use something called a startup assembler file, usually startup.s where the stack, heap and vector table are put at their position.
The vector table in the startup.s is weakly linked with a default handler that does nothing.
If you define a function with exactly the same name somewhere else it overrides this default one.

This is for the Cortex M4, that your chip is from ST does not matter yet.

I do not know which compiler you are using, but here is a writeup of the startup file in detail by ARM: https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/decoding-the-startup-file-for-arm-cortex-m4

\$\endgroup\$
1
  • \$\begingroup\$ thanks! what do you think about my comment below the anser of Marcus? Because I could not achieve what I intended. \$\endgroup\$
    – muyustan
    Commented Jun 17, 2020 at 12:29
2
\$\begingroup\$

That address is program flash. If you want to write to flash, it is possible, you need to first erase it by using the flash peripheral, and you can't really erase the program you are executing, so don't do that. There is two ways to do this correctly. You can copy the vector table to SRAM and tell the NVIC to point the vector table in SRAM, so you can freely change the vector. A more common solution would be to use a fixed interrupt code that takes an address from a variable and jumps to that address, so you can just change where the variable points.

\$\endgroup\$
3
  • \$\begingroup\$ thanks, but I couldn't exactly get what you meant by "a fixed interrupt code" \$\endgroup\$
    – muyustan
    Commented Jun 17, 2020 at 10:06
  • \$\begingroup\$ or if you can, please just ellaborate a bit more the sentence starting with "a more common solution......", \$\endgroup\$
    – muyustan
    Commented Jun 17, 2020 at 10:15
  • \$\begingroup\$ Let the vectors stay in flash, point the vector to code in flash, have the code in flash read a pointer from SRAM where to call (or jump). Update pointer in SRAM as you wish to point to any function you like. In C language terms, make an interrupt routine which calls a function via a function pointer. \$\endgroup\$
    – Justme
    Commented Jun 17, 2020 at 10:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.