Author Topic: Mcu programming 101 writeup  (Read 4968 times)

0 Members and 1 Guest are viewing this topic.

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Mcu programming 101 writeup
« on: May 29, 2022, 10:50:53 am »
[shameless self-promotion] http://efton.sk/STM32/mcu_programming_101.html

Comments welcome.
[/shameless self-promotion]

JW
 
The following users thanked this post: dustooff, wraper, jaromir, MathWizard

Offline pcprogrammer

  • Super Contributor
  • ***
  • Posts: 3710
  • Country: nl
Re: Mcu programming 101 writeup
« Reply #1 on: May 29, 2022, 11:04:08 am »
Good to see someone promote bare metal programming instead of using the manufacturers pile of garbage like STM HAL (Hardware Abstraction Layers) code. I, for sure am no fan of those :-DD
It might be me, but most of my attempts to make a simple program with their IDE and generated code failed to work :palm:

My comment: Since it is aimed towards the novice you might refrain from abbreviations like RMW and use read-modify-write instead.

Offline Electro707

  • Contributor
  • Posts: 25
  • Country: us
Re: Mcu programming 101 writeup
« Reply #2 on: May 30, 2022, 10:33:10 pm »
Nice article! Great for a beginner so they are aware that just calling `digitalWrite()` isn't all there is to it (also that specific function is way too bloated, but that's a conversation for a different day).

Quote
Good to see someone promote bare metal programming instead of using the manufacturers pile of garbage like STM HAL (Hardware Abstraction Layers) code. I, for sure am no fan of those :-DD
From my experience generally HALs tend to be meh. I personally prefer things like ST's LL (Low Level) code as a nice middle-ground, which is nice when needing to switch the micro to a different one of the same family. At least with ST's generator there is an option to switch the initialization from HAL to LL which I do everytime.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4037
  • Country: nz
Re: Mcu programming 101 writeup
« Reply #3 on: May 31, 2022, 05:00:05 am »
Good start. It ended just as I was getting into it :-)
 

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Mcu programming 101 writeup
« Reply #4 on: May 31, 2022, 10:29:35 pm »
Thanks.

Tried to make it as sparse as possible. Got carried away towards the end.

May extend/follow up in the future, but I am not sure how. The topic is too wide and I don't feel confident enough to write authoritatively about the details.

Not to mention time.

JW
« Last Edit: May 31, 2022, 10:31:52 pm by wek »
 

Offline tepalia02

  • Regular Contributor
  • *
  • Posts: 100
  • Country: bd
Re: Mcu programming 101 writeup
« Reply #5 on: July 01, 2022, 08:00:51 am »
Thanks for sharing.
 

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Mcu programming 101 writeup
« Reply #6 on: March 18, 2024, 01:56:25 am »
Part2, on minimalistic toolchain.

Didn't feel that good as the first one, but a friend requested a few words of help and again, I got carried away...

Comments, please.

JW
 
The following users thanked this post: harerod

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4037
  • Country: nz
Re: Mcu programming 101 writeup
« Reply #7 on: March 18, 2024, 08:56:48 am »
"Burning" doesn't sound so bad, especially for EPROM or OTP.  "Flashing" is pretty common, and accurate on most modern MCUs.

There are a number of endearing English grammar mistakes, mostly dropped articles, which I won't enumerate.
 
The following users thanked this post: wek

Offline tellurium

  • Regular Contributor
  • *
  • Posts: 229
  • Country: ua
Re: Mcu programming 101 writeup
« Reply #8 on: March 18, 2024, 04:01:33 pm »
Very nice write up

An idea just came to my mind
To have such tutorial with embedded editor, just like https://go.dev/tour/welcome/1

A dev board can be flashed via webusb. And logs can be observed via webusb. Like here https://mongoose.ws/demo/?board=Nucleo-H743ZI&project=mqtt
Then a tutorial immediately becomes more powerful learning tool, cause readers can experiment on the fly.
Open source embedded network library https://mongoose.ws
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 
The following users thanked this post: wek

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Mcu programming 101 writeup
« Reply #9 on: March 19, 2024, 09:02:27 am »
Thanks for the comments.

@brucehoult, "flashing" sounds good, will rephrase. Shall I do that also in the main text? "Device programming" sounds old, doesn't it.
Sorry for the errors in grammar. I don't think I can improve in that too much.

@tellurium, I see your point, and I beg to disagree. IMO the main thrill in mcu programming is the physical aspect ("see the LED blinking"). Remote debugging also adds "magic", which I propose to minimize at this stage. Don't get me wrong; I understand that there are merits in remote debugging.

JW
 

Offline tellurium

  • Regular Contributor
  • *
  • Posts: 229
  • Country: ua
Re: Mcu programming 101 writeup
« Reply #10 on: March 19, 2024, 02:15:27 pm »
Sorry for the errors in grammar. I don't think I can improve in that too much.

I sometimes use chatgpt - https://chat.openai.com/ to turn my bad English into something more readable.

@tellurium, I see your point, and I beg to disagree. IMO the main thrill in mcu programming is the physical aspect ("see the LED blinking"). Remote debugging also adds "magic", which I propose to minimize at this stage. Don't get me wrong; I understand that there are merits in remote debugging.

Can you elaborate on that please? What do you mean by "remote debugging"? I did not get the point. I did not get the point about the "physical aspect". All I suggested is to have your code snippets be flashable to a real physical board without any external tools, just using a browser.
Open source embedded network library https://mongoose.ws
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Mcu programming 101 writeup
« Reply #11 on: March 19, 2024, 03:06:25 pm »
> chatGPT
I perhaps prefer my English be bad and mine :-)

> What do you mean by "remote debugging"?
Sorry, I did not pay enough attention to your post/links and misunderstood the intention.

> have your code snippets be flashable to a real physical board without any external tools, just using a browser
Dunno. Have strong proponents of "browser-based computing" in my circles, I'm not that sure about these. Let's just say that without experience I don't really should form opinions.

Things move and one learns every day... :-)

Thanks,

JW
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 3698
  • Country: gb
  • Doing electronics since the 1960s...
Re: Mcu programming 101 writeup
« Reply #12 on: March 20, 2024, 03:48:49 pm »
I think the article #2 is very good. I wish I knew this when I was at that stage ~ 3 years ago. Just some random comments:

startup_stm32f407xx.s - it is odd why this is in asm, when all of it (except loading SP) can be done in C, and indeed I have done so for my RAM-based loader code e.g.

Code: [Select]
extern char _loader_ram_start;
extern char _loader_ram_end;
extern char _loader_flash_start;

// Copy loader code and its init data to RAM.
memcpy(&_loader_ram_start, &_loader_flash_start, &_loader_ram_end - &_loader_ram_start);

// Set SP to top of CCM. This is not where the general stack is normally but it doesn't matter because
// the loader always reboots at the end. This assignment can't be done inside loader because it trashes
// the stack frame and any local variables which are allocated *at* the call.
// NOTE local variables cannot be used after the SP load.

asm volatile ("ldr sp, = 0x10010000 \n");

Also as others pointed out years ago, the asm code is very obviously sub-optimal and written by kids.

__libc_init_array - you confirm it is C++ only but when I was working on this I found it extremely hard to get a confirmation, so I left it in

in linkfile
Code: [Select]

.preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH_APP
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH_APP
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(.fini_array*))
    KEEP (*(SORT(.fini_array.*)))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH_APP


and then I call __libc_init_array(void) which is not supplied in source form and lives in libc. I wasted a huge amount of time on this. But I am not 100% sure - see e.g. this
https://stackoverflow.com/questions/49708591/use-of-libc-init-array-call-stm32

removing call to SystemInit() - that call is partly duplicated later on in ST's code :) But only partly. Took me a while to unravel it all.

STLINK-V3 - I may be wrong but I think you need V3 to get the "high speed debugging UART" - the SWV ITM data console

Code: [Select]
/*
 * Copied here from core_cm4.h.
  \brief   ITM Send Character
  \details Transmits a character via the ITM channel 0, and
           \li Just returns when no debugger is connected that has booked the output.
           \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted.
  \param [in]     ch  Character to transmit.
 */

static void ITM_SendChar_2 (uint32_t ch)
{
  if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) &&      /* ITM enabled */
      ((ITM->TER & 1UL               ) != 0UL)   )     /* ITM Port #0 enabled */
  {
    while (ITM->PORT[0U].u32 == 0UL)
    {
      __NOP();
    }
    ITM->PORT[0U].u8 = (uint8_t)ch;
  }
  return;
}

The rest is very good but since I have always used CUBE IDE (horrible to set up but somebody else did it for me) I can't usefully comment on it. A "make" is desirable only for bigger projects; today's PCs are so fast that a batch file based compile-all is fine. In the 1980s, a "make" was desirable again but because PCs were about 100x slower.

Your English is outstanding!


« Last Edit: March 20, 2024, 10:48:46 pm by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Mcu programming 101 writeup
« Reply #13 on: March 25, 2024, 08:41:56 am »
> startup_stm32f407xx.s - it is odd why this is in asm

Chicken/egg. Startup code is to prepare everything needed to run C, so how could startup be in C if it haven't had things prepared?

OTOH, if that C is simple enough and doesn't use globals/statics, it should be fine. I personally don't like it because of the "fundamental" reason above.

Also, what I don't quite get is the urge to set SP. I see that regularly. But, it's set by hardware from the first word in the vector table, after all. Is this some cargo-cult thing or is there any material reason for it? I couldn't find any hints. After all, cargo-cult followers don't know it's a cargo-cult, do they, so they can't report.

> __libc_init_array - you confirm it is C++ only

Following discussion here (also in your "CubeIDE is crap" thread) and elsewhere, I don't; the upcoming version of the 101.5 text is rephrased.

My text is aimed at minimal. Your application is everything but (use of RTOS, printf()...). The more "magic" which comes with the tools you use, the less you will be able to kick out the "why would I need this" stuff.

> STLINK-V3 - I may be wrong but I think you need V3 to get the "high speed debugging UART" - the SWV ITM data console

SWO "UART Rx" is available in STLink/V2, too.

> today's PCs are so fast that a batch file based compile-all is fine

There are merits of using make beyond speed, too, but generally, this is a valid point.

> some libc functions are not reentrant (not in this thread, you've mentioned it elsewhere, but I think it's relevant to the "minimal" and "have control" overarching topic)

It may come as a nasty surprise, but by the C standard, *none* of the standard library functions are to be considered reentrant. In other words, thou shalt not use e.g. abs() both in main and interrupts.

(Also, the standard claims *all* symbols defined in the library chapter (C99 chapter 7)  to be reserved, yes, writing your own abs() may result in nasty surprises and it did in the past - and I know you say the library functions as they are supplied with Cube can't be simply overriden - this is likely to be dependent on several minute details of how exactly things are compiled/linked, not just having library functions weak, and matter for further extensive painful discussion, not here and not now).

Programs written so are not strictly conformant thus not portable. OTOH, who cares about strict standard conformance and portability? Isn't functionality the ultimate goal? Is there any relevant mcu *application* where code portability is of any concern whatsoever?

Now for many library functions (e.g. <math.h>) it would be rather strange if they would be non-reentrant. I can imagine system-level library functions (i.e. those which are not covered by the "freestanding" clause of C99) to be non-reentrant - the printf()/scanf() family may be prime example, although <time.h> may be the prime counter-example, too.

Here's newlib's documentation promising that only a portion of it is non-reentrant, and that they can be made reentrant too.

JW
« Last Edit: March 25, 2024, 09:00:01 am by wek »
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4037
  • Country: nz
Re: Mcu programming 101 writeup
« Reply #14 on: March 25, 2024, 09:21:09 am »
Also, what I don't quite get is the urge to set SP. I see that regularly. But, it's set by hardware from the first word in the vector table, after all.

On a VERY limited set of hardware: Cortex-M.  It's not the case on RISC-V or 6502 or z80 or .. probably most others. Is it true on Cortex-A? I don't know but I think probably not.

Cortex-M is particularly dumbed-down hand-holding hardware. Being able to put pointers to standard C API functions as interrupt vector is most unusual, for example. That costs both hardware (gates) and execution time for interrupt functions that don't actually need that many registers. But it makes training of new bare-metal programmers a little easier.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 3698
  • Country: gb
  • Doing electronics since the 1960s...
Re: Mcu programming 101 writeup
« Reply #15 on: March 25, 2024, 10:20:56 am »
Quote
Being able to put pointers to standard C API functions as interrupt vector is most unusual

Are you referring to the way ISRs can just be written in C, with no special code needed, and implemented via the magic numbers on the stack telling the CPU that it has just exited an ISR so no "RETI" is needed?

I think that's quite elegant, although it does make interrupts a bit slower.

Quote
Startup code is to prepare everything needed to run C, so how could startup be in C if it haven't had things prepared?

Yes; a fair point. I have done 40 years of asm so not complaining :) But the startup.s stuff is entirely memset, memcpy, and I would hope those functions don't need any kind of setup.

Code: [Select]

    .section  .text.Reset_Handler
  .weak  Reset_Handler
  .type  Reset_Handler, %function
Reset_Handler: 

/* SP for all of boot block
/* If we have the extra 64k (32F437) then SP is adjusted later */

  ldr   sp, =_estack

/* Copy the boot block initialised data from FLASH to SRAM */
  movs  r1, #0
  b  LoopCopyDataInit
CopyDataInit:
  ldr  r3, =_si_boot_data
  ldr  r3, [r3, r1]
  str  r3, [r0, r1]
  adds  r1, r1, #4
LoopCopyDataInit:
  ldr  r0, =_s_boot_data
  ldr  r3, =_e_boot_data
  adds  r2, r0, r1
  cmp  r2, r3
  bcc  CopyDataInit

/* Zero fill the boot block bss segment. */
  ldr  r2, =_s_boot_bss
  b  LoopFillZerobss
FillZerobss:
  movs  r3, #0
  str  r3, [r2], #4
LoopFillZerobss:
  ldr  r3, = _e_boot_bss
  cmp  r2, r3
  bcc  FillZerobss

/* Initialise CCM RAM - fills the whole CCM */
ldr r2, = 0x10000000  /* was _sccmram */
b LoopFillZeroCcm
FillZeroCcm:
movs r3, 0xaaaaaaaa /* this fill intentionally differs from the a5a5a5a5 fill used by FreeRTOS for its stacks */
  str  r3, [r2]
adds r2, r2, #4
LoopFillZeroCcm:
ldr r3, = 0x10010000  /* was _eccmram */
cmp r2, r3
bcc FillZeroCcm

/* Initialise the 8k stack at the top of the 128k RAM. This is 32F417 only */
/* For the 32F437, extra 64k, the fill is done later */

ldr r2, = 0x2001e000  /*   = _estack - _Stack_Size  */
b LoopFillStack
FillStack:
movs r3, 0x73737373   /* fill with 's' */
str  r3, [r2]
adds r2, r2, #4
LoopFillStack:
ldr r3, = _estack     /* = 0x20020000 */
cmp r2, r3
bcc FillStack

/* Call the application's entry point - in this case the "main()" in the boot loader */
  bl  main

  bx  lr   
.size  Reset_Handler, .-Reset_Handler

Quote
Is there any relevant mcu *application* where code portability is of any concern whatsoever?

Generally I agree but it is good to be able to test "algorithms" on a PC, in M$ VC++ (or maybe some old C compiler, but stepping through the code is valuable). This can go quite a long way e.g. I have a win32 executable version of MbedTLS which can be used to access https websites and report why something isn't working, which is likely to be an absolute bastard to do in the embedded system.

Good point about the SP getting preloaded, although Cube IDE still does

ldr   sp, =_estack

:)
« Last Edit: March 25, 2024, 11:28:04 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Mcu programming 101 writeup
« Reply #16 on: March 25, 2024, 12:33:44 pm »
Also, what I don't quite get is the urge to set SP. I see that regularly. But, it's set by hardware from the first word in the vector table, after all.

On a VERY limited set of hardware: Cortex-M.  It's not the case on [...]
Yes; but isn't the startup code in question specific to that very VERY limited hardware?

Quote from: brucehoult
Being able to put pointers to standard C API functions as interrupt vector is most unusual, for example.
Quote from: peter-h
Are you referring to the way ISRs can just be written in C, with no special code needed, and implemented via the magic numbers on the stack telling the CPU that it has just exited an ISR so no "RETI" is needed?
Yes that's what @brucehoult refers to; but theres more to it: multi-level nesting/prioritizing including the late arrival optimization, some lengthy instructions are interruptible/replayable in order to reduce latency, FP registers lazy stacking, tail chaining, maybe more.

In all other "usual" processors, you are supposed to take care of all of these "manually", and/or just suffer whatever consequences there are. I like that level of hand-holding and gladly pay for the few millicent's worth of gates spent on that.

Quote from: brucehoult
That costs both hardware (gates) and execution time for interrupt functions that don't actually need that many registers.
I don't think so; most practical ISRs do need those 4 registers and more. I don't remember seeing a real-world ISR disasm without prologue pushing more registers. Of course, you can come up with an artificial counterexample whenever you want (*).

And if you want to talk about wasted gates, what about the constants/tables (and associated address decoders) which nobody ever uses (among other things, because they often don't even conform to ARM's own specification)? So, no, I'd say, those gates in the interrupt logic were quite well spent.

Quote
But it makes training of new bare-metal programmers a little easier.
I doubt it. Given proper documentation, bare metal programmers usually have no problem understanding what RETI is and why.

JW

(*) actually, I've written one, but that was a rather idiotic attempt to salvage existing badly designed hardware, the "you surely can work around it in code, yeah?" kind
« Last Edit: March 25, 2024, 12:46:53 pm by wek »
 

Offline tellurium

  • Regular Contributor
  • *
  • Posts: 229
  • Country: ua
Re: Mcu programming 101 writeup
« Reply #17 on: March 26, 2024, 12:11:46 am »
> startup_stm32f407xx.s - it is odd why this is in asm
Chicken/egg. Startup code is to prepare everything needed to run C, so how could startup be in C if it haven't had things prepared?

It is a common misconception that a startup code is required to run C.
It is perfectly possible to have an ARM code with zero assembly.
In fact I don't really understand why all these vendors keep writing their startup code in assembly, IMO it is just stupid.
The startup code can be easily written in C.

For example, look at Alex Taradov's https://github.com/ataradov/mcu-starter-projects

This is ST project, with startup code in pure C, no assembly stuff: https://github.com/ataradov/mcu-starter-projects/tree/master/stm32g071

The reset handler does everything required in C: initialises data, BSS , VTOR and calls main():

https://github.com/ataradov/mcu-starter-projects/blob/243aa5aceaa7362263806fb52eca7bef28d2f597/stm32g071/startup_stm32g0.c#L144-L159
Open source embedded network library https://mongoose.ws
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4037
  • Country: nz
Re: Mcu programming 101 writeup
« Reply #18 on: March 26, 2024, 01:22:24 am »
It is a common misconception that a startup code is required to run C.

It is on almost all CPUs.

Quote
It is perfectly possible to have an ARM code with zero assembly.
In fact I don't really understand why all these vendors keep writing their startup code in assembly, IMO it is just stupid.
The startup code can be easily written in C.

Only because Arm went out of their way to enable this on the very simple Cortex-M cores by putting the vector table initially at a fixed address of 0, and included the initial stack pointer (which is not, in fact,  the address of a handler) as the first entry, with special handling in the hardware to preload it into SP.

You can change the vector table address later, but only by using asm.

Quote
For example, look at Alex Taradov's https://github.com/ataradov/mcu-starter-projects

In the same project of Alex's, the startup code for FE310 uses inline asm to init sp and gp, then falls though into reset_handler(), which itself uses inline asm (in the write_csr macro) to init the mtvec pointer to the trap handler.

Similarly, if there is an FPU (the FE310 doesn't have one) or vector unit then asm is required to turn those on. Also if you have a chip with User mode then you need asm to switch to running User mode code, and asm to init the PMP (Physical Memory Protection) unit so that the user mode code doesn't trap as soon as it tries to fetch an instruction (not to mention data reads and writes) which it by default has no privilege to do.

This is perfectly normal and not a weakness. The only way to init all these things in C would be if CSRs were memory-mapped and that would be a pretty bad design for many reasons.
 

Offline Circlotron

  • Super Contributor
  • ***
  • Posts: 3180
  • Country: au
Re: Mcu programming 101 writeup
« Reply #19 on: March 26, 2024, 01:39:13 am »
Good to see someone promote bare metal programming instead of using the manufacturers pile of garbage like STM HAL (Hardware Abstraction Layers) code.
Bare metal??? Assembly or nothing!  :-+
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14480
  • Country: fr
Re: Mcu programming 101 writeup
« Reply #20 on: March 26, 2024, 03:18:52 am »
And even so, you still need assembly to at least set up the stack (on ARM Cortex) and possibly other things like setting some CSRs (RISC-V) depending on target, so if you use C with inline assembly and you think you're a big boy not using any assembly, good for you. That's just delusion.

In most cases for MCUs, the startup code, beside doing the above, will zero out the bss section and initialize data, you'll use memcpy() and memset() for this instead of a couple lines of assembly. If you think there's a lot to gain with that, again good for you. Whatever floats one's boat.
 

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 3698
  • Country: gb
  • Doing electronics since the 1960s...
Re: Mcu programming 101 writeup
« Reply #21 on: March 26, 2024, 07:12:24 am »
Another thing is that constructs such as

Code: [Select]
  src = &_etext;
  dst = &_data;
  while (dst < &_edata)
    *dst++ = *src++;

are liable to be detected by the compiler and replaced with memcpy() memset() etc. This is an absolute bastard if your project involves a "boot block" architecture (needed for e.g. non-brickable firmware updates) because the boot block is highly unlikely to have access to stdlib, so this needs additional expertise either in the linking department which is a bastard area - the linkfile syntax - which almost nobody understands (note also the compiler won't be aware of the subsequent inability of the linker to find the relevant functions) or in using things like -O0 (no optimisation) attribute for that code. The GCC compiler option -fno-tree-loop-distribute-patterns to suppress loop structure detection is not reliable (acc. to my project notes from 2021). I wasted days on this stuff and with 40 years of asm from Z80 onwards I am not exactly unfamiliar with how that works :)

It's OK if you document all this in the source but all I see is e.g.

Code: [Select]
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.

Remember that we are discussing code provided by STM (etc) for people who are often starting with some dev kit. These people are going to get totally stumped by issues like above. Anyone not believing this, visit the ST forum ;)

And, probably, unless you are using -O0, the loop identification exposes the project to a compiler version dependence. Already, just now, Cube 1.15.0 (GCC v12) breaks a load of stuff, one of which is some "executable" complaint from the linker. Yet more work...

The great thing about asm is that it never gets touched.



« Last Edit: March 26, 2024, 07:19:36 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 

Offline wekTopic starter

  • Frequent Contributor
  • **
  • Posts: 495
  • Country: sk
Re: Mcu programming 101 writeup
« Reply #22 on: March 26, 2024, 08:14:37 am »
Control (as in microcontroller) is the name of my game.

This very thread, and especially the __libc_init_array() discussion, is the proof, that when using C you are exposed to whatever other strong minded people put in there.

And that "it's normal to have startup in C, everybody does that"? Well, there's a bunch of things "everybody does". I try to understand what others do, how they do that and why(*), because there may be genuine reasons; but just too often there are little to none, and I try not just follow the masses blindly. It's their leg, their shot. I am responsible for mine.

> Bare metal??? Assembly or nothing!

:-D ,  but world is somehow not black and white.

JW


(*)
> In fact I don't really understand why all these vendors keep writing their startup code in assembly, IMO it is just stupid.

Can you please explain, why do you think it's stupid? Whatever I wrote above, I am genuinely interested in what's the reasoning behind this, except "it's possible".
 

Offline tellurium

  • Regular Contributor
  • *
  • Posts: 229
  • Country: ua
Re: Mcu programming 101 writeup
« Reply #23 on: March 26, 2024, 08:49:01 am »

(*)
> In fact I don't really understand why all these vendors keep writing their startup code in assembly, IMO it is just stupid.

Can you please explain, why do you think it's stupid? Whatever I wrote above, I am genuinely interested in what's the reasoning behind this, except "it's possible".

Please note that the "stupid" remark was given to the VENDOR's startup code that they ship with their IDEs and CMSIS packages.

I understand that some assembly would be required. But definitely not the whole startup file should be in assembly. Just few snippets, like setting specific registers, and that's all. Initialising data, BSS, vector table - can be perfectly done in C, and it will be much more readable and understood code.

So the argument here is clarity. If it can be written in C, in a much more clear way than in assembly, then why shouldn't it? Is there a reason?  What's the reason?

I am a bit surprised to be asked giving reasons for "C vs assembly" argument, to be honest.
Open source embedded network library https://mongoose.ws
TCP/IP stack + TLS1.3 + HTTP/WebSocket/MQTT in a single file
 
The following users thanked this post: wek

Offline peter-h

  • Super Contributor
  • ***
  • Posts: 3698
  • Country: gb
  • Doing electronics since the 1960s...
Re: Mcu programming 101 writeup
« Reply #24 on: March 26, 2024, 09:00:25 am »
The reason, as posted above, is obscure side effects, unpredictable compiler optimisation, etc.

Another thing, usually but not always immaterial, is that you can't just "write code" in C. You can only write a C function, so a stack frame will get set up, as shown e.g. here
https://www.eevblog.com/forum/microcontrollers/is-st-cube-ide-a-piece-of-buggy-crap/msg5412443/#msg5412443

So you aren't getting simple direct code at startup.
« Last Edit: March 26, 2024, 09:32:48 am by peter-h »
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 80x86 90S1200 32F417
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf