No Core - Bluepill FreeRTOS setup

Any other microcontroller based boards
Post Reply
User avatar
Rick Kimball
Posts: 71
Joined: Thu Mar 14, 2019 6:27 pm
Location: Eastern NC, US
OS: Linux
IDE: Arduino 1.8.9, vscode+make, eclipse, vi, emacs
Core: libmaple, STM official, fabooh, none
Board: Bluepill, Nucleos, Discovery
Contact:

No Core - Bluepill FreeRTOS setup

Post by Rick Kimball » Sun Apr 14, 2019 8:25 pm

In another thread I had posted example code to help someone get going using gcc with minimal library usage. He wasn't using any Arduino core. I've been looking at learning FreeRTOS because of the ESP32 chips I ordered, so I thought it might be worthwhile to get some exposure to it using the bluepill until my ESP32 boards arrive.

I put together a very simple example using FreeRTOS 10.2 and posted it to github. It doesn't use any helper libraries or frameworks. The user code just uses the stm32f103xb.h header files with the structures and defines in it to manipulate the peripherals and clocks. If you find this interesting you can get the code here:

https://github.com/RickKimball/bluepill ... /example05

It blinks PC13 and PC14 (you supply the led) at different rates using cooperative multitasking feature of FreeRTOS. It generates nice small code:

Code: Select all

$ make
done!
   text	   data	    bss	    dec	    hex	filename
   2440	    104	    232	   2776	    ad8	main.elf
Geared towards people running a unix like OS. I've only tested it on ubuntu with arm-none-eabi-gcc from linaro installed in /usr/bin/arm-none-eabi-gcc.
-rick

User avatar
Vassilis
Posts: 149
Joined: Wed Feb 27, 2019 5:09 pm
Answers: 2
Location: Thessaloniki, Greece
OS: Linux, Win10, MacOS
IDE: Arduino 1.8.9
Core: Roger, STM official
Board: Bluepill, Maple mini, STM32F4xx
Contact:

Re: No Core - Bluepill FreeRTOS setup

Post by Vassilis » Mon Apr 15, 2019 7:14 am

Thanks Rick !
It works great on Win10

- Off topic -
The example04 shows me an error message on windows 10 ( make all )

Code: Select all

"recreating depend file main.d"
"recreating depend file vectors.d"
delay.s: Assembler messages:
delay.s:16: Error: undefined symbol _LOOP_CNT_PER_MSEC used as an immediate value
make: *** [delay.o] Error 1
I solved that by modifying the delay.S file:

Code: Select all

delay:
        .align  4
        //mov     r12,#_LOOP_CNT_PER_MSEC
        ldr     r12,=_LOOP_CNT_PER_MSEC //<------------
        mul     r0,r12                          @ multiply msecs * (cycles per msec/4)

Code: Select all

"recreating depend file main.d"
"recreating depend file vectors.d"
"generating main.elf"
"done!"
   text    data     bss     dec     hex filename
    364       0       8     372     174 main.elf
"generating main.bin main.hex main.lss main.sym"
-Vassilis Serasidis

User avatar
Rick Kimball
Posts: 71
Joined: Thu Mar 14, 2019 6:27 pm
Location: Eastern NC, US
OS: Linux
IDE: Arduino 1.8.9, vscode+make, eclipse, vi, emacs
Core: libmaple, STM official, fabooh, none
Board: Bluepill, Nucleos, Discovery
Contact:

Re: No Core - Bluepill FreeRTOS setup

Post by Rick Kimball » Thu Apr 18, 2019 3:45 pm

Are you using a case-insensitive file system? arm-none-eabi-gcc handles files with .S different than .s. When it sees .S it runs the code through the c preprocessor and invokes it with -x assembler-with-cpp .. when it sees a .s it just hands it off to the gnu as program without preprocessing.
-rick

User avatar
Rick Kimball
Posts: 71
Joined: Thu Mar 14, 2019 6:27 pm
Location: Eastern NC, US
OS: Linux
IDE: Arduino 1.8.9, vscode+make, eclipse, vi, emacs
Core: libmaple, STM official, fabooh, none
Board: Bluepill, Nucleos, Discovery
Contact:

Re: No Core - Bluepill FreeRTOS setup

Post by Rick Kimball » Thu Apr 18, 2019 4:10 pm

So, I spent a little time looking at vscode with the platformio extension and how I would use it with this github repository. I came to the conclusion that platformio adds a lot of hand waving and leaves you unable to create a simple setup that you can tweak.

However, more importantly, I was pleasantly surprised to see that the C/C++ Intellisense in vscode now can use arm-none-eabi-gcc as the preprocessor for its indexing feature. The last time I looked at this, probably 3 years ago, the only choice was clang and that didn't work well with gcc code at all. It is also pretty easy to completely ignore platformio and just use the features of vscode. You just need to add a few .json files (see the ones I added).

Install vscode (I'm using the latest version for ubuntu 64 bit) and the "Native Debug" extension from webfreak. Open a terminal window and Invoke make all install. Then use the vscode Debug menu item to launch an openocd server and the gdb client uses vscode. The only thing it is missing is a way to see a disassembly window. You can step at the asm level by using nexti in the debug command window. However, for most people they will be happy to see a normal style debugger window. You can set break points by clicking to the left of the line number on the instruction where you want to stop.

What the editor window looks like:
Image

Here is an example of me debugging inside of vscode.
Image

This actually feels surprisingly zippy. Last time I tried it, it was very laggy. VSCode by itself with a few extensions makes a nice editing, build, and debug environment.

Look at the vscode files I recently added in https://github.com/RickKimball/bluepill ... 06/.vscode. It is these files that provide the information vscode needs to be able to parse the c code to index functions and variables and also how to launch a gdb session that works with an stlink dongle.
-rick

User avatar
Rick Kimball
Posts: 71
Joined: Thu Mar 14, 2019 6:27 pm
Location: Eastern NC, US
OS: Linux
IDE: Arduino 1.8.9, vscode+make, eclipse, vi, emacs
Core: libmaple, STM official, fabooh, none
Board: Bluepill, Nucleos, Discovery
Contact:

Re: No Core - Bluepill [s]FreeRTOS[/s] setup

Post by Rick Kimball » Tue Apr 23, 2019 12:29 am

So I've been quietly chugging along updating this code with new examples. The latest example shows some interesting techniques for stack and heap usage and debugging. I don't use FreeRTOS with this one, I found a less complex cooperative multitasking library with less features but much smaller. Find the code here: https://github.com/RickKimball/bluepill ... /example08

I've provide a few different linker scripts that work with the 'C" based Reset_Handler. The default script stm32f103cb.ld uses the normal stack and memory layout you would expect. Flash for the code, Stack at 0x20005000 growing down, heap starting after the bss end.

A more interesting ldscript places the stack at the bottom of memory and grows it down towards 0x20000000. You can see how I use the _Min_Stack_Size to set the top of the stack and set the beginning of RAM to start after it. The advantage to this approach is that the stack and the heap will never collide. If you exceed the stack size, it will trigger a HardFault_Handler and you can know that your stack is too small. To help you diagnose the problem you can use the vectorstate macro I include as part of invoking "$ make debug". So if it gets stuck in one of the exception handlers, press CTRL-C and then type vectorstate to see what is going on. Also, if you exceed heap memory, it will also trigger a BusFault if it goes past the end of memory. This is actually much safer than having the heap write over the stack and never being able to detect it.

Another feature I added was "Coloring" the memory. When the Reset_Handler first gets control, it will optionally write a pattern to the STACK (0xcccccccc) memory and HEAP (0xcdcdcdcd) memory. If you use gdb to examine memory, you can see which memory addresses have actually been used. This can help you optimally set your STACK and HEAP sizes.

And finally I created a "ram" make target. This builds the code so it runs all in memory. You will never wear out your flash using this option, assuming all your code, stack and heap can fit in 20K :)

Code: Select all

$ make clean ram
$ make debug
...
(gdb) monitor reset init
(gdb) load
(gdb) continue
...
All the peripherals are being accessed using only the device header (stm32f103xb.h) however I did add some simple cooperative multitasking using the Arduino Scheduler Library. Surprising as it seems, it actually doesn't use any Arduino code at all and it only implemented for arm cortex chips. It is nice and small and doesn't really add much overhead. It is only a couple of files, Scheduler.cpp and Scheduler.h. If you don't use any newlib printing features, the binary for a 2 task .elf file comes in at less than 2K of flash and defaults to 1K of heap memory, however you can probably cut that down to less than 256 bytes of heap.

And finally, I'm compiling all this stuff with the latest linaro arm-eabi-gcc binary. It uses std++17 and gcc 8.3.0.

This exampl08 is still a work in progress, but I thought I'd post an update here and get it into github before I lose it :)

As much as I don't want to admit it, I'm really enjoying using the vscode editor and the environment it provides to hide the ugliness of raw git, raw make, and raw gdb.
-rick

User avatar
Rick Kimball
Posts: 71
Joined: Thu Mar 14, 2019 6:27 pm
Location: Eastern NC, US
OS: Linux
IDE: Arduino 1.8.9, vscode+make, eclipse, vi, emacs
Core: libmaple, STM official, fabooh, none
Board: Bluepill, Nucleos, Discovery
Contact:

Re: No Core - Bluepill FreeRTOS setup

Post by Rick Kimball » Wed Apr 24, 2019 11:07 pm

So I added some novel stuff to the latest example. I'm using the re2c lexer utility to generate code that parses tokens from a command line string. Check out my process.re source code that generates a function that turns the command line into a series of tokens that I use with a big switch statement to implement the command line functions.

[Edit] I made it all table driven now [/Edit]

The code allows me to handle the following commands entered into the serial console:

Code: Select all

example08 - led command line processor
command> help
Help:
  help | 'h' | '?'         - display this message
  led                      - display led settings
  led off                  - led off
  led on                   - led on no blink
  led blink                - led blink on 500 msec, off for 500 msec
  led blink msec           - led blink on for msec and then off for msec
  led blink ontime,offtime - on for ontime, off for offtime
  uptime                   - display msecs since power on
command> led
led is Blinking on time is 100, off time is 900
command> led off
command> led
led is Off
command> led on
command> led
led is On
command> led blink
command> led
led is Blinking on time is 500, off time is 500
command> led blink 250
command> led
led is Blinking on time is 250, off time is 250
command> led blink 1000
command> led
led is Blinking on time is 1000, off time is 1000
command> led blink 50,450
command> led
led is Blinking on time is 50, off time is 450
command> uptime
up 4925694 msecs
command>
In spite of all this code, still weighing in at less than 8K

Code: Select all

TARGET=firmware finished
   text	   data	    bss	    dec	    hex	filename
   7664	    120	    124	   7908	   1ee4	build/src/firmware.elf
-rick

mrburnette
Posts: 90
Joined: Fri Mar 29, 2019 2:22 am
Answers: 1
OS: Linux
IDE: Arduino
Core: Any
Board: Blue, MM, Black

Re: No Core - Bluepill [s]FreeRTOS[/s] setup

Post by mrburnette » Sat Apr 27, 2019 4:20 pm

Rick Kimball wrote:
Tue Apr 23, 2019 12:29 am
So I've been quietly chugging along updating this code with new examples. The latest example shows some interesting techniques for stack and heap usage and debugging. I don't use FreeRTOS with this one, I found a less complex cooperative multitasking library with less features but much smaller. Find the code here: https://github.com/RickKimball/bluepill ... /example08

...
So, we started off in post #1 using FreeRTOS with ESP32 and working with the FreeRTOS API directly. Now it seems we are back to STM32 with a pseudo-rtos like the non-OS used in the ESP8266 where "yield", delay(0), or the top-of-loop allows for thread switching.

Any plans to implement this light-weight version on ESP32?

Ray

User avatar
Rick Kimball
Posts: 71
Joined: Thu Mar 14, 2019 6:27 pm
Location: Eastern NC, US
OS: Linux
IDE: Arduino 1.8.9, vscode+make, eclipse, vi, emacs
Core: libmaple, STM official, fabooh, none
Board: Bluepill, Nucleos, Discovery
Contact:

Re: No Core - Bluepill [s]FreeRTOS[/s] setup

Post by Rick Kimball » Sun Apr 28, 2019 3:53 pm

mrburnette wrote:
Sat Apr 27, 2019 4:20 pm
So, we started off in post #1 using FreeRTOS with ESP32 and working with the FreeRTOS API directly.
Actually I haven't done anything with the ESP32 even though they showed up this week. All my explorations have been with the stm32f103c8 bluepill. My big problem, I'm easily distracted snd go off exploring different shiny things.

I started this exploration as a way to learn a little about FreeRTOS. That seemed kind of heavy weight so I vectored off using the FreeRTOS cooperative multitasking mode. Using very little of the FreeRTOS ecosystem prompted me to vector off into the ArduinoScheduler. That added a bunch of makefile changes so I vectored off in some Makefile mania. Then I went down a gdb rat hole and explored ways to color the stack and heap to provide better debugging, which was all prompted by my messing with the location of stack. Moving it to the bottom of RAM below the .data segment to provide some exception detection when it is overflowed triggered some problems with my code. All this because I was trying to find optimal stack size for each task. Then I got wondering about newlib and using normal posix style programming which led to a vector off into implementing _read(), _write() and simple ftoa conversions while still using the nano.specs newlib. When I was looking at parsing the input stream, I remembered using re2c for some language processing code on desktop code years ago and wondered how it might work with embedded code, which led me to vector off into using re2c to tokenize input streams. Also, during this whole time I've been using vscode and tweaking its settings on linux and found that it is a nice IDE that fits well into my make approach to development. As I said, I'm easily distracted.

I really need to break out those ESP32 and stop mucking about with stm32 until I'm ready to combine the two.
mrburnette wrote:
Sat Apr 27, 2019 4:20 pm
Any plans to implement this light-weight version on ESP32?
It seems the ESP32 is pretty powerful. Does it really need a FreeRTOS lite? I was thinking buying an ESP32 would let me go back to old bad habits of wasting CPU and memory :)

**FREEBIE**
simple ftoa that works with nano.specs newlib:

Code: Select all

/*----------------------------------------------------------------------
  ftoa() - convert float to char * string
    buffer - char array for conversion 
    number - float to be converted
    digits - number of digits after the decimal point
    cnt    - return len of converted string
    bround - round the output
  */
char *ftoa(char *buffer, float number, int digits, int *cnt=0, bool bround=true) {
   // user assumes responsibility for correct buffer size for required digits
  char *p=buffer;
  /* constants */
  const float divf_10 = 1.0f / 10.0f;
  const float mulf_10 = 10.f;

  if ( digits >__FLT32_DECIMAL_DIG__ ) {
    digits = __FLT32_DECIMAL_DIG__;
  }

  // Handle negative numbers
  if (number < 0.0f) {
    *p++ = '-';
    number = -number;
  }

  if ( bround ) {
    // Round correctly so that print(1.999, 2) prints as "2.00"
    float rounding = 0.5f;

    for (int i = 0; i < digits; ++i) {
      rounding *= divf_10; // rounding /= 10.f
    }

    number += rounding;
  }

  // Extract the integer part of the number and print it
  unsigned int_part = (unsigned) number;
  int rc=sprintf(p,"%d",int_part);
  p += rc;

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0) {
    *p++ = '.';
  }

  // Extract digits from the remainder one at a time
  float remainder = number - int_part;
  int remd =0;
  int d=digits;

  while (d-- > 0) {
    remainder *= mulf_10;
    unsigned digit = unsigned(remainder);
    remd *= 10;
    remd += digit;
    remainder = remainder - digit;
  }
  rc=sprintf(p,"%0*d",digits,remd);
  p+=rc;

  if (cnt) {
    *cnt = p-buffer;
  }

  return buffer;
}
char buff[12];
printf("float = %s\n", ftoa(buff,1.234f,3));
-rick

turboscrew
Posts: 4
Joined: Thu May 23, 2019 5:06 am
Location: Nokia, Finland
OS: Linux (mostly)
IDE: Eclipse (mostly)
Core: None (bare metal)
Board: Bluepill

Re: No Core - Bluepill FreeRTOS setup

Post by turboscrew » Sat May 25, 2019 4:08 pm

Rick, maybe you need to write some bare metal assembly?
That tends to make one to write compact and efficient code - just because writing less compact code tends to take a lot more code lines. :lol:

At work I have to use libraries and frameworks, but at home I prefer not to use any.
These days (at home) I mainly write C for a blue pill, and usually the only file not written by me is stdint.h
I consider it compiler-specific.
Debugging is for sissies, real men do demonstrations.

Post Reply