www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Creating a microcontroller startup file

reply "Jens Bauer" <doctor who.no> writes:
I'm currently working on a startup file for Cortex-M.
Thanks to Johannes, I'm now able to implement almost everything I 
need.

While the most important part of the code code works, there are 
still a few things, that I would like added/changed.

Here's a cut-down version of a start.d:
---8<-----8<-----8<-----
/* file: startup.d */

import gcc.attribute;
import core.stdc.config;

//alias extern(C) const void function() VectorFunc;	// currently, 
this won't work for me
alias extern(C) const void *VectorFunc;			// so I'm using a void* 
instead.

extern(C) extern __gshared c_ulong[0] _stack;
const SIGNATURE_VALUE = 0x5a5a5a5a;
 attribute("weak")  attribute("alias", "defaultResetHandler") 
extern(C) void Reset_Handler();
 attribute("weak")  attribute("alias", "defaultExceptionHandler") 
extern(C) void NMI_Handler();

 attribute("section",".isr_vector.ro") VectorFunc[] g_pfnVectors 
= [
	cast(VectorFunc)_stack,					// Initial Stack Pointer
	&Reset_Handler,						// Reset Vector
	&NMI_Handler,							// Non Maskable Interrupt Vector
	cast(VectorFunc)SIGNATURE_VALUE,
	];


extern(C) void main();
 attribute("weak") extern(C) void LowLevelInit();
 attribute("weak") extern(C) void SystemInit();
extern(C) void defaultResetHandler()
{
//	if(&LowLevelInit) LowLevelInit;
//	if(&SystemInit) SystemInit;

	/* (snipped code to copy the DATA section to RAM and clear the 
BSS section) */

//	main();

	while(true){}
}

extern(C) void defaultExceptionHandler()
{
	while(true){}
}
--->8----->8----->8-----

The most important thing here is that I have not been successful 
in making the two subroutines LowLevelInit() and SystemInit() 
optional.
That is: If they are not linked to startup.o, then they should 
simply be NULL pointers.
I can do this in C, by supplying the 'weak' attribute, but so 
far, my attempts to do this in D have not been successful.

If I enable the two lines calling those subroutines, I get link 
errors...

startup.d:(.text+0x2): undefined reference to `LowLevelInit'
startup.d:(.text+0x6): undefined reference to `SystemInit'

Question number 1: How can a C subroutine be made optional, so 
it's called only if it linked ?

You may have noticed that the VectorFunc is not a real function, 
but a void*.
The code will work fine this way, but I'd prefer it to be more 
correct (if possible).

Question number 2: Is it possible to change the VectorFunc to be 
a real function pointer, rather than a void* ?

I've placed an empty main function in a file called main.d, which 
is linked to startup.o.
If I enable calling main(); then suddenly the executable file 
grows from TEXT=20 bytes, DATA=16 bytes, BSS=280 bytes to 
TEXT=10184 bytes, DATA=2132 bytes and BSS=12824 bytes.
The disassembly shows that suddenly malloc & friends are added to 
the executable, even though they're not used at all. I've tried 
renaming the function I call to something different; but that did 
not change anything. The things that seem to trigger that the 
binary file grows, is that if I call the function. I've also 
tried just having a pointer to the function, and nothing extra is 
included.

Question number 3: How can I call an external function and keep 
the binary file size down ?

I've found out that the 'alias' keyword comes in quite handy, in 
order to reduce the size of the source code. In my test source, 
you'll find that the attribute keyword is used twice in front of 
each function declaration. This looks quite bulky, and I'm sure 
it can be much improved upon. ;)
Question number 4: How can I reduce the function declaration of 
the Reset_Handler and NMI_Handler shown above ?
Apr 07 2015
next sibling parent reply "Jens Bauer" <doctor who.no> writes:
On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
 Question number 1: How can a C subroutine be made optional, so 
 it's called only if it linked ?
Question 1 might be answered by the following thread: http://forum.dlang.org/thread/mg1bad$30uk$1 digitalmars.com -So no need to answer question 1. ;)
Apr 07 2015
next sibling parent Rikki Cattermole <alphaglosined gmail.com> writes:
On 8/04/2015 8:38 a.m., Jens Bauer wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
 Question number 1: How can a C subroutine be made optional, so it's
 called only if it linked ?
Question 1 might be answered by the following thread: http://forum.dlang.org/thread/mg1bad$30uk$1 digitalmars.com -So no need to answer question 1. ;)
I was going to say wrap it into a function pointer global declaration and set it in a module constructor.
Apr 07 2015
prev sibling parent reply Johannes Pfau <nospam example.com> writes:
Am Tue, 07 Apr 2015 20:38:52 +0000
schrieb "Jens Bauer" <doctor who.no>:

 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
 Question number 1: How can a C subroutine be made optional, so 
 it's called only if it linked ?
Question 1 might be answered by the following thread: http://forum.dlang.org/thread/mg1bad$30uk$1 digitalmars.com -So no need to answer question 1. ;)
I actually saw these errors when I first tested your examples, but I thought that was a mistake in the example code. I didn't even know that extern weak symbols get default values in C ;-)
Apr 08 2015
parent "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 08:02:35 UTC, Johannes Pfau wrote:
 I actually saw these errors when I first tested your examples, 
 but I thought that was a mistake in the example code. I didn't 
 even know that extern weak symbols get default values in C ;-)
Don't feel bad about that. I think I found out by looking at someone else's source-code. ;) It's not really information that is easy to find on the net.
Apr 08 2015
prev sibling parent reply "Mike" <none none.com> writes:
On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:

 Question number 2: Is it possible to change the VectorFunc to 
 be a real function pointer, rather than a void* ?
I did something along these lines (modified to match your example) and it worked fine for me: alias VectorFunc = void function(); attribute("weak") attribute("alias", "defaultHandler") extern void Reset_Handler(); attribute("weak") attribute("alias", "defaultHandler") extern void NMI_Handler() attribute("weak") attribute("alias", "defaultHandler") extern void HardFault_Handler(); attribute("section",".isr_vector.ro") immutable ISR[3] g_pfnVectors = [ &Reset_Handler , &NMI_Handler , &HardFault_Handler ]; I did this before "weak", "alias", and "section" attributes were added, however. To see my original code, look at the slide in the presentation here: https://youtu.be/o5m0m_ZG9e8?t=2332. My original code had everything decorated with extern(C) as well so I could refer to the symbol directly in my linker scripts. That may not be needed for you, so I left it out.
 Question number 3: How can I call an external function and keep 
 the binary file size down ?
Are you compiling with -ffunction-sections -fdata-sections and linking with --gc-sections? You may need to in order to get rid of some things. What do you using for your D runtime? Perhaps some code in your runtime is implicitly linking to some code you're not directly calling. I also add the following to my linker scripts to get rid of stuff I don't find necessary: /DISCARD/ : { *(.ARM.extab*) *(.ARM.exidx*) } /DISCARD/ : { *(.ARM.attributes*) *(.comment) } You can see the latest incarnation of my linker script here: https://github.com/JinShil/stm32f42_discovery_demo/blob/master/linker/linker.ld
 Question number 4: How can I reduce the function declaration of 
 the Reset_Handler and NMI_Handler shown above ?
Try something along these lines. enum weak = gcc.attribute.attribute("weak"); enum isrDefault = gcc.attribute.attribute("alias", "defaultHandler"); extern weak isrDefault void NMI_Handler(); extern weak isrDefault void HardFault_Handler(); I use this idiom briefly in my code here: https://github.com/JinShil/stm32f42_discovery_demo/blob/master/source/start.d The enum thing kinda bugs me about D, but you'll see it used everywhere, especially phobos. It's called a manifest constant, and you can find a short blurb about it at the bottom of this page: http://dlang.org/enum.html Mike
Apr 08 2015
next sibling parent "Mike" <none none.com> writes:
On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:

 Question number 2: Is it possible to change the VectorFunc to 
 be a real function pointer, rather than a void* ?
I did something along these lines (modified to match your example) and it worked fine for me: alias VectorFunc = void function();
[...]
  attribute("section",".isr_vector.ro")
 immutable ISR[3] g_pfnVectors =
 [
       &Reset_Handler
     , &NMI_Handler
     , &HardFault_Handler
 ];
Sorry, but that code should be: attribute("section",".isr_vector.ro") immutable VectorFunc[3] g_pfnVectors = [ &Reset_Handler , &NMI_Handler , &HardFault_Handler ];
Apr 08 2015
prev sibling next sibling parent reply "Jens Bauer" <doctor who.no> writes:
Something tells me that now is when I have to start doing some 
hard work. ;)
-Sorry, I need to split this up into short replies/questions.

On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
 Question number 2: Is it possible to change the VectorFunc to 
 be a real function pointer, rather than a void* ?
 immutable ISR[3] g_pfnVectors =
 [
       cast(ISR)&_stack
     , &Reset_Handler
     , &NMI_Handler
     , &HardFault_Handler
 ];
In your example, you do not have the initial stack pointer. The above code gives me the following: src/test.d:24:13: error: reinterpreting cast from uint* to void()* is not supported in CTFE cast(ISR)&_stack ^ -That's the only reason I needed to change it to from function() to void*. Can you successfully cast(ISR)&_stack ?
Apr 08 2015
parent reply "Mike" <none none.com> writes:
On Wednesday, 8 April 2015 at 15:25:20 UTC, Jens Bauer wrote:

 Question number 2: Is it possible to change the VectorFunc to 
 be a real function pointer, rather than a void* ?
 immutable ISR[3] g_pfnVectors =
 [
      cast(ISR)&_stack
    , &Reset_Handler
    , &NMI_Handler
    , &HardFault_Handler
 ];
In your example, you do not have the initial stack pointer. The above code gives me the following: src/test.d:24:13: error: reinterpreting cast from uint* to void()* is not supported in CTFE cast(ISR)&_stack ^ -That's the only reason I needed to change it to from function() to void*. Can you successfully cast(ISR)&_stack ?
I don't know if that's a constraint of the language or a limitation of the current CTFE implementation, but either way, I never really liked it. I know the C folks do this stuff all the time, but I think it's kinda janky. I know of two potential alternatives: 1) Do it in the linker script (my current method): MEMORY { CCRAM (rxw) : ORIGIN = 0x10000000, LENGTH = 64k } /* Falling stack starts at the end of the CCM */ _stackStart = ORIGIN(CCRAM) + LENGTH(CCRAM); SECTIONS { .text : { LONG(_stackStart); KEEP(YourISRVectorTable); } } 2) Use a union (See pp. 10 here: http://www.state-machine.com/arm/QDK_ARM-Cortex_STM32-GNU.pdf) C Code to be adapted to D: typedef void (*ExceptionHandler)(void); typedef union { ExceptionHandler handler; void *pointer; } VectorTableEntry; __attribute__ ((section(".isr_vector"))) VectorTableEntry const g_pfnVectors[] = { { .pointer = &__c_stack_top__ }, { .handler = &Reset_Handler }, { .handler = &NMI_Handler }, ... ect ... }; Mike
Apr 09 2015
parent "Jens Bauer" <doctor who.no> writes:
On Friday, 10 April 2015 at 00:05:29 UTC, Mike wrote:
 On Wednesday, 8 April 2015 at 15:25:20 UTC, Jens Bauer wrote:

 Question number 2: Is it possible to change the VectorFunc 
 to be a real function pointer, rather than a void* ?
Can you successfully cast(ISR)&_stack ?
I don't know if that's a constraint of the language or a limitation of the current CTFE implementation, but either way, I never really liked it.
I don't really like typecasting myself, but I know a function pointer and a stack pointer are both pointers, thus they're the same size.
 I know the C folks do this stuff all the time, but I think it's 
 kinda janky.
True, but I need to write my files flexible, so that the majority of people will be able to use it out-of-the-box. I have to keep in mind that there are people who will make a part of their code in C during the transition phase, and I have to keep in mind that those who wrote the library in C, probably won't provide a complete library in D within the first week. ;) I agree with you on the 'minimal' style. I too hate all the junk that's added. 'printf' has always been prohibited in my microcontroller code - I don't have a file system on my microcontroller; no screen, no keyboard and no harddisk, thus I don't want anything that has any connection to printf or a file system. ;) Basically my startup.d will be very similar to the startup.s you already know (I translated my startup.s into a startup.c a long time ago - because I didn't want one for each type of assembler).
 I know of two potential alternatives:
 1)  Do it in the linker script (my current method):
Two things makes me little fond of this solution: 1: The "LONG" type. If it had been "PTR" or "UINT32", then it would be more attractive, but I do not expect those types exist. 2: I like people to be able to define the stack location inside the sources if they want to. That means: Typically the linker script will provide it, but some people need to move the stack, and I don't want them to need to change the linker script (if at all possible).
 2) Use a union (See pp. 10 here:
This solution is probably more appealing to me. I'll need to make some more tests. My initial attempt was to create a function, which did the type conversion via a CTFE function, buuut it didn't like that the symbol was undefined and not a constant, so I'll have to make a few more attempts. Thank you again for your valuable help. I hope that my fiddling will bring you something useful too. ;)
Apr 10 2015
prev sibling next sibling parent reply "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 I did something along these lines (modified to match your 
 example) and it worked fine for me:

 alias VectorFunc = void function();

  attribute("weak")  attribute("alias", "defaultHandler")
 extern void Reset_Handler();
Strange; I can't get it to build without extern(C). Also, if I remove extern(C) from for instance HardFault_Handler, then a HardFault_Handler written in C is not found by the linker.
Apr 08 2015
parent "Mike" <none none.com> writes:
On Wednesday, 8 April 2015 at 15:44:00 UTC, Jens Bauer wrote:
 On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 I did something along these lines (modified to match your 
 example) and it worked fine for me:

 alias VectorFunc = void function();

  attribute("weak")  attribute("alias", "defaultHandler")
 extern void Reset_Handler();
Strange; I can't get it to build without extern(C). Also, if I remove extern(C) from for instance HardFault_Handler, then a HardFault_Handler written in C is not found by the linker.
If HardFault_Handler is written in C then you will definitely need to decorate with extern(C). If your handlers are written in D, and neither the implementation nor the declaration are decorated with extern(C) then it should work. Mike
Apr 08 2015
prev sibling next sibling parent reply "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:

 Question number 3: How can I call an external function and 
 keep the binary file size down ?
Are you compiling with -ffunction-sections -fdata-sections and linking with --gc-sections? You may need to in order to get rid of some things.
I had -fdata-sections for the compiler and --gc-sections for the linker, but I was missing -ffunction-sections. Thank you for letting me know about this. Unfortunately, it did not reduce the size of the output file.
 What do you using for your D runtime?
minlibd by Timo Sintonen.
  Perhaps some code in your runtime is implicitly linking
 to some code you're not directly calling.
Maybe that's what's causing it, but I find it strange that calling an empty function outside the source file will cause that huge difference. -But of course, there's a logic explanation somewhere. ;) Note: I can rename the 'main()' function to 'My1Own2Weird3Function4Name567()' and the same thing happens, so it's not because main() is special.
 I also add the following to my linker scripts to get rid of 
 stuff I don't find necessary:
 [snip]
It might be caused by the linker script; I'll try and see if I can modify it to get rid of those things.
 You can see the latest incarnation of my linker script here: 
 https://github.com/JinShil/stm32f42_discovery_demo/blob/master/linker/linker.ld
Mine is quite huge, so I'll try out yours as a starting point. ;)
Apr 08 2015
parent reply "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 15:53:37 UTC, Jens Bauer wrote:
 [snip] I find it strange that calling an empty function outside
 the source file will cause that huge difference.
 -But of course, there's a logic explanation somewhere. ;)

 It might be caused by the linker script; I'll try and see if I 
 can modify it to get rid of those things.
Nope, that wasn't it. However, I found out that when I call an external function, some unwinding code is forced upon me; it's used by libgcc. I can't seem to get rid of it. I've removed the -lgcc from my linker flags (along with *all* other libraries, and it's still forced upon me. I tried to remove as much of the druntime, as I could, but it did not help a tad.
Apr 08 2015
parent reply "Mike" <none none.com> writes:
On Wednesday, 8 April 2015 at 17:45:01 UTC, Jens Bauer wrote:
 On Wednesday, 8 April 2015 at 15:53:37 UTC, Jens Bauer wrote:
 [snip] I find it strange that calling an empty function outside
 the source file will cause that huge difference.
 -But of course, there's a logic explanation somewhere. ;)

 It might be caused by the linker script; I'll try and see if I 
 can modify it to get rid of those things.
Nope, that wasn't it. However, I found out that when I call an external function, some unwinding code is forced upon me; it's used by libgcc. I can't seem to get rid of it. I've removed the -lgcc from my linker flags (along with *all* other libraries, and it's still forced upon me. I tried to remove as much of the druntime, as I could, but it did not help a tad.
I can think of two places in the runtime where extra code can be added to your binary: runtime initialization and thread-local storage. There may be others depending on what features are implemented in the runtime. You can find the runtime initialization code for GDC's runtime here: https://github.com/D-Programming-GDC/GDC/blob/master/libphobos/libdruntime/rt/dmain2.d#L152 That eventually will call some things that malloc, and more. That all happens before you get to main. Are you compiling with -fno-emit-moduleinfo? That may help reduce some of that runtime initialization. As I recall, thread-local storage also employs malloc as memory is needed for each thread-local variable when a new thread is created. If your project is single-threaded, it still works the same way when the initial thread is created. If you have any thread-local state try removing them or changing them to __gshared, and see if that helps. My runtime is quite minimal, which has both benefits and consequences. You can find it here: https://github.com/JinShil/stm32f42_discovery_demo/tree/master/source/runtime This will give you a C-like programming experience. You can use classes, but won't be able to allocate them on the GC heap. Instead, you can employ some of the patterns here: http://wiki.dlang.org/Memory_Management You may also wnat to compile with -nodefaultlibs -nostdlib -nostartfiles. That removes the cruntime and libgcc. But if you do that, you may have to compensate by adding additional startup code In D. You can see how I've done that here: https://github.com/JinShil/stm32f42_discovery_demo/blob/master/source/start.d#L102 As I understand it, minlibd is a more full-featured runtime, and that too has its benefits and consequences. Mike
Apr 08 2015
parent "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 23:18:41 UTC, Mike wrote:
 You may also wnat to compile with -nodefaultlibs -nostdlib 
 -nostartfiles.  That removes the cruntime and libgcc.
I forgot about those. Yes, when excluded those and added a /DISCARD/ for the exidx and armexidx, I finally got rid of the huge overhead. Thank you so much! I guess that the CTFE optimizes any function calls if they reside in the startup.d file, because if I keep it in the startup.d, then the size stays small, but as soon as I move a called function out from the startup.d into its own file, then the overhead shows up. -But it's no longer a problem. ;)
Apr 10 2015
prev sibling parent reply "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:

 enum weak = gcc.attribute.attribute("weak");
 enum isrDefault = gcc.attribute.attribute("alias", 
 "defaultHandler");

 extern  weak  isrDefault void NMI_Handler();
 extern  weak  isrDefault void HardFault_Handler();
This is indeed helpful. I've now reduced each of the approximately 100 lines declaring exception vectors to something like these: weak ar void Reset_Handler(); weak ae void NMI_Handler(); -It would be neat, if attribute("weak") and attribute("alias","function") could be combined into one, but I haven't found a way to do that - I've done that in C earlier, though: void __attribute__((weak, alias(defaultExceptionHandler))) NMI_Handler(void);
 I use this idiom briefly in my code here: 
 https://github.com/JinShil/stm32f42_discovery_demo/blob/master/source/start.d
Yes. I actually came across it and didn't notice it. But now that you've explained it, it absolutely makes sense. :) -I actually added attribute("naked") to my defaultResetHandler yesterday, as I wanted to get rid of the prologue; so I completely agree; the startup code should have this attribute. I've now changed that to use the enum, to be more consistent. ;)
Apr 08 2015
next sibling parent reply "Mike" <none none.com> writes:
On Wednesday, 8 April 2015 at 16:10:53 UTC, Jens Bauer wrote:
 On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
 -I actually added  attribute("naked") to my defaultResetHandler 
 yesterday, as I wanted to get rid of the prologue; so I 
 completely agree; the startup code should have this attribute.
 I've now changed that to use the enum, to be more consistent. ;)
I actually added that out of necessity, not optimization. Id I use the STM32, and reset the MCU, the CCRAM is disabled by default. Since my stack is in CCRAM, I need to first enable it before any functions can be called. Mike
Apr 08 2015
next sibling parent reply "Mike" <none none.com> writes:
On Wednesday, 8 April 2015 at 23:23:53 UTC, Mike wrote:
 On Wednesday, 8 April 2015 at 16:10:53 UTC, Jens Bauer wrote:
 On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
 -I actually added  attribute("naked") to my 
 defaultResetHandler yesterday, as I wanted to get rid of the 
 prologue; so I completely agree; the startup code should have 
 this attribute.
 I've now changed that to use the enum, to be more consistent. 
 ;)
I actually added that out of necessity, not optimization. Id I use the STM32, and reset the MCU, the CCRAM is disabled by default. Since my stack is in CCRAM, I need to first enable it before any functions can be called.
Sorry, I need to be more careful when typing on a tablet. That should read: I actually added that out of necessity, not optimization. If I use the STM32 system bootloader, and reset the MCU, the CCRAM is disabled by default. Since my stack is in CCRAM, I need to first enable it before any functions can be called. Mike
Apr 08 2015
parent "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 23:28:45 UTC, Mike wrote:
 If I use the STM32 system bootloader, and reset the MCU,
 the CCRAM is disabled by default.
I see. That is absolutely incorrect behaviour of the bootloader. A bootloader should only change the things that are absolutely necessary to change. I'll have a look at the other details in your replies tomorrow, as I'm getting very sleepy; so writing code is not a good idea in my present state. ;)
Apr 08 2015
prev sibling parent reply "Jens Bauer" <doctor who.no> writes:
On Wednesday, 8 April 2015 at 23:23:53 UTC, Mike wrote:
 I actually added that out of necessity, not optimization.  Id I 
 use the STM32, and reset the MCU, the CCRAM is disabled by 
 default.  Since my stack is in CCRAM, I need to first enable it 
 before any functions can be called.
According to ST-Microelectronics, CCMRAM is enabled by default (by hardware). I am using CCMRAM without enabling it, so it must be correct what their User's Manual states.
Apr 08 2015
parent "Mike" <none none.com> writes:
On Thursday, 9 April 2015 at 00:37:32 UTC, Jens Bauer wrote:
 On Wednesday, 8 April 2015 at 23:23:53 UTC, Mike wrote:
 I actually added that out of necessity, not optimization.  Id 
 I use the STM32, and reset the MCU, the CCRAM is disabled by 
 default.  Since my stack is in CCRAM, I need to first enable 
 it before any functions can be called.
According to ST-Microelectronics, CCMRAM is enabled by default (by hardware). I am using CCMRAM without enabling it, so it must be correct what their User's Manual states.
Indeed, that's true. This problem I'm referring to only occurs when when resetting from the system boot loader. Since I want my stack to work under both conditions, I need to add that code. See the discussion here for more information: https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fcortex_mx_stm32%2fLeave%20DFU%20while%20boot0%20is%20high%20%28STM32F4%29&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=1158 Mike
Apr 08 2015
prev sibling parent reply Artur Skawina via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
On 04/08/15 18:10, Jens Bauer via Digitalmars-d-learn wrote:
 On Wednesday, 8 April 2015 at 11:17:12 UTC, Mike wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:

 enum weak = gcc.attribute.attribute("weak");
 enum isrDefault = gcc.attribute.attribute("alias", "defaultHandler");

 extern  weak  isrDefault void NMI_Handler();
 extern  weak  isrDefault void HardFault_Handler();
This is indeed helpful. I've now reduced each of the approximately 100 lines declaring exception vectors to something like these: weak ar void Reset_Handler(); weak ae void NMI_Handler(); -It would be neat, if attribute("weak") and attribute("alias","function") could be combined into one, but I haven't found a way to do that
http://forum.dlang.org/post/mailman.2672.1403379235.2907.digitalmars-d puremagic.com artur
Apr 09 2015
parent "Jens Bauer" <doctor who.no> writes:
On Thursday, 9 April 2015 at 10:47:42 UTC, Artur Skawina wrote:
 On Tuesday, 7 April 2015 at 20:33:26 UTC, Jens Bauer wrote:
-It would be neat, if attribute("weak") and attribute("alias","function") could be combined into one, but I haven't found a way to do that
http://forum.dlang.org/post/mailman.2672.1403379235.2907.digitalmars-d puremagic.com
Thank you, Artur. This is what I did (it's very close to the above; just slightly modified): enum weak = gcc.attribute.attribute("weak"); alias Tuple(A...) = A; alias rst = Tuple!(weak, gcc.attribute.attribute("alias", "defaultResetHandler")); alias exc = Tuple!(weak, gcc.attribute.attribute("alias", "defaultExceptionHandler")); So now the code is much easier to read ... rst extern(C) void Reset_Handler(); exc extern(C) void NMI_Handler(); exc extern(C) void HardFault_Handler(); ... ... exc extern(C) void LTDC_ER_IRQHandler(); exc extern(C) void DMA2D_IRQHandler();
Apr 10 2015