public inbox for ecos-discuss@sourceware.org
 help / color / mirror / Atom feed
* [ECOS] Interrupt and IO-device driver
@ 2000-10-18  0:42 Daniel Lind
  2000-10-18  6:47 ` Jesper Skov
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Lind @ 2000-10-18  0:42 UTC (permalink / raw)
  To: ecos-discuss

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 16363 bytes --]

Hi,
I'm using PowerPC MBX860 and I'm trying to write a device driver for
SCC2. Look bellow for the code....
The interrupts doesn't seem to work right. I have investigated SCCE[Tx]
and this bit is set after a buffert is sent, so this is ok. I have also
checked CIPR (CPM interrupt pending register) and this register tells me
that an interrupt is pending on SCC2, this is also ok. After doing these
tests I think that the problem is that I haven't initialized the
interrupts in the right way.....ISR and DSR are never called.

In the code bellow is the function I use for setting up the interrupts

void
scc_uart_init_int(void){
 cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CPM_SCC2,
       CYGARC_SIU_PRIORITY_HIGH,
       (cyg_addrword_t) &buffers,
       scc_uart_ISR,
       scc_uart_DSR,
       &serial_interrupt_handle,
       serial_interrupt);
  cyg_drv_interrupt_attach(serial_interrupt_handle);
  cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CPM_SCC2);
}


Can somebody help me out? I don't really know if there is anything else
I must set up....

/Daniel Lind


********************************************************************************

This is all my code.....

/*********************************************************
SCC UART Programming Example
BRG1 and SCC2 are used in example, I use BRG2 and SCC2
**********************************************************/
#include <cyg/kernel/kapi.h>
#include <cyg/hal/hal_intr.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

/* *************** Interrupt ******************* */
#include <cyg/hal/hal_intr.h>
#include <cyg/hal/ppc_regs.h>
#include <cyg/hal/drv_api.h>
/* ********************************************* */

#include <cyg/hal/quicc/ppc8xx.h>
#include <string.h>

// Buffer descriptor control bits
#define QUICC_BD_CTL_Ready 0x8000  // Buffer contains data (tx) or is
empty (rx)
#define QUICC_BD_CTL_Wrap  0x2000  // Last buffer in list
#define QUICC_BD_CTL_Int   0x1000  // Generate interrupt when empty (tx)
or full (rx)
#define QUICC_BD_CTL_MASK  0xB000  // User settable bits



#define CYGHWR_HAL_POWERPC_MBX_BOARD_SPEED 40
#define UART_BITRATE(n)
(((CYGHWR_HAL_POWERPC_MBX_BOARD_SPEED*1000000)/16)/n)

#define CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxSIZE 16
#define CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxNUM 4
#define CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_RxSIZE 16
#define CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_RxNUM 4

static unsigned char
quicc_scc2_txbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxSIZE];

static unsigned char
quicc_scc2_rxbuf[CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_RxNUM][CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_RxSIZE];

#define QUICC_BD_CTL_Ready 0x8000  // Buffer contains data (tx) or is
empty (rx)
#define QUICC_SMC_CMD_InitTxRx  (0<<8)
#define QUICC_SMC_CMD_Go        0x0001


int RxBD;
int TxBD;
int length;
volatile struct cp_bufdesc *txbd_transmit;
volatile struct cp_bufdesc *rxbd_receive,*rxbd_debug;

int test;
EPPC* eppc_debug;
struct scc_regs *ctl_debug;



/* ***********Interrupt SCC2****************** */
cyg_handle_t serial_interrupt_handle; //Handle to interrupt object
cyg_interrupt *serial_interrupt; //Memory allocation för interrupt
object

typedef struct buffers{
  volatile struct cp_bufdesc *txbd_transmit;
  volatile struct cp_bufdesc *rxbd_receive;
}buffer_t;

buffer_t buffers;

static cyg_uint32
scc_uart_ISR();

static void
scc_uart_DSR();// Serial I/O - high level interrupt handler (DSR)

/* ******************************************** */



//Initializes SCC2 in UART-mode, baud=38400, 8/N/1
static bool
scc_uart_init()
{
 EPPC *eppc = eppc_base();
 int portAmask;
 int sicrmask;
 int TxSIZE = (int) CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxSIZE;
    int TxNUM = (int) CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxNUM;
 int TxBUF;
 int RxSIZE = (int) CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_RxSIZE;
    int RxNUM = (int) CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_RxNUM;
 int RxBUF;
 int i;
 unsigned int baud_divisor;
 struct uart_pram *uart_pram;

 struct cp_bufdesc *txbd, *rxbd;
 struct scc_regs *ctl;

 TxBD = 0x2830;
 RxBD = TxBD + CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxNUM*8;
 //#define MSG "Hey it works!\r\n"
 //strcpy(quicc_scc2_txbuf[0], MSG);


 //printf("HEJ \n");
 /*unsigned int simode;
 int SIpos;
 int RxBD;
 int TxBD;
 volatile struct smc_uart_pram *uart_pram;
 unsigned int channel;
 struct cp_bufdesc *txbd, *rxbd;
 volatile struct smc_regs *ctl;
 */




 /*
 1. Configure port A to enable TXD2 and RXD2. Set PAPAR[12,13] and clear

 PADIR[12,13] and PAODR[12,13].

 set  PAPAR[12,13] => Use TXD2 and RXD2 on port A
 clear PADIR[12,13] => Use TXD2 and RXD2 on port A
 clear PAODR[12,13] => The signal is actively driven as an output
 */


 portAmask = 0x000C;
 eppc->pio_papar |= portAmask; /* port A pin assignment reg */
 eppc->pio_padir &= ~portAmask; /* port A data direction reg */
 eppc->pio_paodr &= ~portAmask; /* port A open drain reg */


 /*
 2. Configure port C to enable RTS2, CTS2, and CD2. Set PCPAR[14]
andPCSO[8,9]
 and clear PCPAR[8,9] and PCDIR[8,9,14]. See table 34.4 MPC860 Manual*/

 eppc->pio_pcpar |= 0x2000; /* port C pin assignment reg */
 eppc->pio_pcso |= 0x0C00; /* port C special options */
    eppc->pio_pcpar &= 0xF3FF;
 eppc->pio_pcdir &= 0xD3FF; /* port C data direction reg */



 /*3. Configure BRG1. Write BRGC1 with 0x010144. The DIV16 bit is not
used and the
 divider is 162 (decimal). The resulting BRG1 clock is 16´ the preferred
bit rate.
 Baudrate generator 1

 Here we set the baudrate to the value of baud_devisor
 */

 baud_divisor = 38400;
 eppc->brgc2 = 0x10000 | (UART_BITRATE(baud_divisor)<<1);
// eppc->brgc1=0x010144;

 /*
 4. Connect BRG1 to SCC2 using the serial interface. Clear
SICR[R2CS,T2CS].
 In my case I use BRG2, i e R2CS=001 and T2CS=001
 */
 sicrmask = 0x00000900;

 eppc->si_sicr |= 0x00000900; /* SI clock routing */
 eppc->si_sicr &= 0xFFFFC9FF;

 /*
 5. Initialize the SDMA configuration register (SDCR = 0x0001 for normal
operation).
 */

 eppc->dma_sdcr |= 0x0001; /* SDMA configuration reg */

 /*
 6. Connect the SCC2 to the NMSI. Clear SICR[SC2].
 Clear bit 17 in SICR
 */

 eppc->si_sicr &= 0xFFFFDFFF;


 /*
 7. Write RBASE and TBASE in the SCC2 parameter RAM to point to the RxBD
and
 TxBD tables in dual-port RAM. Assuming one RxBD at the start of
dual-port RAM
 followed by one TxBD, write RBASE with 0x0000 and TBASE with 0x0008.

 Look at page 19-11 in MPC860 Manual and compare with ppc8xx.h,
 this will give scc2_pram= &eppc->pram[1].scc.pscc.u

 see page 22-14 in MPC860 Manual for definition of RBASE and TBASE
 */

 uart_pram = &eppc->pram[1].scc.pscc.u;

 //TxBD = 0x0000;
    //RxBD = 0x0008;
 uart_pram->rbase = RxBD;
 uart_pram->tbase = TxBD;


 /*
 8. Write 0x0041 to CPCR to execute the INIT RX AND TX PARAMS command
for SCC2.
 This command updates RBPTR and TBPTR of the serial channel with the new

 values of RBASE and TBASE.

 CPCR, Communication Processor Command Register
 */

 eppc->cp_cr = 0x0041;  /* command register */



 /*
 9. Write RFCR with 0x10 and TFCR with 0x10 for normal operation.
 */

 uart_pram->rfcr = 0x10; /* Rx function code */
 uart_pram->tfcr = 0x10; /* Tx function code */

 /*
 10. Write MRBLR with the maximum number of bytes per Rx buffer. For
this case,
 assume 16 bytes, so MRBLR = 0x0010.
 */

 uart_pram->mrblr = 0x0010; /* Rx buffer length */

 /*
 11. Write MAX_IDL with 0x0000 in the parameter RAM to disable the
maximum idle
 functionality for this example.
 */

 uart_pram->max_idl = 0x0000; /* maximum idle characters */

 /*
 12. Set BRKCR to 0x0001 so STOP TRANSMIT commands send only one break
character.
 */

 uart_pram->brkcr = 0x0001; /* break count register */

 /*
 13. Clear PAREC, FRMEC, NOSEC, and BRKEC in parameter RAM.
 */

 uart_pram->parec = 0x0000;  /* Rx parity error counter */
 uart_pram->frmer = 0x0000;  /* Rx framing error counter */
 uart_pram->nosec = 0x0000;  /* Rx noise counter */
 uart_pram->brkec = 0x0000;  /* Rx break character counter */


 /*
 14. Clear UADDR1 and UADDR2. They are not used.
 */

 uart_pram->uaddr1 = 0x0000;  /* address character 1 */
    uart_pram->uaddr2 = 0x0000;  /* address character 2 */



 /*
 15. Clear TOSEQ. It is not used.
 */
 uart_pram->toseq = 0x0000;  /* Tx out of sequence char */

 /*
 16. Write CHARACTER1Ð8 with 0x8000. They are not used.
 */
 uart_pram->RSRVD1[0] = 0x8000;
 uart_pram->RSRVD1[1] = 0x8000;
 uart_pram->RSRVD1[2] = 0x8000;
 uart_pram->RSRVD1[3] = 0x8000;
 uart_pram->RSRVD1[4] = 0x8000;
 uart_pram->RSRVD1[5] = 0x8000;
 uart_pram->RSRVD1[6] = 0x8000;
 uart_pram->RSRVD1[7] = 0x8000;

 /*
 17. Write RCCM with 0xC0FF. It is not used.
 */

 uart_pram->rccm=0xC0FF;  /* Rx control char mask */

 /*
 18. Initialize the RxBD. Assume the Rx buffer is at 0x0000_1000 in main
memory.
 Write 0xB000 to the RxBD[Status and Control], 0x0000 to RxBD[Data
Length]
 (optional), and 0x0000_1000 to RxBD[Buffer Pointer].
 */

 rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);
 rxbd_debug = (struct cp_bufdesc *)((char *)eppc + RxBD);

 //rxbd->ctrl   = QUICC_BD_CTL_Ready; /* RxBD[Status and Control] */
 //rxbd->length = 0x0000;    /* RxBD[Data Length] */
 //rxbd->buffer = &quicc_scc2_rxbuf[0][0]; /* RxBD[Buffer Pointer] */

 RxBUF = &quicc_scc2_rxbuf[0][0];
 /* setup RX buffer descriptors */
    for (i = 0;  i < RxNUM;  i++) {
        rxbd->length = 0;
        rxbd->buffer = RxBUF;
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
        if (i == (RxNUM-1)) rxbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last
buffer
        RxBUF += RxSIZE;
        rxbd++;
    }

 /*
 19. Initialize the TxBD. Assume the buffer is at 0x0000_2000 in main
memory and
 contains sixteen 8-bit characters. Write 0xB000 to the TxBD[Status and
Control],
 0x0010 to TxBD[Data Length], and 0x00002000 to TxBD[Buffer Pointer].
 */
 txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
 /*txbd->ctrl = 0;
 txbd->length = 0;
 //txbd->length = strlen(MSG);
 txbd->buffer =  &quicc_scc2_txbuf[0][0];*/

  /* setup TX buffer descriptors */
 TxBUF = &quicc_scc2_txbuf[0][0];

    for (i = 0;  i < TxNUM;  i++) {
        txbd->length = 0;
        txbd->buffer = TxBUF;
        txbd->ctrl   = 0;  //look at scc_uart_flush(void) for enabling
interrupt
        if (i == (TxNUM-1)) txbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last
buffer
        TxBUF += TxSIZE;
        txbd++;
    }


 /*
 20. Write 0xFFFF to SCCE2 to clear any previous events.
 */

 ctl = &eppc->scc_regs[1];
 ctl->scc_scce=0xFFFF; /* SCC event reg */

 /*
 21. Write 0x0003 to SCCM2 to allow the TX and RX interrupts.
 */


 ctl->scc_sccm=0x0003; /* SCC mask reg */

 /*
 22. Write 0x2000_0000 to the CPM interrupt mask register (CIMR) to
allow SCC2 to
 generate a system interrupt. The CICR should also be initialized.
 */

 eppc->cpmi_cimr |= 0x20000000;
 eppc->cpmi_cicr = 0x1B9F00;  /* CPM INTERRUPTS LEVEL 4*/
                                    /* PC15 HIGHEST INT PRIOR*/
                                    /* SCC4,HIGHEST PRIORITY */
                                    /* SCC3,2ND HIGHEST PRIOR*/
                                    /* SCC2,2ND LOWEST PRIORI*/
                                    /* SCC1,LOWEST PRIORITY  */
 eppc->cpmi_cicr |= 0x80;  /* ENABLE CPM INTERRUPTS, master enable for
CPM interrupts*/
 /*
 23. Write 0x0000_0020 to GSMR_H2 to configure a small Rx FIFO width.
 */
 ctl->scc_gsmr_h = 0x00000020; /* SCC Gen mode (HIGH) */

 /*
 24. Write 0x0002_8004 to GSMR_L2 to configure 16´ sampling for transmit
and
 receive, CTS and CD to automatically control transmission and reception
(DIAG
 bits), and the SCC for UART mode. Notice that the transmitter (ENT) and
receiver
 (ENR) have not been enabled yet.
 */

 ctl->scc_gsmr_l = 0x00028004; /* SCC Gen mode (LOW) */

 /*
 25. Set PSMR2 to 0xB000 to conÞgure automatic flow control using CTS,
8-bit
 characters, no parity, 1 stop bit, and asynchronous SCC UART operation.

 */

 ctl->scc_psmr = 0xB000; /* protocol specific mode register */

 /*
 26. Write 0x0002_8034 to GSMR_L2 to enable the transmitter and
receiver. This
 ensures that ENT and ENR are enabled last.
 */

 ctl->scc_gsmr_l = 0x00028034;

   /*enable transmitter*/
 //txbd->ctrl = 0xB000;

 return true;

}


void
scc_uart_init_int(void){
 cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CPM_SCC2,
       CYGARC_SIU_PRIORITY_HIGH,
       (cyg_addrword_t) &buffers,
       scc_uart_ISR,
       scc_uart_DSR,
       &serial_interrupt_handle,
       serial_interrupt);
  cyg_drv_interrupt_attach(serial_interrupt_handle);
  cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CPM_SCC2);
}




static void
scc_uart_flush(void)
{
 EPPC *eppc = eppc_base();
 struct uart_pram *uart_pram = &eppc->pram[1].scc.pscc.u;
 volatile struct cp_bufdesc *txbd = txbd_transmit; //Replace
txbd_transmit with scc_chan->txbd
 printf("scc_uart_flush anropad \n");
    if ((txbd->length > 0) && ((txbd->ctrl & QUICC_BD_CTL_Ready) == 0))
{
  //txbd->ctrl |= 0x1000;
  //txbd->ctrl |= 0x8000; Can not modify this bit, doesn't matter.....
  txbd->ctrl |= QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int;  // Signal buffer
ready
        if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
            txbd =(volatile struct cp_bufdesc *) (uart_pram->tbase);
//smc_chan->tbase;
        } else {
            txbd++;
        }
        txbd_transmit = txbd;
    }
}




//Send a character to the device output buffer.
// Return 'true' if character is sent to device
static bool
scc_uart_putc(unsigned char c)
{

 volatile struct cp_bufdesc *txbd, *txfirst;
    EPPC *eppc = eppc_base();
 struct uart_pram *uart_pram = &eppc->pram[1].scc.pscc.u;
 bool res;
 txbd = (volatile struct cp_bufdesc *)((char*) eppc +
uart_pram->tbptr);  //tbptr in pram for SCC2
 txfirst = txbd;
 cyg_drv_dsr_lock();  // Avoid race condition testing pointers
 // Scan for a non-busy buffer
    while (txbd->ctrl & QUICC_BD_CTL_Ready) {
        // This buffer is busy, move to next one
        if (txbd->ctrl & QUICC_BD_CTL_Wrap) {
            txbd = uart_pram->tbase;
        } else {
            txbd++;
        }
        if (txbd == txfirst) break;  // Went all the way around
    }
    txbd_transmit=txbd; //smc_chan->txbd = txbd;
    if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0) {
        // Transmit buffer is not full/busy
        txbd->buffer[txbd->length++] = c;
        if (txbd->length == (int)
CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_TxSIZE) {//smc_chan->txsize) {
            // This buffer is now full, tell SMC to start processing it
            scc_uart_flush();
        }
        res = true;
    } else {
        // No space
        res = false;
    }
    cyg_drv_dsr_unlock();
    return res;
}


static unsigned char
scc_uart_getc(){
 unsigned char c;
 EPPC *eppc = eppc_base();
 struct uart_pram *uart_pram = &eppc->pram[1].scc.pscc.u;
    //quicc_smc_serial_info *smc_chan = (quicc_smc_serial_info
*)chan->dev_priv;
    volatile struct cp_bufdesc *rxbd = rxbd_receive;
    while ((rxbd->ctrl & QUICC_BD_CTL_Ready) != 0) ;
    c = rxbd->buffer[0];
    rxbd->length = (int) CYGNUM_IO_SERIAL_POWERPC_QUICC_SCC_SCC2_RxSIZE;

    rxbd->ctrl |= QUICC_BD_CTL_Ready;
    if (rxbd->ctrl & QUICC_BD_CTL_Wrap) {
        rxbd = uart_pram->tbase; //smc_chan->rbase;
    } else {
        rxbd++;
    }
    rxbd_receive = (struct cp_bufdesc *)rxbd;
    return c;
}

// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32
scc_uart_ISR()
{
 //printf("Anropar scc_uart_ISR \n");
 test=1;
 return CYG_ISR_CALL_DSR; //cause DSR to be run
}

// Serial I/O - high level interrupt handler (DSR)
static void
scc_uart_DSR()
{
 test=2;
 printf("Anropat scc_uart_DSR \n");
}





void cyg_user_start(void)
{

 EPPC *eppc = eppc_base();
 struct uart_pram *uart_pram = &eppc->pram[1].scc.pscc.u;

 unsigned char a;
 int n=0;
 char *msg = "Tjena på dig det här fungerar ju";
 test=0;

 eppc_debug = eppc_base();
 ctl_debug = &eppc->scc_regs[1];

 scc_uart_init_int();
 scc_uart_init();



 while (n<32) {
  if (!scc_uart_putc((unsigned char) *msg)) printf("Error in
scc_uart_putc \n");
  msg++;
  n++;
 // printf("Antal varv i slinga %d \n",n);
 }
 printf("Antal tecken sända %d \n",n);

 printf("Test %d \n",test);
 rxbd_receive = (volatile struct cp_bufdesc *)((char*) eppc +
uart_pram->rbptr);

 while (1){
  a=scc_uart_getc();
  printf("Test %d \n",test);
 // printf('a');
 }

}



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [ECOS] Interrupt and IO-device driver
  2000-10-18  0:42 [ECOS] Interrupt and IO-device driver Daniel Lind
@ 2000-10-18  6:47 ` Jesper Skov
  2000-10-19  4:17   ` Daniel Lind
  0 siblings, 1 reply; 5+ messages in thread
From: Jesper Skov @ 2000-10-18  6:47 UTC (permalink / raw)
  To: Daniel Lind; +Cc: ecos-discuss

>>>>> "Daniel" == Daniel Lind <daniel.lind@sth.frontec.se> writes:

Daniel> Hi, I'm using PowerPC MBX860 and I'm trying to write a device
Daniel> driver for SCC2. Look bellow for the code....  The interrupts
Daniel> doesn't seem to work right. I have investigated SCCE[Tx] and
Daniel> this bit is set after a buffert is sent, so this is ok. I have
Daniel> also checked CIPR (CPM interrupt pending register) and this
Daniel> register tells me that an interrupt is pending on SCC2, this
Daniel> is also ok. After doing these tests I think that the problem
Daniel> is that I haven't initialized the interrupts in the right
Daniel> way.....ISR and DSR are never called.

Does the CPM arbiter in var_intr.c (hal_arbitration_isr_cpm) get
properly set up? It probably does if you selected the 860 variant.

Still, that's the only thing in the chain I can think of (off hand) as
being broken.  Do the mpc8xx/intr0 test PASS on your board?

Daniel> void scc_uart_init_int(void){
Daniel> cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CPM_SCC2,
Daniel> CYGARC_SIU_PRIORITY_HIGH, (cyg_addrword_t) &buffers,
Daniel> scc_uart_ISR, scc_uart_DSR, &serial_interrupt_handle,
Daniel> serial_interrupt);
Daniel> cyg_drv_interrupt_attach(serial_interrupt_handle);
Daniel> cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CPM_SCC2); }

Also please verify that the CPM interrupt is unmasked properly (it
would be if the intr0 test PASSes).

Finally, you should try to enable assertions (enable
CYGDBG_USE_ASSERTS and CYGPKG_INFRA_DEBUG) to catch any unhandled
interrupts.

Jesper

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Re: [ECOS] Interrupt and IO-device driver
  2000-10-18  6:47 ` Jesper Skov
@ 2000-10-19  4:17   ` Daniel Lind
  2000-10-19  6:35     ` Jesper Skov
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Lind @ 2000-10-19  4:17 UTC (permalink / raw)
  To: ecos-discuss

Hi,
I dont really know how to check that the CPM arbiter is properly set.
Where does this ISR attach?
I don't understand how the function hal_arbitration_isr_cpm works. I
placed a breakpoint inside this function but the program never reached
this function. Shall it to do that?

externC cyg_uint32
hal_arbitration_isr_cpm (CYG_ADDRWORD vector, CYG_ADDRWORD data)


Besides this I can't understand how the interrupts in the PowerPC, MPC860,
works. I'm not used to this processor. In other controllers that I have
used there is an interruptvector where you attach adresses to where the
program is going to continue after an interrupt occour. Is there anything
like this in PowerPC? The SIVEC in SIU doesn't seem to work like
this...Where is the actual interrupt that interrupts the processor and
orders the processor to go to another place in the code? I have tried to
read everything about the core, because it's to the core that the
interrupt finally will be sent (or am I wrong?)............(after some
more reading).......Now I have found out that there is an exception vector
table and that external interrupt is in this table.

What function in eCos is called after an interrupt has occured? It must be
some kind of function that finds out what source that have caused the
interrupt.

I have found the function hal_variant_IRQ_init(void) a few lines down in
var_intr.c. Is this a function that I must call, or is it done by eCos?

The mpc8xx/intr0 test doesn't PASS on my board, MBX860. After debugging
the test I find out the following...

// Periodic timer ISR. Should be executing 5 times.
static cyg_uint32 isr_pit(CYG_ADDRWORD vector, CYG_ADDRWORD data)
is called 1 time

atfer this function has finished the program goes to

static inline cyg_uint32
hal_call_isr (cyg_uint32 vector)

from this function the program goes to
externC cyg_uint32
 hal_arbitration_isr_pit (CYG_ADDRWORD vector, CYG_ADDRWORD data)

The program runs through this function and after this goes to function
void hal_variant_init(void) in var_misc.c
The program seems to get stuck in, it never leaves, void
hal_variant_init(void)


When I run the tests in eCos config tool I get the following result.....

*** 12:58:28 Run started
GNU gdb 20000926
Copyright 2000 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you
are
welcome to change it and/or distribute copies of it under certain
conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for
details.
This GDB was configured as "--host=i686-pc-cygwin
--target=powerpc-eabi"...
(gdb) set height 0
(gdb) set remotedebug 0
Warning: command 'set remotedebug' is deprecated.
Use 'set debug remote'.

(gdb) set remotebaud 38400
(gdb) target remote com1
Remote debugging using com1
0xfe005d98 in ?? ()
(gdb) load
Loading section .text, size 0x7d5c lma 0x10000
Loading section .rodata, size 0x16b8 lma 0x17d60
Loading section .data, size 0x778 lma 0x19418
Start address 0x10000 , load size 39820
Transfer rate: 26546 bits/sec, 504 bytes/write.
(gdb) break cyg_test_exit
Breakpoint 1 at 0x138cc: file
//C/PROGRA~1/REDHAT~1/eCos/packages/infra/v1_3_1/src/tcdiag.cxx, line 116.

(gdb) break cyg_assert_fail
Function "cyg_assert_fail" not defined.
(gdb) break cyg_test_init
Breakpoint 2 at 0x137ac: file
//C/PROGRA~1/REDHAT~1/eCos/packages/infra/v1_3_1/src/tcdiag.cxx, line 62.
(gdb) cont
Continuing.

Breakpoint 2, cyg_test_init ()
    at //C/PROGRA~1/REDHAT~1/eCos/packages/infra/v1_3_1/src/tcdiag.cxx:62
62 }
Current language:  auto; currently c++
(gdb) set cyg_test_is_simulator=0
Address of symbol "cyg_test_is_simulator" is unknown.
(gdb) cont
Continuing.
FAIL:<Intr 0 Failed.> Line: 147, File:
//C/PROGRA~1/REDHAT~1/eCos/packages/hal/powerpc/mpc8xx/v1_3_1/tests/intr0.c

EXIT:<done>

Breakpoint 1, cyg_test_exit ()
    at //C/PROGRA~1/REDHAT~1/eCos/packages/infra/v1_3_1/src/tcdiag.cxx:116

116         ;
(gdb) *** 12:59:09 Run complete


I have verified  that the CPM interrupt is unmasked properly, CIMR is
0x20000000 which is SCC2.

One thing that I can't understand is that "PowerPC QUICC/ seriel port 2
driver" functions with interrupts. I have looked at this driver then
writing the SCC2 driver, whats the difference between the initializations
of the interrupts? The code looks just the same to me....is this driver
doing some initializations which I can't see in quicc_smc_serial.c?

/Daniel Lind

Jesper Skov wrote:

> >>>>> "Daniel" == Daniel Lind <daniel.lind@sth.frontec.se> writes:
>
> Daniel> Hi, I'm using PowerPC MBX860 and I'm trying to write a device
> Daniel> driver for SCC2. Look bellow for the code....  The interrupts
> Daniel> doesn't seem to work right. I have investigated SCCE[Tx] and
> Daniel> this bit is set after a buffert is sent, so this is ok. I have
> Daniel> also checked CIPR (CPM interrupt pending register) and this
> Daniel> register tells me that an interrupt is pending on SCC2, this
> Daniel> is also ok. After doing these tests I think that the problem
> Daniel> is that I haven't initialized the interrupts in the right
> Daniel> way.....ISR and DSR are never called.
>
> Does the CPM arbiter in var_intr.c (hal_arbitration_isr_cpm) get
> properly set up? It probably does if you selected the 860 variant.
>
> Still, that's the only thing in the chain I can think of (off hand) as
> being broken.  Do the mpc8xx/intr0 test PASS on your board?
>
> Daniel> void scc_uart_init_int(void){
> Daniel> cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CPM_SCC2,
> Daniel> CYGARC_SIU_PRIORITY_HIGH, (cyg_addrword_t) &buffers,
> Daniel> scc_uart_ISR, scc_uart_DSR, &serial_interrupt_handle,
> Daniel> serial_interrupt);
> Daniel> cyg_drv_interrupt_attach(serial_interrupt_handle);
> Daniel> cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CPM_SCC2); }
>
> Also please verify that the CPM interrupt is unmasked properly (it
> would be if the intr0 test PASSes).
>
> Finally, you should try to enable assertions (enable
> CYGDBG_USE_ASSERTS and CYGPKG_INFRA_DEBUG) to catch any unhandled
> interrupts.
>
> Jesper

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [ECOS] Interrupt and IO-device driver
  2000-10-19  4:17   ` Daniel Lind
@ 2000-10-19  6:35     ` Jesper Skov
  2000-10-20  2:19       ` Daniel Lind
  0 siblings, 1 reply; 5+ messages in thread
From: Jesper Skov @ 2000-10-19  6:35 UTC (permalink / raw)
  To: Daniel Lind; +Cc: ecos-discuss

>>>>> "Daniel" == Daniel Lind <daniel.lind@sth.frontec.se> writes:

Daniel> Hi, I dont really know how to check that the CPM arbiter is
Daniel> properly set.  Where does this ISR attach?  I don't understand
Daniel> how the function hal_arbitration_isr_cpm works. I placed a
Daniel> breakpoint inside this function but the program never reached
Daniel> this function. Shall it to do that?

Yes, it should. See below.

Daniel> Besides this I can't understand how the interrupts in the
Daniel> PowerPC, MPC860, works. I'm not used to this processor. In
Daniel> other controllers that I have used there is an interruptvector
Daniel> where you attach adresses to where the program is going to
Daniel> continue after an interrupt occour. Is there anything like
Daniel> this in PowerPC? The SIVEC in SIU doesn't seem to work like
Daniel> this...Where is the actual interrupt that interrupts the
Daniel> processor and orders the processor to go to another place in
Daniel> the code? I have tried to read everything about the core,
Daniel> because it's to the core that the interrupt finally will be
Daniel> sent (or am I wrong?)............(after some more
Daniel> reading).......Now I have found out that there is an exception
Daniel> vector table and that external interrupt is in this table.

Indeed, the somewhat untraditional behavior is what makes this a bit
different from other HALs.

Seeing as the various interrupt sources can be programmed to trigger
any of the 7 CYGNUM_HAL_INTERRUPT_SIU_LVL interrupts, we need some
magic to route the execution path to the proper interrupt handler.

This is what the arbiters do. They are small functions that you put on
the (appropriate, as per interrupt source configuration) SIU interrupt
vector. When called they examine their dedicated interrupt request
flag, figure out which CYGNUM_HAL_INTERRUPT_ vector the interrupt has,
and jumps to that vector.

And that may repeat something like 3 times, if I rememeber
correctly. Pretty nasty.

In your case, you'd put first the CPM arbiter on one of the SIO_LVL
vectors, and program the CPM to use that level (that's what
hal_variant_IRQ_init() does).

Then when the CPM arbiter is called, it finds the CPM sub-module which
caused the interrupt, and jumps to its vector. In this case, SCC2.


Since the CPM arbiter is attached and enabled per default, it's
somewhat worrying that it doesn't seem to be executed.

So what you should do is (a) ensure that the proper ISRs are set
(CYGNUM_HAL_INTERRUPT_SIU_LVL_?, CYGNUM_HAL_INTERRUPT_SIU_CPM, and
CYGNUM_HAL_INTERRUPT_CPM_SCC2), and (b) follow the flow through these
to make sure they do what you expect them to do, and check that the
hardware registers have the expected contents.

Daniel> What function in eCos is called after an interrupt has
Daniel> occured? It must be some kind of function that finds out what
Daniel> source that have caused the interrupt.

cyg_hal_default_interrupt_vsr, which uses hal_intc_decode (defined in
mpc8xx/variant.inc) that does the SIU level decoding.

Daniel> I have found the function hal_variant_IRQ_init(void) a few
Daniel> lines down in var_intr.c. Is this a function that I must call,
Daniel> or is it done by eCos?

It should be done by eCos during system initialization.

Daniel> The mpc8xx/intr0 test doesn't PASS on my board, MBX860. After
Daniel> debugging the test I find out the following...

Daniel> from this function the program goes to externC cyg_uint32
Daniel> hal_arbitration_isr_pit (CYG_ADDRWORD vector, CYG_ADDRWORD
Daniel> data)

Daniel> The program runs through this function and after this goes to
Daniel> function void hal_variant_init(void) in var_misc.c The program
Daniel> seems to get stuck in, it never leaves, void
Daniel> hal_variant_init(void)

That's plain weird. The pit arbiter should not end up in any of the
init functions.

Daniel> One thing that I can't understand is that "PowerPC QUICC/
Daniel> seriel port 2 driver" functions with interrupts. I have looked
Daniel> at this driver then writing the SCC2 driver, whats the
Daniel> difference between the initializations of the interrupts? The
Daniel> code looks just the same to me....is this driver doing some
Daniel> initializations which I can't see in quicc_smc_serial.c?

The existing driver is a SMC driver. You're doing a SCC driver. There
may well be some extra bits that need fiddling which are not fiddled
by the existing init code.

Jesper

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [ECOS] Interrupt and IO-device driver
  2000-10-19  6:35     ` Jesper Skov
@ 2000-10-20  2:19       ` Daniel Lind
  0 siblings, 0 replies; 5+ messages in thread
From: Daniel Lind @ 2000-10-20  2:19 UTC (permalink / raw)
  To: ecos-discuss

Hi,
Have have one question, where does the siu register sipend reset? What
function? I need to know so I can decide if it's PowerPc problems or board
problems. I'm working on checking that the proper ISRs are set, but I
haven't figured out how to check it yet.

After my Tx interrupt has occoured, the following is in the registers

SIPEND 0 , is not set, and no other function is called that could have
reset SIPEND...as far as I know. Where does sipend reset?

SIMASK 0x10000, ie level mask 7

sivec 0x3c00000, this is not changed during the run of the program, value
after intializing, this corrsponds to level7...hmmmm. It's this value
before intitialization and after and intialization...always the same....

scc_scce 0x102, ie transmit interrupt, ok

CPMI_CIPR 0x200000018, SCC2 interrupt pending, besides this the register
tells me that SMC1 and SMC2 interrupt is pending, I don't understand why.

But if you look at all registers above and think off that no function in
eCos is called ( i stepped through the whole program from the begining to
the end) the problem doesn't seem to be eCos. I must have some problem
with the SIU. Can I be right?

Are the interrupts enabled globally? I write a function that reads
MSR......
msr = 0x10e08 after initialization 1 0000 1110 0000 1000 , this tells that
the interrupts are enabled


/Daniel

Jesper Skov wrote:

> >>>>> "Daniel" == Daniel Lind <daniel.lind@sth.frontec.se> writes:
>
> Daniel> Hi, I dont really know how to check that the CPM arbiter is
> Daniel> properly set.  Where does this ISR attach?  I don't understand
> Daniel> how the function hal_arbitration_isr_cpm works. I placed a
> Daniel> breakpoint inside this function but the program never reached
> Daniel> this function. Shall it to do that?
>
> Yes, it should. See below.
>
> Daniel> Besides this I can't understand how the interrupts in the
> Daniel> PowerPC, MPC860, works. I'm not used to this processor. In
> Daniel> other controllers that I have used there is an interruptvector
> Daniel> where you attach adresses to where the program is going to
> Daniel> continue after an interrupt occour. Is there anything like
> Daniel> this in PowerPC? The SIVEC in SIU doesn't seem to work like
> Daniel> this...Where is the actual interrupt that interrupts the
> Daniel> processor and orders the processor to go to another place in
> Daniel> the code? I have tried to read everything about the core,
> Daniel> because it's to the core that the interrupt finally will be
> Daniel> sent (or am I wrong?)............(after some more
> Daniel> reading).......Now I have found out that there is an exception
> Daniel> vector table and that external interrupt is in this table.
>
> Indeed, the somewhat untraditional behavior is what makes this a bit
> different from other HALs.
>
> Seeing as the various interrupt sources can be programmed to trigger
> any of the 7 CYGNUM_HAL_INTERRUPT_SIU_LVL interrupts, we need some
> magic to route the execution path to the proper interrupt handler.
>
> This is what the arbiters do. They are small functions that you put on
> the (appropriate, as per interrupt source configuration) SIU interrupt
> vector. When called they examine their dedicated interrupt request
> flag, figure out which CYGNUM_HAL_INTERRUPT_ vector the interrupt has,
> and jumps to that vector.
>
> And that may repeat something like 3 times, if I rememeber
> correctly. Pretty nasty.
>
> In your case, you'd put first the CPM arbiter on one of the SIO_LVL
> vectors, and program the CPM to use that level (that's what
> hal_variant_IRQ_init() does).
>
> Then when the CPM arbiter is called, it finds the CPM sub-module which
> caused the interrupt, and jumps to its vector. In this case, SCC2.
>
> Since the CPM arbiter is attached and enabled per default, it's
> somewhat worrying that it doesn't seem to be executed.
>
> So what you should do is (a) ensure that the proper ISRs are set
> (CYGNUM_HAL_INTERRUPT_SIU_LVL_?, CYGNUM_HAL_INTERRUPT_SIU_CPM, and
> CYGNUM_HAL_INTERRUPT_CPM_SCC2), and (b) follow the flow through these
> to make sure they do what you expect them to do, and check that the
> hardware registers have the expected contents.
>
> Daniel> What function in eCos is called after an interrupt has
> Daniel> occured? It must be some kind of function that finds out what
> Daniel> source that have caused the interrupt.
>
> cyg_hal_default_interrupt_vsr, which uses hal_intc_decode (defined in
> mpc8xx/variant.inc) that does the SIU level decoding.
>
> Daniel> I have found the function hal_variant_IRQ_init(void) a few
> Daniel> lines down in var_intr.c. Is this a function that I must call,
> Daniel> or is it done by eCos?
>
> It should be done by eCos during system initialization.
>
> Daniel> The mpc8xx/intr0 test doesn't PASS on my board, MBX860. After
> Daniel> debugging the test I find out the following...
>
> Daniel> from this function the program goes to externC cyg_uint32
> Daniel> hal_arbitration_isr_pit (CYG_ADDRWORD vector, CYG_ADDRWORD
> Daniel> data)
>
> Daniel> The program runs through this function and after this goes to
> Daniel> function void hal_variant_init(void) in var_misc.c The program
> Daniel> seems to get stuck in, it never leaves, void
> Daniel> hal_variant_init(void)
>
> That's plain weird. The pit arbiter should not end up in any of the
> init functions.
>
> Daniel> One thing that I can't understand is that "PowerPC QUICC/
> Daniel> seriel port 2 driver" functions with interrupts. I have looked
> Daniel> at this driver then writing the SCC2 driver, whats the
> Daniel> difference between the initializations of the interrupts? The
> Daniel> code looks just the same to me....is this driver doing some
> Daniel> initializations which I can't see in quicc_smc_serial.c?
>
> The existing driver is a SMC driver. You're doing a SCC driver. There
> may well be some extra bits that need fiddling which are not fiddled
> by the existing init code.
>
> Jesper

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2000-10-20  2:19 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-10-18  0:42 [ECOS] Interrupt and IO-device driver Daniel Lind
2000-10-18  6:47 ` Jesper Skov
2000-10-19  4:17   ` Daniel Lind
2000-10-19  6:35     ` Jesper Skov
2000-10-20  2:19       ` Daniel Lind

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).