Project demo on STM32F103RBT6 using GCC

STM32F103R board is a simple and easy development board to learn STM32 microcontroller programming. Its heart is an STM32F103RBT6 ARM Cortex-M3 microcontroller with 128K of Flash and 20K of SRAM memory. It can be clocked at the maximum 72MHz frequency and considered a medium-density performance line microcontroller. Other features include USB, CAN, seven timers, 2ADCs, and nine communication interfaces.

STM32F103RBT6

The Development board has several excellent features to get started. First of all, it has an RS232 interface for communicating and accessing the bootloader. There also is a USB 2.0 full-speed interface connector that also can work as the power supply. Next is a JTAG connector to program microcontroller using tools like a J-Link adapter. Two pushbuttons and two programmable LEDs are hardwired to MCU pins alongside all I/Os connectors.

To start programming this microcontroller, we need to set up a project template that can be used for further developments. We like GCC tools, so grab Sourcery CodeBench Lite Edition and Eclipse IDE to get started.

We won’t be reinventing the wheel and stick to what’s been done. As a reference, we can take our previous project on STM32F103ZET6 development board. The main difference between those microcontrollers is that the current is medium-density and earlier were high-density with more features and more memory. So few minor changes have to be done in the linker script and interrupt vectors table. As always, Michael Fischer has done the hard work and prepared those files. To get these, you can download STM32F103RB project files for Yagarto and extract files. We will need stm32f103xb_flash.ld and stm32f103xb_ram.ld and make sure that the memory configuration is proper:

MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
}

Also, we will need crt.c and vectors_stm32f10x_hd.c files (Don’t worry you will find all files in a project package). The rest procedure is the same as in the STM32F103ZET6 project mentioned earlier. Let’s focus on hardware programming. First of all, let’s take care of the buttons. Here on board are two push buttons connected between PC0 and PC1 pins and ground:

two push buttons connected between PC0 and PC1 pins

Using CMSIS writing button driver is easy. First buttons.h file:

#ifndef BUTTONS_H_
#define BUTTONS_H_
#include "STM32f10x.h"
#define BS2 				GPIO_Pin_0
#define BS3 				GPIO_Pin_1
#define BPORT				GPIOC
#define BPORTCLK			RCC_APB2Periph_GPIOC
void ButtonsInit(void);
uint32_t ButtonRead(GPIO_TypeDef* Button_Port, uint16_t Button);
#endif /* BUTTONS_H_ */

Then we can write functions in buttons.c file:

#include "buttons.h"
void ButtonsInit(void)
{
  //GPIO structure used to initialize Button pins
  GPIO_InitTypeDef GPIO_InitStructure;
  //Enable clock on APB2 pripheral bus where buttons are connected
  RCC_APB2PeriphClockCmd(BPORTCLK,  ENABLE);
  //select pins to initialize S2 and S3 buttons
  GPIO_InitStructure.GPIO_Pin = BS2|BS3;
  //select pull-up input mode
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  //select GPIO speed
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(BPORT, &GPIO_InitStructure);
}
uint32_t ButtonRead(GPIO_TypeDef* Button_Port, uint16_t Button)
{
  return !GPIO_ReadInputDataBit(Button_Port, Button);
}

When initializing buttons, we first enable the APB2 peripheral clock, then we set internal pull-up resistors for button pins and set I/O speed.

Next, we can write LED drivers. LEDs are connected between PB8, PB9, and VCC as follows:

Initialize LEDs with the following function in leds.c:

void LEDsInit(void)
{
  //GPIO structure used to initialize LED port
  GPIO_InitTypeDef GPIO_InitStructure;
  //Enable clock on APB2 pripheral bus where LEDs are connected
  RCC_APB2PeriphClockCmd(LEDPORTCLK,  ENABLE);
  //select pins to initialize LED
  GPIO_InitStructure.GPIO_Pin = LED1|LED2;
  //select output push-pull mode
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  //select GPIO speed
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(LEDPORT, &GPIO_InitStructure);
  //initially LEDs off
  GPIO_SetBits(LEDPORT, LED1|LED2);
}

and implement three control functions:

voidLEDOn(uint32_t);
voidLEDOff(uint32_t);
voidLEDToggle(uint32_t);

To test if everything works, we can write a simple routine in main.c:

#include "stm32f10x.h"
#include "leds.h"
#include "buttons.h"
//delay function
void Delay(__IO uint32_t nCount)
{
  for(; nCount != 0; nCount--);
}
int main(void)
{
  //init leds
  LEDsInit();
  ButtonsInit();
while (1)
  {
	//read S2 button
	if (ButtonRead(BPORT, BS2))
	{
		//led 1 on
		LEDOn(1);
		//delay
		Delay(2000000);
		//led 1 off
		LEDOff(1);
	}
	//read S3 button
	if (ButtonRead(BPORT, BS3))
	{
		//led 2 on
		LEDOn(2);
		//delay
		Delay(3000000);
		//led 2 off
		LEDOff(2);
	}
  }
}

Here we turn the LED after the button is pressed, and it turns off automatically after some delay.

When compiling the program with the newest CodeBench Lite strange error popped out:

Error: registers may not be the same -- `strexh r0,r0,[r1]'
Error: registers may not be the same -- `strexb r0,r0,[r1]'

Arm specification requires that the Rd register be different from Rt and Rn and that CMSIS seems not to follow this. So to fix this, you need to modify core_cm3.c file as follows:

replace:

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);
}

with

uint32_t __STREXH(uint16_t value, uint16_t *addr)
{
//uint32_t result=0;
register uint32_t result asm ("r2");
__ASM volatile ("strexh %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}

and replace:

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);
}

with:

uint32_t __STREXB(uint8_t value, uint8_t *addr)
{
//uint32_t result=0;
register uint32_t result asm ("r2");
__ASM volatile ("strexb %0, %2, [%1]" : "=r" (result) : "r" (addr), "r" (value) );
return(result);
}

For more information refer to old.nabble.com. After this change code compiles fine. Flash microcontroller using Flash loader demonstrator or via JTAG and run. Download project template if you want to try it by yourself: [STM32F103R_Buttons_LEDs ~660K]

Leave a Reply