In previous article we programmed LED on Nucleo board to blink. In this one I wiil try to explain in detail how I/O pins on STM32 work.
This is basic tutorial on STM32 I/O ports. There are some things marked, that I have yet to check.
On our board there is STM32F401RET6 microcontroller. Above is pinout for it:
On the picture above we can see that this particular STM32 microcontroller uses ports:
PORTA[15:0] -> bits 15…0
PORTB[15:0] -> bits 15…0
PORTC[15:0] -> bits 15…0 (bits 15 and 14 can only be used if LSE oscillator is not used)
PORTD -> only bit 2
PORTH[1:0] -> only bits 1 and 0 (can only be used if HSE (high speed external) oscillator is off)
Each of this ports have a bunch of registers assigned to.
They are, not in particular order (x represents the leter of different ports GPIOx can be GPIOA, GPIOB…):
GPIOx_MODER[31:0] -> used to select the I/O direction (input, output, analog, alternate function)
GPIOx_OTYPER[31:0] -> used to select output type (push-pull, open-drain)
GPIOx_OSPEEDR[31.0] -> used to select switching speed (not the speed of switching, but slope of the transition)
GPIOx_PUPDR[31:0] -> used to select pull-up or pull-down
GPIOx_IDR[15:0] -> input data register, read only
GPIOx_ODR[15:0] -> output dat register, read and write
GPIOx_BSRR[15:0] -> used to set/reset single or multiple bits in GPIOx_ODR
GPIOx_LCKR[15:0*] -> used to lock configuration registers (MODER, OTYPER, OSPEEDR, PUPDR, AFRL and AFRH)
GPIOx_AFRL[31:0] ->used to select alternate function of port
GPIOx_AFRH[31:0] -> used to select alternate function of port
* even if this register is 16-bits wide you need 32-bit acces because you need bit 16 to write at the same time as bits [15:0]
Now we will look each one more detailed.
GPIOx_MODER register is 32 bits wide, but the ports only have 16 pins (bits), why is it so?
If we look at bits in the register we see that bits are grouped in pairs and each pair represent function of one bit of port I/O register. But why is this so?
That is because each pin can operate four different ways:
00 -> Input (this is the state at reset)
01 -> General purpose output mode
10 -> Alternate function mode (pins have different alternate functions)
11 -> Analog mode
So for example, if we want bit 5 of PORT A to be output, we need to set bits 11 and 10 to be 01 in PORTA_MODER.
We do this with this command:
GPIOA->MODER = 0x00000400;
GPIOx_OTYPER is also 32 bit wide and only the lower 16 bits are used. This register is used when pins are configured as outputs.
0 -> Output push-pull (reset state)
1 -> Output open-drain
GPIOx_OSPEEDR register is 32 bit register. As in MODER register here bits are in pairs to be able to select four different speeds for each pin.
00 -> Low speed
01 -> Medium speed
10 -> Fast speed
11 -> High speed
I need to do more research on this register. I read somewhere (internet) that this register does not impact toggle speed of ports but rather rise and fall time of signals. Needs to be determined.
GPIOx_PUPDR is 32 bit register and here also the bits are in pairs. This register controls switches on pull-up and pull-down resistors on microcontroller pins. It only works when pins are configured as inputs.
00 -> No pull-up, pull-down
01 -> Pull-up
10 -> Pull-down
11 -> Reserved
GPIOx_IDR is 16 bit register. In this register the data from port is stored. This is read-only register. This is the register for reading pin values.
GPIOx_ODR is 16 bit register. We write to this register what we want to have on port output. If pins are configured as inputs and pulled different than set here, the reading of this register will not change. <-TODO check
GPIOx_BSSR is 32 bit register. It is used to set/reset some of bits in register without interfering with bits not used in this command.
Setting one in lower bits[15:0] this command sets bits in port, setting one in higher half of bits[31:16] resets bits on port.
GPIOx_LCKR is 17 bit register. It is used to lock configuration of port.
Bit 16 LCCK:
0 -> Port configuration lock not active
1 -> Port configuration lock key active. The GPIOx_LCKR register is locked until an MCU reset or peripheral reset occurs.
0 -> Port configuration not locked
1 -> Port configuration locked
There is a specific write sequence needed:
WR LCKR = ‘1’ + LCKR[15:0]
WR LCKR = ‘0’ + LCKR[15:0]
WR LCKR = ‘1’ + LCKR[15:0]
RD LCKR = ‘1’ (this read operation is optional but it confirms that the lock is active)
During this lock sequence LCKR[15:0] must not change!
GPIOx_AFRL and GPIOx_AFRH
GPIOx_AFRL and GPIOx_AFRH are two 32 bit registers. They are used to select alternate function of port pins. Bits in these registers are grouped into 4 bits per output pin, this is why two 32 bit registers are needed.
0000 -> AF0
0001 -> AF1
1110 -> AF14
1111 -> AF15