Aquí está mi código fuente. Este código funciona perfectamente en el compilador C18. No hasta que migré a Hi Tech C. No ingresa a la rutina de servicio de interrupción. Por otra parte, de alguna manera corrompió la variable sid pasada a una función. En lugar de pasar un valor de 0x501, pasó 0x000. ¿Hay algo que haya faltado en configurar una interrupción?
#include <p18f25k80.h>
#include <stdio.h>
#include "ect_2014_debugger.h"
#include "ect_2014_can.h"
//#pragma config CONFIG1L = 0x15
__CONFIG(1, RETEN_OFF & INTOSCSEL_HIGH & SOSCSEL_DIG & XINST_OFF);
//#pragma config CONFIG1H = 0x92
__CONFIG(2, FOSC_HS2 & PLLCFG_ON & FCMEN_OFF & IESO_ON);
//#pragma config CONFIG2L = 0x78
__CONFIG(3, PWRTEN_ON & BOREN_OFF & BORV_3 & BORPWR_ZPBORMV);
//#pragma config CONFIG2H = 0x7C
__CONFIG(4, WDTEN_OFF & WDTPS_1048576);
//#pragma config CONFIG3H = 0x89
__CONFIG(5, CANMX_PORTB & MSSPMSK_MSK7 & MCLRE_ON);
//#pragma config CONFIG4L = 0x80
__CONFIG(6, STVREN_OFF & BBSIZ_BB1K);
//#pragma config CONFIG5L = 0xF
__CONFIG(7, CP0_OFF & CP1_OFF & CP2_OFF & CP3_OFF);
//#pragma config CONFIG5H = 0xC0
__CONFIG(8, CPB_OFF & CPD_OFF);
//#pragma config CONFIG6L = 0xF
__CONFIG(9, WRT0_OFF & WRT1_OFF & WRT2_OFF & WRT3_OFF);
//#pragma config CONFIG6H = 0xE0
__CONFIG(10, WRTC_OFF & WRTB_OFF & WRTD_OFF);
//#pragma config CONFIG7L = 0xF
__CONFIG(11, EBTR0_OFF & EBTR1_OFF & EBTR2_OFF & EBTR3_OFF);
//#pragma config CONFIG7H = 0x40
__CONFIG(12, EBTRB_OFF);
/* CAN Header */
// CAN = PORTB
#define SID_CAN1 0x500
#define SID_CAN2 0x501
#define NOMASK 0x7FF
void interrupt ISR(void) {
unsigned char rxbuf[8] = {0};
unsigned int sid = 0, dlc = 0, i = 0;
unsigned char rtr = 0;
if (PIR5bits.RXB0IF && PIE5bits.RXB0IE) {
printf("Interrupt inside\n\r");
rtr = receive_can_msg_rxb0(rxbuf, &sid, &dlc); // Automatically clears the interrupt flag.
if (!rtr) { // Data Frame
if (sid == SID_CAN2) {
printf("SID = %x\n\rDLC = %d\n\r", sid, dlc);
for (i = 0; i < 8; i++)
printf("rxbuf[%d] = %d\n\r", i, rxbuf[i]);
printf("\n\r\n\r");
}
}
}
}
//void interrupt ISR(void);
void main() {
unsigned int sid[2] = {SID_CAN2, 0};
unsigned int mask[2] = {NOMASK, NOMASK};
initUART(1); // Used for debugging
RCONbits.IPEN = 0; // Disable Priority Interrupts
initCAN(&sid[0], mask); // SID = 0x501; MASK = NOMASK
while (1);
}
Aquí está la función initCAN:
void initCAN(unsigned int * sid, unsigned int * mask) {
PIE5bits.RXB0IE = 0;
PIE5bits.RXB1IE = 0;
char i = 0;
// 1. Initial LAT and TRIS bits for RX and TX CAN.
TRISBbits.TRISB2 = 0; // TX
TRISBbits.TRISB3 = 1; // RX
LATBbits.LATB2 = 0; // Initialize 0 for TX
// 2. Ensure that the ECAN module is in Configuration Mode
/* CANCON is the CAN Control Register */
CANCONbits.REQOP = 4; // REQOP<2:0> is a group of 3 bits; ensures that ECAN module
#ifdef CAN_DEBUGGER
printf("******* ECAN Module Initialization *******\n\r");
printf("The ECAN Module is currently requesting to be in configuration mode.\n\r");
#endif
while (CANSTATbits.OPMODE != 4);
// A request to configuration mode might not be honored immediately, as do to loopback,
// disable, and etc. It is a good practice though to wait until the request to configuration
// mode is completed.
#ifdef CAN_DEBUGGER
printf("The ECAN Module is now in configuration mode.\n\r");
#endif
// 3. Select ECAN Operational Mode.
/* ECANCON is the Enhanced CAN Control Register.*/
ECANCONbits.MDSEL = 0; // Configures the ECAN module to mode 0.
// 4. Set up the Baud Rate registers.
// Sync Jump Width is subtracted from Phase_seg2 or added to phase_seg1 to synchronize itself
// to the data bit to be sampled.
CIOCONbits.ENDRHI = 1; // 0 - Transcieverless CAN; 1 - Transciever CAN
CIOCONbits.CLKSEL = 0; // Use the PLL as the CAN clock source, 64MHz
// FOSC = 64 Mbps; Tosc = 15.625ns
BRGCON1bits.BRP = 1; // Tq(us) = (2*(1+1))/64MHz = 62.5 ns
// Nominal Bit Time = Tq*sigma
// sigma = 1us/62.5ns = 16Tq
BRGCON1bits.SJW = 0; // SJQ = 1Tq is typically enough as shown in the datasheet.
BRGCON2bits.SEG2PHTS = 1; // Seg_phase 2 length = Freely Programmable
BRGCON2bits.SAM = 0; //Bus line is sampled once at the sample point
BRGCON2bits.SEG1PH = 0b111; //Phase segment 1 = 8TQ
BRGCON2bits.PRSEG = 0b000; //Propagation segment = 1TQ
BRGCON3bits.SEG2PH = 0b101; //Phase segment 2 = 6TQ
// Verifying the baud rate configuration..
// 1+8+1+6 = 16Tq.
// Prop_Seg (1) + Phase_Seg1 (8) >= Phase_seg 2 (6) : TRUE
// Phase_seg2(6) >= Sync Jump Width(1) : TRUE
// 5. Set up the Filter and Mask Registers
RXB0CON = 0; // Receive buffer is open to new messages; Receive all messages filtered dependent on
// EXIDEN bit;
RXB1CON = 0; // Same as RXB0CON.
// // Initialize Acceptance Filters and Masks to 0x00:
RXF0SIDH = 0; // SID10 to SID3
RXF0SIDL = 0; // SID2 to SID0; Standard frame
RXF1SIDH = 0;
RXF1SIDL = 0;
RXF2SIDH = 0;
RXF2SIDL = 0;
RXF3SIDH = 0;
RXF3SIDL = 0;
RXF4SIDH = 0;
RXF4SIDL = 0;
RXF5SIDH = 0;
RXF5SIDL = 0;
RXM0SIDH = 0xFF;
RXM0SIDL = 0xFF;
RXM1SIDH = 0xFF;
RXM1SIDL = 0xFF;
// Acceptance Filters (RXF0 and RXF1) and filter mask (RXM0) are associated with RXB0.
// Acceptance Filters (RXF2 to RXF5) and filter mask (RXM1) are associated with RXB1.
for (i = 0; i < 5 && *sid != 0; i++) {
if (i == 0) {
#ifdef CAN_DEBUGGER
printf("** Associated with RXB0 **\n\r");
printf("Message Acceptance Filter %d: %x\n\r", i, *sid);
#endif
RXF0SIDH = (*sid & 0x7F8) >> 3; // SID10 to SID3
RXF0SIDL = (*sid++ & 0x007) << 5; // SID2 to SID0; Standard frame
RXF0EIDH = 0;
RXF0EIDL = 0;
} else if (i == 1) {
#ifdef CAN_DEBUGGER
printf("Message Acceptance Filter %d: %x\n\r", i, *sid);
#endif
RXF1SIDH = (*sid & 0x7F8) >> 3; // SID10 to SID3
RXF1SIDL = (*sid++ & 0x007) << 5; // SID2 to SID0; Standard frame
RXF1EIDH = 0;
RXF1EIDL = 0;
} else if (i == 2) {
#ifdef CAN_DEBUGGER
printf("** Associated with RXB1 **\n\r");
printf("Message Acceptance Filter %d: %x\n\r", i, *sid);
#endif
RXF2SIDH = (*sid & 0x7F8) >> 3; // SID10 to SID3
RXF2SIDL = (*sid++ & 0x007) << 5; // SID2 to SID0; Standard frame
RXF2EIDH = 0;
RXF2EIDL = 0;
} else if (i == 3) {
#ifdef CAN_DEBUGGER
printf("Message Acceptance Filter %d: %x\n\r", i, *sid);
#endif
RXF3SIDH = (*sid & 0x7F8) >> 3; // SID10 to SID3
RXF3SIDL = (*sid++ & 0x007) << 5; // SID2 to SID0; Standard frame
RXF3EIDH = 0;
RXF3EIDL = 0;
} else if (i == 4) {
#ifdef CAN_DEBUGGER
printf("Message Acceptance Filter %d: %x\n\r", i, *sid);
#endif
RXF4SIDH = (*sid & 0x7F8) >> 3; // SID10 to SID3
RXF4SIDL = (*sid++ & 0x007) << 5; // SID2 to SID0; Standard frame
RXF4EIDH = 0;
RXF4EIDL = 0;
} else if (i == 5) {
#ifdef CAN_DEBUGGER
printf("Message Acceptance Filter %d: %x\n\r", i, *sid);
#endif
RXF5SIDH = (*sid & 0x7F8) >> 3; // SID10 to SID3
RXF5SIDL = (*sid++ & 0x007) << 5; // SID2 to SID0; Standard frame
RXF5EIDH = 0;
RXF5EIDL = 0;
}
}
for (i = 0; i < 2 && *mask != 0; i++) {
if (i == 0) {
#ifdef CAN_DEBUGGER
printf("\n\r** Associated with RXB0 **\n\r");
printf("Message Acceptance Mask %d: %x\n\r", i, *mask);
#endif
//Mask 0
RXM0SIDH = (*mask & 0x7F8) >> 3;
RXM0SIDL = (*mask++ & 0x007) << 5;
RXM0EIDH = 0xFF;
RXM0EIDL = 0xFF;
} else if (i == 1) {
#ifdef CAN_DEBUGGER
printf("** Associated with RXB1 **\n\r");
printf("Message Acceptance Mask %d: %x\n\r", i, *mask);
#endif
//Mask 1
RXM1SIDH = (*mask & 0x7F8) >> 3;
RXM1SIDL = (*mask++ & 0x007) << 5;
RXM1EIDH = 0xFF;
RXM1EIDL = 0xFF;
}
}
// 6. Set the ECAN Module to normal mode or any other mode required by the application logic.
CANCONbits.REQOP = 0; // Normal Mode
while (CANSTATbits.OPMODE != 0); // Wait until ECAN module is configured as normal mode.
#ifdef CAN_DEBUGGER
printf("******* ECAN Module is now operating in normal mode *******\n\r");
#endif
// (Optional) Enable interrupts.
PIR5bits.RXB0IF = 0;
PIR5bits.RXB1IF = 0;
PIE5bits.RXB0IE = 1;
PIE5bits.RXB1IE = 1;
INTCONbits.GIE = 1;
INTCONbits.PEIE = 1;
#ifdef CAN_DEBUGGER
printf("******* Interrupts are also enabled! *******\n\r");
#endif
}
Y aquí está el código fuente de C18:
#include <p18f25k80.h>
#include <stdio.h>
#include "ect_2014_debugger.h"
#include "ect_2014_can.h"
#pragma config RETEN = OFF //Ultra low-power regulator is Disabled
#pragma config XINST = OFF //Extended Instruction Set Disabled
#pragma config IESO = ON //Two speed start-up mode enable
#pragma config FOSC = HS2 //HS oscillator (High power, 16 MHz - 25 MHz)
#pragma config PLLCFG = ON //Enable PLL x4
#pragma config PWRTEN = ON //Enable Power Up timer
#pragma config BOREN = OFF //Disable Brown Out Detection
#pragma config WDTEN = OFF //Disable Watch Dog Timer
#pragma config MCLRE = ON //Enable MCLR
#pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF,CP3 = OFF,CPB = OFF,CPD = OFF
#pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF,WRT3 = OFF,WRTC = OFF,WRTB = OFF,WRTD = OFF
#pragma config EBTR0 = OFF,EBTR1 = OFF,EBTR2 = OFF,EBTR3 = OFF,EBTRB = OFF
#pragma config SOSCSEL = DIG //RC0 and RC1 are digital IO
/* CAN Header */
#pragma config CANMX = PORTB // ECAN TX and RX pins are located on RB2 and RB3, respectively
#define SID_CAN1 0x500
#define SID_CAN2 0x501
#define NOMASK 0x7FF
void isr(void);
#pragma code high_vector=0x08
void interrupt_at_high_vector(void) {
_asm GOTO isr _endasm
}
#pragma code
#pragma interrupt isr
void isr(void) {
unsigned char rxbuf[8] = {0};
unsigned int sid = 0, dlc = 0, i = 0;
unsigned char rtr = 0;
if (PIR5bits.RXB0IF && PIE5bits.RXB0IE) {
printf((const far rom char*) "Interrupt inside\n\r");
rtr = receive_can_msg_rxb0(rxbuf, &sid, &dlc); // Automatically clears the interrupt flag.
if (!rtr) { // Data Frame
if (sid == SID_CAN2) {
printf((const far rom char*) "SID = %x\n\r", sid);
for (i = 0; i < 8; i++)
printf((const far rom char *) "rxbuf[%d] = %d\n\r", i, rxbuf[i]);
printf((const far rom char *) "\n\r\n\r");
}
}
}
}
void main() {
unsigned int sid[2] = {SID_CAN2, 0};
unsigned int mask[2] = {NOMASK, NOMASK};
int i,j;
initUART(1); // Used for debugging
initCAN(sid, mask); // SID = 0x501; MASK = NOMASK
while (1)
for (i = 0; i < 1000; i++)
for (j = 0; j < 1000; j++)
if (i == 999 && j == 999)
printf("RXB0IF = %d\n\rRXB1IF = %d\n\rRXFUL = %d\n\r", PIR5bits.RXB0IF, PIR5bits.RXB0IF,RXB0CONbits.RXFUL);
}