2021/10/10

H4CK3D 2021: sigue el desvío, para bien

Esto más que H4CK3D debería llamarse... no sé, queda H4CK3D pues todas estas entradas son lo que no me alcanzaría jamás el tiempo para mostrar en una charla de una conferencia, es toda la investigación previa, la familiarización con el entorno y las herramientas.


Además, se viene la charla y quizás esté un poquito retrasado, eso me pone en modo procrastinador productivo, no hago lo que debería pero si algo útil en su lugar.

 

La excusa de hoy es haber agregado un módulo de servo. ¿Qué es un servo? Sos una de las pocas personas que lee este blog y calculo que deberías estar en sintonía con estos temas, así que si no sabés, podés buscar mejores detalles en Internet, pero te hago un resumen.

 

Es un motorcito con unos engranajes que dependiendo de una señal se posiciona en un ángulo. Esa señal es un pulso que debe cumplir con que el período sea de 20ms y el pulso mida entre 1 y 2 ms.

 

Servo al máximo
Servo al máximo

Servo al mínimo
Servo al mínimo

Esa forma se puede obtener en un microcontrolador con este sencillo programa,


#define PERIOD    0.020
#define MIN_WIDTH 0.001
#define MAX_WIDTH 0.002
float period = PERIOD;
float width = MIN_WIDTH;
int main() {
    DigitalOut servo1(PC_8);   
    while(1) {
       for(int i=0; i< 200; ++i) {
          servo1=1;
          wait(MIN_WIDTH);
          servo1=0;
          wait(PERIOD - MIN_WIDTH);
       }    
       for(int i=0; i< 200; ++i) {
          servo1=1;
          wait(MAX_WIDTH);
          servo1=0;
          wait(PERIOD - MAX_WIDTH);
       }    
    }


La versión completa en  https://os.mbed.com/users/cpantel/code/servo_software/

 

Si ya programaste alguna vez un microcontrolador o si pensás un rato, notarás que no bien quieras hacer algo más, vas a tener tocar los wait()s para compensar, una pesadilla inmanejable. Podrías entonces usar un timer que genere excepciones pero la verdad es que buena parte del los microcontroladores, al menos todos los que me he cruzado, que no son muchos, tiene un dispositivo llamado PWM al que le decís generame pulsos de tales características y lo hacen, aunque hayas logrado colgar al micro.

 

#define PERIOD    0.020
#define MIN_WIDTH 0.001
DigitalIn openButton(D4);
DigitalIn moveUpButton(D5);
DigitalIn moveDownButton(D6);
DigitalIn closeButton(D7);
PwmOut led1(LED1);
PwmOut servo1(PC_8);
PwmOut servo2(PC_9);
float period = PERIOD;
float width = MIN_WIDTH;
int main() {
    servo1.period(PERIOD);
    servo1.pulsewidth(width);
    while (1) {
// hacé lo que quieras acá
    }
}


Listo,un ejemplo más completo que según aprietes los botones mueve el servo en

https://os.mbed.com/users/cpantel/code/servo_PWM/

Volviendo a la cpu risc v en la edu-ciaa-fpga, agregué un PWM restringido, que sólo sirve para manejar un servo. Esto es, con un PWM normal puedo darle por software cualquier frecuencia y duración de pulso, lo cual no necesariamente es correcto. Con el módulo servo, no importa lo que hagas en software, la salida va a ser correcta.


Tuve algunas dificultades, por ejemplo, tengo módulos en los que puedo leer (rtc), en este escribir, pero no pude leer y escribir, ya le dedicaré un rato a ello.

 

La otra, es que tuve que implementar con una condición lógica bastante larga en lugar de unos case que más adelante me hubiesen permitido usar funciones más avanzadas de (system)verilog para generar los casos, ya le dedicaré un rato a ello.

Ya que estaba, aproveché para mejorar los ifdef que habilitan los puertos y los módulos. Antes hubiese sido así:

En top.sv:


`ifdef ARDUINO
    output logic [31:0] arduino,
`endif

y en la instanciación de icicle, en la interfaz:

`ifdef ARDUINO
        .arduino(arduino),
`endif

 

luego en icicle.sv:

 

`ifdef ARDUINO
    //código...

 

El problema es que al hacer el servo, que usa un pin del arduino, tenía que medio hackearle ese pin pues al habilitar ARDUINO, los pines los usaba el módulo arduino. Lo que hice fue separar en _CONN y _DEV, lo cual me permite habilitar los pines del arduino y luego conectarlos al módulo arduino o no instanciar ese módulo y usarlos desde otro.

Esto nos lleva a que cada programa puede usar distintas configuraciones de hardware, asi que además agregué que a los defines.sv que se le copia la base de la placa, se le agreguen lo que el programa pida, entonces en boards/edufpga-defines.sv tengo


// Defines for EDU-FPGA
`define noPMOD0_DEV
`define noPMOD1_DEV
`define noARDUINO_DEV
`define noRTC_DEV
`define noSERVO_DEV
`define noUART_DEV

`define noPMOD0_CONN
`define noPMOD1_CONN
`define noARDUINO_CONN

que cumple la función de documentar que hay disponible, luego en programs/servo_device/edufpga-defines.sv:

// Defines for servo_device running in EDU-FPGA
`define SERVO_DEV
`define UART_DEV

`define ARDUINO_CONN

y esto se arma en el Makefile:

cat boards/$(BOARD)-defines.sv programs/$(PROGRAM)/$(BOARD)-defines.sv > defines.sv

 

En el mismo camino de facilitar cambiar el programa, pasé a un .h el mapa de memoria, actualmente:


#define LEDS        *((volatile uint32_t *) 0x00010000)
#define BUTTONS     *((volatile uint32_t *) 0x00010004)
#define PMOD0       *((volatile uint32_t *) 0x00010008)
#define PMOD1       *((volatile uint32_t *) 0x0001000c)
#define ARDUINO     *((volatile uint32_t *) 0x00010010)
#define RTC         *((volatile uint32_t *) 0x00010014)
#define SERVO       *((volatile uint32_t *) 0x00010018)
#define UART_BAUD   *((volatile uint32_t *) 0x00020000)
#define UART_STATUS *((volatile uint32_t *) 0x00020004)
#define UART_DATA   *((volatile  int32_t *) 0x00020008)
#define MTIME       *((volatile uint64_t *) 0x00030000)
#define MTIMECMP    *((volatile uint64_t *) 0x00030008)

Con todos estos cambios, si algún día alguien quiere portar el programa a otra placa, le va a resultar más fácil.

Esto me llevó, por completitud, a adaptar todo el "legacy", comprobar que todos los programas funcionen, probablemente, con un poco de suerte... https://github.com/cpantel/evilCodeSequence/tree/v0.2.0


Me faltaría documentar un poco en el readme, uno de estos dias...




 

 




No hay comentarios:

Publicar un comentario