GPIO Initialization For ARM Microprocessor
GPIO Initialization For ARM Microprocessor
and
TIMER
INITIALIZATION
Ernest Gungl
(for internal use ONLY)
2017
Kazalo
2
GPIO INITIALIZATION
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)
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??)
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.
7
Thus, we have successfully turned ON the blue LED!
8
SET PIN AS INPUT
9
Do we need internal PULL-UPs or PULL-DOWNs
10
What about here (BLUE BUTTON ON THE DEVELOPMENT BOARD).
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).
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
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)!
12
GPIO->IDR & (0x1<<0)
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:
Č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.
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 želimo vklopiti diodo LED1, ko je S2 pritisnjena zapišem pogoj: if (S2 != 0) vklopi LED1.
Č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!
15
TIMER INITIALIZATION
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)
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.
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)
Void initGPIO(){
…
}
Void initTimer4(){
…
}
initGPIO();
initTimer4();
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){
If(!BlueButton){
time1=0;
Change mode
left_entry_flag = true
time1 = 0
left_entry_flag = false
numberOfHits++;
previousPad = leftPad
23
//something similiar fort he right pad
oldState = 100;
leftPad = …
rightPad = …
If(state != oldState) {
newState = True
oldState = newState
} else {
newState = False;
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.
25