Laboratorio 1: Gestión de los GPIO
Programación a bajo nivel de registros para el control de pines de entrada/salida en el STM32F103RB.
1. Habilitación del Reloj (RCC)
Antes de usar cualquier puerto GPIO, es imperativo suministrarle señal de reloj. Esto se realiza en el
registro RCC_APB2ENR.
RCC->APB2ENR |= (1 << 2); // Habilita Puerto A (IOPA EN) RCC->APB2ENR |= (1 << 3); // Habilita Puerto B (IOPB EN) RCC->APB2ENR |= (1 << 4); // Habilita Puerto C (IOPC EN)
Nota: Sin este paso, cualquier acceso a los registros del puerto será ignorado por el procesador.
2. Configuración: Registros CRL y CRH
Cada puerto tiene 16 pines, divididos en dos registros de configuración de 32 bits cada uno:
- CRL: Controla los pines del 0 al 7.
- CRH: Controla los pines del 8 al 15.
Cada pin se define mediante 4 bits: MODE (2 bits) y CNF (2 bits).
| Modo Deseado | CNF [1:0] | MODE [1:0] | Valor Hex |
|---|---|---|---|
| Salida Push-Pull (2MHz) | 00 | 10 | 0x2 |
| Salida Open-Drain (2MHz) | 01 | 10 | 0x6 |
| Entrada Flotante | 01 | 00 | 0x4 |
| Entrada Pull-Up/Down | 10 | 00 | 0x8 |
Ejemplo: Configurar PB6 como salida a 2MHz:
GPIOB->CRL &= ~(0xF << 24); // Limpia bits 24-27 GPIOB->CRL |= (0x2 << 24); // Modo Salida Push-Pull (CNF=00, MODE=10)
// Limpiar configuración del pin 6 usando máscaras CMSIS GPIOB->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6); // Configurar como salida 2MHz Push-Pull GPIOB->CRL |= GPIO_CRL_MODE6_1; // MODE6 = 10 (2MHz)
Configuración de Pull-Up / Pull-Down
A diferencia de otros modos, la selección entre Pull-Up y Pull-Down requiere un paso adicional usando el
registro ODR después de configurar el pin como entrada (CNF=10, MODE=00):
- Pull-Up: Escribir un 1 en el bit correspondiente de
ODR. - Pull-Down: Escribir un 0 en el bit correspondiente de
ODR.
Ejemplo: Configurar PA0 como entrada con Pull-Up:
GPIOA->CRL &= ~(0xF << 0); // Limpia configuración PA0 GPIOA->CRL |= (0x8 << 0); // Configura CNF=10, MODE=00 GPIOA->ODR |= (1 << 0); // Activa resistencia de Pull-Up
3. Operaciones de E/S
Escritura (Salida)
Acción directa con ODR o atómica con BSRR.
// Usando BSRR GPIOB->BSRR = (1 << 6); // SET: PB6 a 1 GPIOB->BSRR = (1 << 22); // RESET: PB6 a 0 (6+16)
// Usando BSRR con CMSIS GPIOB->BSRR = GPIO_BSRR_BS6; // SET: PB6 a 1 GPIOB->BSRR = GPIO_BSRR_BR6; // RESET: PB6 a 0
Lectura (Entrada)
Consulta del estado lógico mediante IDR.
// Ejemplo PB6 con Pull-Down
if (GPIOB->IDR & (1 << 6)) {
// PB6 está en HIGH
} else {
// PB6 está en LOW (Pull-Down activo)
}
Ejemplo: Blink en PB6 (Bare Metal)
#include "stm32f10x.h"
int main(void) {
// 1. Reloj para el Puerto B
RCC->APB2ENR |= (1 << 3);
// 2. PB6 como salida 2MHz
GPIOB->CRL &= ~(0xF << 24);
GPIOB->CRL |= (0x2 << 24);
while(1) {
GPIOB->ODR ^= (1 << 6); // Alternar estado
for(int i=0; i<500000; i++); // Retardo software
}
}