This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Interrupt and IO-device driver


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');
 }

}




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]