Microcontroller Interfacing Tutorials
Learn it by examples
By David Kebo Houngninou
On this page, you will find some interfacing experiments using the ARM Cortex M3.
– The evaluation board we target is the MCBSTM32C running on the STM32F107VC microcontroller.
– The tutorial focuses on configuring the MCBSTM32C and interfacing.
– Datasheets and documentation for STMicroelectronics STM32F107VC core is available at: http://www.keil.com/dd/chip/4889.htm.
– The reference used for this tutorial is the RM0008 Reference manual for STM32F107xx advanced ARM®-based 32-bit MCUs.
Table of contents
What is a microcontroller?
A microcontroller is a self-contained system with peripherals, memory, and a processor that can be used as an embedded system.
Overview of the MCBSTM32C board evaluation board
The MCBSTM32C Evaluation Board ships with the STM32F107VC core.
MCBSTM32C board components
MCBSTM32C interfacing features
Tutorial 1: Interfacing with the LEDs
This tutorial will explain how a program that interfaces with the LEDs on the evaluation board works.
The BLINKY example program toggles the LEDs on GPIO1 and prints the converted A-to-D value to the serial port.
The toggle speed of the LEDs depends on the input voltage of the ADC1 input.
The BLINKY program demonstrates assembling, linking, and debugging using the µVision IDE on the MCBSTM32 board.
The on-board LEDs make it easy to visually verify that the program loads and executes properly.
The HyperTerm terminal emulator program makes it easy to verify serial output.
The tutorial will cover the following topics:
- Hardware and software requirements
- Writing the main program
- Explaining the configuration (Ports, registers, pins, etc.)
- How to debug the program?
- How to check the serial output?
- Other project files
Hardware and software requirements
To run this experiment you need the following:
- The MCBSTM32 Evaluation Board
- A ULINK-ME debug adapter for downloading and debugging
- 2 USB cables (One for power and one for debugging)
- The MDK-ARM development environment for Cortex and ARM devices.
You can download the full tutorial program here: BLINKY Tutorial
Writing the main program
This program uses the potentiometer and the LEDs on the board, it blinks the 8 LEDs in a cyclic manner depending on the potentiometer position.
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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
/******************************************************************************/ /* BLINKY.C: LED Flasher */ /******************************************************************************/ /* This file is part of the uVision/ARM development tools. */ /* Copyright (c) 2005-2009 Keil Software. All rights reserved. */ /* This software may only be used under the terms of a valid, current, */ /* end user licence from KEIL for a compatible version of KEIL software */ /* development tools. Nothing else gives you the right to use this software. */ /******************************************************************************/ #include <stm32f10x_cl.h> #define LED_NUM 8 /* Number of user LEDs */ const long led_mask[] = { 1<<15, 1<<14, 1<<13, 1<<12, 1<<11, 1<<10, 1<<9, 1<<8 }; int main (void) { int AD_val, i; int num = -1; int dir = 1; SystemInit(); /* Setup GPIO for LEDs */ RCC->APB2ENR |= 1 << 6; /* Enable GPIOE clock */ GPIOE->CRH = 0x33333333; /* Configure the GPIO for LEDs */ /* Setup and initialize ADC converter */ RCC->APB2ENR |= 1 << 9; /* Enable ADC1 clock */ GPIOC->CRL &= 0xFFF0FFFF; /* Configure PC4 as ADC.14 input */ ADC1->SQR1 = 0x00000000; /* Regular channel 1 conversion */ ADC1->SQR2 = 0x00000000; /* Clear register */ ADC1->SQR3 = 14 << 0; /* SQ1 = channel 14 */ ADC1->SMPR1 = 5 << 12; /* Channel 14 sample time is 55.5 cyc */ ADC1->SMPR2 = 0x00000000; /* Clear register */ ADC1->CR1 = 1 << 8; /* Scan mode on */ ADC1->CR2 = (1 << 20) | /* Enable external trigger */ (7 << 17) | /* EXTSEL = SWSTART */ (1 << 1) | /* Continuous conversion */ (1 << 0) ; /* ADC enable */ ADC1->CR2 |= 1 << 3; /* Initialize calibration registers */ while (ADC1->CR2 & (1 << 3)); /* Wait for initialization to finish */ ADC1->CR2 |= 1 << 2; /* Start calibration */ while (ADC1->CR2 & (1 << 2)); /* Wait for calibration to finish */ ADC1->CR2 |= 1 << 22; /* Start first conversion */ for (;;) { /* Loop forever */ if (ADC1->SR & (1 << 1)) { /* If conversion has finished */ AD_val = ADC1->DR & 0x0FFF; /* Read AD converted value */ ADC1->CR2 |= 1 << 22; /* Start new conversion */ } /* Calculate 'num': 0, 1, ... , LED_NUM-1, LED_NUM-1, ... , 1, 0, 0, ... */ num += dir; if (num >= LED_NUM) { dir = -1; num = LED_NUM-1; } else if (num < 0) { dir = 1; num = 0; } GPIOE->BSRR = led_mask[num]; /* Turn LED on */ for (i = 0; i < ((AD_val << 8) + 100000); i++); GPIOE->BSRR = led_mask[num] << 16; /* Turn LED off */ } } |
The main program consists of 6 main parts
- Initialize the microcontroller
- Enable the clock
- Setup the GPIO for the LEDs
- Setup and initialize the ADC
- Read the ADC values
- Blink the LEDs
We will go over each of these parts and include some code snippets of Blinky.c to explain the configuration
Initialize the microcontroller
SystemInit() is a function defined in the source file system_stm32f10x_cl.c
It initializes the embedded flash interface, and update the system clock frequency.
Enable the clock
In order to conserve power, the ARM microcontroller does not hold the clock active continuously.
It is the responsibility of the programmer to enable the clock for each peripheral.
We have to manually enable the clock for the peripherals that we need to use.
To enable the GPIO, we must set the appropriate bit(s) in the register RCC_APB2ENR.
APB2 peripheral clock enable register (RCC_APB2ENR)
On the Keil MCBSTM32C board, the 8 Port LEDs marked PE.8 – PE.15 connect to port E.
The 8 Port LEDs marked PE.8 – PE.15
To enable port E, clock bit 6 of the register APB2ENR must be set.
RCC->APB2ENR |= 1 << 6; /* Enable GPIOE clock */
The line of code above is the same as:
RCC->APB2ENR = RCC->APB2ENR | 1 << 6;
The sign “<<“ is called a bit left-shift operation and this is why:
Integers are stored, in memory, as a series of bits. For example, the number 1 stored as a 32-bit int would be:
00000000 00000000 00000000 00000001
Shifting this bit pattern to the left by six positions (1 << 6) would result in the number 64:
00000000 00000000 00000000 1000000
As you can see, the digits have shifted to the left by six positions, and the digits on the right is filled with a zero.
You might also note that shifting left is equivalent to multiplication by powers of 2. So 1 << 6 is equivalent to 2^6.
The sign “|=” is called a bitwise OR operation
First, let’s take a look at the truth table of a logic OR:
x1 | x2 | f |
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
The truth table for a logic OR (|)
If a least one of the inputs is set to 1, then the output is set to 1
This is an interesting property to use to set specific bits in a register
By performing a bitwise OR of RCC->APB2ENR by 1 << 6 we set the 6th clock bit of RCC->APB2ENR to 1 and we keep all the other bits unchanged
Setup the GPIO for LEDs
After enabling the clock the next step in using the general-purpose input-output port (GPIO) is to configure it for its desired application.
Before getting into configuration details, we need to understand what a GPIO is.
Basic structure of a standard I/O port bit
What is a GPIO port?
A GPIO port is a group of user-configurable pins for General Purpose Input/Output
- The STM32F107VC has 7 general purpose input/output (GPIO) ports
- The 7 GPIO Ports are A, B, C, D, E, F, and G.
- Each GPIO port can have up to 16 pins
- Each GPIO port has 7 registers
The 7 GPIO Ports are A, B, C, D, E, F, and G on STM32F107 microcontroller
What is a GPIO pin?
A GPIO pin is a generic pin controllable by the user at run time and configurable to be input or output.
GPIO pin
What is a GPIO register?
A GPIO register is a 32-bit storage area that holds configuration bits for a GPIO pin
Example of a configurable 32-bit register
Each of the general purpose I/O ports has a:
- 32-bit configuration register low GPIOx_CRL
- 32-bit configuration register high GPIOx_CRH
- 32-bit input data register GPIOx_IDR
- 32-bit output data register GPIOx_ODR
- 32-bit set/reset register GPIOx_BSRR
- 16-bit reset register GPIOx_BRR
- 32-bit locking register GPIOx_LCKR
where the ‘x’ in each register name acronym represents the port name.
e.g. GPIOA_IDR is the input data register associated with port A.
(Reference: RM0008 Reference manual Page 170)
To configure the STM32F107 microcontroller we perform the following steps:
- Enable the clock to the appropriate GPIO
- Configure the output pin(s) to give the desired function
- Lock the configuration
Setup for Interfacing with the LEDs
- Initialize the microcontroller
- Enable the clock for the LEDs
- Setup the GPIO for the LEDs
- Setup and initialize the ADC
- Read the ADC values
- Blink the LEDs
Initialize the microcontroller
SystemInit() is a function defined in the source file system_stm32f10x_cl.cThe purpose of this function is to:
Initialize the embedded flash interface
Update the system clock frequency
Enable the clock for the LEDs
The ARM microcontroller does not hold the clock active continuously
- Enable the clock for the LEDs manually (Port E)
- Set configuration bit(s) in register RCC_APB2ENR
- RCC_APB2ENR: Advanced Peripheral Bus 2 Enable Register
Enable the clock for the LEDs
Setup the GPIO for the LEDs
- LEDs pins are wired to GPIOE (Port E)
- The 16 pins are PE0 to PE15
- LEDs are wired to pins PE8,…PE15
- Configure the pins as output
- GPIOE->CRH = 0x33333333;
Setup the GPIO for the LEDs
For each pin there is a bit in a register that can be set to configure the pin as an output.
The MCBSTM32C has LEDs wired to pins 8 through 15 of GPIOE.
GPIOE->CRH = 0x33333333; /* Configure the GPIO for LEDs */
Let’s explain what this line of code is doing:
First, we enable the clock to GPIOE and configure pins 8 through 15 as outputs.
By looking at table Table 2, we see that GPIOE_CRH (Control Register High) controls bits 8 through 15.
To configure GPIOE_CRH as a push-pull output we need to use the patterns CNFx[1:0] = 00 and MODEx[1:0] = 01,10 or 11 (See Table 3)
We can use the following pattern:
0011 0011 0011 0011 0011 0011 0011 0011
So the register content is:
GPIOE->CRH = 0x33333333; //Configure the GPIO for LEDs
The table below summarizes how GPIOx_CRH and GPIOx_CRL are connected to the 16 pins of a port
Each pin requires 4 bits to configure 2 bits for CNFx and 2 bits for MODEx
Name | r/w | Bits | Function | |
---|---|---|---|---|
GPIOx_CRL | Port configuration register low | rw | CNF[1:0], MODE[1:0] | Configure lowest 8 bit of port x. IN or OUT |
GPIOx_CRH | Port configuration register high | rw | CNF[1:0], MODE[1:0] | Configure highest 8 bit of port x. IN or OUT |
GPIOx_IDR | port input data register | r | IDR[15:0] | Read state of pins configured for input on port x (Lowest 16 bits of word) |
GPIOx_ODR | port output data register | rw | ODR[15:0] | Write to pins configured for Output on port x (Lowest 16 bits of word) |
GPIOx_BSRR | Port bit set/reset register | w | BS[15:0], BR[15:0] | Atomic Set/Reset individual Pins configured for Output. |
GPIOx_BRR | Port bit reset register | w | BR[15:0] | Atomic Reset individual Pins configured for Output. (Lowest 16 bits of word) |
GPIOx_LCKR | Port configuration lock register | rw | LCK[15:0], LCKK | Lock individual pins of port x (Freeze CRL and CRH of ports) |
Table 2: GPIO Configuration Registers. (Note:x = Port A to G )
Port configuration register low (GPIOx_CRL) (x=A..G)
Port configuration register high (GPIOx_CRH) (x=A..G)
Port configuration register to pins
Configuration mode | CNF1 | CNF0 | MODE1 | MODE0 | PxODR register | |
---|---|---|---|---|---|---|
General Purpose Output | Push-Pull | 0 | 0 | 01 10 11 See Mode below |
0 or 1 | |
Open Drain | 1 | 0 or 1 | ||||
Alternate function Output | Push-Pull | 1 | 0 | Don’t Care | ||
Open Drain | 1 | Don’t Care | ||||
Input | Analog | 0 | 0 | 00 | Don’t Care | |
Input Floating | 1 | Don’t Care | ||||
Input Pull-Down | 1 | 0 | 0 | |||
Input Pull-Up | 1 |
Table 3: Port bit configuration summary
MODE[1:0] | Meaning |
---|---|
00 | Reserved |
01 | Max. output speed 10 MHz |
10 | Max. output speed 2 MHz |
11 | Max. output speed 50 MHz |
Table 4: MODE[1:0] configuration bits
Tutorial 2: Setup and initialize the ADC
This tutorial will explain how to configure the Analog to Digital converter on the evaluation button