CANbus with dsPIC33EV problem - Page 1
Forum section: electronics / general

author: tech_builder
author_rank: Contributor
timestamp: December 12, 2018, 11:27:20 pm
content: Hi,I am trying to work with the CANbus peripheral on a dsPIC33EV256GM106 on the dsPIC33EV 5V CAN-LIN Starter Kit development board. I have been studying the peripheral for a little while now and have gone through the datasheet and various examples for this and other similar dsPIC microcontrollers. I had arrived at what I hoped was the bare code required to send a message on the CANbus; however, I am not able to get it working.I have run the demo code that comes with the board and it works fine. When I scope the output of the transceiver I get nice signal.When I run my code there is no activity on the output of the transceiver, only on the output from the microcontroller to the transceiver, but it is garbage. The signal shown is from the PIC to the CAN transceiver, no signal appears on the output of the CAN transceiver. I'm not sure how to account for the difference in the length of the signals or the shape.My intention is to run the microcontroller at 16MHz, with the CANbus running at 250kbps. The CAN parameters I am using are (register values):Tq: 16BRP: 0x01PRSEG: 0x06SEG1PH: 0x05SEG2PH: 0x01SJW: 0x01Any help getting this working or wise words would be greatly appreciated. Thanks!The code is as follows:Code:// DSPIC33EV256GM106 Configuration Bit Settings// 'C' source line config statements// FSEC#pragma config BWRP = OFF // Boot Segment Write-Protect Bit (Boot Segment may be written)#pragma config BSS = DISABLED // Boot Segment Code-Protect Level bits (No Protection (other than BWRP))#pragma config BSS2 = OFF // Boot Segment Control Bit (No Boot Segment)#pragma config GWRP = OFF // General Segment Write-Protect Bit (General Segment may be written)#pragma config GSS = DISABLED // General Segment Code-Protect Level bits (No Protection (other than GWRP))#pragma config CWRP = OFF // Configuration Segment Write-Protect Bit (Configuration Segment may be written)#pragma config CSS = DISABLED // Configuration Segment Code-Protect Level bits (No Protection (other than CWRP))#pragma config AIVTDIS = DISABLE // Alternate Interrupt Vector Table Disable Bit (Disable Alternate Vector Table)// FBSLIM#pragma config BSLIM = 0x1FFF // Boot Segment Code Flash Page Address Limit Bits (Enter Hexadecimal value)// FOSCSEL#pragma config FNOSC = PRIPLL // Initial oscillator Source Selection Bits (Primary Oscillator with PLL module (XT + PLL, HS + PLL, EC + PLL))#pragma config IESO = OFF // Two Speed Oscillator Start-Up Bit (Start up device with FRC,then automatically switch to user selected oscillator source)// FOSC#pragma config POSCMD = XT // Primary Oscillator Mode Select Bits (XT Crystal Oscillator mode)#pragma config OSCIOFNC = ON // OSC2 Pin I/O Function Enable Bit (OSC2 is general purpose digital I/O pin)#pragma config IOL1WAY = OFF // Peripheral Pin Select Configuration Bit (Allow Multiple reconfigurations)#pragma config FCKSM = CSDCMD // Clock Switching Mode Bits (Both Clock Switching and Fail-safe Clock Monitor are disabled)#pragma config PLLKEN = ON // PLL Lock Enable Bit (Clock switch to PLL source will wait until the PLL lock signal is valid)// FWDT#pragma config WDTPOST = PS32768 // Watchdog Timer Postscaler Bits (1:32,768)#pragma config WDTPRE = PR128 // Watchdog Timer Prescaler Bit (1:128)#pragma config FWDTEN = OFF // Watchdog Timer Enable Bits (WDT and SWDTEN Disabled)#pragma config WINDIS = OFF // Watchdog Timer Window Enable Bit (Watchdog timer in Non-Window Mode)#pragma config WDTWIN = WIN25 // Watchdog Window Select Bits (WDT Window is 25% of WDT period)// FPOR#pragma config BOREN0 = ON // Brown Out Reset Detection Bit (BOR is Enabled)// FICD#pragma config ICS = PGD2 // ICD Communication Channel Select Bits (Communicate on PGEC2 and PGED2)// FDMTINTVL#pragma config DMTIVTL = 0xFFFF // Lower 16 Bits of 32 Bit DMT Window Interval (Enter Hexadecimal value)// FDMTINTVH#pragma config DMTIVTH = 0xFFFF // Upper 16 Bits of 32 Bit DMT Window Interval (Enter Hexadecimal value)// FDMTCNTL#pragma config DMTCNTL = 0xFFFF // Lower 16 Bits of 32 Bit DMT Instruction Count Time-Out Value (Enter Hexadecimal value)// FDMTCNTH#pragma config DMTCNTH = 0xFFFF // Upper 16 Bits of 32 Bit DMT Instruction Count Time-Out Value (Enter Hexadecimal value)// FDMT#pragma config DMTEN = DISABLE // Dead Man Timer Enable Bit (Dead Man Timer is Disabled and can be enabled by software)// FDEVOPT#pragma config PWMLOCK = ON // PWM Lock Enable Bit (Certain PWM registers may only be written after key sequence)#pragma config ALTI2C1 = OFF // Alternate I2C1 Pins Selection Bit (I2C1 mapped to SDA1/SCL1 pins)// FALTREG#pragma config CTXT1 = NONE // Interrupt Priority Level (IPL) Selection Bits For Alternate Working Register Set 1 (Not Assigned)#pragma config CTXT2 = NONE // Interrupt Priority Level (IPL) Selection Bits For Alternate Working Register Set 2 (Not Assigned)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.#include <xc.h>#include <stdio.h>#include <stdlib.h>#define NUM_OF_ECAN_BUFFERS 32void configOsc( void );void configIO( void );void configCAN( void );void configDMA( void );void INTERRUPT_Initialize(void);void CAN_Transmit(void);void TMR1_Initialize (void);void TMR1_Start( void );volatile unsigned int ecan1MsgBuf__attribute__((aligned(NUM_OF_ECAN_BUFFERS * 16)));/***/int main( void ) {configOsc();configIO();configDMA();configCAN();INTERRUPT_Initialize();TMR1_Initialize();PR1 = 0xFFF;TMR1_Start();PORTCbits.RC4 = 0;while(1){CAN_Transmit();}return (EXIT_SUCCESS);}void TMR1_Initialize (void){//TMR1 0;TMR1 = 0x00;//Period = 0 s; Frequency = 16000000 Hz; PR1 0;PR1 = 0x00;//TCKPS 1:1; TON enabled; TSIDL disabled; TCS FOSC/2; TSYNC disabled; TGATE disabled;T1CON = 0x8000;IFS0bits.T1IF = 0;IEC0bits.T1IE = 1;}void TMR1_Start( void ){/*Enable the interrupt*/IEC0bits.T1IE = 1;/* Start the Timer */T1CONbits.TON = 1;}void __attribute__ ( ( interrupt, no_auto_psv ) ) _T1Interrupt ( ){/* Check if the Timer Interrupt/Status is set *///***User Area BeginPORTCbits.RC4 = ~PORTCbits.RC4;//***User Area EndIFS0bits.T1IF = 0;}void configOsc(void){// FRCDIV FRC/2; PLLPRE 2; DOZE 1:8; PLLPOST 1:8; DOZEN disabled; ROI disabled;CLKDIV = 0x31C0;// TUN Center frequency;OSCTUN = 0x0;// ROON disabled; ROSEL disabled; RODIV Base clock value; ROSSLP disabled;REFOCON = 0x0;// PLLDIV 62;PLLFBD = 0x3E;// RND disabled; SATB disabled; SATA disabled; ACCSAT disabled;CORCONbits.RND = 0;CORCONbits.SATB = 0;CORCONbits.SATA = 0;CORCONbits.ACCSAT = 0;// CF no clock failure; NOSC PRIPLL; CLKLOCK unlocked; OSWEN Switch is Complete;__builtin_write_OSCCONH((uint8_t) ((0x300 >> _OSCCON_NOSC_POSITION) & 0x00FF));__builtin_write_OSCCONL((uint8_t) ((0x300 | _OSCCON_OSWEN_MASK) & 0xFF));// Wait for Clock switch to occurwhile (OSCCONbits.OSWEN != 0);while (OSCCONbits.LOCK != 1);}void configIO( void ){/***************************************************************************** Setting the Output Latch SFR(s)***************************************************************************/LATA = 0x0000;LATB = 0x0000;LATC = 0x0000;LATD = 0x0000;LATE = 0x0000;LATF = 0x0000;LATG = 0x0000;/***************************************************************************** Setting the GPIO Direction SFR(s)***************************************************************************/TRISA = 0x1F93;TRISB = 0xFFFF;TRISC = 0x3F87;TRISD = 0x0160;TRISE = 0xF000;TRISF = 0x0001; // CAN RX on RF0, CAN TX on RF1TRISG = 0x03C0;/***************************************************************************** Setting the Weak Pull Up and Weak Pull Down SFR(s)***************************************************************************/// No pull up resistors are used for this programCNPDA = 0x0000;CNPDB = 0x0000;CNPDC = 0x0000;CNPDD = 0x0000;CNPDE = 0x0000;CNPDF = 0x0000;CNPDG = 0x0000;CNPUA = 0x0000;CNPUB = 0x0000;CNPUC = 0x0000;CNPUD = 0x0000;CNPUE = 0x0000;CNPUF = 0x0000;CNPUG = 0x0000;/***************************************************************************** Setting the Open Drain SFR(s)***************************************************************************/ODCA = 0x0000;ODCB = 0x0000;ODCC = 0x0000;ODCD = 0x0000;ODCE = 0x0000;ODCF = 0x0000;ODCG = 0x0000;/***************************************************************************** Setting the Analog/Digital Configuration SFR(s)***************************************************************************/ANSELA = 0x1E93;ANSELB = 0x038F;ANSELC = 0x0F87;ANSELE = 0xF000;ANSELG = 0x03C0;/***************************************************************************** Set the PPS***************************************************************************/RPINR26bits.C1RXR = 0x0060; //; //RF0->ECAN1:C1RXRPOR9bits.RP97R = 0x000E; //; //RF1->ECAN1:C1TX}void configCAN( void ){// Disable interrupts before the InitializationIEC2bits.C1IE = 0;C1INTE = 0;// put CAAN in configuration modeC1CTRL1bits.REQOP = 4;while (C1CTRL1bits.OPMODE != 4);/* clear window bit to access ECAN control registers */C1CTRL1bits.WIN = 0;/* Set up the baud rate*/C1CFG1 = 0x41;//BRP ;C1CFG2 = 0x1EE;//WAKFIL enabled; SEG2PHTS Freely programmable; SEG2PH 1 x TQ; SEG1PH 5 x TQ; PRSEG 6 x TQ; SAM Three times at the sample point;C1FCTRL = 0xC01F;//FSA Transmit/Receive Buffer TRB1; DMABS 32;C1FEN1 = 0x00;//FLTEN8 disabled; FLTEN7 disabled; FLTEN9 disabled; FLTEN0 disabled; FLTEN2 disabled; FLTEN10 disabled; FLTEN1 disabled; FLTEN11 disabled; FLTEN4 disabled; FLTEN3 disabled; FLTEN6 disabled; FLTEN5 disabled; FLTEN12 disabled; FLTEN13 disabled; FLTEN14 disabled; FLTEN15 disabled;C1CTRL1 = 0x800;//CANCKS FOSC; CSIDL disabled; ABAT disabled; REQOP Sets Normal Operation Mode; WIN Uses buffer window; CANCAP disabled;/* ECAN1, Buffer 0 is a Transmit Buffer */C1TR01CONbits.TXEN0 = 0x1; // Buffer 0 is a Transmit BufferC1TR01CONbits.TXEN1 = 0x0; // Buffer 1 is a Receive BufferC1TR23CONbits.TXEN2 = 0x0; // Buffer 2 is a Receive BufferC1TR23CONbits.TXEN3 = 0x0; // Buffer 3 is a Receive BufferC1TR45CONbits.TXEN4 = 0x0; // Buffer 4 is a Receive BufferC1TR45CONbits.TXEN5 = 0x0; // Buffer 5 is a Receive BufferC1TR67CONbits.TXEN6 = 0x0; // Buffer 6 is a Receive BufferC1TR67CONbits.TXEN7 = 0x0; // Buffer 7 is a Receive BufferC1TR01CONbits.TX0PRI = 0x0; // Message Buffer 0 Priority Level 0C1TR01CONbits.TX1PRI = 0x0; // Message Buffer 1 Priority Level 0C1TR23CONbits.TX2PRI = 0x0; // Message Buffer 2 Priority Level 0C1TR23CONbits.TX3PRI = 0x0; // Message Buffer 3 Priority Level 0C1TR45CONbits.TX4PRI = 0x0; // Message Buffer 4 Priority Level 0C1TR45CONbits.TX5PRI = 0x0; // Message Buffer 5 Priority Level 0C1TR67CONbits.TX6PRI = 0x0; // Message Buffer 6 Priority Level 0C1TR67CONbits.TX7PRI = 0x0; // Message Buffer 7 Priority Level 0// Place the ECAN module in Normal mode.C1CTRL1bits.REQOP = 0;while (C1CTRL1bits.OPMODE != 0);// Enable interrupts before the InitializationIEC2bits.C1IE = 1;C1INTE = 1;}void configDMA( void ){// Initialize channels which are enabled// Transmit channelDMA0CONbits.CHEN = 0; //disable DMA0 for initialization// AMODE Peripheral Indirect Addressing mode; CHEN disabled; DIR Reads from RAM address, writes to peripheral address; HALF Initiates interrupt when all of the data has been moved; SIZE 16 bit; NULLW disabled; MODE Continuous, Ping-Pong modes are disabled;DMA0CON= 0x2020;// & 0x7FFF; //Enable DMA Channel later;// FORCE disabled; IRQSEL ECAN1 TX;DMA0REQ= 0x46; //0x70 for kit example from 33EV_main_v11// STA 0;DMA0STAH= (unsigned int)&ecan1MsgBuf; // from 33EV_main_v11// STA 4096;DMA0STAL= (unsigned int)&ecan1MsgBuf; // from 33EV_main_v11// STB 0;DMA0STBH= 0x00;// STB 0;DMA0STBL= 0x00;// PAD 0;DMA0PAD= 0x0442;// CNT 7;DMA0CNT= 0x07;// Clearing Channel 0 Interrupt Flag;IFS0bits.DMA0IF = 0;// Enabling Channel 0 InterruptIEC0bits.DMA0IE = 1;C1TR01CONbits.TXEN0 = 0x1; // Buffer 0 is the Transmit BufferC1TR01CONbits.TX0PRI = 0x0; // transmit buffer priority// enable DMA0DMA0CONbits.CHEN = 1;}/**void INTERRUPT_Initialize (void)*/void INTERRUPT_Initialize (void){// DMA1I: DMA Channel 1// Priority: 1IPC3bits.DMA1IP = 1;// DMA0I: DMA Channel 0// Priority: 1IPC1bits.DMA0IP = 1;// CI: ECAN1 Event// Priority: 1IPC8bits.C1IP = 1;// CTXI: CAN1 TX Data Request// Priority: 1IPC17bits.C1TXIP = 1;// TI: Timer 1// Priority: 1IPC0bits.T1IP = 1;}void CAN_Transmit(void){unsigned int MSG_SID = 0x123;// write to the first transmit buffer// write to the first segment of the first transmit bufferecan1MsgBuf = MSG_SID << 2;ecan1MsgBuf = 0x0000;/* CiTRBnDLC = 0b0000 0000 xxx0 1111EID<17:6> = 0b000000RTR = 0b0RB1 = 0b0RB0 = 0b0DLC = 6 */ecan1MsgBuf = 0x0006;// Write message 6 data bytes://ecan1MsgBuf = 0x3333; // switch data, leading zerosecan1MsgBuf = 0x4444;ecan1MsgBuf = 0x5555;Nop();Nop();Nop();/* Request message buffer 0 transmission */C1TR01CONbits.TXREQ0 = 0x1;/* The following shows an example of how the TXREQ bit can be polled to check if transmissionis complete. */Nop();Nop();Nop();while (C1TR01CONbits.TXREQ0 == 1);// Message was placed successfully on the bus, return}

author: JPortici
author_rank: Super Contributor
timestamp: December 13, 2018, 06:41:00 am
content: Three notes:-ALWAYS check the board schematic. they are using the standby feature of the can transceiver.-Re-read the device datasheet on the can peripheral. For it to work reliably you have to dedicate two DMA channels. One for receiving, one for transmitting. Choose your DMA channels carefully, the one which mustn't be interrupted first. I now use channel 2 and 3 for can, period. I had issues where results from the ADC were screwed up when using CAN because the ADC DMA would get interrupted by the CAN DMA-didn't check your can timing registers but you might want to compare them against the calculators like the one integrated in mplab x (it's a plugin) or from the kvaser website (the peripheral comes from kvaser) o more generally this onehttp://www.bittiming.can-wiki.info/anyway the thing you see looks like an error frame to mebecause it's not getting an ACK from the network, because the transceiver isn't active..

author: AndyC_772
author_rank: Super Contributor
timestamp: December 13, 2018, 07:44:42 am
content: If there's a signal on the output of the PIC, but not on the CAN bus itself, then the transceiver must not be enabled.Without the transceiver, the PIC won't see its own transmission on the Rx pin, and this will confuse the CAN hardware. CAN is designed for a noisy, multi-master environment, and the transmit logic includes checking that the signal is actually appearing correctly on the bus.Check if there's a GPIO output from the PIC which is connected to the transceiver enable, and make sure it's active.

author: tech_builder
author_rank: Contributor
timestamp: December 20, 2018, 02:05:31 am
content: Thanks so much for the help. I went back and started looking at my code again used the CAN calculator mentioned in JPortici's post and lo and behold I had been using Fcy to calculate my numbers instead of Fcan! So I made that change and I also set up the receive buffers and DMA channel, and it works!! Well sort of, I am now getting a stuff error after every successful transmission. It looks like it is starting another transmission right after the first one and then aborting after the start of frame is sent. Maybe something else is interrupting it? Anyways, below is a more documented version of my updated code.For the Configuration bits I have it set to 16MHz crystal oscillator with PLL with clock switch disabled.Code:// DSPIC33EV256GM106 Configuration Bit Settings// 'C' source line config statements// FSEC#pragma config BWRP = OFF// Boot Segment Write-Protect Bit (Boot Segment may be written)#pragma config BSS = DISABLED// Boot Segment Code-Protect Level bits (No Protection (other than BWRP))#pragma config BSS2 = OFF// Boot Segment Control Bit (No Boot Segment)#pragma config GWRP = OFF// General Segment Write-Protect Bit (General Segment may be written)#pragma config GSS = DISABLED// General Segment Code-Protect Level bits (No Protection (other than GWRP))#pragma config CWRP = OFF// Configuration Segment Write-Protect Bit (Configuration Segment may be written)#pragma config CSS = DISABLED// Configuration Segment Code-Protect Level bits (No Protection (other than CWRP))#pragma config AIVTDIS = DISABLE// Alternate Interrupt Vector Table Disable Bit (Disable Alternate Vector Table)// FBSLIM#pragma config BSLIM = 0x1FFF// Boot Segment Code Flash Page Address Limit Bits (Enter Hexadecimal value)// FOSCSEL#pragma config FNOSC = PRIPLL// Initial oscillator Source Selection Bits (Primary Oscillator with PLL module (XT + PLL, HS + PLL, EC + PLL))#pragma config IESO = OFF// Two Speed Oscillator Start-Up Bit (Start up device with FRC,then automatically switch to user selected oscillator source)// FOSC#pragma config POSCMD = XT// Primary Oscillator Mode Select Bits (XT Crystal Oscillator mode)#pragma config OSCIOFNC = ON// OSC2 Pin I/O Function Enable Bit (OSC2 is general purpose digital I/O pin)#pragma config IOL1WAY = OFF// Peripheral Pin Select Configuration Bit (Allow Multiple reconfigurations)#pragma config FCKSM = CSDCMD// Clock Switching Mode Bits (Both Clock Switching and Fail-safe Clock Monitor are disabled)#pragma config PLLKEN = ON// PLL Lock Enable Bit (Clock switch to PLL source will wait until the PLL lock signal is valid)// FWDT#pragma config WDTPOST = PS32768// Watchdog Timer Postscaler Bits (1:32,768)#pragma config WDTPRE = PR128// Watchdog Timer Prescaler Bit (1:128)#pragma config FWDTEN = OFF// Watchdog Timer Enable Bits (WDT and SWDTEN Disabled)#pragma config WINDIS = OFF// Watchdog Timer Window Enable Bit (Watchdog timer in Non-Window Mode)#pragma config WDTWIN = WIN25// Watchdog Window Select Bits (WDT Window is 25% of WDT period)// FPOR#pragma config BOREN0 = ON// Brown Out Reset Detection Bit (BOR is Enabled)// FICD#pragma config ICS = PGD2// ICD Communication Channel Select Bits (Communicate on PGEC2 and PGED2)// FDMTINTVL#pragma config DMTIVTL = 0xFFFF// Lower 16 Bits of 32 Bit DMT Window Interval (Enter Hexadecimal value)// FDMTINTVH#pragma config DMTIVTH = 0xFFFF// Upper 16 Bits of 32 Bit DMT Window Interval (Enter Hexadecimal value)// FDMTCNTL#pragma config DMTCNTL = 0xFFFF// Lower 16 Bits of 32 Bit DMT Instruction Count Time-Out Value (Enter Hexadecimal value)// FDMTCNTH#pragma config DMTCNTH = 0xFFFF// Upper 16 Bits of 32 Bit DMT Instruction Count Time-Out Value (Enter Hexadecimal value)// FDMT#pragma config DMTEN = DISABLE// Dead Man Timer Enable Bit (Dead Man Timer is Disabled and can be enabled by software)// FDEVOPT#pragma config PWMLOCK = ON// PWM Lock Enable Bit (Certain PWM registers may only be written after key sequence)#pragma config ALTI2C1 = OFF// Alternate I2C1 Pins Selection Bit (I2C1 mapped to SDA1/SCL1 pins)// FALTREG#pragma config CTXT1 = NONE// Interrupt Priority Level (IPL) Selection Bits For Alternate Working Register Set 1 (Not Assigned)#pragma config CTXT2 = NONE// Interrupt Priority Level (IPL) Selection Bits For Alternate Working Register Set 2 (Not Assigned)// #pragma config statements should precede project file includes.// Use project enums instead of #define for ON and OFF.This is the oscillator initialization routine. The development board comes with a 8MHz crystal oscillator. I have it set up for a Fcy of 16MHz. FOSCSEL -> FNOSC is set to 0b011 which is primary oscillator with PLL. FOSC -> POSCMD is set to 0b01, which is crystal oscillator mode.Doze is not used CLKDIV -> DOZEN = 0. The CLKDIV -> PLLPOST = 0b11 is set to divide by 8. CLKDIV -> PLLPRE = 0b00000 is set to divide by 2.The PLL feedback divisor is set to 64, which is PLLFBD -> PLLDIV = 0x3E.Not sure if I need to write to OSCCON since the oscillator is setup in the #pragma statements at the beginning of the file.Code:void configOsc(void){// FRCDIV FRC/2; PLLPRE 2; DOZE 1:8; PLLPOST 1:8; DOZEN disabled; ROI disabled;CLKDIV = 0x31C0;// TUN Center frequency;OSCTUN = 0x0;// ROON disabled; ROSEL disabled; RODIV Base clock value; ROSSLP disabled;REFOCON = 0x0;// PLLDIV 62;PLLFBD = 0x3E;// RND disabled; SATB disabled; SATA disabled; ACCSAT disabled;CORCONbits.RND = 0;CORCONbits.SATB = 0;CORCONbits.SATA = 0;CORCONbits.ACCSAT = 0;// CF no clock failure; NOSC PRIPLL; CLKLOCK unlocked; OSWEN Switch is Complete;__builtin_write_OSCCONH((uint8_t) ((0x300 >> _OSCCON_NOSC_POSITION) & 0x00FF));__builtin_write_OSCCONL((uint8_t) ((0x300 | _OSCCON_OSWEN_MASK) & 0xFF));// Wait for Clock switch to occurwhile (OSCCONbits.OSWEN != 0);while (OSCCONbits.LOCK != 1);}Here the pins are set to inputs/outputs. This was set using the MCC. Peripheral Pin Select is also set here to be the CAN receive RF0->ECAN1:C1RX and CAN transmit RF1->ECAN1:C1TXCode:void configIO( void ){/***************************************************************************** Setting the Output Latch SFR(s)***************************************************************************/LATA = 0x0000;LATB = 0x0000;LATC = 0x0000;LATD = 0x0000;LATE = 0x0000;LATF = 0x0000;LATG = 0x0000;/***************************************************************************** Setting the GPIO Direction SFR(s)***************************************************************************/TRISA = 0x1F93;TRISB = 0xFFFF;TRISC = 0x3F87;TRISD = 0x0160;TRISE = 0xF000;TRISF = 0x0001;// CAN RX on RF0, CAN TX on RF1TRISG = 0x03C0;/***************************************************************************** Setting the Weak Pull Up and Weak Pull Down SFR(s)***************************************************************************/// No pull up resistors are used for this programCNPDA = 0x0000;CNPDB = 0x0000;CNPDC = 0x0000;CNPDD = 0x0000;CNPDE = 0x0000;CNPDF = 0x0000;CNPDG = 0x0000;CNPUA = 0x0000;CNPUB = 0x0000;CNPUC = 0x0000;CNPUD = 0x0000;CNPUE = 0x0000;CNPUF = 0x0000;CNPUG = 0x0000;/***************************************************************************** Setting the Open Drain SFR(s)***************************************************************************/ODCA = 0x0000;ODCB = 0x0000;ODCC = 0x0000;ODCD = 0x0000;ODCE = 0x0000;ODCF = 0x0000;ODCG = 0x0000;/***************************************************************************** Setting the Analog/Digital Configuration SFR(s)***************************************************************************/ANSELA = 0x1E93;ANSELB = 0x038F;ANSELC = 0x0F87;ANSELE = 0xF000;ANSELG = 0x03C0;/***************************************************************************** Set the PPS***************************************************************************/RPINR26bits.C1RXR = 0x0060;//; //RF0->ECAN1:C1RXRPOR9bits.RP97R = 0x000E;//; //RF1->ECAN1:C1TX}The CANbus is configured here. Fbaud is set to 250kbps and the time quanta in a bit time is set to 16TQ ie 16 TQ/bit. C1CTRL1 -> CANCKS = 1 which implies Fcan = 2*Fcy which is 2*16MHz = 32MHz. SEG2PHTS is set to be freely programmable = 1; SEG2PH 1 x TQ; SEG1PH 7 x TQ; PRSEG 4 x TQ; SAM is set to sample three times at the sample point =1.The first 8 buffers are configured with the first buffer set as a transmit buffer and the rest as receive buffers. The priority of all the buffers is set to the lowest setting = 0.Code:void configCAN( void ){// Disable interrupts before the InitializationIEC2bits.C1IE = 0;C1INTE = 0;// put CAN in configuration modeC1CTRL1bits.REQOP = 4;while (C1CTRL1bits.OPMODE != 4);/* clear window bit to access ECAN control registers */C1CTRL1bits.WIN = 0;/* Set up the baud rate*///C1CFG1 = 0x0003;//BRP=3 ie CANCKS=1 => Fcan = 2*Fcy = 32MHz ;C1CFG1bits.BRP = 0b11; // BRP value is 3C1CFG1bits.SJW = 0b00; // SJW synchronization jump width is set to 1xTQ//C1CFG2 = 0x01FC;//WAKFIL disabled; SEG2PHTS Freely programmable; SEG2PH 1 x TQ; SEG1PH 7 x TQ; PRSEG 4 x TQ; SAM Three times at the sample point;C1CFG2bits.WAKFIL = 0;C1CFG2bits.SEG2PH = 0b01;C1CFG2bits.SEG2PHTS = 0b1;C1CFG2bits.SAM = 0b1; // sample 3 timesC1CFG2bits.SEG1PH = 0b111;C1CFG2bits.PRSEG = 0b100;//C1FCTRL = 0xC01F;//FSA Transmit/Receive Buffer TRB1; DMABS 32;C1FCTRLbits.DMABS = 0b110; // 32 buffers in device RAMC1FCTRLbits.FSA = 0b011111;C1FEN1 = 0x00;//FLTEN8 disabled; FLTEN7 disabled; FLTEN9 disabled; FLTEN0 disabled; FLTEN2 disabled; FLTEN10 disabled; FLTEN1 disabled; FLTEN11 disabled; FLTEN4 disabled; FLTEN3 disabled; FLTEN6 disabled; FLTEN5 disabled; FLTEN12 disabled; FLTEN13 disabled; FLTEN14 disabled; FLTEN15 disabled;//C1CTRL1 = 0x800;//CANCKS FOSC; CSIDL disabled; ABAT disabled; REQOP Sets Normal Operation Mode; WIN Uses buffer window; CANCAP disabled;C1CTRL1bits.CSIDL = 0; // continue module operation in idle modeC1CTRL1bits.ABAT = 0; // Module will clear this bit when all transmissions are abortedC1CTRL1bits.CANCKS = 1; // Fcan = 2*Fcy => Fcan = 2*16MHz = 32MHzC1CTRL1bits.CANCAP = 0; //disable CAN capture/* ECAN1, Buffer 0 is a Transmit Buffer */C1TR01CONbits.TXEN0 = 0x1; // Buffer 0 is a Transmit BufferC1TR01CONbits.TXEN1 = 0x0; // Buffer 1 is a Receive BufferC1TR23CONbits.TXEN2 = 0x0; // Buffer 2 is a Receive BufferC1TR23CONbits.TXEN3 = 0x0; // Buffer 3 is a Receive BufferC1TR45CONbits.TXEN4 = 0x0; // Buffer 4 is a Receive BufferC1TR45CONbits.TXEN5 = 0x0; // Buffer 5 is a Receive BufferC1TR67CONbits.TXEN6 = 0x0; // Buffer 6 is a Receive BufferC1TR67CONbits.TXEN7 = 0x0; // Buffer 7 is a Receive BufferC1TR01CONbits.TX0PRI = 0x0; // Message Buffer 0 Priority Level 0C1TR01CONbits.TX1PRI = 0x0; // Message Buffer 1 Priority Level 0C1TR23CONbits.TX2PRI = 0x0; // Message Buffer 2 Priority Level 0C1TR23CONbits.TX3PRI = 0x0; // Message Buffer 3 Priority Level 0C1TR45CONbits.TX4PRI = 0x0; // Message Buffer 4 Priority Level 0C1TR45CONbits.TX5PRI = 0x0; // Message Buffer 5 Priority Level 0C1TR67CONbits.TX6PRI = 0x0; // Message Buffer 6 Priority Level 0C1TR67CONbits.TX7PRI = 0x0; // Message Buffer 7 Priority Level 0// Place the ECAN module in Normal mode.C1CTRL1bits.REQOP = 0;while (C1CTRL1bits.OPMODE != 0);// Enable interrupts before the InitializationIEC2bits.C1IE = 1;C1INTE = 1;}This is where the DMA initialization for use with the CAN peripheral is done. DMA0CON is set up as the transmit channel with word size transfer size, peripheral indirect addressing mode and continuous with ping pong disabled mode. DMA3CON is configured as the receive channel with similar setting to DMA0.Code:void configDMA( void ){// Initialize channels which are enabled// Transmit channelDMA0CONbits.CHEN = 0; //disable DMA0 for initialization// AMODE Peripheral Indirect Addressing mode; CHEN disabled; DIR Reads from RAM address, writes to peripheral address; HALF Initiates interrupt when all of the data has been moved; SIZE 16 bit; NULLW disabled; MODE Continuous, Ping-Pong modes are disabled;// DMA0CON= 0x2020;// & 0x7FFF; //Enable DMA Channel later;DMA0CONbits.SIZE = 0; // word size data transferDMA0CONbits.DIR = 1; // read from DPSRAM address, write to peripheral addressDMA0CONbits.NULLW = 0; // normal operationDMA0CONbits.AMODE = 0b10; // peripheral indirect addressing modeDMA0CONbits.MODE = 0b00; // continuous, ping pong modes disabled// FORCE disabled; IRQSEL ECAN1 TX;// DMA0REQ = 0x46;//0x46; //0x70 for kit example from 33EV_main_v11DMA0REQbits.FORCE = 0; // automatic DMA transfer initiation by DMA requestDMA0REQbits.IRQSEL = 0x46; // DMA peripheral IRQ number -> CAN Tx IRQ is 0x46// STA 0;DMA0STAH= 0x00;//(unsigned int)&ecan1MsgBuf; // from 33EV_main_v11// STA 4096;DMA0STAL= (unsigned int)&ecan1MsgBuf; // from 33EV_main_v11// STB 0;DMA0STBH= 0x00;// STB 0;DMA0STBL= 0x00;// PAD 0;DMA0PAD= 0x0442; // Peripheral to DMA association// CNT 7;DMA0CNT= 0x07;// Clearing Channel 0 Interrupt Flag;IFS0bits.DMA0IF = 0;// Enabling Channel 0 InterruptIEC0bits.DMA0IE = 1;// Receive channel DMA3DMA3CONbits.CHEN = 0; //disable DMA0 for initializationDMA3CONbits.SIZE = 0; // word size data transferDMA3CONbits.DIR = 0; // read from peripheral address, write to DPSRAM addressDMA3CONbits.NULLW = 0; // normal operationDMA3CONbits.AMODE = 0b10; // peripheral indirect addressing modeDMA3CONbits.MODE = 0b00; // continuous, ping pong modes disabledDMA3REQbits.FORCE = 0; // automatic DMA transfer initiation by DMA requestDMA3REQbits.IRQSEL = 0x22; // DMA peripheral IRQ number -> CAN Rx IRQ is 0x22// STA 0;DMA3STAH= 0x00;//(unsigned int)&ecan1MsgBuf; // from 33EV_main_v11// STA 4096;DMA3STAL= (unsigned int)&ecan1MsgBuf; // from 33EV_main_v11// STB 0;DMA3STBH= 0x00;// STB 0;DMA3STBL= 0x00;// PAD 0;DMA3PAD= 0x0440; // Peripheral to DMA association// CNT 7;DMA3CNT= 0x07;// Clearing Channel 0 Interrupt Flag (table pg 66 device datasheet);IFS2bits.DMA3IF = 0;// Enabling Channel 0 InterruptIEC2bits.DMA3IE = 1;// enable DMA0DMA0CONbits.CHEN = 1;// enable DMA3DMA3CONbits.CHEN = 1;}The IPCxbits set the priority for each of the peripheral interrupts. They have all been set to 1.Code:/**void INTERRUPT_Initialize (void)*/void INTERRUPT_Initialize (void){// The priority of each interrupt for each peripheral is set below//DMA1I: DMA Channel 1//Priority: 1IPC3bits.DMA1IP = 1;//DMA0I: DMA Channel 0//Priority: 1IPC1bits.DMA0IP = 1;//CI: ECAN1 Event//Priority: 1IPC8bits.C1IP = 1;//CTXI: CAN1 TX Data Request//Priority: 1IPC17bits.C1TXIP = 1;//TI: Timer 1//Priority: 1IPC0bits.T1IP = 1;}This is the CAN transmit function and was copied from the demo code that came with the development board.Code:void CAN_Transmit(void){unsigned int MSG_SID = 0x123;// write to the first transmit buffer// write to the first segment of the first transmit bufferecan1MsgBuf = MSG_SID << 2;ecan1MsgBuf = 0x0000;/* CiTRBnDLC = 0b0000 0000 xxx0 1111EID<17:6> = 0b000000RTR = 0b0RB1 = 0b0RB0 = 0b0DLC = 6 */ecan1MsgBuf = 0x0006;// Write message 6 data bytes://ecan1MsgBuf = 0x3333; // switch data, leading zerosecan1MsgBuf = 0x4444;ecan1MsgBuf = 0x5555;Nop();Nop();Nop();/* Request message buffer 0 transmission */C1TR01CONbits.TXREQ0 = 0x1;/* The following shows an example of how the TXREQ bit can be polled to check if transmissionis complete. */Nop();Nop();Nop();while (C1TR01CONbits.TXREQ0 == 1);// Message was placed successfully on the bus, return}There it is. Hopefully this can get somebody else started with CAN on the dev board

author: JPortici
author_rank: Super Contributor
timestamp: December 20, 2018, 08:57:38 am
content: Quote from: tech_builder on December 20, 2018, 02:05:31 amcould be, could be nothttps://www.kvaser.com/about-can/the-can-protocol/can-error-handling/(go to Bit Stuffing)a stuff condition is seen, doesn't mean it's an errorI happen to know the guy that wrote the code for that demo board (he once was a microchip FAE, he now builds killer synthesizers!http://www.synthtech.com/)it's failry easy to understand, but i decided to throw all the CAN part away and write my own, one bit at a time until i had my library.It is just a suggestion but divide your problem in three parts1) the application code, with its buffers and data, with interfaces that generate can frames and retreive data from single frames2) the can protocol code, which has its buffers for can RX and TX and handles stuff like networking (ISO15765-2 and -3 for example). here i defined my can_t frame (ID, flags, data) and can_buffer_t3) the device specific code, so the interrupts, configuration and the interfaces that get a can_t frame and stuff the registers or the hardware buffers in the format required by the MCU and vice-versa. This is the part that you will have to change when porting code.Case in point, i have designed a couple of OBD gadgets i ported between three architectures in which1) Has the error codes list, status variables, IO over can handling etc. It also has the state machine that runs in the superloop so it doesn't hang in there too much2) Is the code that get CAN frames and put them in a separate frame types which i called uds_t and obd_t which have a DTC list, size, index for read/write etc. Also handles the merging and splitting of multi-frame messages3) Is the only part of code i had to change, no issues at all.the three architectures were dsPIC33EV, PIC32MX and ATSAMC21. Luckily for me the 33EV and the 32MX both use the same CAN IP from kvaser, but with minor differences in other registers and how DMA plays a role in the peripheral (mandatory in the dsPIC and eats up two channels, dedicated in the PIC32) whereas the ATSAM used a completely different peripheral. Easy peasy.

author: tech_builder
author_rank: Contributor
timestamp: December 24, 2018, 01:39:43 am
content: Thanks again. I will need to work with the J1939 protocol, so this is just the beginning of the journey. I am glad I finally have something working! This is a very complicated peripheral and to mix it in with the DMA controller adds another level of complexity to the confusion. I will be looking into your suggestions for program structure when I get there. Thanks again!

author: PIC18F2550
author_rank: Newbie
timestamp: September 14, 2019, 10:35:52 am
content: hello friend tech_builderif you can send me the firmware i tree to help you , the DMA system is for controlle automaticly the address ram buffers[][] in the dsPIC33EV onlythe DMA is option ,can you don't use this optionhttp://ww1.microchip.com/downloads/en/devicedoc/70182c.pdf