4
\$\begingroup\$

I have an interesting problem with the dsPIC33FJ128GP802.

I have it configured as a slave SPI device connected to an Arduino acting as the master.

Timer1 is set up to trigger an interrupt at specific times in a certain sequence.

One of the sequences of interrupts takes about 50µs to execute. Yes, I know it's not "good practice" to have in interrupt routine lasting that long, but there is only the one interrupt being used in the system, and timing restraints mean that it has to take that long.

Now, it's all working - the SPI is running and receiving commands from the Arduino. The Timer1 is triggering the interrupt at just the right times, and everything is looking good.

Except, I am seeing corruption on the SPI. I can only assume that it is due to the interrupt for Timer1 firing during the SPI transfer. If I disable the timer and its interrupt I get no problems with the SPI transfer at all.

From what I understand of interrupts, all the registers etc are supposed to be in exactly the same state when the ISR returns as they were when the interrupt was triggered. That is certainly what the C30 user manual claims.

I have tried re-writing my C code for the SPI reception in assembly, but the problem still persists.

Here is a snippet of my C code:

while(PORTAbits.RA3==1);     // Wait for a transfer to be requested     
SPI1STATbits.SPIEN=1;        // Enable the SPI module     
SPI1BUF=0x0;                 // Prime the buffer to start a transfer     
LATAbits.LATA1=0;            // Signal to the master it may transfer     
while(PORTAbits.RA3==0);     // Wait for the master to signal it has transferred   
in = SPI1BUF;                // Store the resultant word     
SPI1STATbits.SPIEN=0;        // Turn off the SPI module     
               ... perform operations depending on SPI command received ...     
LATAbits.LATA1=1;            // Signal to the master the command has finished and it may transfer again.
  • RA3 is the Slave Select pin for the SPI
  • LATA4 is reverse handshaking back from the slave to the master

Both are active-low.

As you can see I am using more handshaking than normal SPI, as I need to feed back from the slave to the master when it is safe to start transferring another SPI command.

My ISR is defined as:

void __attribute__((__interrupt__,no_auto_psv)) _T1Interrupt(void)   

I have tried adding the __shadow__ attribute to use the shadow registers, but it has had no effect.

So what actually happens to the SPI in this chip when a timer interrupt is triggered? As it's clocked independently from the main CPU, and just shifts bits in/out of a shift register, surely it should be unaffected by interrupts.

It's doing my nut, so any pointers would be most welcome.

\$\endgroup\$
1
\$\begingroup\$

Normally you would set up the SPI peripheral once, then leave it on. The extra handshaking you are doing is preventing you from using the hardware to its full capability. Also doing a busy wait for the master to assert slave select is a bad idea if you ever want the processor to do something else.

Since you are transferring 16 bits of less per message, I would just let the hardware take care of it. Then you can monitor the SPI interrupt flag to determine when new data has been received from the master. If you need to slow down the master for flow control reasons, I would do that outside of the SPI message. I suspect the interrupt is adding latency to your home grown handshaking scheme, and something somewhere isn't quite right and can't tolerate that latency. That's assuming of course that the interrupt doesn't try to touch the SPI hardware or any of its I/O lines.

\$\endgroup\$
  • 1
    \$\begingroup\$ Unfortunately it is not possible for me to use the hardware's SS handling. On this chip it is shared with one of the PORTB pins, and the data sheet states that "Driving the pin high aborts the transfer", and I have to use the entire PORTB for this system (it acts as a shift register). So I have to manually use a PORTA pin as the SS signal. The processor will never be wanting to do anything else during the busy waits. There are 2 basic operations. The SPI reading, and the timer interrupt. That's all that is going on, and all that will ever be going on. \$\endgroup\$ – Majenko Oct 15 '11 at 13:56
  • \$\begingroup\$ The interrupt does manipulate PORTB, and the SPI functionality is shared with some of the PORTB pins. However, the remapping facility of the dsPIC disables the PORT functionality of those pins when the SPI is enabled on them. The interrupt does not manipulate SPI in any way. \$\endgroup\$ – Majenko Oct 15 '11 at 13:58
  • \$\begingroup\$ I have re-written it all to be 100% interrupt driven - By playing with the interrupt levels on this chip I have got it to actually function right. Thanks for the pointers. \$\endgroup\$ – Majenko Oct 15 '11 at 15:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.