P1: Introducción a la RPi Pico 2 - myTeachingURJC/Arq-computadores-01 GitHub Wiki

Sesión 1: Introducción a Raspberry Pi Pico 2 con RISC-V

A lo largo de estas sesiones llevaremos al mundo real todo lo que hemos aprendido con el RISC-V utilizando la Raspberry Pi Pico 2.

Esta placa integra un microprocesador con arquitectura dual: 2 núcleos ARM y 2 núcleos RISC-V. Nosotros activaremos y utilizaremos exclusivamente los núcleos RISC-V para programar en lenguaje ensamblador nativo.

1. Hardware y Pinout

Para simplificar las conexiones y la visualización, la Pico 2 se encuentra montada sobre una Breakout Board. Esta placa adicional nos proporciona acceso sencillo a los pines y dispone de LEDs indicadores para el estado de los mismos.

Mapeo de Memoria (MMIO)

La placa dispone de 27 pines GPIO (General Purpose Input Output). Un GPIO es un pin genérico capaz de comportarse como entrada o salida digital, o bien asumir funciones especiales (SPI, I2C, PWM, etc.).

Para esta asignatura hemos preconfigurado el entorno de modo que el acceso a los pines sea idéntico al funcionamiento de la MMIO en RARS.

Pines Función Dirección de Memoria Descripción
GP0 - GP7 Salida 0xD0000010 Escribe aquí para encender los LEDs.
GP8 - GP15 Entrada 0xD0000005 Lee de aquí para obtener el estado de los interruptores.

Instrucciones de uso:

  • Usar sb (store byte) en 0xD0000010 para escribir en los LEDs.
  • Usar lb (load byte) en 0xD0000005 para leer las entradas.

2. Flujo de trabajo: Cargar un programa

Vamos a cargar nuestro primer programa ("Hola Mundo" en hardware) que encenderá los LEDs conectados a GP0-GP7.

Pasos para la compilación y carga:

  1. Preparación: Descarga y descomprime el archivo Pico2.zip con el entorno de trabajo.
  2. Compilación: Abre una terminal en la carpeta descomprimida y ejecuta:
./build.sh template

Este script ensambla el código de template.s y genera el archivo binario template.uf2.

  1. Modo Bootloader: Mantén pulsado el botón BOOTSEL de la Pico 2. Sin soltarlo, conéctala al PC mediante el USB.
  2. Carga: El PC reconocerá la placa como una unidad de almacenamiento externa (similar a un Pendrive). Arrastra el archivo template.uf2 dentro de esa unidad.
  3. Ejecución: La placa se reiniciará automáticamente y ejecutará el código. Deberías ver los 8 primeros LEDs encendidos.

Ahora ya puedes hacer tus propios programas en ensamblador, generar el binario y probarlos en la Pico.

Cada vez que quieras cargar un nuevo programa, tendrás que desconectar y conectar la PICO manteniendo pulsado BOOTSEL.

[!WARNING] ⚠️ PRECAUCIÓN HARDWARE ⚠️ El conector micro-USB de la Pico es frágil y tiene un número limitado de ciclos de conexión.

  • NO desconectes el cable del lado de la Pico repetidamente.
  • Para reiniciar o cargar un nuevo programa, desconecta y conecta el extremo del cable que va al ordenador, manteniendo siempre el cable conectado a la placa.

3. Análisis del código: template.s

El salto del simulador al mundo real implica considerar detalles que antes gestionaba el simulador. Analicemos el archivo base template.s.

# ----------------------------------------------
# -- Template that turns on all output leds
# ----------------------------------------------

# -- Include library headers
.include "lib/boot.h"
.include "lib/gpio.h"

# -- Constants definitions
.eqv GPIO_IN,       0xD0000005
.eqv GPIO_OUT,      0xD0000010
.global _start

# -- Data Section
.data

valor:  .byte 0xAA

# -- Code Section
.text

# ------------------------------
# -- Main Loop
# ------------------------------

_start:
    # -- Initialization and GPIO setup
    jal init
    li s0, GPIO_IN
    li s1, GPIO_OUT

    # -- Logic to turn on LEDs
    la t1, valor
    lb t0, 0(t1)       # Load value from RAM
    sb t0, 0(s1)       # Write to LEDs (Output)

    # -- Infinite loop
loop:
    j loop

Diferencias clave con RARS

1. Archivos de cabecera (.include)

  • lib/boot.h: Contiene la "firma" especial necesaria (los primeros 256 bytes) para que la Pico 2 identifique el archivo como un ejecutable RISC-V válido al arrancar.
  • lib/gpio.h: Realiza dos tareas críticas:
  1. Configura los registros físicos de los pines para que actúen como entradas o salidas.
  2. Copia de datos: Al encenderse la placa, tu programa está en la memoria Flash (lenta y de solo lectura). Esta rutina copia tu sección .data desde la Flash a la memoria RAM para que puedas usar variables modificables.

2. La rutina de inicio (jal init)

Esta instrucción es obligatoria al principio de _start. Si la omites, los pines no funcionarán y tus variables en .data no estarán inicializadas en la RAM.

3. Ausencia de Sistema Operativo (ecall)

En RARS usábamos la llamada al sistema 10 para terminar el programa. En este hardware no hay sistema operativo al que devolver el control. El procesador nunca se detiene.

Por ello existen dos estrategias:

  • Bucle de trabajo: El programa se repite indefinidamente realizando una tarea.
  • Detención: Si el programa termina su tarea, debemos capturarlo en un bucle infinito (j loop) para evitar que el contador de programa (PC) siga avanzando y ejecute instrucciones basura de la memoria memoria vacía.

4. Ejercicios Propuestos

Ejercicio 1: Contador Binario

Implementa un programa que utilice los LEDs (GP0-GP7) para mostrar un contador binario de 8 bits que incremente su valor continuamente.

Resultado esperado: Los LEDs deben contar en binario (00000001, 00000010, etc.).

WhatsApp Video 2026-01-15 at 13 12 13(1)

Ejercicio 2: Entradas

Prueba las entradas de los pines GP8-GP15. Crea un programa que encienda los leds GP0-GP7 en función de la entrada de GP8-GP15, es decir si la entrada es 1 en GP8, se enciende GP0, si la entrada es 1 en GP9, se enciende GP1, etc.

Autores

Licencia

Enlaces