Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: SPI Interrupt not firing?

2005-10-17 by Guillermo Prandi

I'm a newbie, so don't take my comment too seriously, but... why are 
you disabling SPIE interrupts in your enqueue function? Couldn't this 
adversedly affect the expected behavior? If your intention is to 
protect the buffer pointers while these are being updated, I'd go for 
a full IRQ disable rather than a targeted masking; of course this is 
acceptable only if you can afford a small lag between interrupts. 
Also, as I read the pseudo-code example in the LPC2138 user's manual, 
the SPI control register should be written to before writing onto the 
data register (which in some way may suggest that it should not be 
written to after the data is set in the shift register). Yhis is what 
I'd do:

int spi0Putch(int ch)
{
uint16_t temp;
unsigned cpsr;

cpsr = disableIRQ(); // disable global interrupts before atempting to 
read spi0_tx_insert_idx (in case of multitasking being used)
// Avoid using modulo operator in ARM7 for performance reasons
//temp = (spi0_tx_insert_idx + 1) % SPI0_TX_BUFFER_SIZE;
temp = spi0_tx_insert_idx + 1;
if( temp == SPI0_TX_BUFFER_SIZE ) temp = 0;
if (temp == spi0_tx_extract_idx)
{
  restoreIRQ(cpsr); // restore global interrupts
  return -1; // no room
}

// check if in process of sending data
if (spi0_tx_running){
  // add to queue
  spi0_tx_buffer[spi0_tx_insert_idx] = (uint8_t)ch;
  spi0_tx_insert_idx = temp;
}
else{
  // set running flag and write to output register
  S0SPCR |= SPCR_SPIE; // enable TX interrupts before writing to 
SOSPDR
  spi0_tx_running = 1;
  S0SPDR = (uint8_t)ch;
}
restoreIRQ(cpsr); // restore global interrupts

return (uint8_t)ch;
}


Hope this helps.

Guille

--- In lpc2000@yahoogroups.com, "ee_gary" <ee_gary@y...> wrote:
>
> --- In lpc2000@yahoogroups.com, Sten <list@n...> wrote:
> >
> > ee_gary wrote:
> > > Long time lurker, first time poster...
> > > 
> > > I've set the SPIE bit in the Control Register.  I can see the 
SPIF bit
> > > get set in the Status Register.  However, I do NOT see the SPI
> > > Interrupt bit get set in the Interrupt Register.  Shouldn't 
this occur
> > > as soon as the SPIF bit is set, regardless of how the VIC is 
set up? 
> > > I have the VIC set up "correctly", but the ISR never executes
> > > (presumably because the SPI Interrupt never fires).  I've had
> > > interrupts working correctly for UART0 and a timer, so I know 
that
> > > interrupts can work (they just aren't in this occasion).
> > > 
> > > I can do non-interrupt SPI transmits (i.e. the 1st byte of an
> > > interrupt-based multibye transfer) so I know the hardware is ok 
(SSEL
> > > = 1).  I've duplicated this on the MCB2130 and a LPC2214 dev 
board.
> > > 
> > > Any insight from those that have implemented interrupt based 
SPI is
> > > appreciated.
> > > 
> > > Stumped in Seattle...
> > > 
> > 
> > Please can you send a small portion of source code? It sounds
> unbelievable.
> > 
> >   Sten
> > 
> > -- 
> > /************************************************
> >  Do you need a tiny and efficient real time
> >  operating system (RTOS) with a preemtive
> >  multitasking for LPC2000 or AT91SAM7?
> > 
> >    http://nanortos.net-attack.de/
> > 
> >  Or some open-source tools and code for LPC2000?
> > 
> >    http://www.net-attack.de/
> > 
> > ************************************************/
> >
> 
> It'd be my pleasure.  Here's the init function:
> void spi0Init(void)
> {
>   // Set port pins for SPI0
>   PINSEL0 = (PINSEL0 & ~S0_PINMASK) | S0_PINSEL;
> 
>   // Set SPI Registers
>   S0SPCR = 0;           // Clear all bits
>   S0SPCR |= SPCR_CPHA;  // Data sampled on rising edge
>   S0SPCR |= SPCR_CPOL;	// SCK active low
>   S0SPCR |= SPCR_MSTR;	// Master mode
> 
>   S0SPSR;         // Cleared by a read of this register
>   S0SPDR;         // Cleared by a read of this register
>   S0SPCCR = 128;  // 8 is max speed
>   S0SPINT = 1;    // Cleared by writing a 1 to it
> 
>   // initialize the interrupt vector
>   VICIntSelect = 0;  // Select IRQ
>   VICIntEnable = 0x00000400;
>   VICVectAddr0 = (unsigned long)spi0ISR;
>   VICVectCntl0 = 0x0000002A;
> 								
	
>   // initialize the transmit data queue
>   spi0_tx_extract_idx = spi0_tx_insert_idx = 0;
>   spi0_tx_running = 0;
> }
> 
> and the transmit function:
> int spi0Putch(int ch)
> {
>   uint16_t temp;
>   unsigned cpsr;
> 
>   temp = (spi0_tx_insert_idx + 1) % SPI0_TX_BUFFER_SIZE;
> 
>   if (temp == spi0_tx_extract_idx)
>     return -1;                          // no room
> 
>   cpsr = disableIRQ();                  // disable global interrupts
>   S0SPCR &= ~SPCR_SPIE;                 // disable TX interrupts
>   restoreIRQ(cpsr);                     // restore global interrupts
> 
>   // check if in process of sending data
>   if (spi0_tx_running){
>     // add to queue
>     spi0_tx_buffer[spi0_tx_insert_idx] = (uint8_t)ch;
>     spi0_tx_insert_idx = temp;
>   }
>   else{
>     // set running flag and write to output register    
>     spi0_tx_running = 1;
>     S0SPDR = (uint8_t)ch;
>   }
>   cpsr = disableIRQ();                  // disable global interrupts
>   S0SPCR |= SPCR_SPIE;                  // enable TX interrupts
>   restoreIRQ(cpsr);                     // restore global interrupts
> 
>   return (uint8_t)ch;
> }
> 
> and finally, the ISR that never fires...
> void spi0ISR(void)
> {
>   // perform proper ISR entry so thumb-interwork works properly
>   ISR_ENTRY();
> 
>   // check if more data to send
>   if (spi0_tx_insert_idx != spi0_tx_extract_idx){
>     S0SPDR = spi0_tx_buffer[spi0_tx_extract_idx++];
>     spi0_tx_extract_idx %= SPI0_TX_BUFFER_SIZE;
>   }
>   else{ // No more to transmit
>     S0SPCR &= ~SPCR_SPIE;
>     spi0_tx_running = 0;
>   }
>   
>   S0SPINT = 1;  
>   VICVectAddr = 0x00000000;   
> 
>   ISR_EXIT();
> }
> 
> It seems like it should be something simple.  Everything looks okay,
> but the ISR never fires.
> 
> Thanks,
> 
> Gary
>

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.