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