ecan_example_nofifo.c - Illustrate CAN transmit, receive¶
Uses only one buffer for RX receive, and uses a standard data frame.
#include "pic24_all.h"
#include <stdio.h>
//minimum number of buffers, 1 for TX, 1 for RX
#define NUM_TX_BUFS 1 //reserve 1 for TX
#define NUM_BUFS 2 //make this a power of 2 for the alignment to work or enter alignment manually
//base message ID
#define MSG_ID 0x7A0 //arbitrary choice for 11-bit messsage ID
#if defined(__PIC24H__) || defined (__dsPIC33F__)
ECANMSG msgBuf[NUM_BUFS] __attribute__((space(dma),aligned(NUM_BUFS*16)));
//configure DMA transmit buffer
void configDMA0(void) {
DMACS0 = 0;
_DMA0IF = 0;
DMA0PAD = (unsigned int) &C1TXD;
DMA0REQ = DMA_IRQ_ECAN1TX;
DMA0STA = __builtin_dmaoffset(msgBuf);
DMA0CNT = sizeof(ECANMSG)/2 -1; // == 7
DMA0CON = //configure and enable the module Module
(DMA_MODULE_ON |
DMA_SIZE_WORD |
DMA_DIR_WRITE_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_PERIPHERAL_INDIRECT |
DMA_MODE_CONTINUOUS);
}
//configure DMA receive buffer
void configDMA1(void) {
_DMA1IF = 0;
DMA1PAD = (unsigned int) &C1RXD;
DMA1REQ = DMA_IRQ_ECAN1RX;
DMA1STA = __builtin_dmaoffset(msgBuf);
DMA1CNT = sizeof(ECANMSG)/2 -1; // == 7
DMA1CON = //configure and enable the module Module
(DMA_MODULE_ON |
DMA_SIZE_WORD |
DMA_DIR_READ_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_PERIPHERAL_INDIRECT |
DMA_MODE_CONTINUOUS);
}
#elif defined(__dsPIC33EP512GP806__)
dsPIC33EP512GP806 must be handled differently than the rest of the family due to errata in the DMA subsystem (see document DS80000526E - silicon issue 15). DPRAM must be used to ensure that the DMA cannot be held in the “OFF” state by the system arbiter. [Ryan Taylor; November 2015]
__eds__ ECANMSG msgBuf[NUM_BUFS] __attribute__((space(dma),aligned(NUM_BUFS*16),eds));
//configure DMA transmit buffer
void configDMA0(void) {
DMAPWC = 0; // Reset the DMA Peripheral Write Collision Status Register
_DMA0IF = 0;
DMA0PAD = (unsigned int) &C1TXD;
DMA0REQ = DMA_IRQ_ECAN1TX;
DMA0STAL = (unsigned long int) &msgBuf;
DMA0STAH = 0;
DMA0CNT = sizeof(ECANMSG)/2 -1; // == 7
DMA0CON = //configure and enable the module Module
(DMA_MODULE_ON |
DMA_SIZE_WORD |
DMA_DIR_WRITE_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_PERIPHERAL_INDIRECT |
DMA_MODE_CONTINUOUS);
}
//configure DMA receive buffer
void configDMA1(void) {
_DMA1IF = 0;
DMA1PAD = (unsigned int) &C1RXD;
DMA1REQ = DMA_IRQ_ECAN1RX;
DMA1STAL = (unsigned long int) &msgBuf;
DMA1STAH = 0;
DMA1CNT = sizeof(ECANMSG)/2 -1; // == 7
DMA1CON = //configure and enable the module Module
(DMA_MODULE_ON |
DMA_SIZE_WORD |
DMA_DIR_READ_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_PERIPHERAL_INDIRECT |
DMA_MODE_CONTINUOUS);
}
#elif defined(__dsPIC33E__)
ECANMSG msgBuf[NUM_BUFS] __attribute__((space(xmemory),aligned(NUM_BUFS*16)));
//configure DMA transmit buffer
void configDMA0(void) {
DMAPWC = 0; // Reset the DMA Peripheral Write Collision Status Register
_DMA0IF = 0;
DMA0PAD = (unsigned int) &C1TXD;
DMA0REQ = DMA_IRQ_ECAN1TX;
DMA0STAL = (unsigned int) &msgBuf;
DMA0STAH = 0;
DMA0CNT = sizeof(ECANMSG)/2 -1; // == 7
DMA0CON = //configure and enable the module Module
(DMA_MODULE_ON |
DMA_SIZE_WORD |
DMA_DIR_WRITE_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_PERIPHERAL_INDIRECT |
DMA_MODE_CONTINUOUS);
}
//configure DMA receive buffer
void configDMA1(void) {
_DMA1IF = 0;
DMA1PAD = (unsigned int) &C1RXD;
DMA1REQ = DMA_IRQ_ECAN1RX;
DMA1STAL = (unsigned int) &msgBuf;
DMA1STAH = 0;
DMA1CNT = sizeof(ECANMSG)/2 -1; // == 7
DMA1CON = //configure and enable the module Module
(DMA_MODULE_ON |
DMA_SIZE_WORD |
DMA_DIR_READ_PERIPHERAL |
DMA_INTERRUPT_FULL |
DMA_NULLW_OFF |
DMA_AMODE_PERIPHERAL_INDIRECT |
DMA_MODE_CONTINUOUS);
}
#else
#error "Configure DMA for your chip here."
#endif
#define RX_BUFFER_ID 1
void configECAN1() {
uint8_t u8_i;
CHANGE_MODE_ECAN1(ECAN_MODE_CONFIGURE);
configBaudECAN1();
//use Filter 0 with Mask 0, write to RX_BUFFER_ID
configRxFilterECAN1(0, MSG_ID, ECAN_MATCH_SID, RX_BUFFER_ID, 0);
configRxMaskECAN1(0, 0x7FC, 0, 1); //check all but last 2 bits
clrRxFullOvfFlagsECAN1(); //clear all RX full, overflow flags.
//first 8 buffs must be configured as either TX or TX
for (u8_i = 0; u8_i<8; u8_i++) {
if (u8_i < NUM_TX_BUFS)
configTxRxBufferECAN1(u8_i,ECAN_TX_BUFF,3);
else
configTxRxBufferECAN1(u8_i,ECAN_RX_BUFF,3);
}
configDMA0(); //do DMA config after ECAN has been initialized
configDMA1();
CHANGE_MODE_ECAN1(ECAN_MODE_NORMAL);
}
uint32_t rrot32(uint32_t u32_x) {
if (u32_x & 0x1) {
u32_x = u32_x >> 1;
u32_x = u32_x | 0x80000000;
} else u32_x = u32_x >> 1;
return u32_x;
}
int main (void) {
uint32_t u32_out0, u32_out1, u32_in0, u32_in1;
uint8_t rx_buff_id, u8_cnt;
configBasic(HELLO_MSG);
configECAN1();
CHANGE_MODE_ECAN1(ECAN_MODE_LOOPBACK); //loopback to ourself for a test.
u32_out0 = 0xFEDCBA98;
u32_out1 = 0x76543210;
u8_cnt = 0;
while (1) {
DELAY_MS(500);
msgBuf[0].data.u32[0] = u32_out0; //save in CAN message
msgBuf[0].data.u32[1] = u32_out1;
//format Buffer 0 for TX with SID=MSG_ID, data length = 8 bytes
formatStandardDataFrameECAN(&msgBuf[0], MSG_ID+u8_cnt, 8);
startTxECAN1(0); //start transmission of buffer 0
while (getTxInProgressECAN1(0)) {
doHeartbeat(); //wait for transmission to end.
}
_DMA0IF = 0;
DELAY_MS(10); //delay for reception
if (!_DMA1IF) {
printf("Message ID 0x%X rejected by acceptance filter.\n",MSG_ID+u8_cnt);
} else {
_DMA1IF = 0; //RX message accepted
rx_buff_id = RX_BUFFER_ID;
u32_in0 = msgBuf[rx_buff_id].data.u32[0];
u32_in1 = msgBuf[rx_buff_id].data.u32[1];
printf("Msg ID: 0x%X, Out: 0x%08lX%08lX, In: 0x%08lX%08lX\n",
msgBuf[rx_buff_id].w0.SID,u32_out0, u32_out1, u32_in0, u32_in1 );
clrRxFullFlagECAN1(rx_buff_id);
}
u32_out0 = rrot32(u32_out0);
u32_out1 = rrot32(u32_out1);
u8_cnt++;
if (u8_cnt == 8) u8_cnt = 0;
} //end while
}//end main