Microblaze lelkivilág...

     A mai bejegyzés egy kicsit rámutat a Microblaze softcore processzor lelkivilágának sötét bugyraira. Egy pár tipikus hibát szeretnék elemezni, ami szerintem egy idő után úgyis mindenkinél (aki aktivan foglalkozik a témával) elő fog jönni...

     Tehát. Adott a következő kód:

#include "xparameters.h"

#include "stdio.h"

#include "xutil.h"

#include "xuartlite.h"

#include "xuartlite_l.h"

#include "xintc_l.h"

#include "xgpio.h"

//====================================================
// Definitions
//====================================================

#define BAUDRATE 115200
#define USE_PARITY 0
#define PARITY_ODD 1
#define DATABITS 8

//====================================================
// GLOBAL VARIABLES
//====================================================
unsigned int counter = 0;
unsigned int c2 = 0;
int buchstabe;
XGpio leds;
XUartLite serial,second_serial;

//====================================================
// INTERRUPT HANDLER FUNCTION
//====================================================

void serial_interrupt_handler(void* addr_p)
{ 
    int empty;
        //XGpio_DiscreteWrite(&leds, 1, 255);
            empty = XUartLite_IsReceiveEmpty(XPAR_RS232_PORT_BASEADDR);
            if (empty == FALSE )
            buchstabe = XUartLite_RecvByte(XPAR_RS232_PORT_BASEADDR);
        //XGpio_DiscreteWrite(&leds, 1, buchstabe);
        xil_printf("::%c::",buchstabe);
}

void second_serial_interrupt_handler(void* addr_p)
{ 
    int empty;
        //XGpio_DiscreteWrite(&leds, 1, 255);
            empty = XUartLite_IsReceiveEmpty(XPAR_RS232_SECOND_BASEADDR);
            if (empty == FALSE )
            buchstabe = XUartLite_RecvByte(XPAR_RS232_SECOND_BASEADDR);
        //XGpio_DiscreteWrite(&leds, 1, buchstabe);
        xil_printf("XX%cXX",buchstabe);
}

//====================================================
// Delay
//====================================================

void ussleep(unsigned int delay)
{
unsigned int j, i; 

for(i=0; i<delay; i++)
   for(j=0; j<100; j++);
}


void mssleep(unsigned int delay)
{
unsigned int j, i; 

for(i=0; i<delay; i++)
   for(j=0; j<100; j++)
        ussleep(1);
}

void ssleep(unsigned int delay)
{
unsigned int j, i; 

for(i=0; i<delay; i++)
   for(j=0; j<100; j++)
        mssleep(1);
}


int main()
{
Xuint8 hello[4];
unsigned int i;
//-----------------
hello[0]=72;
hello[1]=69;
hello[2]=76;
hello[3]=79;
//-----------------
XUartLite_Config UART_Configuration;
UART_Configuration.DeviceId = XPAR_RS232_PORT_DEVICE_ID;
UART_Configuration.RegBaseAddr = XPAR_RS232_PORT_BASEADDR;
UART_Configuration.BaudRate = BAUDRATE;
UART_Configuration.UseParity = USE_PARITY;
UART_Configuration.ParityOdd = PARITY_ODD;
UART_Configuration.DataBits = DATABITS; 

XUartLite_Config UART_Second_Configuration;
UART_Second_Configuration.DeviceId = XPAR_RS232_SECOND_DEVICE_ID;
UART_Second_Configuration.RegBaseAddr = XPAR_RS232_SECOND_BASEADDR;
UART_Second_Configuration.BaudRate = BAUDRATE;
UART_Second_Configuration.UseParity = USE_PARITY;
UART_Second_Configuration.ParityOdd = PARITY_ODD;
UART_Second_Configuration.DataBits = DATABITS; 


 //UART init:
XUartLite_CfgInitialize (&serial, &UART_Configuration, XPAR_RS232_PORT_BASEADDR) ;
XUartLite_CfgInitialize (&second_serial, &UART_Configuration, XPAR_RS232_SECOND_BASEADDR) ;

xil_printf("First and Second UART configured to send any data.\n");
//-----------------


    XGpio_Initialize(&leds, XPAR_LEDS_8BIT_DEVICE_ID);
    XGpio_SetDataDirection(&leds, 1,0x0);  
    XGpio_DiscreteWrite(&leds, 1, 1);
    
    XIntc_RegisterHandler(XPAR_XPS_INTC_0_BASEADDR,
                                 XPAR_XPS_INTC_0_RS232_PORT_INTERRUPT_INTR,
                                 (XInterruptHandler)serial_interrupt_handler,
                                 (void *)XPAR_RS232_PORT_BASEADDR);    
                                 
    XIntc_RegisterHandler(XPAR_XPS_INTC_0_BASEADDR,
                                 XPAR_XPS_INTC_0_RS232_SECOND_INTERRUPT_INTR,
                                 (XInterruptHandler)second_serial_interrupt_handler,
                                 (void *)XPAR_RS232_SECOND_BASEADDR);                                     
    XGpio_DiscreteWrite(&leds, 1, 2);
    
    XIntc_MasterEnable(XPAR_XPS_INTC_0_BASEADDR);
    XGpio_DiscreteWrite(&leds, 1, 3);
    
    XIntc_EnableIntr(XPAR_XPS_INTC_0_BASEADDR, XPAR_RS232_PORT_INTERRUPT_MASK);
    XGpio_DiscreteWrite(&leds, 1, 4);
    
    XIntc_EnableIntr(XPAR_XPS_INTC_0_BASEADDR, XPAR_RS232_SECOND_INTERRUPT_MASK);
    XGpio_DiscreteWrite(&leds, 1, 5);
    
    //XUartLite serial,second_serial;
    XUartLite_Initialize(&serial,XPAR_RS232_PORT_DEVICE_ID);
    XUartLite_Initialize(&second_serial,XPAR_RS232_SECOND_DEVICE_ID);
    XGpio_DiscreteWrite(&leds, 1, 6);
    
    XUartLite_SetRecvHandler(&serial,
                                     (XUartLite_Handler)  serial_interrupt_handler,  
                                     (void *)XPAR_RS232_PORT_BASEADDR);  
    XUartLite_SetRecvHandler(&second_serial,
                                     (XUartLite_Handler)  second_serial_interrupt_handler,  
                                     (void *)XPAR_RS232_SECOND_BASEADDR);  
    XGpio_DiscreteWrite(&leds, 1, 7);
    
    XUartLite_EnableInterrupt(&serial);  
    XUartLite_EnableInterrupt(&second_serial);  
    XGpio_DiscreteWrite(&leds, 1, 8);
    
    microblaze_enable_interrupts();
    XGpio_DiscreteWrite(&leds, 1, 0);
    
    //------------------------------------
        while(XUartLite_IsSending(&serial));
        XUartLite_Send(&serial, (Xuint8*)(hello), 4);
        while(XUartLite_IsSending(&second_serial));
        XUartLite_Send(&second_serial, (Xuint8*)(hello), 4);
        //XGpio_DiscreteWrite(&leds, 1, (Xuint8)i);
    //------------------------------------
    while(1);
} 

     A program nem nagyon hosszú és szerintem könnyű is megérteni. Lényeg belőle : adott két soros bemenet. Azt szeretnénk elérni, hogy az egyik soros bemeneten érkező adat irányítsa a ledeket (8 biten beküldött karakter 8 ledet... semmi extra), a másik soros porton küldött adat pedig vissza legyen küldve az elsőn (vagyis egy sima átirányítás). Az elgondolásom a következő volt : írok két interrupt kezelő függvényt, egyet az első számú soros portra (erre megy a xil_printf() függvény is), ami a ledeket villogtatja, majd írok egy másik szintén megszakítás kezelő függvényt, amiben csak továbbküldöm az érkezett adatokat xil_printf segítségével.

     Induljunk ki abból, hogy a hardver kompozíció hibátlan, viszont a kód hibás. Hogyan jövünk rá, hogy mi a hiba? Az egyik legegyszerűbb változat az, amit Balázs is mondott, villogtatjuk a ledeket, mikor elértünk valahová. Ez megvolt. A program kiküldte a HELO üzenetet mindkét soros terminálra. És valami mégsem megy. Aki most megkapja a hibát, továbbolvasás nélkül, annak van egy söre... ;)

     Amit még tudni kell, hogy az interrupt kontrollerben prioritás szerint rendezni lehet a megszakítás kéréseket, annak érdekében, hogy egy alacsonyabb szintű megszakítás kiszolgálását félbe lehessen hagyni, ha egy magasabb szintű megszakítás kérés érkezik.

     Mégegy részlet a programbol, amire szükség lesz a mai debuggoláshoz a következő:

#define XPAR_INTC_SINGLE_BASEADDR 0x81800000
#define XPAR_INTC_SINGLE_HIGHADDR 0x8180FFFF
#define XPAR_INTC_SINGLE_DEVICE_ID XPAR_XPS_INTC_0_DEVICE_ID
#define XPAR_RS232_PORT_INTERRUPT_MASK 0X000001
#define XPAR_XPS_INTC_0_RS232_PORT_INTERRUPT_INTR 0
#define XPAR_RS232_SECOND_INTERRUPT_MASK 0X000002
#define XPAR_XPS_INTC_0_RS232_SECOND_INTERRUPT_INTR 1

     Miután háromszor újraírtam az interrupt kezelő függvényt kezdtem gyanakodni, hogy a hiba valahol máshol leledzik, és sorrol sorra megvizsgáltam a teljes programot. Legelső szarvashiba a következő volt:

 //UART init:
XUartLite_CfgInitialize (&serial, &UART_Configuration, XPAR_RS232_PORT_BASEADDR) ;
XUartLite_CfgInitialize (&second_serial, &UART_Configuration, XPAR_RS232_SECOND_BASEADDR) ;

      Minek kínlódtam én azzal, hogy két soros eszközt definiáljak, ha az inicializálásnál mindkettőhöz az &UART_Configuration prekonfigurált beállítás került? Ennek kellett egy gyors csere. Tovább tesztelve a progit rájöttem, hogy csak egyetlen interrupt aktiválódik, bármennyire is kínozom... S mindig az, amelyiket másodiknak írom be... Nem az számít, hogy melyik magasabb prioritású, hanem az, hogy a forráskódban melyiknek a maszkját írtam később... Lássuk a kódot megint:

    XIntc_EnableIntr(XPAR_XPS_INTC_0_BASEADDR, XPAR_RS232_PORT_INTERRUPT_MASK);
    XGpio_DiscreteWrite(&leds, 1, 4);
    
    XIntc_EnableIntr(XPAR_XPS_INTC_0_BASEADDR, XPAR_RS232_SECOND_INTERRUPT_MASK);
    XGpio_DiscreteWrite(&leds, 1, 5);

     Aztán ide is megjött a megvilágosodás. Ha én veszek egy lapot s ráírom, hogy 0x00000001 majd letörlök mindent a lapról és ráírom, hogy 0x00000002, akkor a másodikat fogja látni mindenki, aki benéz oda. Binárisan felbontva a  feladatot :
Az "1" binárisan 8 biten: 00000001
A  "2" binárisan 8 biten: 00000010
Ez egy megszakítás maszk. Amikor egy megszakítás érkezik a megszakítás vonalra, a CPU megnézi, hogy szabad-e attól az egységtől megszakítást fogadni, vagy sem. S ezt az az egyes határozza meg, amit két sorral fennebb leírtam. Vagyis ha én 00000001-et írok, akkor csak az első soros porttól jöhet megszakítás. Ha 00000010-et írok, akkor csak a második soros port megszakításait kezelem. Ha viszont 00000011-et írok, akkor mindkét megszakítás kérést engedélyezem.

      Hibák kijavítva. Az eredmény az lett, amit vártam. Villogtak a ledek, jöttek a számok. Mindenki boldog.

0 megjegyzés:

Megjegyzés küldése

Return top