Thursday, April 4, 2013

Hello World tutorial for STM32 Discovery boards using CooCox CoIDE and GCC ARM

ST Microelectronics has been supporting their Discovery line of ARM demonstration and development boards for a while now.  I was first introduced to the STM32 Value line discovery (STM32-F1), getting a free one at one of the embedded development conferences in San Jose or Santa Clara.  I had tucked it away for safe keeping (or hoarding), and over the years also acquired a STM32-F0, STM32-F4, and STM32-F3.  These are low cost (most $8-$11, with one at $15 US), and some of the more advanced boards include an accelerometer, gyroscope, or compass and multiple LEDs.

I recently stumbled across the CooCox CoIDE for working with the Simplecortex (I'll blog more about NXP chips and boards another time), and while starting to play with it, discovered that this IDE also supported the STM32 boards.  Which is great, as I had just started reading Discovering the STM32 Microcontroller by Geoffrey Brown of Indiana University and wanted to try my hand at developing for ARM in C.

As stated in their tagline, CooCox is a set of "Free and Open ARM Cortex MCU Development Tools."  CoIDE is an Eclipse based integrated development enviroment supporting the standard GCC ARM tool set: compiler, assembler, linker, and debugger.  The STM32 discovery boards include an embedded ST-LINK or ST-LINK/V2 which is supported by CoIDE for flashing and debugging.  The real value add by CoIDE is point and click choice of MCU library modules for various peripherals, with hypertext library references and examples.  CooCox supports a variety of ARM Cortex MCUs from various manufacturers.  ST is just one of the manufacturers.

Here I will show you how to install CoIDE and essential dependencies to develop a simple Hello World program for the STM32 Value line discovery board.  The steps are very similar for the other boards (except STM32-F3 is not directly supported at this time).  The program will display debug output from printf() through the ST-LINK to the IDE's console window.  This is the essential first program to see results from a program running on an embedded board.  And it's not just a blinking LED, though we'll do that too.

One time installation and configuration.

1. Download ARM GCC
2. Download CoIDE
3. Download STM32 ST-LINK Utility
3. Install ARM GCC
4. Install CoIDE
5. Configure CoIDE to point to ARM GCC
6. Install STM32 ST-LINK Utility
7. Plug in USB cable from PC to ST-LINK on discovery board


Creating your first project.

1. Click Create Project, name it hello
2. When prompted Chip or Board, choose Chip
3. Choose ST, and STM32F100RB.  Click Finish
4. In the Repository window, click on Semihosting and GPIO.  Required dependencies will autoselect
5. Double click on main.c in the Project window, and modify to contain

#include <stdio.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_rcc.h>


int main(void)
{
 GPIO_InitTypeDef gpio;
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);


 GPIO_StructInit(&gpio);
 gpio.GPIO_Pin = GPIO_Pin_9; // Green LED
 gpio.GPIO_Mode = GPIO_Mode_Out_PP;
 gpio.GPIO_Speed = GPIO_Speed_2MHz;
 GPIO_Init(GPIOC, &gpio);


 gpio.GPIO_Pin = GPIO_Pin_8; // Blue LED
 GPIO_Init(GPIOC, &gpio);


 printf("Hello World!\r\n");

 while(1)
 {
  static int count=0;
  static int i;
  static int led_state=0;


  for (i=0; i<1000000; ++i);
  GPIO_WriteBit(GPIOC, GPIO_Pin_9, led_state ? Bit_SET : Bit_RESET);
     led_state = !led_state;
     GPIO_WriteBit(GPIOC, GPIO_Pin_8, led_state ? Bit_SET : Bit_RESET);


  printf("%d\r\n", ++count);
 }
}


6. Open printf.c from the Project window
7. Add #include <semihosting.h> after the other includes.
8. In the PrintChar method, add the following line before the closing brace



SH_SendChar(c);
 
9. Right click on hello in tree of Project Window and choose Configuration
10. Navigate to Debugger tab, and verify ST-Link is chosen
11. Click on Semihosting Enable
12. Choose Project + Build, should be successful
13. Choose Debug + Debug, will deploy to board and stop at top of main
14. Choose Debug + Run to continue the program, should see output in Semihosting window









 


38 comments:

  1. what changes are to be done if using the STM32F4 instead?

    ReplyDelete
  2. // STM32F4DISCOVERY

    #include
    #include
    #include

    int main(void)
    {
    GPIO_InitTypeDef gpio;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    GPIO_StructInit(&gpio);
    gpio.GPIO_Pin = GPIO_Pin_12; // Green LED
    gpio.GPIO_Mode = GPIO_Mode_OUT;
    gpio.GPIO_Speed = GPIO_Speed_2MHz;
    gpio.GPIO_OType = GPIO_OType_PP;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD, &gpio);

    gpio.GPIO_Pin = GPIO_Pin_15; // Blue LED
    GPIO_Init(GPIOD, &gpio);

    printf("Hello World!\r\n");

    while(1)
    {
    static int count=0;
    static int i;
    static int led_state=0;

    for (i=0; i<1000000; ++i);
    GPIO_WriteBit(GPIOD, GPIO_Pin_12, led_state ? Bit_SET : Bit_RESET);
    led_state = !led_state;
    GPIO_WriteBit(GPIOD, GPIO_Pin_15, led_state ? Bit_SET : Bit_RESET);

    printf("%d\r\n", ++count);
    }
    }

    ReplyDelete
  3. Correction to last comment. The three includes for STM32F4 should be stdio.h, stm32f4xx_gpio.h and stm32f4xx_rcc.h

    ReplyDelete
  4. Dave,
    your tutorial is a very good start with CooCox and STM32 Discovery boards.
    I tried your example with my STM32F4 DISCOVERY and it worked fine.

    Since I already had a small test code for this board written for Keil uVision4 (evaluation, 32k limited), I tried moving its source files to CooIDE. It compiled fine.
    But I noticed that the initialization code in source file system_stm32f4xx.c is not executed.
    What I care now is setting FLASH->ACR, which I found in system_stm32f4xx.c.
    Then I noticed that in Project Configuration, Link,
    "don't use the standard system startup files" is ticked.
    I tried removing the tick mark, but build failed with a long list of errors like
    error: ..\obj\startup_stm32f4xx.o uses VFP register arguments, hello.elf does not

    Am I tampering with the project the wrong way?

    Thanks

    ReplyDelete
  5. I would recommend starting from a CooIDE created project started from scratch and merge in your other project a file at a time. Only bring over the .c files. Probably don't bring over the .elf and .o files from the other compiler in case they wouldn't cooperate.

    Good luck! Some tinkering will be required but you can get it!

    ReplyDelete
  6. Hi Dave,
    I have a STM32F407VG Discovery Board plugged into a BB. I tried an example in CooIDE then found your tutorial and completed the steps with the added modification of the code for STM32F4. I still have the ST preloaded example running on the board. The tutorial gives an error of:
    C:\CooCox\CoIDE>"C:/CooCox/CoIDE/bin\coflash.exe" program STM32F407VG "C:/CooCox/CoIDE/workspace/hello/hello/Debug/bin/hello.elf" --adapter-name=ST-Link --port=SWD --adapter-clk=1000000 --erase=affected --driver="C:/CooCox/CoIDE/flash/STM32F4xx_1024.elf"
    Error: Connect failed, check config and cable connection
    Program Download Failed !
    I am a first time user. Please could you help. Thanks.

    ReplyDelete
  7. Hi Dave,
    Although I thought the driver was installed in fact it wasn't. I used:

    To upgrade ST-Link over STM32F4 Discovery
    1. Select JTAG mode in setting of STM32 ST-LINK Utility
    (Select "JTAG", from menu "Target->Settings->Connexion Protocol")
    2. Disconnect and reconnect the target and execute "Firmware update" from "ST-LINK" menu
    3. When the upgrad is over, Restore the setting to "SWD"

    The disconnect and reconnect needed plugging the USB plug. Now I have completed your tutorial! Many thanks for your blog. Regards Kevin.

    ReplyDelete
  8. hi , I'm new and i don't know how to solve this problem :
    "BUILD FAILED
    Output filename conflict: stm32f4xx_rcc.o would be produced from C:\CooCox\CoIDE\workspace\testled\STM32F4xx_StdFramework_V1.0_2013_03_15\StdPeriphLib\STM32F4xx_StdPeriph_Driver\src\stm32f4xx_rcc.c and stm32f4xx_rcc.c
    Total time: 0 seconds"

    ReplyDelete
  9. Hi benfraj elmokhtar - looks like the output file (stm32f4xx_rcc.o) already exists. Try to do a Project + Clean first, or start from scratch. More help may be available at the CooCox forums.

    ReplyDelete
  10. Thanks Dave, this is a great tutorial - it helped me get started.
    I did notice that I am not able to print floats to the debug window, so I wrote a simple function to do it (it might need tweaking if you want to print very small or large numbers)...

    void printfloat(float f_num, int dplaces)
    {
    int p = 1;
    int i;

    for (i = 0; i < dplaces; i++){p*=10;}
    printf("%d.%d",(int)floor(f_num),(int)round(p*(f_num-floor(f_num))));
    }

    ReplyDelete
    Replies
    1. Oh, I forgot to say that you will need the following line at the top of the file...

      #include < math.h >

      and that you need to add m to the Linked Libraries box in the Link tab in the project configuration - this is to include the maths library for the floor() and round() functions.

      Delete
  11. Hello, Dave.
    It is my first experience of programming a µC.
    I get "Unresolved inclusion: " . I don´t know how to fix it.

    I installed STM32 ST-LINK Utility on my C-drive but then I moved the whole folder to D-drive to the same folder where I have installed my CooxIDE.

    ReplyDelete
  12. / Unresolved inclusion: /
    Non of header files can be included

    ReplyDelete
  13. Thanks for the tutorial. I had an error that I fixed by modifying core_cm3.c. After that all was good.

    ReplyDelete
  14. Hi.

    Great tutorial.
    Unfortunetaly i've got a problem. I Did everything u said and when i right-click on project to select Configuration i CoIDE crashes :< Dunno why. Maybye u know what couses this problem?

    ReplyDelete
    Replies
    1. Sorry, haven't seen that problem. You may want to check with the CoIDE forums.

      Delete
    2. Ok, i worked it out.
      Reconnecting the board helped :d

      Now i got aanother problem - with compiler.
      I can't build project, and i found out that I can't set the same toolchain path as here http://www.coocox.com/CoIDE/Compiler_Settings.html after the GCC ARM Embedded installation. What am I doing wrong?

      Delete
    3. Common issue is pointing to the wrong folder. UI will refuse to let you set it to the wrong place, but gives a hint that a certain executable must be present there. Mine is set to:

      C:\Program Files (x86)\GNU Tools ARM Embedded\4.7 2013q1\bin

      Delete
    4. Thx for advice and patience. That helped :D
      But now, when I'm building, an error shows up:
      Error: registers may not be the same -- `strexb r3,r2,[r3]

      Delete
    5. Can't help you there. Sorry!

      Delete
    6. Ok, works. Solution:
      http://www.cesareriva.com/fix-registers-may-not-be-the-same-error/

      Delete
    7. Thanks for the follow up. Someone else had that error and mentioned a fix, and now it all makes sense. Hope this reference helps others too. Google search is a great resource right? Otherwise how did you find your way here? :-)

      Delete
  15. Hi, I'd like to explain a bug I had and corrected. I'm using a STM32f100RB ST-Link device:
    I followed all the instructions as described above and had the following error at compilation:
    [cc] C:\Users\SBASTI~1\AppData\Local\Temp\ccLngF0b.s:772: Error: registers may not be the same -- `strexb r3,r2,[r3]'
    [cc] C:\Users\SBASTI~1\AppData\Local\Temp\ccLngF0b.s:818: Error: registers may not be the same -- `strexh r3,r2,[r3]'
    After looking on the web, it appears it is an error in the CMSIS implementation file core_cm3.c. Two functions are badly implemented: STREXB and STREXH. The bug is easily corrected by replacing the initial code by the following (just add the & caracter):
    uint32_t __STREXB(uint8_t value, uint8_t *addr)
    {
    uint32_t result=0;

    __ASM volatile ("strexb %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
    return(result);
    }

    uint32_t __STREXH(uint16_t value, uint16_t *addr)
    {
    uint32_t result=0;

    __ASM volatile ("strexh %0, %2, [%1]" : "=&r" (result) : "r" (addr), "r" (value) );
    return(result);
    }
    Now everything works as expected !

    ReplyDelete
  16. For the STM32F0-discovery board (STM32F051) change the following:

    /* RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); */
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);

    /* gpio.GPIO_Mode = GPIO_Mode_Out_PP; */
    gpio.GPIO_Mode = GPIO_Mode_OUT;
    gpio.GPIO_OType = GPIO_OType_PP;

    Thanks for taking the time to write this up. It has save me a ton of time.
    -H

    ReplyDelete
  17. Thanks for the great post. I am using eclipse and tried to utilize semihosting library files with STM32F0Discovery. I enabled semihosting in eclipse and I could build it after minor changes in the code. Everything seems to be fine except SH_DoCommand function defined in SH_cmd.s file. I get "no source for SH_DoCommand()" message during debug process. HAs anybody got it worked in eclipse?

    ReplyDelete
  18. Hi Dave.
    This tutorial is very useful and precise.
    I want to use this CoIDE tool to move projects to Linux using Makefile.
    Hopeful someday, Coocox will have a Linux port.
    We need something that good and open source over in Linux world!


    Thank you very much for making my transition and leaning esay,
    Mike

    ReplyDelete
  19. Thank you very much for "printf" in semihosting !!!

    ReplyDelete
  20. Thank you so much for this guide! may i ask regarding this issue im encountering when Im using the LCD drivers?
    error: unknown type name 'xtBoolean'
    I have already have the xhw_types.h in the projects but still getting this error.

    ReplyDelete
    Replies
    1. Sorry Patrick, I am not familiar with that type and error.

      Delete
  21. Hi,
    i tried this code for blinking led. But it didn't work. Can you help me. i share tihs code.

    #include
    #include "stm32f2xx_gpio.h"
    #include "stm32f2xx_rcc.h"


    int main(void)
    {
    GPIO_InitTypeDef gpio;
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);

    gpio.GPIO_Pin = GPIO_Pin_14;
    gpio.GPIO_Mode = GPIO_Mode_OUT;
    gpio.GPIO_Speed = GPIO_Speed_2MHz;
    gpio.GPIO_OType = GPIO_OType_PP;
    gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOD,&gpio);

    printf("Hello World! \r\n");



    while(1)
    {
    GPIO_WriteBit(GPIOD, GPIO_Pin_14,Bit_SET);
    }
    }

    ReplyDelete
    Replies
    1. When you want to flash an LED in a loop, you usually need to have code that turns the LED off, turns the LED on, and delays in between each change. I only see one of these three in your code. Review my original code again that has these elements.

      Delete
  22. thanks for the excellent tutorial dave ant it helped me a lot.
    i ran into problem when i wanted to print a double number type or a float
    printf("%f \r\n", ADCResult/2.6 );
    i do not get anything printed when in debugging. please help.
    thanks

    ReplyDelete
  23. Ran through the demo again today, almost 3 years later. Note that to enable Semihosting, the Debugger tab is within the Configuration View while not running. That is where you have to click on "Semihosting Enable" before printf will be redirected to the Semihosting window. Also it was necessary to upgrade the firmware on the STM32F4DISCOVERY board using the ST-Link Desktop application.

    ReplyDelete
    Replies
    1. Tested with

      * CooCox CoIDE version 1.78
      * GNU Tools ARM Embedded 5.2 2015q4
      * STM32 ST-Link v3.6.0
      * STM32F4DISCOVERY, ST-Link firmware V2.J23.S0

      Delete