Hola,
Tenemos un nuevo video en el canal sobre como crear un timer en VHDL y conectarlo a un procesador ARM dentro de una FPGA Zynq. Todo ello desde cero.
Cuando creamos periféricos para conectar un procesador embebido como un Microblaze o un ARM en las Zynq, siempre tendemos a utilizar métodos de polling, es decir, tener un bit en un registro y estar todo el rato preguntando si el periférico ha terminado ya de ejecutar la tarea. Este método es muy sencillo, y si no tenemos que hacer nada mas que hacer mientras esperamos a que termine el periférico es suficiente.
No obstante, muchas veces si que tenemos que atender a varias tareas y en esas ocasiones el polling no es suficiente y es necesario utilizar interrupciones. A lo largo de los años he visto cosas increíbles que hace la gente con tal de no utilizar interrupciones, tienen un halo de misterio y fama de difíciles que hace que la gente las evite a toda costa.
Si que es cierto que en ocasiones si que tenemos un sistema operativo y varias fuentes de interrupciones pueden dar lugar a fallos misteriosos, pero en nuestras aplicaciones bare metal son muy sencillas de utilizar. En el siguiente video veremos cómo crear un sistema completo para la FPGA Zynq con un pequeño periférico que crea interrupciones cada cierto tiempo. El software dentro del ARM nos avisará cada vez que esto ocurra a través del puerto serie.
Os dejamos el video y debajo todo el código utilizado.
Indice de contenido
Timer en VHDL
library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity interrupt is port( clk : in std_logic; int_o : out std_logic ); end interrupt; architecture Behavioral of interrupt is type contador_t is range 0 to 100000000; signal contador : contador_t; begin process(clk) begin if (clk'event and clk='1') then int_o <= '1'; if(contador = contador_t'high) then contador <= 0; int_o <= '1'; else contador <= contador + 1; end if; end if; end process; end Behavioral;
Código fuente del programa para el procesador ARM
#include <stdio.h> #include "platform.h" #include "xil_printf.h" #include "xparameters.h" #include "xscugic.h" #include "xil_exception.h" #define INTC_INTERRUPT_ID 61 // IRQ [0] #define INTC XScuGic #define INTC_HANDLER XScuGic_InterruptHandler #define INTC_DEVICE_ID XPAR_PS7_SCUGIC_0_DEVICE_ID static INTC Intc; void PIsr(void *InstancePtr){ // INTERRUPT SERVICE ROUTINE(ISR) xil_printf("Received"); } int SetupInterruptSystem() { int result; XScuGic *IntcInstancePtr = &Intc; XScuGic_Config *IntcConfig; IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); if (IntcConfig == NULL) { return XST_FAILURE; } result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress); if (result != XST_SUCCESS) { return XST_FAILURE; } /* Connect the interrupt handler */ result = XScuGic_Connect(IntcInstancePtr, INTC_INTERRUPT_ID, (Xil_ExceptionHandler) PIsr, 0); if (result != XST_SUCCESS) { return result; } XScuGic_SetPriorityTriggerType(IntcInstancePtr, INTC_INTERRUPT_ID, 0xA0, 0x3);// 0x3 is trigger to rising edge /* Enable the interrupt for the controller device. */ XScuGic_Enable(IntcInstancePtr, INTC_INTERRUPT_ID); /* Enable interrupts in the ARM*/ Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr); Xil_ExceptionEnable(); /* Enable non-critical exceptions */ return XST_SUCCESS; } int main(void) { int status = XST_SUCCESS; status = SetupInterruptSystem(); if (status != XST_SUCCESS) { return XST_FAILURE; } print("Hola\n"); return 0; }