Timers - Integrated Systems Laboratory

Introduction to Microcontrollers
LAB
Michele Magno
IIS Group - ETH Zurich
michele.magno@iis.ee.ethz.ch
1
EXERCISE – LAB ACTIVITIES
STM32F401DISCOVERY
 STM32F401VC MCU
 ST-LINK/V2 embedded debugger
 ST MEMS digital accelerometer,
 ST MEMS digital microphone,
 audio DAC + class D speaker
 LEDs/ pushbuttons
 USB OTG micro-AB connector
 DATASHEET STM32F401; User Manual UM1669; Reference Manual RM0368
2
Application Cross-Development
C files (.c)
Target
Toolchain
object files
(.o)
Debugger
Target HW simulator
Development board
3
Embedded Systems Debugging
 It is inconvenient or even impossible to run a
software debugger together with the debuger
 Embedded systems are usually debugged using
remote debugging
 The debugger is running on a host computer and
controls the target either through hardware or a
small software running on the target
4
TOOLCHAIN FOR STM32
 toolchains officially supported by STM, (STM
provide simple tutorials and file of set up):
ATOLLIC
CooCox
HITEX
IAR
KEIL
RAISONANCE
 STM not support toolchain for Linux
but fortunately, multiple toolchain exist also for
Linux users.
5
JTAG
 Integrated Debug Circuitry / On-Chip Debug:
every chip shipped contains the debug functionality.
A serial communication channel is used to connect
the debug circuitry to a host debugger
 Besides debugging, another application of JTAG is
allowing device programmer to transfer data into
iternal memory
6
JTAG for programming
 To program a device we have two alternatives:


Using a USB / UART / … connection in bootloader mode
Using JTAG and programmer to write flash memory
7
JTAG for debugging
Build
App.exe
IDE
Build
Debug
App.hex
Driver
HostOS
JTAG
x86
CPU
Target board
8
JTAG for debugging
The HW debug support block is within the cortex-M3 core. The debug
interface has access to the register bank, ALU, memory, etc …
9
Keil MDK-ARM
 The MDK-ARM is a complete software development environment for
Cortex™-M, Cortex-R4, ARM7™ and ARM9™ processor-based devices.
 MDK-ARM is specifically designed for microcontroller applications, it is
easy to learn and use, yet powerful enough for the most demanding
embedded applications.
10
Your First Porject
 Open the Template.uvproj
 Keil uVision4 will open
11
uVision IDE
 Integrated Development Environment with MDK-ARM software
environment and compiler
 Manual at: http://www.keil.com/
12
uVision IDE
File Browser
Editor
Output Window
13
uVision IDE – Project Files
Project files can be organized in groups for an easy menagment. This
organization is independent of the actual files organization on the disk.
The code is usually organized in subgroups following the abstraction layers
and libraries. In this example:
Core library CMSIS and MDK-ARM (startup and system)
ST StdPeriph_Driver library (on-chip devices init and use)
Discovery Library (on-board devices init and use)
User code (main and all the application code)
14
Project Options
 Choose the correct target
15
Project Options
 Choose the compilation output
Where compiled files are saved
Other information that might be useful
16
Project Options
 Global Defines
17
Project Options
 Debug Settings
18
Project Options
 ST-LINK configuration
19
Project Options
 ST-LINK configuration
20
Project Options
 Target programming options
21
Write Your Code!
 In main.c write a
simple function
 no printf, no getch
22
Code Compilation
Compile and build
solution
Compilation Result
23
Code Debugging
Donwload code to device
and start debugging
Reset device
Control execution
Stop execution
Set / remove
breakpoint
Start execution
24
Code Debugging
Code
window
25
Code Debugging
Disassembly window: shows program
execution in assembly code
26
Code Debugging
Current instruction location
ARM
Internal
register
status
Set the breakpoint. A breakpoint is
set with a double click on the lateral
bar.
27
Code Debugging
Step: executes next instruction
int main(void)
{
u16 count = 0;
u32 b = 0;
int c =0;
c = SumValues(5, 18);
/* main while */
while(1)
{
count++;
if (count==10000)
b++;
}
}
SumValues(int add1, int add2){
volatile int sum_result = 0;
sum_result = add1 + add2;
return sum_result;
}
28
Code Debugging
Step Over: executes next line
int main(void)
{
u16 count = 0;
u32 b = 0;
int c =0;
c = SumValues(5, 18);
/* main while */
while(1)
{
count++;
if (count==10000)
b++;
}
}
SumValues(int add1, int add2){
volatile int sum_result = 0;
sum_result = add1 + add2;
return sum_result;
}
29
Code Debugging
Step Out: Exit from the current
function
int main(void)
{
u16 count = 0;
u32 b = 0;
int c =0;
c = SumValues(5, 18);
/* main while */
while(1)
{
count++;
if (count==10000)
b++;
}
}
SumValues(int add1, int add2){
volatile int sum_result = 0;
sum_result = add1 + add2;
return sum_result;
}
30
Code Debugging
The Call Stack + Locals window shows
local variables and functions.
31
Code Debugging
The Memory window displays the memory
area content. Several separate windows
can be used at a time.
32
Code Debugging
The Watch window allows to evaluate
symbols, registers, and expressions. The
window displays the item name, value, and
type.
To add a variable just type the name (case
sensitive)
33
Code Debugging
The Symbols window shows debug
information about the application symbol
name, location, and the symbol type. For
functions, the window shows the return and
parameter type.
34
#1 Turn On a LED
35
General Purpose IO
The STM32 is well served with general purpose IO pins, having up to 80 bidirectional IO pins. The IO pins
are arranged as five ports each having 16 IO lines.
PA [15:0]
GPIO port A
PB [15:0]
GPIO port B
PC [15:0]
GPIO port C
PD [15:0]
GPIO port D
PE [15:0]
AHB1
•
GPIO port E
36
DATASHEET CPU PIN OUT
INFORMATION
(DM00086815.pdf)
37
Where are the CPU pins connected?
DATASHEET DISCOVERY
BOARD INFORMATION
(DM00093902.pdf)
38
General Purpose IO (what)
•
I want to use a GPIO. What do I need to know?

Which bus GPIOs are connected to?
➡ GPIO ports are always on the AHB1bus

Which port are we going to use?
➡ All LED are connected to the I/O Port D of STM32F401

Which PINs the LEDs are connected to?
➡ Orange LED is connected to the pin 13 of Port D
➡ Green LED is connected to the pin 12 of Port D
➡ Red LED is connected to the pin 14 of Pin D
➡ Blue LED is connected to the pin 15 pin D

What do I need to do with this GPIO? (input, output, ...)
➡ I need to write (output) to control the voltage on the LEDs
39
General Purpose IO (where)
•
I want to use a GPIO. Where can I gather these information?
➡
The datasheet contains all the information we need
➡
Look at the UM1669 User Manual
✓ we learn about the bus AHB1
✓ all the information we need about our LEDs
40
General Purpose IO (how)
•
I want to use a GPIO. How can I use this information to actually turn on a LED?

We need to enable the High Speed AHB (AHB1) peripheral.
➡
void RCC_AHB1PeriphClockCmd(uint32_t
RCC_AHB1Periph, New);
✓ Look at: stm32f4xx_rcc.c

We need to configure the GPIO Port
➡ Fill up a GPIO_InitTypeDef structure
✓ Look at: stm32f4xx_gpio.h
➡ Init the GPIO Port with void
GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef*
GPIO_InitStruct);
✓ Look at: stm32f4xx_gpio.c

Turn ON the LED
➡
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
✓ Look at: stm32f4xx_gpio.c
41
General Purpose IO (code)
main.c (green LED)
#include "stm32f4xx.h"
must include stm32f4xx_gpio.h
#include "stm32f4xx_conf.h"
int main(void)
Enable AHB1 bus Port D
{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable the GPIO_RED Clock */

/* GPIOD Periph clock enable */
Configuration for Pin 14 Port D as
output
 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
“And light was made”


/* Configure the GPIO_LED pin */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOD, &GPIO_InitStructure);

/* Turn ON */

GPIO_SetBits(GPIOD, GPIO_Pin_14);


while(1);
}
42
General Purpose IO (exercises)
1. Turn ON the BLUE LED
➡ Remember: the LED is connected to the Pin 15 of the Port D (on AHB1 bus)
2. Turn ON both the LEDs
3. Make the LEDs blink together
➡ Tip: use an empty for cycle to create a delay routine
4. Make the LEDs alternately blink
5. Make ALL (Pin 12, 13, 14, 15) the LEDs alternately blink.
43
General Purpose IO (questions)
1. Look at the Reference manual and stm32f4xx_gpio.h
➡ Why do we set
/ stm32f4xx_gpio.c
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP
(and also using google)
?
➡ Can you indicate the other modes a GPIO can be configured?
➡ What do “Input pull-up” and “Input pull-down” mean for the GPIO configuration? In which case
are these modes useful?
44
#2 SysTick
45
SysTick
• SysTick is used to schedule periodic events
• When the SysTick expires an IRQ handler is called
46
SysTick (how)
•
I want to schedule a periodic event. How can I use SysTick?

We need to setup the SysTick
➡
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
➡
ticks
➡
SystemCoreClock
is the number of ticks between two interrupts
is the number of ticks in 1 sec
✓ Look at: core_cm3.h

We need to setup the callback (Interrupt Service Routine)
➡ The ISR is always define in stm32f40x_it.c
➡ The name of the ISR for SysTick is void
SysTick_Handler(void)
➡ Here is the code executed every ticks ticks
47
SysTick (code)
main.c
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
int main(void)
{
if (SysTick_Config(SystemCoreClock / 1000))
/* Capture error */
while (1);
}
{
ISR executed every 1 ms
while (1);
}
stm32f4xx_it.c
...
void SysTick_Handler(void){
/* Here goes the code to periodically execute */}
...
48
SysTick (exercises)
1. Make the LEDs blink using the SysTick
2. Make the LEDs alternately blink using the SysTick
3. Make the LEDs that blik at diferrent frequency
4. Make the LEDs alternately blink with a frequency lower than 1Hz.
• The SysTick does not support a frequency lower than 1 Hz.
2. Look at the code (not just your code, everywhere):
➡ What SystemCoreClock is?
➡ What is its value?
➡ Why must the ISR be named SysTick_Handler ?
49
#3 Mixed Exercises and Solutions
50
1.1 Turn ON the BLUE LED
main.c (blue LED)
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
int main(void)
{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable the GPIO_LED Clock */

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

/* Configure the GPIO_LED pin */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOD, &GPIO_InitStructure);

/* Turn ON */

GPIO_SetBits(GPIOD, GPIO_Pin_15);


while(1);
}
51
1.2 Turn ON both the LEDs
main.c
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
int main(void)
{

GPIO_InitTypeDef GPIO_InitStructure;

/* Enable the GPIO_LED Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

/* Configure the GPIO_LED pin */

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14| GPIO_Pin_15; /* TRY TO PUT GPIO_Pin_All instead of GPIO_Pin_14| GPIO_Pin_15. Try to find out why of LED8 is ON!!

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOD, &GPIO_InitStructure);

/* Turn ON */

GPIO_SetBits(GPIOD, GPIO_Pin_14);

GPIO_SetBits(GPIOD, GPIO_Pin_15);


while(1);
}
52
1.3 Make the LEDs Alternately Blink
main.c
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
int main(void)
{

u32 i;

GPIO_InitTypeDef GPIO_InitStructure;



/* Enable the GPIO_LED Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);





/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);

while(1) {




/* Turn ON */
GPIO_SetBits(GPIOD, GPIO_Pin_14);
GPIO_ResetBits(GPIOD, GPIO_Pin_15);
for(i=0;i <720895;i++);




/* Turn OFF */
GPIO_ResetBits(GPIOD, GPIO_Pin_14);
GPIO_SetBits(GPIOD, GPIO_Pin_15);




for(i=0;i <720895;i++);
};

}
53
1.4 Make the LEDs blink together
main.c
#include "stm32f4xx.h”
#include "stm32f4xx_conf.h"
int main(void)
{

u32 i;

GPIO_InitTypeDef GPIO_InitStructure;


/* Enable the GPIO_LED Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);





/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);

while(1) {



for(i=0;i <720895;i++);
GPIO_ResetBits(GPIOD, GPIO_Pin_14);
GPIO_ResetBits(GPIOD, GPIO_Pin_15);

for(i=0;i <720895;i++);




GPIO_SetBits(GPIOD, GPIO_Pin_14);
GPIO_SetBits(GPIOD, GPIO_Pin_15);
};

}
54
2.1Make the LEDs blink using the SysTick
main.c
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
int main(void) {
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable the GPIO_LED Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
if (SysTick_Config(SystemCoreClock/10)){
/* Capture error */
while (1);
} while (1);
}
stm32f4xx_it.c
int i=0;
void SysTick_Handler(void)
{
i++;
if(i%2){
GPIO_SetBits(GPIOD, GPIO_Pin_14);
GPIO_SetBits(GPIOD, GPIO_Pin_15);
}
else{
GPIO_ResetBits(GPIOD, GPIO_Pin_14);
GPIO_ResetBits(GPIOD, GPIO_Pin_15);
}
}
55
3 Make the LEDs blink using the SysTick
main.c
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
int main(void) {
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable the GPIO_LED Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
if (SysTick_Config(SystemCoreClock/10)){
/* Capture error */
while (1);
} while (1);
}
stm32f4xx_it.c
int i=0;
void SysTick_Handler(void)
{
i++;
if(i%2){
GPIO_SetBits(GPIOD, GPIO_Pin_14);
GPIO_SetBits(GPIOD, GPIO_Pin_15);
}
else{
GPIO_ResetBits(GPIOD, GPIO_Pin_14);
GPIO_ResetBits(GPIOD, GPIO_Pin_15);
}
}
56
1. USE ALL THE LED AVAILABLE
2. Increase the duty cycling of blink
3. Make ALL (Pin 12, 13, 14, 15) the LEDs alternately blink with different combination of
times
4. Find on the board other LEDs to be controlled.
57
#4 Button and Interrupts
58
Interrupts
The Nested Vector Interrupt Controller (NVIC):
•
facilitates low-latency exception and interrupt handling
•
controls power management
•
implements System Control Registers.
NVIC supports up to 64 dynamically reprioritizable interrupts each with up to16levels of priority. There are an
additional 16 interrupt sources within the Cortex core.
The NVIC maintains knowledge of the stacked (nested) interrupts to enable tail-chaining of interrupts.
Although the NVIC is a standard unit within the Cortex core, in order to keep the gate count to a minimum the
number of interrupt lines going into the NVIC is configurable when the microcontroller is designed.
59
EXTI
•
•
•
We want to configure an external interrupt line.
An EXTI line is configured to generate an interrupt on each falling edge.
In the interrupt routine a led connected to a specific GPIO pin is toggled.
Pressing the button
EXTI + Interrupt
Interrupt Service Routine
60
EXTI (what)
•
I want to turn on a LED using the button. What do I need to know?

Which bus LEDs and the button are connected to?
➡ LED We know
➡ BUTTON????

Which port are we going to use for LEDS and the button?
➡ LEDS PORT D
➡ BUTTON?

Which PINs the LEDs and the button are connected to?
➡ Red LED is connected to the pin 14 of Port D
➡ Blue LED is connected to the pin 15 of Port D
➡ The button is connected to the pin ?????

What do I need to do with this GPIO? (input, output, ...)
➡ I need to write (output) for the LEDs
➡ I need to read (input) for the button
61
EXTI (how)
•
I want to turn on a LED using the button. How can I do that?

We need to setup LEDs as seen before in exercise #1

We need to setup the button. 3 steps needed.
1.
Configuration of the GPIO for the button (button is connected to a GPIO)
2.
Configuration of the EXTI line (because we want to use the button as a trigger for an external
interrupt)
3.
Configuration of the NVIC (because we want to call an ISR when button is pressed)
-
GPIO configuration
✓
Look at: stm32f4xx_gpio.c
/ stm32fxx_gpio.h
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable the BUTTON Clock */
RCC_APXXPeriphClockCmd(RCC_APXXPeriph_GPIOAXX, ENABLE); // INSERT THE RIGHT NAME IN XX
/* Configure Button pin as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_INXXX; // INSERT THE RIGHT MODE
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // INSERT THE RIGHT PIN
GPIO_Init(GPIOA, &GPIO_InitStructure);
62
EXTI (how)
• The external interrupt/event controller consists of up to 23 edge detectors for generating
event/interrupt requests. Each input line can be independently configured to select the type (pulse or
pending) and the corresponding trigger event (rising or falling or both). Each line can also masked
independently. A pending register maintains the status line of the interrupt requests
63
EXTI (how)
-
EXTI line configuration
-
// THIS IS JUST AN EXAMPLE LOOK IN THE Reference Manual change it properly
Look at: stm32f4xx_exti.c
/ stm32f4xx_exti.h
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //CHECK FOR THE CLOCK
/* Connect Button EXTI Line to Button GPIO Pin */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
/* Configure Button EXTI line */
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
-
NVIC configuration
-
// THIS IS JUST AN EXAMPLE LOOK IN THE Reference Manual change it properly
✓
Look at: misc.c
/ misc.h
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable and set Button EXTI Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

We need to setup the ISR
➡ The name of the EXTI0 IRQ is void
EXTI0_IRQHandler(void)
64
EXTI (code)
main.c
#include "stm32f4xx.h"
#include "stm32f4xx_conf.h"
Decomment:
stm32f10x_gpio.h / stm32f10x_exti.h / misc.h
void LEDs_Setup(void)
{
INSERT THE SETUP CODE FOT THE LED
}
void BUTTON_Setup(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the BUTTON Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AhB1Periph_AFIO, ENABLE);
/* Configure Button pin as input floating */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Connect Button EXTI Line to Button GPIO Pin */
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
...
65
EXTI (code)
main.c /// THIS IS AN EXAMPLE, PLEASE CHECK IN YOUR DATASHEET AND FIX THE CODE
...
/* Configure Button EXTI line */
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable and set Button EXTI Interrupt to the lowest priority */
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
int main(void)
{
LEDs_Setup();
BUTTON_Setup();
}
while (1);
stm32f10x_it.c // YOU NEED TO MODIFY THE Interrupt Routine as you like.
...
void EXTI0_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line0) != RESET) {
/* Turn ON LED BLUE */
GPIO_SetBits(GPIOD, GPIO_Pin_15);
/* Clear the User Button EXTI line pending bit */
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
...
66
EXTI (exercises)
1. Write a code to avoid bouncing (google “button debounce”)
•
Write a code to toggle the status of the LED (press button -> LED ON, press button again -> LED
OFF, and so on...)
•
Write a program in which the button starts and stops the blinking of the led
•
Write a program to modify the frequency of LED blinking by pressing the button (i.e. switch
ON-> LED blinks at 1 Hz / Press the button -> LED blinks at 5 Hz / Press the button -> LED blinks at
10 Hz ...)
•
Write a program to recognize double click on the button to turn ON the LED. If the frequency
of the clicking is too low the program should not recognize the double click. The behavior is similar
to that one of a mouse: double click is recognized only if the frequency of the two clicks is high
enough.
67
EXTI (questions)
1. Look at the Reference manual RM0368 and standard peripheral library code (and also using google)
http://www.st.com/web/en/resource/technical/document/reference_manual/DM00096844.pdf
➡ Why do we set GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING for the button?
➡ Why EXTI_InitStructure.EXTI_Line = EXTI_Line0; ?
What happens if we set
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
?
68
#5 Flash Memory
69
FLASH
•
•
•
Flash memory is a non-volatile computer storage chip that can be electrically erased and reprogrammed
Flash memory is non-volatile, meaning no power is needed to maintain the information stored in the chip
Flash memory offers fast read access times (although not as fast as volatile DRAM memory used for main
memory in PCs) and better kinetic shock resistance than hard disks
• Limitations:
-
although it can be read or programmed a byte or a word at a time in a random access fashion, it can only
be erased a "block" at a time (once a bit has been set to 0, only by erasing the entire block can it be
changed back to 1)
-
another limitation is that flash memory has a finite number of program-erase cycles (typically written
as P/E cycles)
70
FLASH (what)
•
I want to write data in flash memory. What do I need to know?

We need to know the starting address and the end address of the memory we are going to write to
➡ IMPORTANT: in flash there is also your program. So be careful: the addresses you are going to
use MUST be different from the addresses where your program is.
Your Program
Available Space
71
FLASH (where)
•
I want to write data in flash memory. . Where can I gather the information I need?
➡
The datasheet and reference manual contain all the information we need
➡
Look at the Reference manual
✓ Datasheet➠ we learn about the Flash module organization
✓ (In the low pages there is our program, so we can safely choose addresses from 0x0808000 to
0x08003FFFF)
USEFULL DATA AND DEFINE:
✓ /* Base address of the Flash sectors */
✓ #define ADDR_FLASH_SECTOR_0
*/
✓ #define ADDR_FLASH_SECTOR_1
*/
✓ #define ADDR_FLASH_SECTOR_2
*/
✓ #define ADDR_FLASH_SECTOR_3
*/
✓ #define ADDR_FLASH_SECTOR_4
*/
✓ #define ADDR_FLASH_SECTOR_5
Kbytes */
((uint32_t)0x08000000) /* Base @ of Sector 0, 16 Kbytes
((uint32_t)0x08004000) /* Base @ of Sector 1, 16 Kbytes
((uint32_t)0x08008000) /* Base @ of Sector 2, 16 Kbytes
((uint32_t)0x0800C000) /* Base @ of Sector 3, 16 Kbytes
((uint32_t)0x08010000) /* Base @ of Sector 4, 64 Kbytes
((uint32_t)0x08020000) /* Base @ of Sector 5, 128
72
FLASH (how)
•
I want to store data in flash. How can I store data in flash memory?

Unlock the Flash Bank1
➡ Using void
FLASH_UnlockBank1(void);
✓ Look at: stm32f4xx_flash.c

Clear All pending flags
➡ Using void
FLASH_ClearFlag(uint32_t FLASH_FLAG);
✓ Look at: stm32f4xx_flash.c

Erase the FLASH pages
➡ Using FLASH_Status
FLASH_ErasePage(uint32_t Page_Address);
✓ Look at: stm32f4xx_flash.c

Program Flash Bank1
➡ Using FLASH_Status
FLASH_ProgramWord(uint32_t Address, uint32_t Data);
✓ Look at: stm32f4xx_flash.c
73
FLASH (code)
main.c //THIS IS JUST AN EXAMPLE YOU NEED TO ADAPT IT .
#include "stm32f4xx.h"
#define FLASH_PAGE_SIZE ((uint16_t)0x400)
#define BANK1_WRITE_START_ADDR ((uint32_t)0x08008000)
#define BANK1_WRITE_END_ADDR ((uint32_t)0x0800C000)
uint32_t EraseCounter = 0x00, Address = 0x00;
uint32_t Data = 0x3210ABCD;
__IO uint32_t NbrOfPage = 0x00;
volatile FLASH_Status FLASHStatus = FLASH_COMPLETE;
int main(void){
/* Unlock the Flash Bank1 Program Erase controller */
FLASH_UnlockBank1();
/* Define the number of page to be erased */
NbrOfPage = (BANK1_WRITE_END_ADDR - BANK1_WRITE_START_ADDR) / FLASH_PAGE_SIZE;
/* Clear All pending flags */
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
/* Erase the FLASH pages */
for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++) {
FLASHStatus = FLASH_ErasePage(BANK1_WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
}
/* Program Flash Bank1 */
Address = BANK1_WRITE_START_ADDR;
while((Address < BANK1_WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))
FLASHStatus = FLASH_ProgramWord(Address, Data);
Address = Address + 4;
}
FLASH_LockBank1();
{
while(1);
}
74
FLASH (exercises)
1. Check the correctness of the written data using the debugger (memory window)
•
Check the correctness of the data using code
➡ Tip: you can access the flash memory using the pointers (Memory Mapping I/O)
➡ ((*(__IO uint32_t *) Address) != Data)
•
Write a program to store in flash memory the number of times a button is pressed in a unit of
time. After this time a LED is turned ON if this number is above a threshold (i.e. a LED is
turned ON if the button is pressed more than 2 times in 5 seconds)
•
Modify the code to write in FLASH the half-word 0xBEEF and check the correctness of the
data
➡ Tip: FLASH_ProgramWord() cannot be used anymore.
75
#6 Using the ST Examples
76
Timers (what)
•
I want a LED blinking at 1Hz using a timer.

We need to setup the GPIO port and pin the LED is connected to
➡ We already know how to do that

Since we are going to use interrupts generated by timers we need to setup NVIC
➡ The IRQChannel for TIMER2 is TIM2_IRQn
➡ The ISR is void TIM2_IRQHandler(void)

We need a generic timer because we want the LED blinking at a fixed frequency

We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
77
Timers (how)
•
We need to setup the GPIO port and pin the LED is connected to
•
Since we are going to use interrupts generated by timers we need to setup NVIC
void NVIC_Configuration(void) // EXAMPLE OF TIM2. PLEASE CHECK YOUR Reference Manual and make change is needed
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
78
Timers (how)
•
We need a generic timer because we want the LED blinking at a fixed frequency
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t PrescalerValue = 0;
As usual a struct is used for the configuration
of the peripheral
79
Timers (how)
•
We need a generic timer because we want the LED blinking at a fixed frequency
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t PrescalerValue = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
Clock enable for the TIMER2
80
Timers (how)
•
We need a generic timer because we want the LED blinking at a fixed frequency
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t PrescalerValue = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
upcounting mode
81
Timers (how)
•
We need a generic timer because we want the LED blinking at a fixed frequency
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t PrescalerValue = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (SystemCoreClock / 1000) - 1;
To set the prescaler we use the formula:
Prescaler = (SystemCoreClock / Fx) - 1
where Fx is the counter clock of the TIMER (CK_CNT) we want.
In this case we are setting the TIM2 counter clock to 1KHz
82
Timers (how)
•
We need a generic timer because we want the LED blinking at a fixed frequency
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t PrescalerValue = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (SystemCoreClock / 1000) - 1;
TIM_TimeBaseStructure.TIM_Period = 999;
The frequency of the timer (frequency at which the timer
interrupt is generated) is set using the period parameter:
TIM2 frequency = counter clock / (period + 1)
In our case we are using period=999, then:
TIM2 frequency = 1KHz / (999 + 1) = 1Hz
83
Timers (how)
•
We need a generic timer because we want the LED blinking at a fixed frequency
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
uint16_t PrescalerValue = 0;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) (SystemCoreClock / 1000) - 1;
TIM_TimeBaseStructure.TIM_Period = 999;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
As usual the init routine
84
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
As usual a struct is used for the configuration
of the peripheral
85
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
The comparison between the output compare register and the
counter has no effect on the outputs.
(this mode is used to generate a timing base).
We are interested in interrupt not in output waveform.
86
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
OC1 signal is active high on the corresponding output pin
87
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
The compare register is set to 0.
The blinking frequency is then 1 Hz
88
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
Init as usual
89
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
The compare register can be written at anytime,
the new value is taken in account immediately
90
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
We are interested in the interrupt of the CHANNEL 1
of the TIMER2
91
Timers (how)
•
We use the TIM2_CH1 (Timer 2 channel 1) in output compare mode
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
TIM_Cmd(TIM2, ENABLE);
TIMER2 enabled
92
Timers (how)
•
Handle the interrupt
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
GPIO_WriteBit(GPIOD, GPIO_Pin_15, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOD, GPIO_Pin_15)));
}
}
1. Check the flags to see what channel the interrupt is related to
2. Clear the flag
3. Turn on/off the LED
93
Timers (code)
main.c
#include "stm32F4xx.h“
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void LEDs_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable the GPIO_LED Clock */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
/* Configure the GPIO_LED pin */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
}
94
Timers (code)
int main(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
uint16_t PrescalerValue = 0;
LEDs_Configuration();
NVIC_Configuration();
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Compute the prescaler value */
PrescalerValue = (uint16_t) (SystemCoreClock / 1000) - 1;
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 999;
TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* Output Compare Timing Mode configuration: Channel1 */
/* Frozen - The comparison between the output compare register TIMx_CCR1 and the
counter TIMx_CNT has no effect on the outputs.(this mode is used to generate a timing
base). */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
/* OC1 signal is output on the corrisponding output pin */
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
/* OC1 active high */
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
/* TIMx_CCR1 can be written at anytime, the new value is taken in account immediately */
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable);
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
/* TIM2 enable counter */
TIM_Cmd(TIM2, ENABLE);
while(1);
return(0);
}
95
Timers (code)
stm32f4xx_it.c
...
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
GPIO_WriteBit(GPIOD, GPIO_Pin_15, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOD, GPIO_Pin_15)));
}
}
...
96
Timers (exercises)
1. Modify the blinking frequency to 2Hz, 5Hz, 0.5Hz, 0.1Hz
2. Make a LED blinking at 2Hz, the other one at 3Hz
➡ Tip: use TIM_GetCapture1() and TIM_SetCompare1()
➡ Tip: you need to use two different channels
•
Use the button to modify the blinking frequency of the LEDs (using timers)
•
(+) Generate a 500Hz square wave in output from TIM2_CH1 pin (check using the oscilloscope)
➡ Tips: You should use Toggle of the Output Compare mode
➡ More information: RM0008, STM32F10x Standard Peripherals Library, AN2581
•
(+) Generate a 50Hz square wave in output from TIM2_CH1 pin and a 1KHz square wave in
output from TIM2_CH2.
•
(++) Generate a PWN signal @ 25KHz duty cycle 10%
97
#7 Using the ST Examples
98
3 Using ST Examples and Library

Which Source Code for the examples?
➡ STM32F401-Discovery_FW_V1.0.0 ( THE CPU MODEL IS CRITICAL) Download the right
version of your cpu.
http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/DM00092826.pdf
99
Opening MEMS L3GD 20 Project
100
Main in Examples
BE ALWAYS AWARE OF CLOCKS!!
c
c
IF you don’t know some definition
101
Main in Examples
BE ALWAYS AWARE OF CLOCKS!!
c
c
IF you don’t know some definition
102
DEMO MEMS FUNCTION
static void MEMS_Test(void)
{
float Buffer[6];
uint8_t Xval, Yval = 0x00;
/* Demo Gyroscope */
c
Demo_GyroConfig();
if ( Xval>Yval)
{
if ((int8_t)Buffer[0] > 15.0f)
{
STM_EVAL_LEDOn(LED4);
STM_EVAL_LEDOff(LED3);
STM_EVAL_LEDOff(LED5);
STM_EVAL_LEDOff(LED6);
}
if ((int8_t)Buffer[0] < -15.0f)
{
STM_EVAL_LEDOn(LED5);
STM_EVAL_LEDOff(LED3);
STM_EVAL_LEDOff(LED4);
STM_EVAL_LEDOff(LED6);
}
}
else
{
if ((int8_t)Buffer[1] < -15.0f)
{
STM_EVAL_LEDOn(LED3);
STM_EVAL_LEDOff(LED4);
STM_EVAL_LEDOff(LED5);
STM_EVAL_LEDOff(LED6);
}
if ((int8_t)Buffer[1] > 15.0f)
{
STM_EVAL_LEDOn(LED6);
STM_EVAL_LEDOff(LED3);
STM_EVAL_LEDOff(LED4);
STM_EVAL_LEDOff(LED5);
}
}
Configuration
/* Read Gyro Angular data */
c
Demo_GyroReadAngRate(Buffer);
Data
/* Update autoreload and capture compare
registers value*/
Xval = ABS((int8_t)(Buffer[0]));
Yval = ABS((int8_t)(Buffer[1]));
Processing and
Leds
}
103
CONTINUE TO TRY AND TEST ALL THE
EXAMPLES AND YOU WILL KNOW ALL
ABOUT THE STM32 FEATURES!!!
104