NUCLEO-F103RB: Difference between revisions

From Embedded Workshop
Jump to navigation Jump to search
 
(12 intermediate revisions by the same user not shown)
Line 5: Line 5:
  2) MBed - The on-board STM32 loader / debugger supports loading web site created binaries
  2) MBed - The on-board STM32 loader / debugger supports loading web site created binaries
     See https://os.mbed.com/
     See https://os.mbed.com/
  3) STMicro's STM32CubeMX / Keil uVision or STMicro's new STM32CubeIDE
  3) STMicro's STM32CubeIDE
     See https://www.st.com/en/development-tools/stm32cubeide.html
     See https://www.st.com/en/development-tools/stm32cubeide.html
  I prefer STMicro's environment, allowing me easy access to peripherals, registers,
  I prefer STMicro's environment, allowing me easy access to peripherals, registers,
Line 21: Line 21:
   and as such, has the following peripherals:
   and as such, has the following peripherals:
  3 USARTs
  3 USARTs
  3 16-bit timers
  4 16-bit timers: TIM1, TIM2, TIM3, TIM4
  2 SPIs, 2 I2Cs, USB, CAN, 1 PWM Timer, 2 ADCs
  2 SPIs, 2 I2Cs, USB, CAN, 2 ADCs
  Notes:
  Notes:
     "Low-density device" has fewer peripherals.
     "Low-density device" has fewer peripherals.
Line 44: Line 44:
ST Website for the STM32F1 family: http://www.st.com/stm32f1
ST Website for the STM32F1 family: http://www.st.com/stm32f1


==Getting Started==
==New Project - Blinky==
* Install STM32CubeIdE - https://www.st.com/en/development-tools/stm32cubeide.html
Create a New STM32CubeIDE Project - Blinky
 
  1 Click "Start new STM32 project", then select the "Board Selector" tab
  1 Open STM32CubeIDE
  2 In the Commercial Part Number box, type "NUCLEO-F103RB", select the board, and then click "Next>" at the bottom
2 Create '''New Project''' using "Start My project from ST Board" selector button
  3 Since I have several STM32 boards, I like to have the board name in the name of the project
  3 In the "Commercial Part Number" box, enter '''NUCLEO-F103RB'''
  I used: "NUCLEO-F103RB_Blinky" as the project name
  4 The board will display in the lower right part of the screen.  Select the board.
  4 Select "C" Executable, STM32Cube Project Type, Finish
  5 Click on '''Start Project''' in upper right corner of window
  5 Initialize all peripherals with their default Mode ? - Yes
  6 A dialog will be displayed, asking "Initialize all peripherals with their default Mode ?"
6 Device Configuration Tool editor is associated with Device Configuration Tool perspective.
    Select '''Yes'''
  Do you want to open this perspective now?  (Select Yes to see what's configured)
  7 Using the '''Clock Configuration''' tab, a 64MHz SYSCLK is configured by default.  This can be adjusted to 72MHz if desired.
  8 Using the '''Project Manager''' tab, give the project a name.  Something like '''"Blinky"''' will work well.
  7 Under "Project Manager Tab", Linker Settings, I set both Minimum Heap Size and Minimum Stack Size to 0x800 (2K bytes each)
  9 Within this same tab, select '''MDK-ARM''' for "Toolchain/IDE".  This instructs the Keil uVision application to be used.
  8 On the left, Project Explorer window, Open Core->Src->main.c
10 Select '''GENERATE CODE''' button in upper right corner.
  Note: If you examine the source code, you will see that the following functions get called:
    (You may get a dialog box indicating you are missing some dependencies.  Select "Yes" to download them now.)
  * HAL_Init()
11 Select '''Open Project''' when prompted.
  * SystemClockConfig()
    (Keil may need to run it's package installer if it doesn't have support for the board.  This will take some time.  Don't click anything!)
  * MX_GPIO_Init()
  12 Within Keil IDE, before we make any changes / additions to the code, let's make sure it buildsClick on '''Project''' -> '''Build Target'''
  Then, the code enters an empty while loopUsing the JTAG/SWD debugger, we can build, run, and debug the code,
    You can use the short-cut icon, available in the tool-bar, to '''Build(F7)'''
  but it will be rather boring...
  13 Within the project view, open the project, and then the Application/User/Core folder and then double click '''main.c'''
   
  14 The LED GPIO should already have initialization code within '''MX_GPIO_Init()'''.
9 Find the infinite loop inside the main() function, and add the following two bold lines of code:
    Find the infinite loop inside the main() function, and add the following two bold lines of code:
 
/* Infinite loop */
  /* Infinite loop */
/* USER CODE BEGIN WHILE */
  /* USER CODE BEGIN WHILE */
while (1)
  while (1)
{
  {
  '''HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);'''
    '''HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);'''
  '''HAL_Delay(500);'''
    '''HAL_Delay(500);'''
  /* USER CODE END WHILE */
    /* USER CODE END WHILE */
  /* USER CODE BEGIN 3 */
}
   
   
    /* USER CODE BEGIN 3 */
NOTE:
  }
'''Be sure to always place your code between the USER CODE BEGIN and USER CODE END comments'''
 
This will protect your code from being removed should you make changes using the STM32CubeMX again.
  NOTE:
  Be sure to always place your code between the '''USER CODE BEGIN''' and '''USER CODE END''' comments
  This will protect your code from being removed should you make changes using the STM32CubeMX again.
   
   
  14 Click Build (F7)
  10 Click the Hammer Icon for "Build"
  15 Click Download (F8)
  The program will be compiled, linked, and located to run on your NUCLEO-F103RB
16 At this point the board should now contain your code.  Press the reset button to watch it run.
  11 Click the Right Pointing Green Arrow Icon for "Run"
  The program will be downloaded to the device and begin execution.
  You should see LED2 blinking at this point.


==PWM - Driving an RC Servo, 20ms period, 1.5ms initial pulse-width==
==PWM - Driving an RC Servo, 20ms period, 1.5ms initial pulse-width==
Line 93: Line 94:
  1) Looking at the PCBA, I see the Arduino connector set and the PWM marking for Arduino D6
  1) Looking at the PCBA, I see the Arduino connector set and the PWM marking for Arduino D6
  2) Looking at the MB1136.pdf schematic for this board, the D6 signal is mapped to PB10
  2) Looking at the MB1136.pdf schematic for this board, the D6 signal is mapped to PB10
  3) Select PB10 using STM32CubeMX, Pinout & Configuration tab.  From the drop-down menu, choose {{Highlight|TIM2_CH3}}.
  3) Select PB10 using STM32CubeMX, Pinout & Configuration tab.  From the drop-down menu, choose '''TIM2_CH3'''.
  4) Select Timers ->TIM2.
  4) Select Timers ->TIM2.
  4.1) Change Channel3 from '''Disable''' to {{Highlight|PWM Generation CH3}}
  4.1) Change Channel3 from '''Disable''' to '''PWM Generation CH3'''
  4.2) Set "Clock Source" to "Internal Clock"
  4.2) Set "Clock Source" to "Internal Clock"
  4.3) Set Prescaler (PSC - 16 bits value) to "72-1"  (This will reduce our 72MHz SYSCLK to 1MHz (1us period))
  4.3) Set Prescaler (PSC - 16 bits value) to "72-1"  (This will reduce our 72MHz SYSCLK to 1MHz (1us period))
Line 107: Line 108:
   /* Infinite loop */
   /* Infinite loop */
   /* USER CODE BEGIN WHILE */
   /* USER CODE BEGIN WHILE */
   {{Highlight|// Initialize TIM2_CH3, for PB10 (Arduino D6)
   '''// Initialize TIM2_CH3, for PB10 (Arduino D6)'''
   HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);}}
   '''HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);'''
   while (1)
   while (1)
   {
   {
Line 141: Line 142:
==STM32-F103 Timers==
==STM32-F103 Timers==
  Trying to find a 32-bit timer for micro-second time measurements.  Examining the hardware timers available:
  Trying to find a 32-bit timer for micro-second time measurements.  Examining the hardware timers available:
  Timer 1 & 8  : 16-bit
  TIM1 : 16-bit each
  Timer 2 & 5  : 16-bit
  TIM2, TIM3, TIM4 : 16-bits each
  Timer 9 & 14 : 16-bit
  Note: Although documentation may mention other timers, they are NOT available on the F103RB.
Timer 6 & 7  : 16-bit
   
   
  It appears if we desire a 32-bit timer, we need to check if any of the above timers are cascadable - combine two
  It appears if we desire a 32-bit timer, we need to check if any of the above timers are cascadable - combine two

Latest revision as of 13:07, 14 June 2024

The NUCLEO-F103RB development board uses the STM32F103RBT6 as the target processor. (The is the same processor used on "Blue Pill" boards.) It was after playing with the "Blue Pill" boards that I decided I need a REAL STMicro development board. This board is a rock solid development board with on-board ST-Link loader / debugger, using an STM32F103CBT6.

This development board functions well in at least three development environments:
1) Arduino & Arduino IDE using the STM32 processor plug-in
2) MBed - The on-board STM32 loader / debugger supports loading web site created binaries
    See https://os.mbed.com/
3) STMicro's STM32CubeIDE
    See https://www.st.com/en/development-tools/stm32cubeide.html
I prefer STMicro's environment, allowing me easy access to peripherals, registers,
  and clock systems, with full access to every part of this system on chip.

Processor: STM32F103RBT6

Arm® Cortex®-M3 core
128KB Flash
20KB SRAM
72MHz clock
Single-cycle multiplication and hardware division
2.0 to 3.6 V application supply and I/Os
Within this part series, this is considered a "Medium-density device",
  and as such, has the following peripherals:
3 USARTs
4 16-bit timers: TIM1, TIM2, TIM3, TIM4
2 SPIs, 2 I2Cs, USB, CAN, 2 ADCs
Notes:
   "Low-density device" has fewer peripherals.
   "High-density device" has more peripherals.

Hardware

  • Green LED, LD2, connected to PA5, illuminates when driven high
  • Blue PushButton, B1, connects to PC13, grounding the signal when pressed. Button signal has 4.7K and 0.1uF capacitor hardware filter
  • 32,768Hz crystal oscillator, LSE, used for Real Time Clock (RTC)
  • 8MHz HSE, is provided by the 8MHz crystal oscillator from the attached ST-Link, into PD0
  • UART2 connects the target processor to the ST-Link, providing a USB COM port connection on the host computer. Uses PA2 for TX, and PA3 for RX.
  • ST-Link connects to TCK (PA14), TMS (PA13)

https://www.st.com/en/evaluation-tools/nucleo-f103rb.html

Firmware

https://www.st.com/en/evaluation-tools/nucleo-f103rb.html https://www.st.com/en/embedded-software/stm32cubef1.html

The firmware packages (including examples) installs in this directory:
C:\Users\UserName\STM32Cube\Repository

ST Website for the STM32F1 family: http://www.st.com/stm32f1

New Project - Blinky

Create a New STM32CubeIDE Project - Blinky
1 Click "Start new STM32 project", then select the "Board Selector" tab
2 In the Commercial Part Number box, type "NUCLEO-F103RB", select the board, and then click "Next>" at the bottom
3 Since I have several STM32 boards, I like to have the board name in the name of the project
  I used: "NUCLEO-F103RB_Blinky" as the project name
4 Select "C" Executable, STM32Cube Project Type, Finish
5 Initialize all peripherals with their default Mode ? - Yes
6 Device Configuration Tool editor is associated with Device Configuration Tool perspective.
  Do you want to open this perspective now?  (Select Yes to see what's configured)

7 Under "Project Manager Tab", Linker Settings, I set both Minimum Heap Size and Minimum Stack Size to 0x800 (2K bytes each)
8 On the left, Project Explorer window, Open Core->Src->main.c
Note: If you examine the source code, you will see that the following functions get called:
 * HAL_Init()
 * SystemClockConfig()
 * MX_GPIO_Init()
Then, the code enters an empty while loop.  Using the JTAG/SWD debugger, we can build, run, and debug the code,
but it will be rather boring...

9 Find the infinite loop inside the main() function, and add the following two bold lines of code:

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
  HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
  HAL_Delay(500);
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
}

NOTE:
Be sure to always place your code between the USER CODE BEGIN and USER CODE END comments
This will protect your code from being removed should you make changes using the STM32CubeMX again.

10 Click the Hammer Icon for "Build"
  The program will be compiled, linked, and located to run on your NUCLEO-F103RB
11 Click the Right Pointing Green Arrow Icon for "Run"
 The program will be downloaded to the device and begin execution.
 You should see LED2 blinking at this point.

PWM - Driving an RC Servo, 20ms period, 1.5ms initial pulse-width

See: https://en.wikipedia.org/wiki/Servo_control and https://en.wikipedia.org/wiki/Servo_(radio_control)
This assumes the instructions from "Getting Started" have already been performed...

1) Looking at the PCBA, I see the Arduino connector set and the PWM marking for Arduino D6
2) Looking at the MB1136.pdf schematic for this board, the D6 signal is mapped to PB10
3) Select PB10 using STM32CubeMX, Pinout & Configuration tab.  From the drop-down menu, choose TIM2_CH3.
4) Select Timers ->TIM2.
4.1) Change Channel3 from Disable to PWM Generation CH3
4.2) Set "Clock Source" to "Internal Clock"
4.3) Set Prescaler (PSC - 16 bits value) to "72-1"  (This will reduce our 72MHz SYSCLK to 1MHz (1us period))
4.4) Counter Mode: Up
4.5) Set Counter Period to "20000-1" (This configures the period to be 20,000us long - 20ms / 50Hz)
4.6) Set Pulse (16 bits value) to 1500  (This configures the pulse width to 1500us / 1.5ms
5) Select GENERATE CODE button in upper right corner. This will produce the code that will initialize the TIM2_CH3 accordingly
6) If you have the Arduino D6 pin connected to your RC-Servo control signal pin,
   you won't see any changes even after building and downloading the code.
7) Add the following lines of highlight code:  (1 line of code with 1 line for comment)
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 // Initialize TIM2_CH3, for PB10 (Arduino D6)
 HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
 while (1)
 {
8) Build (F7), Download (F8), press reset button.  The Arduino D6 pin will begin creating the desired PWM pulse,
   causing the servo to center itself.
9) Add the following additional code to the while (1) loop:
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 // Initialize TIM2_CH3, for PB10 (Arduino D6)
 HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);
 while (1)
 {
    htim2.Instance->CCR3 = 1000; // 1.0ms
    HAL_Delay(1000);
    htim2.Instance->CCR3 = 1250; // 1.25ms
    HAL_Delay(1000);
    htim2.Instance->CCR3 = 1500; // 1.5ms
    HAL_Delay(1000);
    htim2.Instance->CCR3 = 1750; // 1.75ms
    HAL_Delay(1000);
    htim2.Instance->CCR3 = 2000; // 2.0ms
    HAL_Delay(1000);
    /* USER CODE END WHILE */
10) Build (F7), Download (F8), press reset button.
    The while (1) loop will create multiple pulse widths, causing the servo to move to five distinct positions.

Arduino IDE Support

Using the Arduino Board Manager for the "duino" family
https://www.instructables.com/id/Quick-Start-to-STM-Nucleo-on-Arduino-IDE/
http://www.emcu.eu/2017/03/13/how-to-use-stm32-and-arduino-ide/

STM32-F103 Timers

Trying to find a 32-bit timer for micro-second time measurements.  Examining the hardware timers available:
TIM1 : 16-bit each
TIM2, TIM3, TIM4 : 16-bits each
Note: Although documentation may mention other timers, they are NOT available on the F103RB.

It appears if we desire a 32-bit timer, we need to check if any of the above timers are cascadable - combine two
16-bit timers together with the first one feeding into the second.  The problem with this is that the "total count"
is contained in two 16-bit registers, that while reading, one can overflow producing an erroneous 32-bit result.
ST Micro App Note: https://www.st.com/resource/en/application_note/an2592-achieving-32bit-timer-resolution-with-software-expansion-for-stm32cube-and-standard-peripheral-library-stmicroelectronics.pdf

External STLink V2

External STLink V2: https://www.st.com/resource/en/user_manual/dm00026748-stlinkv2-incircuit-debuggerprogrammer-for-stm8-and-stm32-stmicroelectronics.pdf