This is the mail archive of the
ecos-discuss@sources.redhat.com
mailing list for the eCos project.
SPI interface does not work with Viper & AdderII running eCos
- From: Paul Randall <prandall at delta-info dot com>
- To: "ecos-discuss at sources dot redhat dot com" <ecos-discuss at sources dot redhat dot com>
- Date: Thu, 02 Oct 2003 11:03:21 -0400
- Subject: [ECOS] 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