![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
ZackM
Joined: 14 Jun 2006 Posts: 6 Location: Manhattan, Ks
|
CAN and SPI interrupt do not work together? |
Posted: Mon Jun 19, 2006 3:28 pm |
|
|
Hello, I’m trying to get a PIC18F2680 to run can_rx interrupt, along with ssp interrupt. I have both of these interrupts working fine on the same PIC individually. The problem occurs when I combine the 2, sspbuf dominates the PIC. With the SPI on, no CAN packet comes in or out of that PIC.
I’m out of ideas, is there something I’m missing?
The layout:
___
|18F| ---- SPI ---- > ADCs & MAX3100
----
| |
| \--------CAN-----> Another 18F & PC w/ PCMCIA-CAN/2
\
\------RS232---> PC monitoring |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 19, 2006 3:33 pm |
|
|
Use the #priority statement to give the CAN interrupt priority over
the SSP interrupt. |
|
![](templates/subSilver/images/spacer.gif) |
ZackM
Joined: 14 Jun 2006 Posts: 6 Location: Manhattan, Ks
|
|
Posted: Mon Jun 19, 2006 3:59 pm |
|
|
Wow, you were quick. I gave #priority a run, and I also tried the fast extension with #device high_ints =true. No luck with either.
CAN packets from the 18F are also not going out. The routine that sends the CAN packets are not on a CAN interrupt but TIMER0. I can see that the timer0 interrupt works and runs the code with the debugger. Unfortunately, with SPI on, the packet never gets sent. I'm using the CAN-18F4580.c library. I can see that all the register get loaded and the transmit flag set. For some reason, having activity on SPI doesn't let anything go through. I don't know what the deal is. Does this bring any ideas to mind?
Thanks for your speedy response!
-Zack |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 19, 2006 5:16 pm |
|
|
1. Are you using SPI as a master or slave ? Is the SSP interrupt
for an SPI slave or a master ? If you are using it as a Master
and you if enable interrupts and the buffer is empty, you will get
continuous interrupts. The program will appear to lock up.
To prevent this, when you're in the isr, you need to check if there
is any data remaining to be sent, and if not, then disable SSP
interrupts.
2. Are you testing all this by trying to single-step through it with the
debugger, or are you testing it at full speed operation with the
program running in stand-alone mode ? There are limitations
to the ICD2 debugger. For example, the help file in MPLAB
says "You cannot single step through an interrupt".
3. When you enable interrupts, are you using two separate
enable_interrupts() statements to do so ? You need to do it that
way. Don't try to bitwise "OR" the interrupt constants together in
one statement. |
|
![](templates/subSilver/images/spacer.gif) |
ZackM
Joined: 14 Jun 2006 Posts: 6 Location: Manhattan, Ks
|
|
Posted: Mon Jun 19, 2006 7:42 pm |
|
|
Thanks, PCM Programmer for your time.
The answer to your questions,
#1) The program is running as Master on SPI, I wasn’t aware that SPI interrupt always went off. This code I’m developing is for telemetry and motor contol system on an electric car. There is always ADCs to be polled over SPI. To allow time for other things to be processed, I set the SPI clock to 1/64th of internal. It seems to work, as the main while loop works (There’s a code snippet below with the main while loop labeled).
#2) I’ve been testing the program with and without the Debugger. I make the clam that no packet are being sent or received with the chip running without the debugger. I make the claim that the CAN receive interrupt never gets ran from observation of setting a stop in the CAN receive interrupt routine with the debugger.
#3) All interrupts are enabled with their own and separate command.
I’ll include a cut down (snippet) of my code, as the actual thing is rather big ..
Code: |
#include <18f2680.h>
#device high_ints=true
#use delay(clock=20000000)
#fuses HS,NOWDT,PUT,NOPROTECT,NOLVP
#include <can-18F4580.c>
#priority CANRX1
#use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
//The main routine
void main()
{
printf("Hello");
//Starting up the process
delay_ms(1000);
SET_TRIS_B(0x00);
SET_TRIS_C(0x4A); //Inputs: RX, SDO, PIN_C2
spi_setup();
can_setup();
serial_setup();
//Gonna set the world in motion
enable_interrupts(GLOBAL);
delay_ms(1000);
//Da main funky loop
while (1)
{
//Blinky light, purdy light
output_bit(PIN_C1,!INPUT_STATE(PIN_C1));
Display_windmill(); //A routine that produces a windmill on a display
//connected to a display on a MAX3110
delay_ms(17);
}
}
void can_setup(){
can_init();
//Change baud to 500k
can_set_mode(CAN_OP_CONFIG);
BRGCON1=0x01; //These values were created using a calc from Microchip
BRGCON2=0xA0;
BRGCON3=0x02;
can_set_mode(CAN_OP_NORMAL);
//Set additional buffers to be receivers
can_set_functional_mode(10); //Set ECAN to run FIFO mode
can_enable_b_receiver(B0);
can_enable_b_receiver(B1);
can_enable_b_receiver(B2);
can_enable_b_receiver(B3);
can_enable_b_receiver(B4);
can_enable_b_receiver(B5);
//Code to setup up timer0 snipped
enable_interrupts(INT_CANRX1);
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
}
void spi_setup()
{
setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_64);
//Setup MAX3110 for Display
CHNL_SEL(CHNL_DISPLAY);
spi_read(MAX_WRITE_CONFIG | MAX_TBE_ON);
spi_read(MAX_96BAUD);
CHNL_SEL(CHNL_NONE);
//Additional so TBE interrupt starts going
CHNL_SEL(CHNL_DISPLAY);
spi_read(MAX_WRITE_DATA);
spi_read('_');
CHNL_SEL(CHNL_NONE);
//Time for the display to powerup
delay_ms(500);
enable_interrupts(INT_SSP);
//Allow for spi to pick a task
spi_root();
}
spi_root(){
//Snipped
//Code here assigns what to talk to on SPI, every option ends with
//loading the SSPBUF
}
#INT_SSP
void spi_isr()
{ //Snipped
//Stores data, and also loads SSPBUF when required, when finished
//talking to device it calls spi_root again.
}
#INT_TIMER0
void can_isr_timer(){
can_tx(); //Code that decides what to send, and ends with a
//can_putd();
}
#INT_CANRX1 FAST
void can_rx_isr(){
can_fifo_getd(rx_id,&rxdata[0],rx_len,rxstat);
//Code that processes this data was snipped
}
void serial_setup()
{
//Snip
enable_interrupts(INT_RDA);
}
#INT_RDA
void serial_rda_isr()
{ ser_rx_buf = RCREG;
ser_tx_char(ser_rx_buf); //This enables INT_TBE
if (ser_rx_buf == '`')
{ serMode = 1; //Starts a process of unloading the data on the serial
}
}
#INT_TBE
void serial_tbe()
{
TXREG = ser_tx_buf[ser_tx_tail];
//Snip
//Unloads all the data it has stored
//Ends with disable_interrupt(INT_TBE);
}
|
There is serial, in this code. It has never been a problem and it only executes when I send it a backtick for testing. I've seen no change in the problem with the serial added/removed from the code.
Thanks, PCM for looking at this thread and trying to help. I'm very grateful for that. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 19, 2006 8:32 pm |
|
|
I see one immediate problem. You have declared this isr to be FAST.
Quote: | #INT_CANRX1 FAST
void can_rx_isr(){
can_fifo_getd(rx_id,&rxdata[0],rx_len,rxstat);
//Code that processes this data was snipped
} |
Here is what the CCS manual says about this:
Quote: |
An interrupt marked FAST is performed without saving or
restoring any registers. You should do as little as possible
and save any registers that need to be saved on your own. |
But you're not doing that.
I think that you actually want to use the 'HIGH' keyword instead of 'FAST'.
Read Ttelmah's article on interrupts near the end of this thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=26093 |
|
![](templates/subSilver/images/spacer.gif) |
ZackM
Joined: 14 Jun 2006 Posts: 6 Location: Manhattan, Ks
|
|
Posted: Mon Jun 19, 2006 9:39 pm |
|
|
I add FAST by accident. I was just trying to set some priority to the routine so I could recieve some CAN messages.
I switch it to HIGH. My problem still exists, the PIC can neither send or recieve when it uses it SPI routines.
Thanks for the information, though. I didn't know that about FAST. |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Jun 19, 2006 10:13 pm |
|
|
In your code, you have set_tris_x() statements. But you don't have a
#use fast_io() statement. So the compiler's functions, which you use
after the set_tris_x() statements, will change the TRIS.
In the code below, you set the TRIS for port C to 0x4A.
Quote: | SET_TRIS_C(0x4A); //Inputs: RX, SDO, PIN_C2
spi_setup();
can_setup();
serial_setup(); |
But in the .LST file shown below, the setup_spi() function sets up
the TRIS for the hardware SPI pins. These TRIS values don't match
what you have specified in set_tris_c(0x4A). Are you trying to use
non-hardware pins for the SPI ? The CCS spi functions only work
with the hardware pins.
Code: |
bit: 7654 3210
set_tris_c: 0100 1010
setup_spi: 01 0 |
Code: | ... setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_XMIT_L_TO_H|SPI_CLK_DIV_64);
00138: BCF SSPCON.5
0013A: BCF TRISC.5 // TRISC5 = 0
0013C: BSF TRISC.4 // TRISC4 = 1
0013E: BCF TRISC.3 // TRISC3 = 0
00140: MOVLW 22
00142: MOVWF SSPCON
00144: MOVLW 40
00146: MOVWF SSPSTAT |
|
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|