STM32F4 discovery – Keil example step-by-step

Keil development tools are excellent and they surprise with new toys with every new release. With version 5 they started with “packs”. I was confused with this new concept and without any training it took me a while to adapt new approach. Now, after a while and after reading few manuals I can only say it’s fantastic. Preparing new application is a breeze. What I was missing is step-by-step tutorial for newcomers to the “packs”. I would like to present step-by-step tutorial for simple application.

We will start with STM32F4 Discovery board, a low cost nice development board with some interesting periphery. First example will be simple “blinky” with blinking blue LED.

OK, let’s start with new project. I will not explain CMSIS and other MDK Components in detail. All necessary background is available from the products literature, check links at the end of this page.

1. From the µVision menu bar, choose Project – New µVision Project.

2. Create new folder somewhere in your disk and name your new application, eg “mynewapp” – not really smart name 🙂

c1

3. Click “Save” and select the target microcontroller. STM32F4 Discovery board is populated with STM32F407VG microcontroller:

c2

4. Click OK and new dialog wil appear to manage runtime environment. Expand ::CMSIS:RTOS and enable :Keil RTX :

c3

The Validation Output field shows dependencies to other software components.  In this case, the component ::Device:Startup is required. Press “Resolve” and OK. Now all required components are included into the project together with the startup file, the RTX configuration file, and the CMSIS system files.

5. You can rename the target to STM32F5 Discovery:

c4

 

6. Now it’s time to make some initial configuration adjustments. First, adjust the clock to match the on-board quartz frequency. The core clock is defined in the system_stm32f4xx.c file. Open this file and microcontroller reference manual, paragraph “6.2.3 PLL configuration”:

c5

The STM32F4-Discovery has 8MHz crystal. We would like to run the core at 168MHz. In order to generate a core clock frequency of 168MHz, according to formulae above, we need M=8 and N=336. Change the #define in the file system_stm32f4xx.c:

252
253
254
255
/********************* PLL Parameters **********************************/ 
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */ 
#define PLL_M 8 
#define PLL_N 336

7. Configure the RTOS clock to match the device settings. Open the file RTX_Conf_CM.c and select the configuration wizard at the bottom of the editor window. Press “Expand all” and edit the RTOS Kernel Timer input clock frequency. Units are Hz. Enter value 168000000:

c6

That finishes the configuration adjustments. Now it’s time to generate some source code for our application.

8. Right click on “Source group 1” in project window and select the dialog Add New Item to Group. New window will open:

c7

Select User Code Template and click on  “CMSIS-RTOS ‘main’ function”. Click Add.

c8

The file main.c will be generated from the template.

9. Edit the main program code. First add the CMSIS-RTOS RTX header. Right-click on a blank line at the beginning of the file main.c and from popup menu select Insert ‘#include files’. Include the header file cmsis_os.h.

10. Add new file to the project to control the LEDs. Create an empty C-file named LED.c using the dialog Add New Item to Group and add the code to initialize and access the GPIO port pins that control the LEDs.

ledc

The source code for led.c is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*------------------------------------------------------------------------ 
 * File LED.c 
 *----------------------------------------------------------------------*/ 
#include "stm32f4xx.h" // Device header 
#include "cmsis_os.h" // RTOS:Keil RTX header 
 
void blink_LED (void const *argument); // Prototype function 
 
osThreadDef (blink_LED, osPriorityNormal, 1, 0); // Define blinky thread 
 
// Initialize GPIO Port 
void LED_Initialize (void) { 
 RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; // Enable Port D clock 
 GPIOD->MODER |= GPIO_MODER_MODER15_0; // Port D.13 output 
} 
 
/* Turn LED on */ 
void LED_On (void) { 
 GPIOD->BSRRL = (1<<15); // LED on: set Port 
} 
 
/* Turn LED off */ 
void LED_Off (void) { 
 GPIOD->BSRRH = (1<<15); // LED off: clear Port 
} 
// Blink LED function 
void blink_LED(void const *argument) { 
 for (;;) { 
 LED_On (); // Switch LED on 
 osDelay (500); // Delay 500 ms 
 LED_Off (); // Switch off 
 osDelay (500); // Delay 500 ms 
 } 
} 
 
void Init_BlinkyThread (void) { 
 osThreadCreate (osThread(blink_LED), NULL); // Create thread 
}

11. Add an empty header file named LED.h using the dialog Add New Item to Group and define the function prototypes of LED.c

ledh

with following code:

1
2
3
4
5
6
7
8
9
/*------------------------------------------------------------------------ 
 * File LED.h 
 *----------------------------------------------------------------------*/ 
void LED_Initialize ( void ); // Initialize GPIO 
void LED_On ( void ); // Switch Pin on 
void LED_Off ( void ); // Switch Pin off 
 
void blink_LED ( void const *argument ); // Blink LEDs in a thread 
void Init_BlinkyThread ( void ); // Initialize thread

 

12. Edit the main.c and add LED initialization and thread creation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*------------------------------------------------------------------------ 
 * CMSIS-RTOS 'main' function template 
 *----------------------------------------------------------------------*/ 
 
#define osObjectsPublic // Define objects in main module 
#include "osObjects.h" // RTOS object definitions 
#include "cmsis_os.h" // ARM::CMSIS:RTOS:Keil RTX 
#include "LED.h" // Initialize and set GPIO Port 
 
/* 
 * main: initialize and start the system 
 */ 
int main (void) { 
 osKernelInitialize (); // Initialize CMSIS-RTOS 
 // initialize peripherals here 
 LED_Initialize (); // Initialize LEDs 
 
 // create 'thread' functions that start executing, 
 // example: tid_name = osThreadCreate (osThread(name), NULL); 
 Init_BlinkyThread (); // Start Blinky thread 
 osKernelStart (); // Start thread execution 
 
 while (1); 
}

12. Change some cosmetic options for the target. Press the magic wand in the toolbar to show the “Options for target” window. Select the Output tab and click Select folder for Objects. Create new folder “out” or similar, open it and confirm by clicking OK:

c9

13. Do exactly the same with “listing” tab:

c10

14. Now connect the Discovery board and select the debugger. Without any changes you should use the ST-Link debugger. I am using U-link with modified Discovery board. The modifications are explained in this article. The debugger is selected in the “Debug” tab:

c11

The device should be active in the device list.

15. Now compile the application (F7) and the output window should indicate no errors or warnings if everything is done correctly:

Build target 'STM32F4 Discovery'
compiling main.c...
compiling RTX_Conf_CM.c...
assembling startup_stm32f40_41xxx.s...
compiling system_stm32f4xx.c...
linking...
Program Size: Code=6192 RO-data=512 RW-data=96 ZI-data=4752 
".\out\mynewapp.axf" - 0 Error(s), 0 Warning(s).

16. Load the compiled project to flash by pressing “DownLoad” button dl …

Load "E:\\shara\\keil-test\\out\\mynewapp.axf"
 Erase Done.
 Programming Done.
 Verify OK.

17. Press the Reset button on target board and blue LED should start blinking.

 

Next excercise will be adding USB device to the same application. We will add CDC class device to control the board with the terminal and virtual COM port.

 

Useful literature and links:

http://www2.keil.com/docs/default-source/default-document-library/mdk5-getting-started.pdf?sfvrsn=0

http://www.keil.com/pack/doc/mw/General/html/index.html

3 Comments

  1. toni says:

    eno oprašanje mam ali bi se dal naštimat da bi lahko poslušu preko tebe ali je kaka možnost hvala l.p.toni

  2. George Harnes says:

    Hi, thank you for the tutorial. Before finding your post, I watched an STM32 tutorial using a different board and decided to get it. How different is the code for the stm32 keil getting started? My board has the STM32F0 controller.

    Thanks,
    George