|
|
View previous topic :: View next topic |
Author |
Message |
matthewsachs
Joined: 19 Jun 2016 Posts: 22
|
PIC18F66K80 CAN Rx Interrupt Not Working |
Posted: Sun Apr 22, 2018 6:19 pm |
|
|
I have been trying for days to get CANBus interrupts to work, but I am having no success. I looked over the older posts and tried some code that seemed relevant, but it didn't work.
My PIC is running off 5V using a 40MHz powered oscillator. I am using a Peak Systems CAN-USB converter to communicate with the PIC board. Termination is OK and all the CANBus connections are solid.
The PIC's CAN transmissions work well and it receives incoming CAN frames fine via the polled if (can_kbhit()) in the main(). This confirms the HW side of things is ok.
However, no matter what I try, I can't get the RX interrupts to trigger.
I am using PCH v5.077. If anyone has any tips please let me know.
Here is my code
Code: |
#include <18F66K80.h>
#device adc=12
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES NOWDT //No Watch Dog Timer
#FUSES ECH_IO //External clock
#FUSES NOPLLEN //4X HW PLL disabled, 4X PLL enabled in software
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES PUT //Power Up Timer
#FUSES BROWNOUT
#FUSES BORV30 //Brownout reset at 3.0V
#FUSES MCLR //Master Clear pin enabled
#FUSES STVREN //Stack full/underflow will cause reset
#FUSES NODEBUG
#FUSES PROTECT
#use delay(clock=40000000)
//
#define CAN_USE_EXTENDED_ID FALSE
#define CAN_BRG_SEG_2_PHASE_TS TRUE
#define CAN_BRG_PRESCALAR 4
#define CAN_BRG_SYNCH_JUMP_WIDTH 1
#define CAN_BRG_PROPAGATION_TIME 1
#define CAN_BRG_PHASE_SEGMENT_1 2
#define CAN_BRG_PHASE_SEGMENT_2 1
#define CAN_BRG_WAKE_FILTER TRUE
#define CAN_BRG_SAM TRUE
#include <can-18F4580.c>
//CAN Variables
int32 rx_id;
int rx_len, can_rx_buffer[8];
struct rx_stat rxstat;
int32 tx_id;
int tx_len = 8;
int can_tx_buffer[8];
int can_rx_message_byte_0 = 0;
int can_B_reply = 0;
int32 can_B_tx_id = 0xAA;
int current_control_byte = 0xFF;
int CAN_frame_count = 0;
long CAN_msg_idx = 9;
#int_canrx0
void canrx0_int ( )
{
usb_forward(0xA0);
can_getd(rx_id, &can_rx_buffer[0], rx_len, rxstat);
}
#int_canrx1
void canrx1_int ( )
{
usb_forward(0xA1);
can_getd(rx_id, &can_rx_buffer[0], rx_len, rxstat);
}
void main()
{
can_init();
can_set_mode(CAN_OP_CONFIG);
can_set_functional_mode(CAN_FUN_OP_ENHANCED);
can_set_id(RX0MASK,0,CAN_USE_EXTENDED_ID);
can_set_id(RX1MASK,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER0,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER1,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER2,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER3,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER4,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER5,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER6,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER7,0xAA,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER8,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER9,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER10,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER11,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER12,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER13,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER14,0,CAN_USE_EXTENDED_ID);
can_set_id(RXFILTER15,0,CAN_USE_EXTENDED_ID);
can_associate_filter_to_buffer(ARXB0,F0BP);
can_associate_filter_to_buffer(ARXB0,F1BP);
can_associate_filter_to_buffer(ARXB0,F2BP);
can_associate_filter_to_buffer(ARXB0,F3BP);
can_associate_filter_to_buffer(ARXB0,F4BP);
can_associate_filter_to_buffer(ARXB0,F5BP);
can_associate_filter_to_buffer(ARXB0,F6BP);
can_associate_filter_to_buffer(ARXB0,F7BP);
can_associate_filter_to_buffer(ARXB0,F8BP);
can_associate_filter_to_buffer(ARXB0,F9BP);
can_associate_filter_to_buffer(ARXB0,F10BP);
can_associate_filter_to_buffer(ARXB0,F11BP);
can_associate_filter_to_buffer(ARXB0,F12BP);
can_associate_filter_to_buffer(ARXB0,F13BP);
can_associate_filter_to_buffer(ARXB0,F14BP);
can_associate_filter_to_buffer(ARXB0,F15BP);
can_enable_filter(RXF0EN|RXF1EN|RXF2EN|RXF3EN|RXF4EN|RXF5EN|RXF6EN|RXF7EN|RXF8EN|RXF9EN|RXF10EN|RXF11EN|RXF12EN|RXF13EN|RXF14EN|RXF15EN);
can_set_mode(CAN_OP_NORMAL);
clear_interrupt(int_canrx0);
enable_interrupts(int_canrx0);
clear_interrupt(int_canrx1);
enable_interrupts(int_canrx1);
enable_interrupts(GLOBAL);
while(TRUE)
{
if (can_kbhit())
{
if(can_getd(rx_id, &can_rx_buffer[0], rx_len, rxstat))
{
usb_forward(0xF1);
}
}
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Apr 23, 2018 2:03 am |
|
|
can_getd, polls the interrupt flags and clears them inside the function. I hate to think what is happening, trying to call this both inside and outside an interrupt. Since it does it by direct access to the flags (not using the CCS functions), I don't think the compiler will automatically disable interrupts round the function in the external code. Result may well be deadlock..... |
|
|
matthewsachs
Joined: 19 Jun 2016 Posts: 22
|
|
Posted: Mon Apr 23, 2018 10:04 am |
|
|
I deleted the polling code from the main() function
Code: |
if (can_kbhit())
{
if(can_getd(rx_id, &can_rx_buffer[0], rx_len, rxstat))
{
usb_forward(0xF1);
}
}
} |
and replaced it with a delay_cycles(1); but the RX interrupts never trigger. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Apr 23, 2018 10:13 am |
|
|
OK. The question is how the FIFO is actually configured?. You are going to have to go through the code and find how this is configured. These are the FIFO interrupts and obviously depend on how this is actually configured. |
|
|
matthewsachs
Joined: 19 Jun 2016 Posts: 22
|
|
Posted: Mon Apr 23, 2018 10:23 am |
|
|
I assume that implies analyzing the CCS' #include <can-18F4580.c> file, which I will go and do right away.
Last edited by matthewsachs on Mon Apr 23, 2018 10:52 am; edited 1 time in total |
|
|
matthewsachs
Joined: 19 Jun 2016 Posts: 22
|
|
Posted: Mon Apr 23, 2018 10:51 am |
|
|
So I looked over the datasheet and noticed that RXBnIF behaves differently depending on what mode ECAN is configured for.
Quote: |
When the receive interrupt is enabled, an interrupt will
be generated when a message has been successfully
received and loaded into the associated receive buffer.
This interrupt is activated immediately after receiving
the End-of-Frame (EOF) field.
In Mode 0, the RXBnIF bit is set to indicate the source
of the interrupt. The interrupt is cleared by the MCU,
resetting the RXBnIF bit to a ‘0’.
In Mode 1 and 2, all receive buffers share RXBnIE,
RXBnIF and RXBnIP in PIE5, PIR5 and IPR5, respectively.
Bits, RXBnIE, RXBnIF and RXBnIP, are not
used. Individual receive buffer interrupts can be controlled
by the TXBnIE and BIE0 registers. In Mode 1,
when a shared receive interrupt occurs, user firmware
must poll the RXFUL bit of each receive buffer to detect
the source of interrupt. In Mode 2, a receive interrupt
indicates that the new message is loaded into FIFO.
FIFO can be read by using FIFO Pointer bits, FP. |
I initially used Mode 1 because it gave me more filters, but I can get by with the smaller number.
So I changed this line in my init section
Code: |
//can_set_functional_mode(CAN_FUN_OP_ENHANCED);
can_set_functional_mode(CAN_FUN_OP_LEGACY);
|
and #int_canrx0 started firing.
Based on the datasheet info I can't tell why the interrupts didn't fire in Mode 1 since the only difference seems to be that in Mode 1 the user's FW must determine the source of interrupt. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19497
|
|
Posted: Mon Apr 23, 2018 11:02 am |
|
|
Well done.
The standard code is very much setup on the assumption it'll be polled rather than interrupt driven, so I'm not surprised it needed a tweak!...
It's a long time since I looked at it.
I think in mode1, you don't get the separate interrupts for the FIFO buffers, just the main can interrupt. |
|
|
|
|
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
|