- En esta práctica se desarrollara la implementación del Bus AXI para comunicar la parte PS con la PL y poder tener acceso a los puertos GPIO. El esquema siguiente muestra en general lo que se realizara:
- El sistema PL se encargara de controlar el display OLED y crear los módulos de interfaz I/O de 32 bits internos. Toda la descripción del hardware se hizo en DK Handel-C cuyo código principal se muestra a continuación:
par
{
while(1)
{
OledClear();
OledSetCursor(0, 0);
OledPutString("x[0-31] = ");
conv = b_itoab((signed 32)(LEDS_AXI_wrapper.salida_0_31_tri_o));
OledPutString(conv);
OledSetCursor(0, 2);
OledPutString("x[31-63] = ");
conv = b_itoab((signed 32)(LEDS_AXI_wrapper.salida_32_63_tri_o));
OledPutString(conv);
delay_ms(C_MHZ,1000);
}
while(1)
{
par
{
LEDS++;
PS_OUT_0_31++;
PS_OUT_32_63++;
}
delay_ms(C_MHZ,1000); //1000 ms
}
}
{
while(1)
{
OledClear();
OledSetCursor(0, 0);
OledPutString("x[0-31] = ");
conv = b_itoab((signed 32)(LEDS_AXI_wrapper.salida_0_31_tri_o));
OledPutString(conv);
OledSetCursor(0, 2);
OledPutString("x[31-63] = ");
conv = b_itoab((signed 32)(LEDS_AXI_wrapper.salida_32_63_tri_o));
OledPutString(conv);
delay_ms(C_MHZ,1000);
}
while(1)
{
par
{
LEDS++;
PS_OUT_0_31++;
PS_OUT_32_63++;
}
delay_ms(C_MHZ,1000); //1000 ms
}
}
El primer While se encarga de
recibir lo que está mandando la parte PS
e imprimiéndola en el display OLED separando los 2 canales de 32 bits.
En el segundo While PL estará enviando hacia PS el valor de los 2 canales de salida
de 32 bits. Para este demos solo se envía contadores incrementándose.
Nótese que los 2 whiles son independientes y se ejecutan en paralelo.
- La metodología aplicada para la creación PL (VIVADO - DK Handel-C) de la interfaz es la mostrada en la figura siguiente:
- La parte PS (VIVADO diagrama de bloques) queda de la siguiente manera:
A partir de este sistema se
obtiene el archivo AXI_GPIO.dcp parte sintetizable de vivado que servirá para
integrarlo en la PL (vivado y Dk Handel-C).
- La configuración de ZYNQ se muestra en las siguientes imágenes:
- La estructura de los archivos para PL es:
El archivo final que contiene tanto PL como PS es
AXI_GPIO.bit
- El código para la parte de SDK eclipse C/C++ es el siguiente:
/*****************************************************************************/
/* I N C L U D E F I L E S */
/*****************************************************************************/
#include <stdio.h>
#include "xparameters.h"
#include "xgpio.h"
#include "xuartps.h"
#include "xtime_l.h"
#include "xscugic.h"
#include "xil_exception.h"
/*****************************************************************************/
/* C O N S T A N T S */
/*****************************************************************************/
//The
following constant maps to the name of the hardware instances that
//
were created in the Vivado system.
#define
INTC_DEVICE_ID
XPAR_PS7_SCUGIC_0_DEVICE_ID
#define
INTC_GPIO_INTERRUPT_ID
XPAR_FABRIC_AXI_GPIO_1_IP2INTC_IRPT_INTR
#define
INTC XScuGic
#define
INTC_HANDLER
XScuGic_InterruptHandler
#define
BUTTON_INTERRUPT
XGPIO_IR_MASK
#define
CPU_CLOCK_FREQ XPAR_PS7_CORTEXA9_0_CPU_CLK_FREQ_HZ
#define
FPGA_CLOCK_FREQ 100000000
#define
GPIO_EXAMPLE_DEVICE_ID
XPAR_AXI_GPIO_0_DEVICE_ID
#define
GPIO_EXAMPLE_DEVICE_ID_1 XPAR_AXI_GPIO_1_DEVICE_ID
//
The following constant is used to determine which channel of the GPIO is
//
used for the LED if there are 2 channels supported.
#define
LED_CHANNEL_1 1
#define
LED_CHANNEL_2 2
/*******************************************************************************/
/*
F U N C T I O N D E C L A R A T
I O N S */
/*******************************************************************************/
int SetupInterruptSystem ();
void GpioIsr (void
*InstancePtr);
/*****************************************************************************/
/* V A R I A B L E
S */
/*****************************************************************************/
XUartPs Uart_Ps; /* The instance of the UART Driver */
XGpio Gpio, Gpio1; // The Instance of the GPIO Driver
static INTC Intc;
/*****************************************************************************/
/* M A I N */
/*****************************************************************************/
int main(void)
{
int Status,SentCount = 0;
long int
ust_limit = 83333323;
long int
delay, i;
XUartPs_Config *Config;
u8 HelloZynq[] = "Hello Zynq\n";
long int
a,b;
XTime t1, t2;
//
Initialize the UART 1 driver
Config = XUartPs_LookupConfig(XPAR_PS7_UART_1_DEVICE_ID);
if (NULL == Config)
{
return
XST_FAILURE;
}
Status =
XUartPs_CfgInitialize(&Uart_Ps, Config, Config->BaseAddress);
if (Status != XST_SUCCESS)
{
return
XST_FAILURE;
}
// Initialize
the GPIO driver
Status = XGpio_Initialize(&Gpio,
GPIO_EXAMPLE_DEVICE_ID);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XGpio_Initialize(&Gpio1,
GPIO_EXAMPLE_DEVICE_ID_1);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = SetupInterruptSystem();
if (Status !=
XST_SUCCESS) {
return XST_FAILURE;
}
//
Clear the LEDs
XGpio_DiscreteWrite(&Gpio,
LED_CHANNEL_1, 0);
XGpio_DiscreteWrite(&Gpio,
LED_CHANNEL_2, 0);
printf("
Microcarsil, 2014\n");
while (1)
{
for(i=0;i<4294967295;i++) // 32
bits = 0-4294967295
{
//a =
XGpio_DiscreteRead(&Gpio1, LED_CHANNEL_1);
//b =
XGpio_DiscreteRead(&Gpio1, LED_CHANNEL_2);
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL_1,
i);
XGpio_DiscreteWrite(&Gpio, LED_CHANNEL_2,
i);
XTime_GetTime(&t1); // Get time before delay
for(delay=0;delay<ust_limit;delay++){};
XTime_GetTime(&t2); // Get time after delay
u32 clocks = 2 * (t2 - t1); // Compute time for memcpy (Note: ARM PERIPHCLK
is twice period of CPU clock)
float dt = (float)clocks
/ (float)CPU_CLOCK_FREQ; //
Compute clock time
//printf(" CPU_CLOCK_FREQ = %d MHz\n", CPU_CLOCK_FREQ);
//printf(" CPU clocks = %d\n", clocks);
//printf(" CPU Time = %f\n", dt);
//printf(" PS_OUT_0_31 = %d\n", a);
//printf(" PS_OUT_32_63 = %d\n", b);
//Send
"Hello Zynq"
//
while (SentCount < (sizeof(HelloZynq) - 1))
//{
//SentCount += XUartPs_Send(&Uart_Ps,
&HelloZynq[SentCount], 1);
//}
//SentCount
= 0;
//while
(!XUartPs_IsReceiveData(Config->BaseAddress));
//XUartPs_Recv(&Uart_Ps, &RecvBuf[RecvCount],
1);
}
}
return XST_SUCCESS;
}
/*******************************************************************************/
/* I N T E R R U P T S E R V I C E R O U T I N E */
/*******************************************************************************/
void GpioIsr(void
*InstancePtr)
{
u32 a,b;
XGpio *GpioPtr =
(XGpio
*)InstancePtr;
// Disable the interrupt
XGpio_InterruptDisable(GpioPtr,
BUTTON_INTERRUPT);
// There should not be any other interrupts occuring
other than the the button changes
if
((XGpio_InterruptGetStatus(GpioPtr) & BUTTON_INTERRUPT)!= BUTTON_INTERRUPT)
{
return;
}
// Read state of push buttons and determine which ones
changed
// states from the previous interrupt. Save a copy of
the buttons
// for the next interrupt
a = XGpio_DiscreteRead(&Gpio1,
LED_CHANNEL_1);
b = XGpio_DiscreteRead(&Gpio1,
LED_CHANNEL_2);
printf("
PS_OUT_0_31 = %d\n", a);
printf("
PS_OUT_32_63 = %d\n\n", b);
// Clear the interrupt such that it is no longer
pending in the GPIO
(void)XGpio_InterruptClear(GpioPtr,
BUTTON_INTERRUPT);
// Enable the interrupt
XGpio_InterruptEnable(GpioPtr, BUTTON_INTERRUPT);
}
/*******************************************************************************/
/* S E
T U P I N T E R R U P T S Y S T E M */
/*******************************************************************************/
int SetupInterruptSystem()
{
int Result;
INTC *IntcInstancePtr = &Intc;
XScuGic_Config
*IntcConfig;
// Initialize the interrupt controller driver so that
it is ready to use.
IntcConfig =
XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig)
{
return
XST_FAILURE;
}
Result =
XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Result !=
XST_SUCCESS) {
return
XST_FAILURE;
}
XScuGic_SetPriorityTriggerType(IntcInstancePtr,
INTC_GPIO_INTERRUPT_ID,
0xA0,
0x3);
// Connect the interrupt handler that will be called
when an
// interrupt occurs for the device.
Result =
XScuGic_Connect(IntcInstancePtr, INTC_GPIO_INTERRUPT_ID,
(Xil_ExceptionHandler)GpioIsr, &Gpio1);
if (Result !=
XST_SUCCESS) {
return Result;
}
// Enable the interrupt for the GPIO device.
XScuGic_Enable(IntcInstancePtr,
INTC_GPIO_INTERRUPT_ID);
// Enable the GPIO channel interrupts so that push
button can be
// detected and enable interrupts for the GPIO device
XGpio_InterruptEnable(&Gpio1, BUTTON_INTERRUPT);
XGpio_InterruptGlobalEnable(&Gpio1);
// Initialize the exception table and register the
interrupt
// controller handler with the exception table
Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)INTC_HANDLER, IntcInstancePtr);
// Enable non-critical exceptions
Xil_ExceptionEnable();
return
XST_SUCCESS;
}
- En la siguiente imagen se muestra corriendo y funcionando la interfaz.
No hay comentarios.:
Publicar un comentario