|
|
View previous topic :: View next topic |
Author |
Message |
pmuldoon
Joined: 26 Sep 2003 Posts: 218 Location: Northern Indiana
|
18F26K83 CAN interrupt confusion |
Posted: Wed Jul 21, 2021 7:20 am |
|
|
ccs ver 5.105
18f26K83 chip
can-pic18f_ecan.c/h
What is the proper way to use the CAN RX interrupt?
I had the strangest thing happen.
Everything worked fine until I tried to add a pace delay to the main loop. Then it acted like my timer1 interrupt wasn't running.
I also broke it by adding a LampTest() before the main loop. In this case the LampTest simply wouldn't run. It ran fine in the main loop, but not before the main loop.
The whole problem seems to revolve around the CAN interrupts. All I want to to is fire an interrupt whenever a CAN msg is rec'd. If I do a
Code: |
enable_interrupts(INT_TIMER1 | INT_CANRXB0 | INT_CANRXB1);
|
it breaks. But if I just enable the TMR1 interrupt and enable the CAN interrupts in the main loop (as a test) then the CAN interrupts activate and everything works properly.
I don't really understand how the can_enable_interrupts() function plays into this, it doesn't seem to be necessary for what I'm doing. And I only really intend to use 2 rx buffers, to keep things simple.
So, what is the proper way to set that up?
Also, can I use both #INT_CANRXBx labels to point to the same function?
It seemed to work fine when the program worked, but I can't find any reference to tell me if that's acceptable or not. Would it clear the int flags properly or just be a bad practice? I can do it with separate functions - just curious.
Code: |
#INT_CANRXB0
#INT_CANRXB1
void CanRxB0Interrupt()
{
can_ec_t CanError;
CanError = can_getd(&LastCanMsg, CanDataBuf, CAN_RX_BUFFER_ANY);
if(LastCanMsg.Id == 0xCF00400)
MoveCanData(0);
else if(LastCanMsg.Id == 0x18FEDF00)
MoveCanData(1);
else if(LastCanMsg.Id == 0x18FEF700)
MoveCanData(2);
} |
Here is the MAIN. Sorry for the mess. I just don't have time to send a clean demo of the issue. I'm hoping my clues will help. You can see the context of the locations of the enable_interrupts(). The LampTest() is just outputs and delays, so I didn't show it. I'm really just interested in how to setup for 2 rx buffers and an rx interrupt.
[ Code: |
/******************************* MAIN *****************************************/
void main()
{
uint16_t TerminalCntr = 0; // sets the update rate for the terminal display
InitializeOutputs();
SetDefaults();
// setup SPI for display TLC5925
// 30MHz clock max; reads data on L->H clk transition
setup_spi(SPI_MASTER | SPI_SCK_IDLE_LOW | SPI_CLK_FOSC | SPI_TX_ONLY_MODE | SPI_XMIT_L_TO_H, 16000000);
// setup Timers
setup_timer_1(T1_FOSC | T1_DIV_BY_8); // 16MHz / 8 = 2 counts per uS
set_timer1(0xFFFF - 20000); // 20000 = 10ms
// setup ADC
// ADC_CLOCK_DIV_16 for 16MHz xtal = 1us per Tad
//setup_adc(ADC_LEGACY_MODE | ADC_CLOCK_DIV_16 | ADC_TAD_MUL_8); // ADC_CLOCK_DIV_16 for 16MHz xtal = 1us per Tad
setup_adc(ADC_LOW_PASS_FILTER_MODE | ADC_CLOCK_DIV_16 | ADC_TAD_MUL_8, 5, 255);
//setup_adc(ADC_ACCUMULATE_MODE | ADC_CLOCK_DIV_16 | ADC_TAD_MUL_8, 5, 255);
setup_adc_ports(sAN0|sAN1|sAN4|sAN5|sAN16, VREF_VREF );
// setup CAN
can_init(CAN_OP_NORMAL);
can_set_baud(16000000, 250000);
can_enable_interrupts(CAN_INTERRUPT_RXB0 | CAN_INTERRUPT_RXB1);
// setup interrupts
enable_interrupts(INT_TIMER1);
// enable_interrupts(INT_TIMER1 | INT_CANRXB0 | INT_CANRXB1);
enable_interrupts(GLOBAL);
#if USE_TERMINAL == TRUE
// setup debug terminal
printf("\x1B[2J"); // VT100 clear screen
printf("\n press SPACE to activate terminal");
#endif
output_low(OUT_IGN);
LampTest();
//**************************** MAIN LOOP ***********************************
while(TRUE){
output_low(TESTPIN); // test interrupt timing
// pace the main loop
while(MyLoopDelayMs < 10);
MyLoopDelayMs = 0;
output_high(TESTPIN); // test interrupt timing
enable_interrupts(INT_TIMER1 | INT_CANRXB0 | INT_CANRXB1);
// test ADC by doing a channel read
// output_high(TESTPIN); // test interrupt timing
ReadAnalog();
// output_low(TESTPIN); // test interrupt timing
// test 7-segment display
DisplayValue(TimeSeconds, 0);
// calculate units
FuelOhms = Count2Ohms(FuelCnt);
CompPresPsi = Count2Psi(CompPresCnt);
ExtPotOhms = Count2Ohms(ExtPotCnt);
CompTempOhms = Count2Ohms(CompTempCnt);
VbattMv = Count2Mv(VbattCnt);
#if USE_TERMINAL == TRUE
if(TerminalActive & (TerminalCntr++ > 50)){
TerminalCntr = 0;
// update debug terminal
printf("\x1B[10;10f"); //VT100 move cursor to screen location LINE,COL
printf("\n TimeSeconds : %3u ", TimeSeconds);
printf("\n Vbatt count : %4lu : %5lu mV", VbattCnt, VbattMv);
printf("\n Fuel count : %4lu : %5lu ohms", FuelCnt, FuelOhms);
printf("\n CompPres count: %4lu : %5lu psi ", CompPresCnt,CompPresPsi);
printf("\n ExtPot count : %4lu : %5lu ohms", ExtPotCnt, ExtPotOhms);
printf("\n CompTemp count: %4lu : %5lu ohms", CompTempCnt, CompTempOhms);
printf("\n Oil Pressure : %u", input(IN_OIL_PRES));
// display CAN msgs
printf("\n CAN Real ENG Revolution :");
for (int i =0; i<8; i++) printf(" %x",CanRxDataBuf[0][i]);
printf("\n CAN Target ENG Revolution:");
for (int i =0; i<8; i++) printf(" %x",CanRxDataBuf[1][i]);
printf("\n CAN Battery Voltage :");
for (int i =0; i<8; i++) printf(" %x",CanRxDataBuf[2][i]);
printf("\n 1-Starter 2-Fan 3-Inlet 4-Ign 5-InletB");
}
// check for keypress
if(kbhit()){
switch(getc()){
case '1': output_toggle(OUT_STARTER); break;
case '2': output_toggle(OUT_FAN); break;
case '3': output_toggle(OUT_INLET); break;
case '4': output_toggle(OUT_IGN); break;
case '5': output_toggle(OUT_INLET_B); break;
case ' ': TerminalActive = TRUE; break;
}
}
#endif
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Wed Jul 21, 2021 7:38 am |
|
|
Key critical error:
enable_interrupts(INT_TIMER1 | INT_CANRXB0 | INT_CANRXB1);
You cannot OR together interrupts in the enable line. In the header, it tells you
where things 'can' be ored together. This is not such a place.
In fact the CANRX interurpts will probably OR together without causing a
problem, but when you add the timer interrupt, the result of the OR is
to enable timer5, not timer1, for which you don't have a handler. Result
'disaster'.
Interrupt enables should/must be separate. |
|
|
pmuldoon
Joined: 26 Sep 2003 Posts: 218 Location: Northern Indiana
|
|
Posted: Wed Jul 21, 2021 7:59 am |
|
|
Great catch, T.
Thanks. That seems to have fixed it.
I've only been programming PIC's for about 25 yrs. How did I not know that? I must be getting old! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu Jul 22, 2021 12:07 am |
|
|
Historically, none could be ored here. However more recently, some stuff
can be ored (for example on the interrupt edge commands you can or in the
edge involved). Result it gets more and more confusing!. It really would
be worth CCS adding a bit note saying 'must not be ored' for these values.
Glad I got it!... |
|
|
pmuldoon
Joined: 26 Sep 2003 Posts: 218 Location: Northern Indiana
|
|
Posted: Thu Jul 22, 2021 5:19 am |
|
|
Yes, it's working great now.
And thanks for the quick response. That kept a rush project from going sideways on me.
Half of my mistakes are something so incredibly obvious I just can't see the problem, the other half are so insidiously obscure I can't find them.
The third half I can usually figure out pretty quickly on my own. |
|
|
|
|
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
|