2021/09/23

H4CK3D 2021: un desvío innecesario

Recordemos, para la charla necesito comprender como funciona, por una cuestión de completitud y para colaborar con el proyecto edu-ciaa-fpga terminé de incorporar el conector arduino y un pmod como input.

Para el ataque de la charla, viene bien tener un evento de activación, o sea, que no funcione siempre sino en un rango temporal reducido para que sea más difícil que salte en un test, para ello necesito algo que lleve el tiempo, un reloj, independiente del programa, lo llamé ambiciosamente RTC pero es mucho menos, es un trocito de verilog que cuenta los segundos y minutos y desborda a la hora.

¿Por qué no me sirve un reloj por software? pues por que para ello necesitaría software colgado de systick o similar y saber en la RAM donde guarda el valor. Me pareció más sencillo y sin colisión con un escenario real el circuito independiente.

Es muy sencillo:

counter <= counter + 1;
if (counter == COUNT ) begin
  counter <= 0;
  secondsLo <= secondsLo + 1;
  if (secondsLo == 9) begin
    secondsLo <= 0;
    secondsHi <= secondsHi + 1;
    if (secondsHi == 5) begin
      secondsHi <= 0;
      minutesLo <= minutesLo + 1;
      if (minutesLo == 9) begin
        minutesLo <= 0;
        minutesHi <= minutesHi + 1;
        if (minutesHi == 5) begin
          minutesHi <= 0;
        end
      end
    end
  end
end

Te juro que quise tomarlo de uno existente, pero eran muy complicados, quizás no sea una maravilla pero funciona.

En la primera versión tiré eso dentro de un always en el top.sv y lo conecté al arduino, pero era muy sucio y no manifestaba desafío, entonces decidí convertirlo en un módulo y además conectarlo a los buses de datos, direcciones y control como cualquier otro dispositivo.

Como es un módulo, existe en su propio .sv, rtc.sv y en icicle.sv hay que incluirlo:

`include "rtc.sv"

 

Luego hay que agregar el registro donde se lo lee:

logic [31:0] rtc_read_value;

 

y su asignación al registro de lectura:

assign mem_read_value =
       ram_read_value |... | rtc_read_value | ...;

 

Las señales de selección: 

logic rtc_sel;

Las de ready:

logic rtc_ready;
assign mem_ready = ram_ready | ... | rtc_ready | ...;


Mapearlo al direccionamiento:


32'b..001_00000000_000101??: rtc_sel = 1; //0x00010014


Y finalmente a los buses:

 

rtc #(.COUNT(36000000)) rtc (
    .clk_in(clk),
    .reset(reset),
    /* memory bus */
    .address_in(mem_address),
    .sel_in(rtc_sel),
    .read_in(mem_read),
    .read_value_out(rtc_read_value),
    .write_mask_in(mem_write_mask),
    .write_value_in(mem_write_value),
    .ready_out(rtc_ready)
);

 

Puse las señales de escritura tambien, no por copiar y pegar sino por que en el diseño original, en la flash que entiendo no se puede escribir tal como está, están presentes. Intuyo que dado que no se usan no se sintetizan, así que no molestan e igual me queda para el futuro si quisiera cambiar la hora desde el programa.


En el rtc.sv, además de conectar los buses, como la lectura es inmediata:


assign ready_out = sel_in;

Y la lectura proviene de:


assign read_value_out = 

{16'b0,
 sel_in ?
   {minutesHi,minutesLo,secondsHi,secondsLo}
   : 16'b0};


Como usa 16 bits (cuatro para cada dígito), los primeros 16 son ceros. Si está activo sel_in, van los valores apropiados, sino, otros 16 ceros.

Finalmente el programa de ejemplo, lo basé en el hello original para recuperar la uart, el mapeo se hace con:


#define RTC    *((volatile uint32_t *) 0x00010014)


El main lo que hace es leer el RTC, lo copia al conector de arduino para manifestar los valores binarios y 

 

for (;;) {

    uint32_t rtc = RTC;
    ARDUINO = rtc;
    msg[5] = ((rtc & 0xf000 ) >> 12 ) + '0';
    msg[6] = ((rtc & 0xf00 ) >> 8 ) + '0';
    msg[8] = ((rtc & 0xf0 ) >> 4 ) + '0';
    msg[9] = ( rtc & 0xf ) + '0';
    uart_puts(msg);
    LEDS = ~LEDS;
    uint32_t start = rdcycle();
    while ((rdcycle() - start) <= FREQ);
}


Con los msg[x] se parchea un mensaje:

"RTC: ..:..\r\n";


Va tomando de a cuatro bits, los desplaza al nibble menos significativo y lo convierte en el ascii apropiado sumándolo al caracter '0'.


Este mensaje lo tuve que definir con:


    char msg[13];
    msg[0]='R';
    msg[1]='T';
    msg[2]='C';
    msg[3]=':';
    msg[4]=' ';
    msg[5]='.';
    msg[6]='.';
    msg[7]=':';
    msg[8]='.';
    msg[9]='.';
    msg[10]='\r';
    msg[11]='\n';
    msg[12]='\0';

 

En lugar de:

 

char msg[] = "RTC: ..:..\r\n";

 

Debido a este mensaje de error, cuyo significado intuyo pero prefiero no decir nada sin fundamentos para no generar información errónea:

 

/usr/local/lib/gcc/riscv64-unknown-elf/11.1.0/../../../../riscv64-unknown-elf/bin/ld: /usr/local/lib/gcc/riscv64-unknown-elf/11.1.0/../../../../riscv64-unknown-elf/lib/libc.a(lib_a-memcpy.o): ABI is incompatible with that of the selected emulation:
 

target emulation `elf64-littleriscv' does not match `elf32-littleriscv'

 

Funciona ok, el programa toma el valor del RTC y lo pone en el arduino, falta video, creeme y lo muestra en la uart:

 

Minutos y segundos transcurridos desde el inicio
Minutos y segundos transcurridos desde el inicio, reset o último overflow

 







No hay comentarios:

Publicar un comentario