¡Hola! Quiero presentarte el proyecto Rust Embedded . Nos permite utilizar el lenguaje de programación Rust para el desarrollo de plataformas integradas (Linux incorporado / RTOS / Bare Metal).
En este artículo, consideraremos los componentes necesarios para comenzar el desarrollo de los microprocesadores Cortex-M3. Después de eso, escribiremos un ejemplo simple: parpadeo del LED incorporado.Para hacer esto, necesitamos una placa de depuración china asequible y barata STM32F103C8T6 o Black Pill (debido al color negro y al tamaño pequeño). También hay una versión del tablero en azul: Blue Pill. No lo recomiendo, ya que escuché que tiene una resistencia incorrecta, lo que causa problemas al usar el puerto USB. Su segunda diferencia de la píldora negra en la disposición de los pines (conclusiones). Pero más sobre eso más tarde.También necesitaremos un programador para placas de depuración STM32. En este artículo, utilizaremos el programador chino ST-Link V2 barato y asequible.
Versión del compilador de óxido
Para comenzar, debe asegurarse de que su versión del compilador sea 1.31 o más reciente. Puede verificar la versión de su compilador ingresando el comando:> rustc --version
Instalación de componentes
Ahora podemos comenzar a instalar los componentes necesarios.GNU Arm Embedded Toolchain
Necesitaremos un depurador para chips ARM: arm-none-eabi-gdb. Inicie el instalador y siga las instrucciones. Al final de la instalación, asegúrese de marcar la opción " Agregar ruta a la variable de entorno ".Enlace de descargaDespués de la instalación, puede verificar si todo está en orden ingresando lo siguiente en la línea de comando:> arm-none-eabi-gdb -v
Si todo está en orden, verá la versión del componente instalado.Controlador ST-Link
Pasemos a instalar el controlador para el programador ST-Link.Siga las instrucciones del instalador y asegúrese de instalar la versión correcta ( sesenta y cuatro bits o treinta y dos bits ) del controlador, dependiendo de la profundidad de bits de su sistema operativo.Enlace para descargarHerramientas ST-Link
El siguiente paso es instalar las herramientas necesarias para el firmware: Herramientas ST-Link. Descargue el archivo comprimido y descomprímalo en cualquier lugar conveniente, también debe especificar la ruta a la subcarpeta bin ( stlink-1.3.0 \ bin ) en la variable de entorno " PATH ".Enlace para descargarcarga-binutils
Finalmente, instale el paquete cargo-binutils, esto se realiza mediante dos comandos en la consola.> cargo install cargo-binutils
> rustup component add llvm-tools-preview
Esto completa la instalación de componentes.Crear y configurar un proyecto
Para continuar, necesitamos crear un nuevo proyecto con el nombre " stm32f103c8t6 ". Déjame recordarte que esto se hace mediante el comando:> cargo new stm32f103c8t6
Dependencias y Optimización de Proyectos
Conecte las bibliotecas necesarias en el archivo Cargo.toml :[package]
name = "stm32f103c8t6"
version = "0.1.0"
authors = ["Nick"]
edition = "2018"
# Cortex-M3
[dependencies]
cortex-m = "*"
cortex-m-rt = "*"
cortex-m-semihosting = "*"
panic-halt = "*"
nb = "0.1.2"
embedded-hal = "0.2.3"
# stm32f1
[dependencies.stm32f1xx-hal]
version = "0.5.2"
features = ["stm32f100", "rt"]
# `cargo fix`!
[[bin]]
name = "stm32f103c8t6"
test = false
bench = false
#
[profile.release]
codegen-units = 1 #
debug = true # , Flash
lto = true #
Además, puede ver que, al final del archivo, se ha habilitado la optimización del código.La biblioteca cortex-m-rt requiere que creemos un archivo en el directorio raíz del proyecto, debe llamarse " memory.x ". Indica cuánta memoria tiene nuestro dispositivo y su dirección:MEMORY
{
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 20K
}
Establecer la plataforma objetivo y los objetivos de compilación predeterminados
Es necesario establecer la plataforma de destino para el compilador, esto se hace mediante el comando:> rustup target add thumbv7m-none-eabi
Después de eso, cree la carpeta " .cargo " en el directorio raíz y el archivo " config " en él .El contenido del archivo de configuración :[target.thumbv7m-none-eabi]
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
rustflags = ["-C", "link-arg=-Tlink.x"]
[build]
target = "thumbv7m-none-eabi" # Cortex-M3
En él, identificamos el objetivo de compilación predeterminado, esto nos permite compilar nuestro código en un archivo ARM .elf con un comando simple y familiar:> cargo build --release
Ejemplo
Para asegurarse de que funciona, considere el ejemplo más simple: parpadear un LED.El contenido del archivo main.rs :#![deny(unsafe_code)]
#![no_std]
#![no_main]
use panic_halt as _;
use nb::block;
use stm32f1xx_hal::{
prelude::*,
pac,
timer::Timer,
};
use cortex_m_rt::entry;
use embedded_hal::digital::v2::OutputPin;
#[entry]
fn main() -> ! {
let cp = cortex_m::Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let clocks = rcc.cfgr.freeze(&mut flash.acr);
let mut gpiob = dp.GPIOB.split(&mut rcc.apb2);
let mut led = gpiob.pb12.into_push_pull_output(&mut gpiob.crh);
let mut timer = Timer::syst(cp.SYST, &clocks)
.start_count_down(1.hz());
loop {
block!(timer.wait()).unwrap();
led.set_high().unwrap();
block!(timer.wait()).unwrap();
led.set_low().unwrap();
}
}
En la primera línea, usando el atributo - #![deny(unsafe_code)]
, eliminamos la posibilidad de usar código inseguro.En la segunda línea, colocamos el atributo #![no_std]
, es obligatorio, porque estamos creando una aplicación para hierro puro, y la biblioteca estándar necesita un sistema operativo.Luego viene un atributo #![no_main]
que le dice al compilador que no estamos usando la función predeterminada predeterminada con el vector de argumento y el tipo de retorno. Esto no tiene sentido, ya que no tenemos un sistema operativo u otro tiempo de ejecución que llame a la función y procese el valor de retorno.Después de los atributos, conectamos los módulos necesarios en el ámbito.Esto es seguido por una función, en nuestro caso, por costumbre, la llamamos:main()
. Este es el punto de entrada al programa, está determinado por el atributo #[entry]
.Dentro de la función principal, creamos un identificador para un objeto periférico que "posee" todos los dispositivos periféricos.Después de eso, podemos configurar el pin responsable de la salida del LED integrado en la placa. Como en mi caso es una placa de píldora negra , el LED está conectado al pin B12 . Si tiene una placa de píldora azul , entonces el pin C13 es responsable del LED incorporado . Por lo tanto, configuramos el pin B12 como una salida push-pull y lo asignamos a una variable led
.Ahora podemos establecer el tiempo de activación del evento de actualización para el temporizador del sistema y guardarlo en una variabletimer
. En nuestro ejemplo, esta vez es un segundo.Luego, en un bucle sin fin, podemos describir la lógica de nuestro programa. Es muy simple, primero timer
bloquea la ejecución del programa hasta que el tiempo especificado en él haya pasado. El siguiente paso es configurar el pin del LED incorporado en alto , para que se ilumine. Después de eso, la ejecución del programa se bloquea nuevamente por el mismo temporizador, durante un segundo. Y el pin del LED está configurado en bajo , por lo tanto se apaga. Además, el programa se repite cíclicamente.Compilacion
Ahora que hemos descubierto el código y la lógica del programa, podemos compilarlo en un archivo .elf con el comando:> cargo build --release
Este formato contiene no solo código binario, sino también algunos encabezados y más. Esto es útil cuando el archivo se inicia con otro software, como el sistema operativo o el gestor de arranque.Pero, para ejecutar el programa en el bare metal, no necesitamos un archivo .elf , sino un archivo .bin . Un archivo .bin es una imagen de software que puede escribirse en bytes en la memoria del microcontrolador. El archivo .elf se puede convertir a un archivo .bin usando el comando:> cargo objcopy --bin stm32f103c8t6 --target thumbv7m-none-eabi --release -- -O binary stm32f103c8t6.bin
Ahora nuestro archivo binario está listo para el firmware.Conexión
Vamos a flashear la placa usando el programador ST-Link V2. Para hacer esto, primero debe conectarlo a la placa.En la caja del programador hay una disposición de pines del conector. Debe prestar atención al recorte en el conector, también se muestra en el diagrama, lo que le permite comprender cómo realizar la conexión.Conecte los pines 3.3V y GND del programador con los pines correspondientes en la placa. Haga ping a SWDIO connect para fijar el DIO y pin SWCLK para fijar el CLK .Después de conectar la placa al programador, podemos conectar el ST-Link a la computadora.¡Atención!Antes de conectar, desconecte todas las demás fuentes de alimentación de la placa, si las hay, de lo contrario podría dañar la placa o la computadora.Ahora podemos verificar la conexión:> st-info --descr
En la consola, deberíamos ver la línea " F1 Dispositivo de densidad media ".Firmware
Opcionalmente, antes de flashear, puede borrar la memoria de la pizarra si hay algo escrito en ella:> st-flash erase
Finalmente, podemos iniciar el firmware:> st-flash write stm32f1.bin 0x8000000
Si todo se hace correctamente, debería ver un LED parpadeante. ¡Felicidades!Conclusión
Entonces, para actualizar el tablero, debe usar este conjunto de comandos ingresados secuencialmente:> cargo build --release
> cargo objcopy --bin stm32f103c8t6 --target thumbv7m-none-eabi --release -- -O binary stm32f103c8t6.bin
> st-flash erase
> st-flash write stm32f1.bin 0x8000000
Para simplificar nuestra vida, podemos crear un archivo .bat con estos comandos y ejecutarlo desde la consola.Del autor
Si está interesado en estas guías, bienvenido a mi canal de YouTube .Además, recientemente, comencé un canal de Telegram donde publico varias traducciones de manuales y libros, noticias, humor y otras cosas relacionadas con el lenguaje de programación Rust. Allí puede encontrar enlaces a varias salas de chat para hacer sus preguntas y obtener ayuda, enviar sus proyectos o simplemente chatear con personas de ideas afines.¡Gracias por la atención!