PIC24HJGP504 CAN Example Code (not working)
Trying to get basic CAN Transmission working on a PIC24HJ64GP504. There are a couple of app note examples, but all of them are complex and none seem to cover using CAN with PPS. I tried them anyway, and no success. In an attempt to make the simplest example possible I cut and pasted the code examples from the Family Guide into this application.
Speed is 500kbit with a 16mhz crystal and no PLL. I have a CANUSB adapter and an older 18F2580 based product on the bus. I can see frames from the 18F, but frames from the 24HJ just retransmit over and over until the EC reaches 128 and cause bus errors on the CANUSB. I don't have a bus analyzer, but on the scope the good frames look similar to the bad ones, so I think the timing is in the ballpark. Is there a way to tell which of the five CAN errors it is experiencing? Did I do my speed calculations correct?
#include <p24hxxxx.h>
_FBS( RBS_NO_RAM & BSS_NO_FLASH & BWRP_WRPROTECT_OFF );
_FSS( RSS_NO_RAM & SSS_NO_FLASH & SWRP_WRPROTECT_OFF );
_FGS( GSS_OFF & GCP_OFF & GWRP_OFF );
_FOSCSEL( FNOSC_PRI & IESO_OFF );
_FOSC( FCKSM_CSDCMD & IOL1WAY_OFF & OSCIOFNC_OFF & POSCMD_HS );
_FWDT( FWDTEN_OFF );
unsigned int ecan1MsgBuf[32][8] __attribute__(( space(dma)) );
int main(void) {
AD1PCFGL = 0xFFFF;
__builtin_write_OSCCONL(OSCCON & 0xbf);
_C1RXR = 9; // RX = RP9
_RP22R = 0b10000; // TX = RP22
__builtin_write_OSCCONL(OSCCON | 0x40);
/* Assign 32x8word Message Buffers for ECAN1 in DMA RAM */
DMA0STA = __builtin_dmaoffset(ecan1MsgBuf);
/* Data Transfer Size: Word Transfer Mode */
DMA0CONbits.SIZE = 0x0;
/* Data Transfer Direction: DMA RAM to Peripheral */
DMA0CONbits.DIR = 0x1;
/* DMA Addressing Mode: Peripheral Indirect Addressing mode */
DMA0CONbits.AMODE = 0x2;
/* Operating Mode: Continuous, Ping-Pong modes disabled */
DMA0CONbits.MODE = 0x0;
/* Assign ECAN1 Transmit event for DMA Channel 0 */
DMA0REQ = 70;
/* Set Number of DMA Transfer per ECAN message to 8 words */
DMA0CNT = 7;
/* Peripheral Address: ECAN1dmaxcnt Transmit Register */
DMA0PAD = (volatile unsigned int)&C1TXD;
/* Start Address Offset for ECAN1 Message Buffer 0x0000 */
DMA0STA = 0x0000;
/* Channel Enable: Enable DMA Channel 0 */
DMA0CONbits.CHEN = 0x1;
/* Channel Interrupt Enable: Enable DMA Channel 0 Interrupt */
IEC0bits.DMA0IE = 1;
/* Set the ECAN module for Configuration Mode before writing into the Baud
Rate Control Registers*/
C1CTRL1bits.REQOP = 4;
/* Wait for the ECAN module to enter into Configuration Mode */
while(C1CTRL1bits.OPMODE != 4);
/* Phase Segment 1 time is 8 TQ */
C1CFG2bits.SEG1PH = 0x8;
/* Phase Segment 2 time is set to be programmable */
C1CFG2bits.SEG2PHTS = 0x1;
/* Phase Segment 2 time is 6 TQ */
C1CFG2bits.SEG2PH = 0x6;
/* Propagation Segment time is 1 TQ */
C1CFG2bits.PRSEG = 1;
/* Bus line is sampled three times at the sample point */
C1CFG2bits.SAM = 0x1;
/* Synchronization Jump Width set to 1 TQ */
C1CFG1bits.SJW = 1;
/* Baud Rate Prescaler bits set to 1:1 */
C1CFG1bits.BRP = 0x0 ;
/* Put the ECAN Module into Normal Mode Operating Mode*/
C1CTRL1bits.REQOP = 0;
/* Wait for the ECAN module to enter into Normal Operating Mode */
while(C1CTRL1bits.OPMODE != 0);
/* Configure Message Buffer 0 for Transmission and assign priority*/
C1TR01CONbits.TXEN0 = 0x1;
C1TR01CONbits.TX0PRI = 0x3;
/* WRITE TO MESSAGE BUFFER 0 */
/* CiTRBnSID = 0bxxx1 0010 0011 1100
IDE = 0b0
SRR = 0b0
SID<10:0>= 0b100 1000 1111 */
ecan1MsgBuf[0][0] = 0x123C;
/* CiTRBnEID = 0bxxxx 0000 0000 0000
EID<17:6> = 0b0000 0000 0000 */
ecan1MsgBuf[0][1] = 0x0000;
/* CiTRBnDLC = 0b0000 0000 xxx0 1111
EID<17:6> = 0b000000
RTR = 0b0
RB1 = 0b0
RB0 = 0b0
DLC = 0b1000 */
ecan1MsgBuf[0][2] = 0x8;
/* WRITE MESSAGE DATA BYTES */
ecan1MsgBuf[0][3] = 0xabcd;
ecan1MsgBuf[0][4] = 0xabcd;
ecan1MsgBuf[0][5] = 0xabcd;
ecan1MsgBuf[0][6] = 0xabcd;
/* REQUEST MESSAGE BUFFER 0 TRANSMISSION */
C1TR01CONbits.TXREQ0 = 0x1;
while (C1TR01CONbits.TXREQ0);
while(1);
return 0;
}
void __attribute__((interrupt, no_auto_psv)) _DMA0Interrupt(void)
{
IFS0bits.DMA0IF = 0; // Clear the DMA0 Interrupt Flag;
}

Leave a comment