1 puntos por GN⁺ 2025-04-06 | 1 comentarios | Compartir por WhatsApp
  • Con el objetivo de crear una computadora mínima que se pueda ensamblar en casa, se implementó un sistema de 8 MB de RAM y alrededor de 1 MIPS capaz de ejecutar Debian Linux, vi, gcc y make usando solo componentes de 8 pines
  • La placa final está compuesta por tres chips: STM32G031, 8 MB de SPI PSRAM y un puente USB-serial PL2303GL; por la restricción de los encapsulados de 8 pines, solo hay 6 I/O disponibles
  • La falta de pines es la principal dificultad del diseño: la RAM usa SPI normal, la tarjeta SD usa SDIO de 1 bit compartiendo los pines de la RAM, y la transmisión UART se maneja por bit banging
  • El software reutiliza un emulador MIPS existente basado en ensamblador ARMv6M, y un bootloader de 8 KB actualiza el firmware desde FIRMWARE.BIN en el sistema de archivos FAT de la tarjeta SD
  • El STM32G031 se overclockea más allá de los 64 MHz oficiales mediante la configuración VOS0, y con una CPU host a 148 MHz arranca Debian en menos de un minuto, con un rendimiento similar a un MIPS R3000 de unos 1.65 MHz

Computadora Linux mínima hecha solo con chips de 8 pines

  • El objetivo es crear una computadora moderna en formato kit, fácil de ensamblar en casa, usando solo chips de 8 pines
  • El criterio mínimo para considerarla una computadora moderna se definió como la capacidad de ejecutar Debian Linux, vi, gcc y make
  • A partir de experimentos anteriores, las especificaciones mínimas necesarias para ejecutar Linux se fijaron en 8 MB de RAM y una CPU de 1 MIPS
  • El almacenamiento usa una tarjeta SD, y la conexión de consola usa USB-serial
  • La placa tiene una forma circular pequeña y un conector USB-C en el borde superior de la placa
  • Se redujeron la cantidad de componentes y de pines para que incluso personas con muy poca experiencia soldando puedan ensamblarla con un cautín de 45 W

Selección de componentes

  • Para la conexión USB se eligió PL2303GL
    • Es un puente USB-serial que funciona sin componentes externos y también ofrece una salida de regulador de 3.3 V de 100 mA
    • Tiene drivers para los principales sistemas operativos; en macOS requiere instalación desde la App Store
  • También se evaluó como alternativa una implementación USB con ATTINYx5 y V-USB
    • Según la especificación, USB low-speed no puede usar bulk endpoints, pero los principales sistemas operativos no lo hacen cumplir, por lo que una implementación de puerto serial ACM funciona
    • V-USB consume mucho tiempo de CPU, flash y RAM, lo que resulta pesado para este proyecto
  • Para la RAM se usa SPI PSRAM en SOIC-8
    • ISSI, APMEMORY, Vilsion y otros fabrican componentes relacionados, y los componentes de 8 MB se consiguen en canales de distribución comunes
    • Aunque varios fabricantes prometieron chips de 16 MB, se concluyó que en la práctica no hubo suministro
  • Para el microcontrolador se compararon las familias PIC16F, RL78, PSoC1, eZ8, S08CPUv2, STM8, MSP430, AVR, PSoC4, MSPM0C, CH32V003, CH570E y STM32G0
  • La elección final fue la familia STM32G031J4M6/STM32G031
    • Ofrece núcleo Cortex-M0+, 64 MHz oficiales, 32 KB de flash y 8 KB de RAM
    • En encapsulado de 8 pines, resultó más favorable que otros candidatos en rendimiento y memoria
    • Aunque preocupaba la calidad de los documentos de errata de los chips STM, el diseño usa un mínimo de periféricos en chip, por lo que la elección era viable

Diseño de hardware dentro de 6 pines I/O

  • UART de consola

    • UART RX y TX son difíciles de combinar con otras funciones
    • Si se comparte RX, se pueden perder datos entrantes durante otras operaciones; si se comparte TX, incluso un pulso low corto puede verse como un carácter en la PC
    • Por eso, 2 de los 6 I/O se asignan a la consola UART
    • En la asignación final de pines, el pin 8 se usa como USART2 RX y el pin 7 hace UART TX mediante bit banging
    • Durante la transmisión UART se detiene toda la ejecución, así que se usa la velocidad más alta posible, 115,200 bps
    • Enviar un carácter toma unos 87 microsegundos, y como la placa no emite salida durante la mayor parte del tiempo, este enfoque es aceptable
  • Conexión de RAM

    • La SPI PSRAM soporta QSPI, pero QSPI requiere 6 pines, por lo que no se puede usar
    • dual-SPI podría ser 2 veces más rápido que SPI normal sin usar pines adicionales, pero el STM32G031 no soporta dual-SPI
    • Se concluyó que hacer dual-SPI por bit banging con la CPU difícilmente superaría la combinación de SPI por hardware y DMA
    • Como resultado, la RAM se conecta por SPI normal, y esa conexión usa los 4 pines restantes
  • Conexión de tarjeta SD

    • Para usar una tarjeta SD en modo SPI haría falta un pin adicional de chip select, pero ya no quedaban pines
    • Usar un inversor para invertir RAM nCS y utilizarlo como SD card nCS causó problemas con algunas tarjetas y además requería un componente extra
    • También se evaluó compartir el pin UART TX como SD card nCS con un filtro pasa bajos, pero requería UART a 300 bps o menos y era vulnerable cuando la tarjeta SD era lenta
    • La solución final fue implementar directamente el protocolo SDIO de 1 bit de la tarjeta SD
    • RAM nCS se comparte como SD CLK, RAM CLK como SD CMD y RAM MOSI como SD DAT
    • El acceso a la RAM se ve desde la tarjeta SD como un estado idle de 1 bit, y el acceso a la SD se ve desde la RAM como simples ciclos repetidos de selección y liberación, por lo que funciona de manera segura
    • Sin embargo, no se pueden usar lecturas/escrituras multibloque, porque no puede intercalarse un acceso a RAM en medio de una transacción SD
    • Por la disposición de pines del STM32G031, no se puede usar SDIO como periférico de hardware, así que todo el acceso a SD se hace por bit banging
    • La implementación en ensamblador alcanza un rendimiento de unos 14 CPU cycles/bit

Bootloader y flujo de arranque de Linux

  • Emulador

    • Se reutiliza el emulador MIPS del proyecto existente LinuxCard
    • El emulador estaba escrito en ensamblador ARMv6M y podía arrancar Linux
    • También se escribió un JIT de MIPS a ARMv6M para ejecutar más rápido, pero el tamaño del código era de 46 KB, demasiado grande, y en una caché de traducción de 6 KB la ganancia de velocidad no era suficiente, así que no se usa
    • La flash de 32 KB del STM32G031 se divide en un bootloader de 8 KB y 24 KB de código principal
  • Bootloader para actualización de firmware

    • Como no se podían reservar pines de depuración, hizo falta un bootloader para actualizar el firmware desde la tarjeta SD
    • El bootloader incluye un driver SDIO, un driver de sistema de archivos FAT, código de escritura en flash, logging y código de transmisión UART por bit banging
    • Su tamaño real es de unos 6.5 KB, pero por la granularidad de los bloques de flash usa un área de 8 KB
    • Busca FIRMWARE.BIN en la tarjeta SD y aplica la actualización si pasa las verificaciones básicas y cumple la condición de incremento de versión
    • La word en el offset 16 de la imagen de la aplicación se usa como número de versión
    • El byte en el offset 8 del bootloader es la versión del bootloader y no se usa salvo para mostrar el texto de arranque de la app principal
    • El bootloader también busca en el sistema de archivos FAT archivos o directorios cuyos nombres empiecen con CLOCK
    • Los números que siguen se usan como velocidad de reloj de la aplicación principal; si están fuera del rango 32–200 MHz o no hay valor, se usa 132 MHz
  • Particiones de la tarjeta y carga del kernel

    • El flujo de arranque está estructurado de forma similar al proceso de arranque de una PC
    • Lee el primer sector de la tarjeta SD al inicio de la RAM y salta allí
    • El código de primera etapa busca una partición de tipo 0xBB, la carga en 0x80001000 y luego salta allí
    • El bootloader de segunda etapa monta como FAT16 la partición marcada como active y carga el archivo VMLINUX como ELF
    • La línea de comandos del kernel está integrada en el bootloader
    • root es /dev/pvd3 e init es /sbin/uMIPSinit
    • Se intenta montar /dev/pvd1 como /boot
    • El orden de particiones del proyecto es: partición FAT, partición del bootloader y rootfs
    • Como Windows y macOS montan la primera partición, se pueden copiar y sacar archivos fácilmente mediante la partición FAT
    • En el Linux arrancado, esa misma partición aparece como /boot

Rendimiento y overclocking

  • Aunque la velocidad oficial de operación del STM32G031 es 64 MHz, se probaron relojes más altos usando la configuración interna de voltaje
  • La documentación de STM incluye configuraciones VOS2 a 1.0 V y VOS1 a 1.2 V; con VOS1, por encima de unos 75 MHz no resulta estable
  • Usar la configuración VOS0 a 1.35 V, mencionada en documentación antigua y en documentos de chips similares, aumenta mucho el margen de overclocking
  • La mayoría de los chips funciona bien a 136 MHz, y algunos llegan hasta 180 MHz
  • Como la memoria flash no se vuelve más rápida, hay que administrar correctamente los flash wait states
  • Con una CPU host a 148 MHz, la CPU MIPS emulada es similar a un MIPS R3000 de unos 1.65 MHz con FPU desactivada
  • El sistema arranca en menos de un minuto, y vi, make, objdump y gcc funcionan
  • Como es un sistema Debian completo, se pueden traer paquetes .deb a /boot e instalarlos

Ensamblado y primer arranque

  • Flujo de ensamblado

    • Se proporcionan los archivos de diseño para fabricar la placa, y se está buscando una empresa que venda kits
    • El ensamblado se realiza en el orden: socket de tarjeta SD, capacitores, resistencias, STM32G031 y PL2303GL
    • R101, R102, R201 y R202 no se colocan al principio
    • Primero hay que grabar el bootloader en el STM32
    • Se puentean R101 y R201 para configurar el cableado serial del bootloader ROM
    • Se hace sin insertar la tarjeta SD y antes de soldar el chip de RAM
    • Después de grabar el bootloader, se retira el puente R101/R201 y se puentean R102/R202
    • Luego se suelda el chip de RAM APS6408 o VTI7064 en la posición U2, y con eso termina el ensamblado de hardware
  • Firmware y primer arranque

    • La tarjeta SD debe ser de al menos 1 GB, y se graba la imagen de disco proporcionada
    • La imagen incluye un bootloader MIPS de primera etapa, un bootloader MIPS de segunda etapa, una partición con el kernel Linux y una copia del firmware, y el rootfs de Debian
    • Si se coloca FIRMWARE.BIN en la partición FAT, el bootloader se flashea a sí mismo en el primer arranque
    • La terminal serial se configura a 115,200 bps, 8N1
    • En la primera ejecución se programan los fuse del STM32, y puede ser necesario desconectar y volver a conectar el cable USB-C
    • Después de unos 20 segundos empiezan los mensajes de arranque del kernel Linux, y el arranque completo toma cerca de 1 minuto
    • Como solo hay 8 MB de RAM, se recomienda enfáticamente ejecutar swapon /swapfile como primer comando
    • Activar swap tarda decenas de segundos, pero después permite ejecutar más programas

Archivos de descarga y uso

  • La descarga principal es uMIPS.8PL.zip
  • El archivo incluye los archivos necesarios para fabricar y ejecutar la placa
    • schematics: esquemas del circuito
    • gerbers: archivos Gerber para fabricar la placa
    • srcs: código fuente del emulador y el bootloader
    • binaries/SD.img: imagen para grabar en la tarjeta SD
    • BOOTLOADER.BIN: bootloader para grabar en el chip durante el ensamblado
    • FIRMWARE.BIN: imagen de firmware precompilada
  • Después de arrancar, el shell predeterminado es sh, y también se puede ejecutar bash
  • Para evitar falta de RAM, conviene activar el swapfile incluido en la imagen con swapon /swapfile
  • Suponiendo que el MCU se ejecute a 120 MHz, la velocidad efectiva de CPU es de unos 1.5 MHz
  • Compilar un programa C simple con gcc tarda varios minutos, pero funciona
  • Como ejemplos se proporcionan generadores de Mandelbrot de punto flotante y punto fijo, tanto en código fuente como en binario
  • Las herramientas instaladas incluyen vim, make y gcc, y se pueden agregar paquetes Debian mediante la partición FAT16 compartida de la tarjeta SD

1 comentarios

 
GN⁺ 2025-04-06
Opiniones de Hacker News
  • La parte en la que, tras pensar qué pines podían combinarse con los tres pines de SDIO, se llegó a la solución de usar nCS de la RAM como CLK de la tarjeta SD, CLK de la RAM como CMD de la tarjeta SD y MOSI de la RAM como DAT de la tarjeta SD es un hack genial
    Al analizar las posibles interacciones con cada dispositivo, también resulta convincente que funcione de forma segura, y definitivamente merece estar en Hacker News

    • La frase “después de pensarlo un buen rato, la solución era clara” también quedaría perfecta como frase de camiseta
  • Siempre me da un poco de pena ver que usar un chip aparte para conectarse por USB se vuelva la opción predeterminada
    USB es un protocolo demasiado complejo, y más allá del nivel básico de V-USB para ejecutar USB 1.1 de baja velocidad, en general parece difícil sin hardware especial y una pila de software bastante grande
    En cambio, SPI es ridículamente simple: el hardware mínimo necesario es más o menos un registro de desplazamiento que pueda recibir el reloj lo bastante rápido
    Extraño la época en que, como en las desktops y laptops antiguas, había puertos serie/paralelo expuestos al exterior que permitían este tipo de comunicación de bajo nivel
    Si los periféricos simples hubieran usado UART, I2C y SPI multidrop a distancias cortas, con unas pocas frecuencias de reloj estándar y un único conector, y los dispositivos con muchos datos, como monitores o unidades externas, hubieran pasado directamente a IEEE 802.3 Ethernet, quizá no habría hecho falta soportar USB y Ethernet por separado, sino solo enlaces Ethernet

    • Es cierto que SPI es simple, y originalmente es un protocolo diseñado para implementarse con la menor cantidad posible de silicio con el fin de ahorrar presupuesto de transistores
      SPI no contempla varias comodidades que USB sí ofrece, como suministro de energía, hot-plug, descubrimiento de dispositivos o errores de bits
      Para un desarrollador de software tiene valor entender los modismos de SPI y la forma en que los diseñadores de hardware lo usan
      Normalmente SPI se usa para llenar registros de periféricos, y su naturaleza es distinta de la comunicación asíncrona de alto nivel que se suele ver en USB o Ethernet y en las capas de abstracción por encima
      No hay un estándar universal para las tramas SPI, pero sí patrones idiomáticos, y eso ha sido suficiente en innumerables aplicaciones
    • Suena como si se propusiera cambiar el USB PHY por un conversor serie-Ethernet y un Ethernet PHY
      En la práctica, protocolos simples como SPI e I2C no son suficientes
      No son rápidos, usan señalización de terminación única y por eso son muy sensibles al ruido, y tampoco tienen corrección de errores
      Estos protocolos encajan muy bien con su uso previsto, es decir, conectar IC entre sí sobre una PCB, pero si se expone al exterior un puerto sin terminación, es difícil garantizar algo
      Incluso en las PC modernas estos protocolos y sus variantes se usan mucho, pero solo como buses internos
      No he revisado en detalle la especificación de USB, pero es probable que el principal problema del bit-banging sea la velocidad requerida
      Como un microcontrolador no es lo bastante rápido para alternar pines y al mismo tiempo decodificar el protocolo y gestionar la corrección de errores, hace falta hardware dedicado
      Al hacer bit-banging de I2C también se puede encontrar el mismo problema
      Con una CPU de 20 MHz, el reloj máximo que se puede obtener es de unos 250 KHz, apenas algo más de la mitad de la velocidad máxima típica de 400 KHz, y la versión de 1 MHz es prácticamente imposible
      La razón por la que existen los PHY es que trasladar los protocolos de comunicación al hardware es abrumadoramente más barato
      De lo contrario habría que sobredimensionar mucho la CPU para disponer de recursos con los que gestionar manualmente la comunicación, y por eso los microcontroladores modernos incluyen hardware para I2C, SPI y comunicación serial
      En conclusión, protocolos seriales simples como SPI, I2C y UART son una muy mala elección para periféricos externos
      Es difícil hacerlos funcionar a velocidades adecuadas, y no toleran cables largos ni ruido
      Aunque RS-232 queda como excepción porque no es UART, por la naturaleza y el diseño de estos protocolos no pueden usarse de esa manera, y si se cambiara la especificación para soportarlo, al final se terminaría reinventando USB
    • En la industria AV, aunque el hardware nuevo supere los 10.000 dólares, RS-232 sigue siendo el rey para las señales de control entre dispositivos
      Las pantallas de señalización o los televisores para salas de reuniones a menudo también ofrecen RS-232 para un control más flexible que HDMI-CEC
      Muchas veces no se necesita una tasa de bits superior a 9600 bps, y el conector más común es un terminal de tornillo de 3 pines con Tx, Rx y GND
      En las instalaciones actuales casi siempre hay al menos un adaptador RS232-USB en alguna parte, y en salas grandes se puentea RS232 sobre Ethernet
      Cuando entré por primera vez en este campo me sorprendió, pero se entiende al considerar que muchas instalaciones tienen décadas y que sus componentes se han ido reemplazando uno por uno
    • El artículo repasa largamente los chips de 8 pines, pero omite el muy popular CH32V003
      Este chip cuesta alrededor de 0,10 dólares y funciona con 2 KB de RAM, 16 KB de Flash, 48 MHz y 1 CPI
      El nuevo CH570 también ronda los 0,10 dólares en SOIC8, pero trae 100 MHz, 16 KB de RAM, 256 KB de Flash, USB y hasta radio de paquetes de 2,4 GHz; ya pedí una placa de desarrollo
    • Hay muchos microcontroladores que pueden funcionar como dispositivo USB, pero esta vez se excluyeron por la restricción de encapsulado
  • Estaría bueno que también indicaran el grosor de la placa necesario para quienes quieran fabricar la placa por su cuenta
    Si no recuerdo mal, es de unos 0,8 mm, y ese grosor hace falta para que el “conector de borde USB-C” encaje en el enchufe

  • Es un artículo excelente, pero me pregunto si habría sido mucho más simple si el requisito de 8 pines se hubiera tomado con un poco más de flexibilidad
    Con solo unos pocos pines más, la complejidad del proyecto habría bajado mucho, y el tiempo de soldadura habría aumentado apenas un poco

    • Entonces no habría sido ningún desafío ni habría tenido gracia
      Hay muchos chips mucho más rápidos con USB integrado
      Allwinner V3s también se puede soldar a mano, tiene RAM integrada y arranca Linux de forma nativa sin problemas
      RP2350 también es una buena opción, con una excelente interfaz QSPI RAM con caché integrada y soporte USB
  • Es casi un proyecto de apenas 2 chips
    Uno es simplemente un IC USB a serial, y si no se cuenta la tarjeta SD, al incluirla vuelve a ser de 3
    Como la cantidad total de pines es tan baja, dan ganas de armarlo con el método dead bug

    • No hice una versión dead bug, así que si alguien la hace sería el primer caso
      Un adaptador de microSD a SD sirve bastante bien como soporte de microSD soldable
    • La propia tarjeta SD también tiene un procesador bastante potente, probablemente un ARM de 32 bits
      Hacer un truco similar apuntando a eso también sería un hack interesante
    • El IC USB a serial se puede sacar hacia un cable hecho por otra persona y así “no contarlo”, algo parecido a no contar la microSD
  • Técnicamente es un proyecto muy genial, pero parece haber llevado las cosas a un extremo que se aparta un poco del objetivo de crear un nuevo kit de computadora para principiantes
    Para un principiante no hay gran diferencia entre soldar un SOIC8 y soldar un SOIC28
    Diría que un SOIC28 es tan fácil o difícil como un SOIC8
    Si se usa un chip más grande, se le podría agregar sonido mínimo, teclado y, más adelante, incluso salida real a monitor tipo VGA, convirtiéndola en una computadora mucho más útil
    La dificultad de soldadura casi no aumenta, y se vuelve una buena base para que los usuarios interesados la amplíen

    • Exacto
      Si quieres hacer algo en esa dirección, puedes usar mi código
      Yo lo hice así porque me parecía divertida la restricción artificial de 8 pines
  • Me da un impulso extraño de omitir incluso la placa y hacerlo como una escultura de circuito

    • Si lo haces así, uno de los IC debería llevar “555” en la serigrafía
    • Sería bueno verlo
      Yo no soy artista ni escultor, así que no me atreví a intentarlo
  • Sería lindo usar Flash SPI de 8 pines como almacenamiento en vez de una tarjeta SD

    • Lo consideré, pero eso complica la forma de meter y sacar archivos
  • Dice que “por razones personales le tiene alergia a RISC-V”, y me da curiosidad saber por qué

    • No me gusta el conjunto de instrucciones
      No quiero iniciar una guerra santa; es solo mi opinión personal, pero bastante firme
      RISC-V fue diseñado lo suficientemente tarde en la historia como para poder aprovechar mucho conocimiento existente, pero creo que casi no lo aprovechó
      Por eso ahora se proponen varias extensiones para corregir cosas que deberían haberse hecho bien desde el principio
      Con cada vez más añadidos, recién después de 10 años empieza poco a poco a acercarse a algo que tiene sentido
      Tampoco me convence la excusa de que hacía falta un proceso de aprendizaje
      La información necesaria estaba disponible desde el inicio, y los errores eran claros para la mayoría de nosotros
      Algunas extensiones no son más que curitas sobre problemas de diseño fundamentales
      Por ejemplo, shadd2 es una curita para compensar la falta de un modo de direccionamiento adecuado para acceder a arreglos
      La respuesta habitual a eso es prometer una fusión mágica de instrucciones dentro del núcleo, algo que se promete a menudo pero que en la práctica no se ofrece
      Mucho menos en los procesadores baratos, que parecen ser el único objetivo de RISC-V
      La ausencia de instrucciones de extracción e inserción de campos de bits también es un error de aficionado, y por eso existe una extensión para corregirlo
      Pero debería haber sido evidente desde el principio que esa funcionalidad era necesaria
      Las instrucciones para hacer saltos condicionales según un bit específico dentro de un registro también aparecen con frecuencia, así que eran una función obvia que debió considerarse desde el inicio
      Un análisis mínimo del software moderno lo habría revelado
      Lo irritante es que la información ya existía
      Se sabía qué hace el software moderno, pero se ignoró todo, y el resultado, en mi opinión, fue un MIPS-1 apenas actualizado
      Ahora, con tantas extensiones pegadas encima, la fragmentación se volvió grave
      Uno podría apuntar a algo como RV23, un resultado final razonable en cierta medida, pero no hay hardware que lo implemente; o si no, hay que apuntar al mínimo común denominador que corre en todas partes pero funciona pésimamente
      Al intentar usar RISC-V para cómputo de alto rendimiento real hay problemas de diseño todavía más serios, pero eso lo dejo para el próximo rant
      Otro conjunto de instrucciones diseñado en una época similar sí aprovechó realmente el conocimiento sobre cómo es el software moderno, y el resultado se nota: aarch64
  • El proyecto en sí también es muy bueno, pero esta página además es un gran recurso para obtener información sobre microcontroladores pequeños
    Falta la familia WLCSP, pero también enlaza a la página del emulador de MIPS para ARM https://dmitry.gr/?r=05.Projects&proj=33.%20LinuxCard, que parece bastante interesante