0% found this document useful (0 votes)
179 views

GPIO Initialization For ARM Microprocessor

The document provides instructions for initializing GPIO pins and timers on a microcontroller. It describes enabling the clock for GPIO ports, configuring pins as outputs or inputs, and whether to use pull-up or pull-down resistors. It also covers initializing a timer and using timer interrupts to generate timed events. The document is intended as an internal reference for initialization procedures.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
179 views

GPIO Initialization For ARM Microprocessor

The document provides instructions for initializing GPIO pins and timers on a microcontroller. It describes enabling the clock for GPIO ports, configuring pins as outputs or inputs, and whether to use pull-up or pull-down resistors. It also covers initializing a timer and using timer interrupts to generate timed events. The document is intended as an internal reference for initialization procedures.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 25

GPIO

and

TIMER
INITIALIZATION
Ernest Gungl
(for internal use ONLY)

2017
Kazalo

GPIO INITIALIZATION ............................................................................................................................... 3


ENABLE CLOCK FOR PORTx .................................................................................................................. 3
GPIO PINS AS OUTPUTS ...................................................................................................................... 4
OUTPUT PUSH-PULL VS OUTPUT OPEN-DRAIN ............................................................................... 6
PUSH-PULL: ...................................................................................................................................... 6
OPEN-DRAIN: ................................................................................................................................... 6
GPIO PINS AS INPUTS ......................................................................................................................... 8
ENABLE CLOCK FOR PORTx .............................................................................................................. 8
SET PIN AS INPUT............................................................................................................................. 9
PULL-UP, PULL-DOWN, No PULL-UP and PULL-DOWN ................................................................... 9
READING A PIN .............................................................................................................................. 12
TIMER INITIALIZATION........................................................................................................................... 16
TIM4 clock enable.......................................................................................................................... 16
We want to call our TIM4 ISR every 10ms .................................................................................... 16
SET the PRIORITY for TIM4 interrupts and ENABLE TIM4 interrupts ............................................ 19
ISR – Interrupt Service Routine ..................................................................................................... 19
HOW CAN I USE TIMERS FOR DESIRED TIME GENERATION? ........................................................ 20
Time-dependent loops .................................................................................................................. 22

2
GPIO INITIALIZATION

GPIO (General Purpose Input Output)


To be able to use names of the registers in our microcontroller (uC), we need to include a
standard header at the beginning of our file. For our microcontroller, this is stm32l1xx.h.

ENABLE CLOCK FOR PORTx

All peripherals (including GPIO) for its operation require clock source which is disabled by
default (to have a low power consumption).
In the reference manual for our uC we can see under the chapter RCC (Reset and Clock
settings) the following table:

3
From here we can enable a clock for the desired GPIO ports.
For example, to enable the clock for GPIOA and GPIOB ports, we do so:
RCC->AHBENR | = (1<<0) | (1<<1);
How can we understand this? RCC is the name of the data structure that contains all the
registers refer to clock settings. AHBENR is one of the registers inside this data structure (it
has bits for enabling GPIO's ports clocks).
From language C we (should) know that we use the arrow (->) to access elements of the
structure. In our case, we access (or set) the register AHBENR in data structure RCC. We will
use the same syntax for everything.
DON't FORGET the similarity between registers names in the reference manual (RCC_AHBENR)
and the names of the data structures. We only replace the underline (_) with the arrow (->):
(RCC_AHBENR becomes RCC->AHBENR)

GPIO PINS AS OUTPUTS


GPIO pins configuration (RM0038, chapter General-Purpose I/Os (GPIO), subchapter »GPIO
registers«. Here we need to set up more registers.

Assume that we want to set the pin 6 of the port B as output. In our development board, BLUE
LED is connected to this pin.

In the table above, substitute the suffix x (GPIOx) with the name of the port that you want to use
(in this case with the letter B).

GPIOB->MODER &= ~(0x3 << (6*2)) // first delete the contents of these bits

4
GPIOB->MODER |= (0x3 << (6*2)) //enter 01 (output) in the filed MODER3

REMEMBER: if we want to write 11 or 00 into a register field than we can do that in a single step.
For writing 11 into a field we use the operator | (OR) and for writing 00 into a field we use the
operator & (AND).

BUT … if we want to write 01 or 10 into a register field, then we need to do that in two steps.
FIRST, we need to clear the content (&) and SECOND we write desired bits in the field (|).

The same is true when we want to set or reset more than two bits in the register. FIRST, all ones
or zeroes can be written in a single step, SECOND mixtures of ones and zeroes require two steps.

5
OUTPUT PUSH-PULL VS OUTPUT OPEN-DRAIN

PUSH-PULL:

OPEN-DRAIN:

6
On our development board, we have a situation like this (push-pull or open drain??)

»Push-pull«, of course (the uC should provide the power to the LEDs)


GPIOB->OTYPER &= ~(0x1<<6); // Clear bit 6
Thus, we have successfully configured the pin 6 of the port B (GPIOB.6).

TURN ON/OFF the LED

Do we need to write a logic 0 or 1 in bit 6 of the register ODR (Output Data Register)?
We need to know the scheme of the circuit (bellow)! We need to put 1 on pin PB6 (3.3V) to
turn the LED on. Only this way the electric current will flow through a LED.

The next expression outputs a logic 1 on the output pin 6:


GPIOB->ODR |= (1<<6); // bit 6 of the register GPIOB is set to 1, all other bits remain
// unchanged

7
Thus, we have successfully turned ON the blue LED!

GPIO PINS AS INPUTS


On pin 0 of the port A, the blue button is connected.
Blue button of our development board is connected to the pin 0 of port A ( PA.0). We want
to configure that pin as an input. We do that as it follows (RM GPIO registers):

ENABLE CLOCK FOR PORTx


Enable the clock for port GPIOA (we have already done this above for outputs but anyway…).

RCC->AHBENR | = (1<<0); //GPIOA clock enabled

8
SET PIN AS INPUT

GPIOA->MODER &= ~(0x3<<0); //00 -> input  default value!

PULL-UP, PULL-DOWN, No PULL-UP and PULL-DOWN


We can enable internal pull-ups or pull-downs by software if needed. We need to know the
scheme of inputs (a development board's datasheet provides that information). We need to
ensure that input line is at 0 or 1 (anything in between is not allowed => we achieve the well-
known logic level (0 or 1) with pull-ups or pull-downs).

Do we need internal PULL-UPs or PULL-DOWNs

9
Do we need internal PULL-UPs or PULL-DOWNs

Do we need internal PULL-UPs or PULL-DOWNs

Do we need internal PULL-UPs or PULL-DOWNs

10
What about here (BLUE BUTTON ON THE DEVELOPMENT BOARD).

Do we need an internal pull-ups or pull-downs? No (External pull-down is provided)!


Here we do that …

11
READING A PIN
Pin 0 of a port A is now configured as an input with no pull-ups and no pull-downs and is
ready to use. If we look again at the blue button scheme bellow, we can see that when the
button is pressed PA0 is 1 (VDD) otherwise is 0 (GND).

So we can write a condition expression like this:

If (isBlueButonON) {

//turn ON the BLUE and GREEN LEDs on pins PB6 and OB7

} else {

//turn OFF the BLUE and GREEN LEDs on pins PB6 and OB7

How can we write a condition isBlueButonON?

From the table bellow, we need to check the bit 0 (blue button is connected to it).

The expression GPIO->IDR yields the whole register IDR (bits for all inputs + reserved)!

We want to get only the value of the pin IDR0 …

… so we need to set a mask!

12
GPIO->IDR & (0x1<<0)

If (isBlueButonON) { If ( GPIO->IDR & (0x1<<0) ) {


//turn ON the BLUE and GREEN LEDs //turn ON the BLUE and GREEN LEDs
on pins PB6 and OB7 on pins PB6 and OB7
} else { } else {
//turn OFF the BLUE and GREEN LEDs //turn OFF the BLUE and GREEN LEDs
on pins PB6 and OB7 on pins PB6 and OB7
} }

That's it … and more … Everything is the same!

13
V pogovoru s študenti ugotavljam, da nekatere pojme še vedno
mešate …
Upor pull-up je povezan proti Vcc (napajanju) in nastavi stanje na vhodu mikrokrmilnika na 1, ko tipka
ni pritisnjena.

Upor pull-down je povezan proti GND (masi) in nastavi stanje na vhodu mikrokrmilnika na 0, ko tipka
ni pritisnjena.

Ker so tipke lahko tudi drugačne (sklenjena v mirovanju ali odprta v mirovanju), lahko
podamo splošen povzetek:

POVZETEK: Upore PULL-UP oziroma PULL-DOWN dodamo po potrebi tako, da bo


v vsakem stanju tipke (pritisnjena ali odprta)

mikrokmilnik "čutitil" RAZLIČNI vrednosti (enkrat 0, drugič 1).

Kdaj je potrebno vključiti notranje pull-up oz. pull-down upore?

Za razlago naj služi spodnja slika.

Poglejmo vhod GPIOD.7 (tipka S2):

Če je S2 sklenjena, "čuti" mikrokrmilnik logično 1 (vhod GPOID.7 je povezan na napajanje VCC).

Če je S2 odprta, mikrokrmilnik ne more "čutiti" niti logične 0 in niti logične 1, saj linija ni vezana ne na
maso in ne na napajanje. TOREJ vemo, da je potrebno vključiti notranji pull-down upor (povezavo
proti masi), da bo mikrokrmilnik, ko tipka S2 NI pritisnjena čutil različno stanje (logična 0), od stanja, ko
je tipka pritisnjena (logična 1).

14
Poglejmo vhod GPIOE.0 (tipka S1):

Če je tipka S1 odprta, "čuti" mikrokrmilnik logično 1 (vhod GPOIE.0 je povezan, preko pull-up upora,
na napajanje VCC). Ni pomebno, če je upor obrnjen navdol, navgor ali vodorvavno, pomembno je le
poznavanje, ali je linija vezana proti masi, napajanju ali ni nikamor

Če je tipka S1 sklenjena, mikrokrmilnik "čuti" logične 0, saj je njegov GPIOE.0 povezan na maso.

Poglejmo izhod GPIOC.2:

Ker imamo zunanje napajanje (VCC) LED diode (tok teče v mikrokrmilnik), vemo po primerih iz
priročnika, da moramo izbrati način "open-drain", sicer bi izbrali push-pull (tok bi
tekel iz mikrorkmilnika proti masi).

Da bo ta LED dioda svetila (lahko tekel tok v mikrokrmilnik), moramo GPIOC.2 postaviti na 0 (maso).
LED izklopim (ne sveti) tako, da postavim GPIOC.2 na 1 (VCC).

Še preverjanje pogojev v if stavkih


Prepostavka: Pull-up, pull-down so že pravilno nastavljeni!

Kako ugotovim, da je tipka S2 pritisnjena?

Če je tipka S2 pritisnjena, vidimo da je GPIOD.7 = 1, sicer 0 (notranji pull-down).

Če želimo vklopiti diodo LED1, ko je S2 pritisnjena zapišem pogoj: if (S2 != 0) vklopi LED1.

POMNITE: V splošnem ne pišite if (S2 ==1) ampak if (S2 != 0)!!

(pogoj if S2 == 0) pomeni, da je tipka je odprta (imamo notranji pull-down)).

Kako ugotovim, da je tipka S1 pritisnjena?

Če je tipka S1 pritisnjena, vidimo da je GPIOE.0 = 0 (linijo povežemo na maso), sicer 1 (zunanji pull-
up => upor proti napjanju VCC).

Če želimo vklopiti diodo LED1, ko je S1 pritisnjena zapišem pogoj: if (S1 == 0) vklopi LED1!

(pogoj if S1 != 0) pomeni tipka je odprta).

15
TIMER INITIALIZATION

General-purpose timers (TIM2 to TIM5) reference manual

ISR form: »void TIM4_IRQHandler()«


TIM4 clock enable
APB1 peripheral clock enable register (RCC_APB1ENR)

See RM page 159, 6.3.10

We want to call our TIM4 ISR every 10ms

We decide to call the timer interrupt routine ISR every 10 ms (every hundredth of a second).
How to realize this desire? By reducing the input frequency 2.097 MHz (fCL_PSC) to 1 KHz
(fCL_CNT) and with the appropriate value in the register ARR.
First we will reduce the frequency: This is achieved by setting the correct value in the
register PSC:
fCL_CNT = fCL_PSC / (PSC + 1) => PSC = 2097000/1000 - 1 = 2096

16
TIM4->PSC = 2096
Now we have to determine the value in the register of ARR. As the counter is increased every
millisecond (driven by the clock of 1KHz), we need to set the value of the register ARR to 10
=> ISR will be invoked once every 10 ms (every hundredth of a second).

To ENSURE initial state => set flag UG and delete flag UIF

17
REQUEST FOR AN TIM4 INTERRUPT TRIGGERING (or call TIM4 ISR when CNT reaches value
in ARR)

ENABLE THE TIMER4

18
SET the PRIORITY for TIM4 interrupts and ENABLE TIM4 interrupts
(We need to do that in the device NVIC (Nested Vector Interrupt Controller that resides in the
ARM core -> it is the part of ARM company and not of the uC producer; ST Microelectronics in
our case)

NVIC_SetPriority(TIM4_IRQn,1);

NVIC_EnableIRQ(TIM4_IRQn);

Due to the simplicity, we have used CMSIS (Cortex Microcontroller Software Interface Standard)
functions, which have the same format for each of the microcontrollers. Again, the reference manual
for STM32L1 contains no detailed information on registers and ARM devices in the core. These can
be found in the ARM reference manuals.

ISR – Interrupt Service Routine


ISR is shown below. Although this ISR should be called each time counter in TIM4 reaches ARR,
it is a good practice to check this is true (check if the flag UIF is set - TIM4 set this flag when
the counter reaches a value ARR).
Important: Do not forget to delete this flag UIF before ISR exits. Otherwise, we cannot
continue with our main program after ISR exit (we would continue to enter into the ISR
because we did not delete the flag UIF
void TIM4_IRQHandler(){
if((TIM4->SR & TIM_SR_UIF) == 1){ //we need to chek that the flag UIF is set
TIM4->SR &= ~TIM_SR_UIF; //we need to delete "pending" interrupt flag

GPIOB->ODR ^= GPIO_ODR_ODR_6; // every 10 ms turn on and turn off the LED


GPIOB->ODR ^= GPIO_ODR_ODR_7; // every 10 ms turn on and turn off the LED

19
HOW CAN I USE TIMERS FOR DESIRED TIME GENERATION?

Example 1: Initializing a timer and waiting in the endless loop. ISR lights LEDs. To slow down the flashing
of the LEDs (now flashes every 10 ms, which's hard to observe clearly with your eyes), increase the
time between two entries in the ISR (e.g., Set the RCC 100  100 ms)

20
Example 2: Realization of the function mojDelay which receives as a parameter the desired delay in
hundredths (in 10ms). To test a working of this program, first, you need to write functions initTimer4
and initGPIO. ISR for TIM4 increases the value of the variable Timer1 every 10 ms.

We also define the variable time1 (counts the required time), which is accessible everywhere in this
file. Since the use of global variables is not desirable (it is hard to detect errors), we use a STATIC
reserve word in front of it to prevent the use of a variable outside of the file in which it is defined.

mojDelay function is called from the main function with a parameter 100 (100 * 10 ms = 1 s).
Function mojDelay first set the value of the variable time1 to 0 and waits in a loop (while) until the
value of time1 variable (increases by ISR every 10 ms) reaches the desired latency (delay; 100 in our
example).

21
Time-dependent loops (it follows from example 2 => this
template is suitable for lab exercise 3)

Static uint32_t time1=0;

Void initGPIO(){

}
Void initTimer4(){

}

Int main (void) {

initGPIO();
initTimer4();

time1 = 0; // this variable is automatically increased each 10ms by ISR (TIM4_IRQHandler


// function).
while(time1<<500){ //this loop automatically finishes after 5 sekund! We don't care aboutb
trhat!
//Here we can check if button is pressed and do whatever we wish to do …
}

22
Here is a template for ex. 3. It does not use EXTI interrupts. They would make
the implementation much simpler and intuitive. It is based on the timer4 ISR
above.
//main loop

While(1){

//time1 is incremented by TIM4 ISR

While(NOT left or right pad is touched){

If(!BlueButton){

time1=0;

If(time1>300) { //3 seconds

Change mode

If mode1 => calling a function for counting HITS

else => calling a function for rhythm recording

Here is a function for counting HITS:


right_entry_flag = true

left_entry_flag = true

time1 = 0

while(time < 20 seconds){

leftPad = … // leftPad <> 0 if leftPad is not pressed otherwise is 0

rightPad = … // rightPad <> 0 if rightPad is not pressed otherwise is 0

if (leftPad && left_entry_flag) {

left_entry_flag = false

if(previousPad is not leftPad){

numberOfHits++;

previousPad = leftPad

23
//something similiar fort he right pad

if (rightPad && right_entry_flag) {

} //return to the main loop

Here is a function for rhythm recording


Uint8_t rhythmRecordsSTATE[10] //it stores 10 states

uint32_t rhythmRecordsTIME[10] //it stores 10 times (duration of a state) for 10


states

//possible states are:

0  00 (not left, not right, duration of this state)

1  01 (not left, right, duration of this state)

2  10 (left, not right, duration of this state)

3  11 (left, right, duration of this state)

oldState = 100;

For (hit goes from 0 to 10) {

leftPad = …

rightPad = …

If (NOT leftPad and NOT rightPad) state = 0

If (NOT leftPad and rightPad) state = 1

If (leftPad and NOT rightPad) state = 2

If (leftPad and rightPad) state = 3

If(state != oldState) {

newState = True

oldState = newState

time1 = 0 //when the change of a state is perceived a time measuring begins

} else {

newState = False;

rhythmRecordsSTATE[hit] = state //state

rhythmRecordsTIME[hit] = time1 //duration of a state

24
You need to provide a Playback function (a fuction for turning the blue and green LEDS on and off ) which reads
the array rhythmRecordsSTATE and rhythmRecordsTIME, decodes RED and GREEN LEDs and
performs required delay.

//return to the main loop

25

You might also like