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]
Other format: [Raw text]

SPI interface does not work with Viper & AdderII running eCos


Hi All,

I recently wrote an eCos driver for the PowerQUICC SPI interface. It works great on a A&M Viper with a MPC860T processor. Unfortunately, it does not work on the AdderII modules (which use a MPC852T processor) or a Viper I have fitted with a XPC866T processor.

The driver code is attached to this e-mail. When the driver tries to send the first buffer of data (spi_write in spi.c) and it tries to start the transmission (line 392 of spi.c):

eppc->spi_spcom = QUICC_SPIC_STR;

At this point, my Insight debugger loses contact with the board. I have a feeling that either the board is locking up or the debug output is getting stepped on somehow.

I noticed in the MPC866 manual (which applies to both the MPC852T and MPC866T) there is a note on page 18-10 which says:

The entire dual-port RAM should be cleared as the first step in
system initialization. This step should be followed by issuing a
CPM reset using the CPCR. Only after these two steps should
the dual-port RAM be programmed for speci.c CPM
functions.

This note is not in the MPC860 manual. Is this procedure followed in the Viper and AdderII initialization code for eCos? If not where should it be done? Should it be done in RedBoot as well?

I also noticed that the SPI and I2C parameter RAM areas can be relocated, which was not the case with the MPC860T. Do I need to do that to get the SPI interface to work? Or, is it possible the SPI RAM area is inadvertently being relocated by a bad value in the SPI_BASE (offset 0x1DAC0x1DAD from the dual port RAM base)? Is the SPI_BASE value being initialized properly? Is this why the procedure above was added to the MPC866 manual?

Any suggestions would be greatly appreciated.

Best regards,

Paul Randall
Delta Digital Video
//==========================================================================
//
//      spi.c
// 
//      SPI Driver
//
//==========================================================================


// Network throughput test code

#include <pkgconf/system.h>
#include <cyg/io/devtab.h>
#include <cyg/infra/diag.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/hal/hal_cache.h>
#include <cyg/hal/drv_api.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/io/config_keys.h>
#include CYGBLD_HAL_PLATFORM_H

#define SCC1 0
#define SCC2 1
#define SCC3 2
#define SCC4 3

// SPI Mode Register SPMODE
#define QUICC_SPMODE_LOOP       0x4000      // Loop mode
#define QUICC_SPMODE_CI         0x2000      // Clock Invert
#define QUICC_SPMODE_CP         0x1000      // Clock Phase
#define QUICC_SPMODE_DIV16      0x0800      // Divide BRGCLK by 16
#define QUICC_SPMODE_REV        0x0400      // Reverse Data
#define QUICC_SPMODE_MS         0x0200      // Master/Slave
#define QUICC_SPMODE_EN         0x0100      // Enable SPI
#define QUICC_SPMODE_LEN        0x0070      // Character length (8 bits)
#define QUICC_SPMODE_PM         0x000F      // Prescale Modulus
#define QUICC_SPMODE_PM_0       0x0000      // PM=0 (BRGCLK/4  = 15.0 MHz)
#define QUICC_SPMODE_PM_1       0x0001      // PM=1 (BRGCLK/8  = 7.5 MHz)
#define QUICC_SPMODE_PM_2       0x0002      // PM=2 (BRGCLK/12 = 5.0 MHz)
#define QUICC_SPMODE_PM_3       0x0003      // PM=3 (BRGCLK/16 = 3.7 MHz)
#define QUICC_SPMODE_PM_4       0x0004      // PM=4 (BRGCLK/20 = 3.0 MHz)
#define QUICC_SPMODE_PM_5       0x0005      // PM=5 (BRGCLK/24 = 2.5 MHz)

// SPI Events Register
#define QUICC_SPIE_MME          0x20        // Multimaster Error
#define QUICC_SPIE_TXE          0x10        // Tx Error
#define QUICC_SPIE_BSY          0x04        // Busy - receive buffer overrun
#define QUICC_SPIE_TXB          0x02        // Tx interrupt
#define QUICC_SPIE_RXB          0x01        // Rx interrupt

// SPI Command Register
#define QUICC_SPIC_STR          0x80        // Start Transmit

// SPI Commands
#define QUICC_CPM_SPI           0x0050
#define QUICC_SPI_CMD_InitTxRx  (0<<8)
#define QUICC_SPI_CMD_InitRx    (1<<8)
#define QUICC_SPI_CMD_InitTx    (2<<8)
#define QUICC_SPI_CMD_CloseRxBD (7<<8)
#define QUICC_SPI_CMD_Reset     0x8000
#define QUICC_SPI_CMD_Go        0x0001

#define SPI_NAME                "/dev/spi"

#define SPI_TxNUM               1
#define SPI_RxNUM               10
#define SPI_TxSIZE              940
#define SPI_RxSIZE              940
#define SPI_RxBUFS              16

static unsigned char spi_txbuf[SPI_TxNUM][SPI_TxSIZE]; // + HAL_DCACHE_LINE_SIZE-1];
static unsigned char spi_rxbuf[SPI_RxNUM][SPI_RxSIZE]; // + HAL_DCACHE_LINE_SIZE-1];

static unsigned char spi_in_buf[SPI_RxBUFS][SPI_RxSIZE];  // input buffer

// macro for aligning buffers to cache lines
//#define ALIGN_TO_CACHELINES(b) ((cyg_uint8 *)(((CYG_ADDRESS)(b) + (HAL_DCACHE_LINE_SIZE-1)) & ~(HAL_DCACHE_LINE_SIZE-1)))

typedef struct {
    unsigned char           *data[SPI_RxBUFS];  // array of pointers to buffers
    volatile int             nb;                // count of buffers currently full
    volatile int             put;               // where to add next buffer  
    volatile int             get;               // where to remove next buffer
    cyg_drv_cond_t           wait;
    cyg_drv_mutex_t          lock;
    bool                     waiting;
    volatile bool            abort;             // Set by an outsider to kill processing
} fbuf_t;

typedef struct quicc_spi_serial_info {
    CYG_WORD                            int_num;          // Interrupt number
    cyg_uint32                          *brg;             // Which baud rate generator
    volatile struct spi_pram            *pram;            // Parameter RAM pointer
    volatile struct cp_bufdesc          *txbd, *rxbd;     // Next Tx,Rx descriptor to use
    struct cp_bufdesc                   *tbase, *rbase;   // First Tx,Rx descriptor
    int                                 txsize, rxsize;   // Length of individual buffers
    cyg_interrupt                       serial_interrupt;
    cyg_handle_t                        serial_interrupt_handle;
    fbuf_t                              out_fbuf;
    fbuf_t                              in_fbuf;
} quicc_spi_serial_info;

static bool       spi_init(struct cyg_devtab_entry *tab);
static Cyg_ErrNo  spi_lookup(struct cyg_devtab_entry **tab, 
                             struct cyg_devtab_entry *sub_tab,
                             const char *name);
static Cyg_ErrNo  spi_write(cyg_io_handle_t handle, 
                            const void *buffer, 
                            cyg_uint32 *len);
static Cyg_ErrNo  spi_read(cyg_io_handle_t handle, 
                           void *buffer, 
                           cyg_uint32 *len);
static cyg_bool   spi_select(cyg_io_handle_t handle, 
                             cyg_uint32 which, 
                             cyg_addrword_t info);
static Cyg_ErrNo  spi_set_config(cyg_io_handle_t handle, 
                                 cyg_uint32 key, 
                                 const void *buffer, 
                                 cyg_uint32 *len);
static Cyg_ErrNo  spi_get_config(cyg_io_handle_t handle, 
                                 cyg_uint32 key, 
                                 void *buffer, 
                                 cyg_uint32 *len);
static cyg_uint32 spi_ISR(cyg_vector_t vector, 
                          cyg_addrword_t data);
static void       spi_DSR(cyg_vector_t vector, 
                          cyg_ucount32 count, 
                          cyg_addrword_t data);

static quicc_spi_serial_info quicc_spi_serial_info1 = {
    CYGNUM_HAL_INTERRUPT_CPM_SPI // interrupt
};

DEVIO_TABLE(spi_handlers,
            spi_write,                                   
            spi_read,
            spi_select,
            spi_get_config,
            spi_set_config);

DEVTAB_ENTRY(spi_device,
             SPI_NAME,
             NULL,                                   // Base device name
             &spi_handlers,
             spi_init,
             spi_lookup,
             &quicc_spi_serial_info1);

static bool      
spi_init(struct cyg_devtab_entry *tab)
{
    quicc_spi_serial_info *spi_chan = (quicc_spi_serial_info *)tab->priv;
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    volatile struct spi_pram *spi = &eppc->pram[SCC2].scc.pothers.spi_timer_idma.spi;
    int TxBD, RxBD;
    struct cp_bufdesc *txbd, *rxbd;
    cyg_uint8 *TxBUF, *RxBUF;
    int cache_state;
    int i;

    HAL_DCACHE_IS_ENABLED(cache_state);
    HAL_DCACHE_SYNC();
    HAL_DCACHE_DISABLE();

    // initiialize out_fbuf and in_fbuf
    for( i=0; i<SPI_RxBUFS; i++ ) spi_chan->out_fbuf.data[i] = NULL;
    spi_chan->out_fbuf.nb  = 0;
    spi_chan->out_fbuf.put = 0;
    spi_chan->out_fbuf.get = 0;
    cyg_drv_mutex_init( &spi_chan->out_fbuf.lock ); 
    cyg_drv_cond_init( &spi_chan->out_fbuf.wait, &spi_chan->out_fbuf.lock );
    spi_chan->out_fbuf.waiting = false;
    spi_chan->out_fbuf.abort = false;

    for( i=0; i<SPI_RxBUFS; i++ ) spi_chan->in_fbuf.data[i] = &spi_in_buf[i][0];
    spi_chan->in_fbuf.nb  = 0;
    spi_chan->in_fbuf.put = 0;
    spi_chan->in_fbuf.get = 0;
    cyg_drv_mutex_init( &spi_chan->in_fbuf.lock ); 
    cyg_drv_cond_init( &spi_chan->in_fbuf.wait, &spi_chan->in_fbuf.lock );
    spi_chan->in_fbuf.waiting = false;
    spi_chan->in_fbuf.abort = false;

    TxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*SPI_TxNUM);
    RxBD = _mpc8xx_allocBd(sizeof(struct cp_bufdesc)*SPI_RxNUM);

    TxBUF = &spi_txbuf[0][0]; // = ALIGN_TO_CACHELINES( temp_ptr );
    RxBUF = &spi_rxbuf[0][0]; // = ALIGN_TO_CACHELINES( temp_ptr );

    spi_chan->pram = spi;

    /* Set up PortB pins for SPI operation (Tx and Rx) */
    eppc->pip_pbpar |= 0x0000000E;  // set   pbpar for SPICLK, SPIMOSI, SPIMISO
    eppc->pip_pbdir |= 0x0000000E;  // set   pbdir for SPICLK, SPIMOSI, SPIMISO
    eppc->pip_pbodr &= 0xFFFFFFF1;  // clear pbodr for SPICLK, SPIMOSI, SPIMISO

    /* Set pointers to buffer descriptors */
    spi->rbase = RxBD;
    spi->tbase = TxBD;

    /* Reset Rx & Tx params */
    eppc->cp_cr = QUICC_CPM_SPI | QUICC_SPI_CMD_InitTxRx | QUICC_SPI_CMD_Go;

    /* SDMA & LCD bus request level 5 */
    eppc->dma_sdcr = 1;

    /* Set Rx and Tx function code */
    spi->rfcr = 0x10;  // Byte ordering = big-endian or true little endian
    spi->tfcr = 0x10;

    /* max receive buffer length */
    spi->mrblr = SPI_RxSIZE;

    /* tx and rx buffer descriptors */
    txbd = (struct cp_bufdesc *)((char *)eppc + TxBD);
    rxbd = (struct cp_bufdesc *)((char *)eppc + RxBD);

    spi_chan->txbd   = txbd;
    spi_chan->tbase  = txbd;
    spi_chan->txsize = SPI_TxSIZE;
    spi_chan->rxbd   = rxbd;
    spi_chan->rbase  = rxbd;
    spi_chan->rxsize = SPI_RxSIZE;

    /* setup RX buffer descriptors */
    for (i = 0; i < SPI_RxNUM; i++)
    {
        rxbd->length = 0;
        rxbd->buffer = RxBUF;
        rxbd->ctrl   = QUICC_BD_CTL_Ready | QUICC_BD_CTL_Int;
        if (i == (SPI_RxNUM-1)) rxbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
        memset( RxBUF, 0x00, SPI_RxSIZE ); // + HAL_DCACHE_LINE_SIZE-1 );
        RxBUF += SPI_RxSIZE; // + HAL_DCACHE_LINE_SIZE-1;
        rxbd++;
    }
    /* setup TX buffer descriptors */
    for (i = 0; i < SPI_TxNUM; i++)
    {
        txbd->length = 0;
        txbd->buffer = TxBUF;
        txbd->ctrl   = QUICC_BD_CTL_Last;
        if (i == (SPI_TxNUM-1)) txbd->ctrl |= QUICC_BD_CTL_Wrap;  // Last buffer
        memset( TxBUF, 0x00, SPI_TxSIZE ); //+ HAL_DCACHE_LINE_SIZE-1 );
        TxBUF += SPI_TxSIZE; // + HAL_DCACHE_LINE_SIZE-1;
        txbd++;
    }

    /* Clear any previous events. Enable interrupts. (Section 16.15.7.14 and 16.15.7.15) */
    eppc->spi_spie = 0xFF;
    eppc->spi_spim = QUICC_SPIE_BSY | QUICC_SPIE_TXB | QUICC_SPIE_MME | QUICC_SPIE_TXE | QUICC_SPIE_RXB;

    /* NOTE: I get RXB interrupts even when SPI interrupt mask has RXB interrupts turned off */

    eppc->spi_spmode = QUICC_SPMODE_MS | QUICC_SPMODE_LEN | QUICC_SPMODE_REV | QUICC_SPMODE_PM_0;

    cyg_drv_interrupt_create(spi_chan->int_num,
                             CYGARC_SIU_PRIORITY_HIGH, // Priority - unused (but asserted)
                             (cyg_addrword_t)spi_chan, // Data item passed to interrupt handler
                             spi_ISR,
                             spi_DSR,
                             &spi_chan->serial_interrupt_handle,
                             &spi_chan->serial_interrupt);
    cyg_drv_interrupt_attach(spi_chan->serial_interrupt_handle);
    cyg_drv_interrupt_unmask(spi_chan->int_num);

    if (cache_state)
        HAL_DCACHE_ENABLE();

    eppc->spi_spmode |= QUICC_SPMODE_EN;

    return true;
}

static Cyg_ErrNo 
spi_lookup(struct cyg_devtab_entry **tab, 
           struct cyg_devtab_entry *st, 
           const char *name)
{

    return ENOERR;
}

static Cyg_ErrNo 
spi_write(cyg_io_handle_t handle, const void *buffer, cyg_uint32 *len)
{
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
    quicc_spi_serial_info *spi_chan = (quicc_spi_serial_info *)t->priv;
    cyg_int32 size = *len;
    cyg_uint8 *buf = (cyg_uint8 *)buffer;
    fbuf_t *fbuf = &spi_chan->out_fbuf;
    Cyg_ErrNo res = ENOERR;
    EPPC *eppc = eppc_base();
    volatile struct cp_bufdesc *txbd, *txfirst;
    cyg_bool found = true;
    int cache_state;

    if( (size <= 0) || (size > SPI_TxSIZE) || ( buf == NULL ) ) return -EINVAL;

    cyg_drv_mutex_lock( &fbuf->lock );
    fbuf->abort = false;
    cyg_drv_dsr_lock();  // avoid race condition testing pointers

    // Scan for an idle buffer
    txbd = (struct cp_bufdesc *)((char *)eppc + spi_chan->pram->tbptr);
    txfirst = txbd;
    while (txbd->ctrl & QUICC_BD_CTL_Ready)
    {
        // This buffer is busy, move to next one
        if (txbd->ctrl & QUICC_BD_CTL_Wrap)
        {
            txbd = spi_chan->tbase;
        }
        else
        {
            txbd++;
        }
        if (txbd == txfirst)  // Went all the way around
        {
            found = false;
            break;
        }
    }

    // if no idle buffer found, wait for a transmit interrupt & check again
    if( found == false )
    {
        // Block until transmit interrupt is detected
        fbuf->waiting = true;
        if( !cyg_drv_cond_wait(&fbuf->wait) )
        {
            fbuf->abort = true;
            res = -EINTR;   // interrupted
        }
        else
        {
            found = true;
            // Scan for a non-busy buffer
            txbd = (struct cp_bufdesc *)((char *)eppc + spi_chan->pram->tbptr);
            txfirst = txbd;
            while (txbd->ctrl & QUICC_BD_CTL_Ready)
            {
                // This buffer is busy, move to next one
                if (txbd->ctrl & QUICC_BD_CTL_Wrap)
                {
                    txbd = spi_chan->tbase;
                }
                else
                {
                    txbd++;
                }
                if (txbd == txfirst)  // Went all the way around
                {
                    found = false;
                    res = -ENOSPC;
                    break;
                }
            }
        }
    }

    if( found == true )
    {

        spi_chan->txbd = txbd;

        if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == 0)
        {

            // Transmit buffer is not full/busy - copy data into bd
            memcpy( (unsigned char *)txbd->buffer, buf, size );
            txbd->length = size;

            // This buffer is now full, tell SCC to start processing it

            HAL_DCACHE_IS_ENABLED(cache_state);
            if (cache_state)
            {
                HAL_DCACHE_FLUSH(txbd->buffer, spi_chan->txsize);
            }

            txbd->ctrl |= QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int;  // Signal buffer ready
            if (txbd->ctrl & QUICC_BD_CTL_Wrap)
            {
                txbd = spi_chan->tbase;
            }
            else
            {
                txbd++;
            }
            spi_chan->txbd = txbd;

            eppc->spi_spcom = QUICC_SPIC_STR;

            res = ENOERR;
        } 
        else 
        {
            // No space
            res = -ENOSPC;
        }

    }

    cyg_drv_dsr_unlock();
    cyg_drv_mutex_unlock(&fbuf->lock);

    return res;
}

static Cyg_ErrNo 
spi_read(cyg_io_handle_t handle, void *buffer, cyg_uint32 *len)
{
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
    quicc_spi_serial_info *spi_chan = (quicc_spi_serial_info *)t->priv;
    cyg_uint8 *buf = (cyg_uint8 *)buffer;
    fbuf_t *fbuf = &spi_chan->in_fbuf;
    Cyg_ErrNo res = ENOERR;

    cyg_drv_mutex_lock( &fbuf->lock );
    fbuf->abort = false;
    cyg_drv_dsr_lock();  // avoid race condition testing pointers

    if( fbuf->nb == 0 ) // no data yet - wait for receive interrupt 
    {

        fbuf->waiting = true;  // set to false in DSR       

        if( !cyg_drv_cond_wait(&fbuf->wait) )  // block waiting for data
            fbuf->abort = true;
    }

    if( fbuf->abort )
    {
        fbuf->abort = false;
        fbuf->waiting = false;
        res = -EINTR;
    }
    else
    {
        // remove buffer from fbuf and copy to read buffer
        memcpy( buf, fbuf->data[fbuf->get], SPI_RxSIZE );
        if( ++fbuf->get == SPI_RxBUFS ) fbuf->get = 0;
        fbuf->nb--;
    }
    
    cyg_drv_dsr_unlock();
    cyg_drv_mutex_unlock(&fbuf->lock);

    return res;
}

static cyg_bool  
spi_select(cyg_io_handle_t handle, 
           cyg_uint32 which, 
           cyg_addrword_t info)
{

    return false;
}

static Cyg_ErrNo 
spi_set_config(cyg_io_handle_t handle, 
               cyg_uint32 key, 
               const void *buffer, 
               cyg_uint32 *len)
{
    return EINVAL;
}

static Cyg_ErrNo 
spi_get_config(cyg_io_handle_t handle, 
               cyg_uint32 key, 
               void *buffer, 
               cyg_uint32 *len)
{
    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;
    quicc_spi_serial_info *spi_chan = (quicc_spi_serial_info *)t->priv;
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    fbuf_t *out_fbuf = &spi_chan->out_fbuf;
    fbuf_t *in_fbuf  = &spi_chan->in_fbuf;
    Cyg_ErrNo res = ENOERR;

    switch( key )
    {
    case CYG_IO_GET_CONFIG_SERIAL_ABORT:
        // Abort blocked reads and writes
        in_fbuf->abort = true;
        cyg_drv_cond_signal( &in_fbuf->wait );
        out_fbuf->abort = true;
        cyg_drv_cond_signal( &out_fbuf->wait );
        break;
    case 0x2000:  // start SPI
        /* Enable transmitter & receiver */
        eppc->spi_spcom = QUICC_SPIC_STR;
        break;
    case 0x3000:  // stop SPI
        /* Enable transmitter & receiver */
        //ctl->scc_gsmr_l &= ~(QUICC_GSMRL_ENR | QUICC_GSMRL_ENT);
        break;

    default:
        res = -EINVAL;
    }

    return res;
}

// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32 
spi_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
    quicc_spi_serial_info *spi_chan = (quicc_spi_serial_info *)data;
    cyg_drv_interrupt_mask(spi_chan->int_num);
    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Cause DSR to be run
}

// Serial I/O - high level interrupt handler (DSR)
static void       
spi_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
    quicc_spi_serial_info *spi_chan = (quicc_spi_serial_info *)data;
    volatile struct cp_bufdesc *txbd;
    volatile struct cp_bufdesc *rxbd = spi_chan->rxbd;
    struct cp_bufdesc *rxlast;
    volatile EPPC *eppc = (volatile EPPC *)eppc_base();
    fbuf_t *out_fbuf = &spi_chan->out_fbuf;
    fbuf_t *in_fbuf  = &spi_chan->in_fbuf;
    int cache_state;
    unsigned char *slot;

    if (eppc->spi_spie & QUICC_SPIE_TXB)
    {
        // Transmit interrupt
        eppc->spi_spie = QUICC_SPIE_TXB;  // Reset interrupt state
        txbd = spi_chan->tbase;  // First buffer
        while (true)
        {
            if ((txbd->ctrl & (QUICC_BD_CTL_Ready|QUICC_BD_CTL_Int)) == QUICC_BD_CTL_Int)
            {
                txbd->length = 0;
                txbd->ctrl &= ~QUICC_BD_CTL_Int;  // Reset interrupt bit
            }
            if (txbd->ctrl & QUICC_BD_CTL_Wrap) 
            {
                txbd = spi_chan->tbase;
                break;
            }
            else 
            {
                txbd++;
            }
        }
        out_fbuf->waiting = false;
        cyg_drv_cond_signal( &out_fbuf->wait );
    }

    while (eppc->spi_spie & QUICC_SPIE_RXB) 
    {
        // Receive interrupt
        eppc->spi_spie = QUICC_SPIE_RXB;  // Reset interrupt state;
        rxlast = (struct cp_bufdesc *) ( (char *)eppc_base() + spi_chan->pram->rbptr );

        if( rxbd == rxlast ) 
        {

            /* Disable transmitter & receiver */
            //ctl->scc_gsmr_l = QUICC_GSMRL_NONE; 

            rxbd->ctrl |= QUICC_BD_CTL_Ready;

            /* Enable transmitter & receiver */
            //ctl->scc_gsmr_l = QUICC_GSMRL_ENR | QUICC_GSMRL_ENT; 
        }
        else 
        {

            while (rxbd != rxlast) 
            {
                if ((rxbd->ctrl & QUICC_BD_CTL_Ready) == 0) 
                {
                    if( in_fbuf->nb < SPI_RxBUFS ) 
                    {
                        // add rxbd buffer to fbuf
                        slot = in_fbuf->data[in_fbuf->put++];
                        memcpy( slot, (unsigned char *)rxbd->buffer, rxbd->length );
                        if( in_fbuf->put == SPI_RxBUFS ) in_fbuf->put = 0; // wrap
                        in_fbuf->nb++;
                    }
                    else 
                    {
                        // overrun
                    }
                    // if spi_read is blocked, unblock it
                    if( in_fbuf->waiting ) 
                    {
                        in_fbuf->waiting = false;
                        cyg_drv_cond_signal( &in_fbuf->wait );
                    }
                    // Note: the MBX860 does not seem to snoop/invalidate the data cache properly!
                    HAL_DCACHE_IS_ENABLED(cache_state);
                    if (cache_state) 
                    {
                        HAL_DCACHE_INVALIDATE(rxbd->buffer, spi_chan->rxsize);  // Make sure no stale data
                    }
                    rxbd->length = 0;
                    rxbd->ctrl |= QUICC_BD_CTL_Ready;
                }
                if (rxbd->ctrl & QUICC_BD_CTL_Wrap)
                {
                    rxbd = spi_chan->rbase;
                }
                else 
                {
                    rxbd++;
                }
            }
        }
        spi_chan->rxbd = (struct cp_bufdesc *)rxbd;
    }

    if (eppc->spi_spie & QUICC_SPIE_BSY) 
    {
        //diag_printf("RX BUSY interrupt\n");
        eppc->spi_spie = QUICC_SPIE_BSY;  // Reset interrupt state;
        eppc->cp_cr = QUICC_CPM_SPI | QUICC_SPI_CMD_Go; // enter hunt mode
    }

    cyg_drv_interrupt_acknowledge(spi_chan->int_num);
    cyg_drv_interrupt_unmask(spi_chan->int_num);

}
-- 
Before posting, please read the FAQ: http://sources.redhat.com/fom/ecos
and search the list archive: http://sources.redhat.com/ml/ecos-discuss

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