/* Copy message to CAN module - internal usage only. * * @param CANbaseAddress CAN module base address * @param dest Pointer to CAN module transmit buffer * @param src Pointer to source message */ static void CO_CANsendToModule(uint16_t CANbaseAddress, __eds__ CO_CANrxMsg_t *dest, CO_CANtx_t *src){ uint8_t DLC; __eds__ uint8_t *CANdataBuffer; uint8_t *pData; volatile uint16_t C_CTRL1old; /* CAN-ID + RTR */ dest->ident = src->ident; /* Data lenght */ DLC = src->DLC; if(DLC > 8) DLC = 8; dest->DLC = DLC; /* copy data */ CANdataBuffer = &(dest->data[0]); pData = src->data; for(; DLC>0; DLC--) *(CANdataBuffer++) = *(pData++); /* control register, transmit request */ C_CTRL1old = CAN_REG(CANbaseAddress, C_CTRL1); CAN_REG(CANbaseAddress, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */ CAN_REG(CANbaseAddress, C_TR01CON) |= 0x08; CAN_REG(CANbaseAddress, C_CTRL1) = C_CTRL1old; }
void CO_CANsetNormalMode(uint16_t CANbaseAddress){ uint16_t C_CTRL1copy = CAN_REG(CANbaseAddress, C_CTRL1); /* set REQOP = 0x0 */ C_CTRL1copy &= 0xF8FF; CAN_REG(CANbaseAddress, C_CTRL1) = C_CTRL1copy; /* while OPMODE != 0 */ while((CAN_REG(CANbaseAddress, C_CTRL1) & 0x00E0) != 0x0000); }
void CO_CANsetConfigurationMode(uint16_t CANbaseAddress){ uint16_t C_CTRL1copy = CAN_REG(CANbaseAddress, C_CTRL1); /* set REQOP = 0x4 */ C_CTRL1copy &= 0xFCFF; C_CTRL1copy |= 0x0400; CAN_REG(CANbaseAddress, C_CTRL1) = C_CTRL1copy; /* while OPMODE != 4 */ while((CAN_REG(CANbaseAddress, C_CTRL1) & 0x00E0) != 0x0080); }
void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){ uint16_t C_CTRL1copy = CAN_REG(CANmodule->CANbaseAddress, C_CTRL1); /* set REQOP = 0x0 */ C_CTRL1copy &= 0xF8FF; CAN_REG(CANmodule->CANbaseAddress, C_CTRL1) = C_CTRL1copy; /* while OPMODE != 0 */ while((CAN_REG(CANmodule->CANbaseAddress, C_CTRL1) & 0x00E0) != 0x0000); CANmodule->CANnormal = true; }
CO_ReturnError_t CO_CANrxBufferInit( CO_CANmodule_t *CANmodule, uint16_t index, uint16_t ident, uint16_t mask, bool_t rtr, void *object, void (*pFunct)(void *object, const CO_CANrxMsg_t *message)) { CO_ReturnError_t ret = CO_ERROR_NO; if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){ /* buffer, which will be configured */ CO_CANrx_t *buffer = &CANmodule->rxArray[index]; uint16_t RXF, RXM; uint16_t addr = CANmodule->CANbaseAddress; /* Configure object variables */ buffer->object = object; buffer->pFunct = pFunct; /* CAN identifier and CAN mask, bit aligned with CAN module registers (in DMA RAM) */ RXF = (ident & 0x07FF) << 2; if(rtr){ RXF |= 0x02; } RXM = (mask & 0x07FF) << 2; RXM |= 0x02; /* configure filter and mask */ if(RXF != buffer->ident || RXM != buffer->mask){ volatile uint16_t C_CTRL1old = CAN_REG(addr, C_CTRL1); CAN_REG(addr, C_CTRL1) = C_CTRL1old | 0x0001; /* WIN = 1 - use filter registers */ buffer->ident = RXF; buffer->mask = RXM; /* Set CAN hardware module filter and mask. */ if(CANmodule->useCANrxFilters){ volatile uint16_t *pRXF; volatile uint16_t *pRXM0, *pRXM1, *pRXM2; uint16_t selectMask; /* align RXF and RXM with C_RXF_SID and C_RXM_SID registers */ RXF &= 0xFFFD; RXF <<= 3; RXM &= 0xFFFD; RXM <<= 3; RXM |= 0x0008; /* write to filter */ pRXF = &CAN_REG(addr, C_RXF0SID); /* pointer to first filter register */ pRXF += index * 2; /* now points to C_RXFiSID (i == index) */ *pRXF = RXF; /* write value to filter */ /* configure mask (There are three masks, each of them can be asigned to any filter. */ /* First mask has always the value 0xFFE8 - all 11 bits must match). */ pRXM0 = &CAN_REG(addr, C_RXM0SID); pRXM1 = &CAN_REG(addr, C_RXM1SID); pRXM2 = &CAN_REG(addr, C_RXM2SID); if(RXM == 0xFFE8){ selectMask = 0; } else if(RXM == *pRXM1 || *pRXM1 == 0xFFE8){ /* RXM is equal to mask 1 or mask 1 was not yet configured. */ *pRXM1 = RXM; selectMask = 1; } else if(RXM == *pRXM2 || *pRXM2 == 0xFFE8){ /* RXM is equal to mask 2 or mask 2 was not yet configured. */ *pRXM2 = RXM; selectMask = 2; } else{ /* not enough masks */ ret = CO_ERROR_OUT_OF_MEMORY; selectMask = 0; } if(ret == CO_ERROR_NO){ /* now write to appropriate mask select register */ if(index<8){ uint16_t clearMask = ~(0x0003 << (index << 1)); selectMask = selectMask << (index << 1); CAN_REG(addr, C_FMSKSEL1) = (CAN_REG(addr, C_FMSKSEL1) & clearMask) | selectMask; } else{ uint16_t clearMask = ~(0x0003 << ((index-8) << 1)); selectMask = selectMask << ((index-8) << 1); CAN_REG(addr, C_FMSKSEL2) = (CAN_REG(addr, C_FMSKSEL2) & clearMask) | selectMask; } } } CAN_REG(addr, C_CTRL1) = C_CTRL1old; } } else{ ret = CO_ERROR_ILLEGAL_ARGUMENT; } return ret; }
CO_ReturnError_t CO_CANmodule_init( CO_CANmodule_t *CANmodule, uint16_t CANbaseAddress, CO_CANrx_t rxArray[], uint16_t rxSize, CO_CANtx_t txArray[], uint16_t txSize, uint16_t CANbitRate) { uint16_t i; volatile uint16_t *pRXF; uint16_t DMArxBaseAddress; uint16_t DMAtxBaseAddress; __eds__ CO_CANrxMsg_t *CANmsgBuff; uint8_t CANmsgBuffSize; uint16_t CANmsgBuffDMAoffset; #if defined(__HAS_EDS__) uint16_t CANmsgBuffDMApage; #endif /* verify arguments */ if(CANmodule==NULL || rxArray==NULL || txArray==NULL){ return CO_ERROR_ILLEGAL_ARGUMENT; } /* Get global addresses for CAN module 1 or 2. */ if(CANbaseAddress == ADDR_CAN1) { DMArxBaseAddress = CO_CAN1_DMA0; DMAtxBaseAddress = CO_CAN1_DMA1; CANmsgBuff = &CO_CAN1msg[0]; CANmsgBuffSize = CO_CAN1msgBuffSize; CANmsgBuffDMAoffset = __builtin_dmaoffset(&CO_CAN1msg[0]); #if defined(__HAS_EDS__) CANmsgBuffDMApage = __builtin_dmapage(&CO_CAN1msg[0]); #endif } #if CO_CAN2msgBuffSize > 0 else if(CANbaseAddress == ADDR_CAN2) { DMArxBaseAddress = CO_CAN2_DMA0; DMAtxBaseAddress = CO_CAN2_DMA1; CANmsgBuff = &CO_CAN2msg[0]; CANmsgBuffSize = CO_CAN2msgBuffSize; CANmsgBuffDMAoffset = __builtin_dmaoffset(&CO_CAN2msg[0]); #if defined(__HAS_EDS__) CANmsgBuffDMApage = __builtin_dmapage(&CO_CAN2msg[0]); #endif } #endif else { return CO_ERROR_ILLEGAL_ARGUMENT; } /* Configure object variables */ CANmodule->CANbaseAddress = CANbaseAddress; CANmodule->CANmsgBuff = CANmsgBuff; CANmodule->rxArray = rxArray; CANmodule->rxSize = rxSize; CANmodule->txArray = txArray; CANmodule->txSize = txSize; CANmodule->useCANrxFilters = (rxSize <= 16U) ? true : false; CANmodule->bufferInhibitFlag = false; CANmodule->firstCANtxMessage = true; CANmodule->CANtxCount = 0U; CANmodule->errOld = 0U; CANmodule->em = NULL; for(i=0U; i<rxSize; i++){ rxArray[i].ident = 0U; rxArray[i].pFunct = NULL; } for(i=0U; i<txSize; i++){ txArray[i].bufferFull = false; } /* Configure control registers */ CAN_REG(CANbaseAddress, C_CTRL1) = 0x0400; CAN_REG(CANbaseAddress, C_CTRL2) = 0x0000; /* Configure CAN timing */ switch(CANbitRate){ case 10: i=0; break; case 20: i=1; break; case 50: i=2; break; default: case 125: i=3; break; case 250: i=4; break; case 500: i=5; break; case 800: i=6; break; case 1000: i=7; break; } if(CO_CANbitRateData[i].scale == 2) CAN_REG(CANbaseAddress, C_CTRL1) |= 0x0800; CAN_REG(CANbaseAddress, C_CFG1) = (CO_CANbitRateData[i].SJW - 1) << 6 | (CO_CANbitRateData[i].BRP - 1); CAN_REG(CANbaseAddress, C_CFG2) = ((uint16_t)(CO_CANbitRateData[i].phSeg2 - 1)) << 8 | 0x0080 | (CO_CANbitRateData[i].phSeg1 - 1) << 3 | (CO_CANbitRateData[i].PROP - 1); /* setup RX and TX control registers */ CAN_REG(CANbaseAddress, C_CTRL1) &= 0xFFFE; /* WIN = 0 - use buffer registers */ CAN_REG(CANbaseAddress, C_RXFUL1) = 0x0000; CAN_REG(CANbaseAddress, C_RXFUL2) = 0x0000; CAN_REG(CANbaseAddress, C_RXOVF1) = 0x0000; CAN_REG(CANbaseAddress, C_RXOVF2) = 0x0000; CAN_REG(CANbaseAddress, C_TR01CON) = 0x0080; /* use one buffer for transmission */ CAN_REG(CANbaseAddress, C_TR23CON) = 0x0000; CAN_REG(CANbaseAddress, C_TR45CON) = 0x0000; CAN_REG(CANbaseAddress, C_TR67CON) = 0x0000; /* CAN module hardware filters */ CAN_REG(CANbaseAddress, C_CTRL1) |= 0x0001; /* WIN = 1 - use filter registers */ CAN_REG(CANbaseAddress, C_FEN1) = 0xFFFF; /* enable all 16 filters */ CAN_REG(CANbaseAddress, C_FMSKSEL1) = 0x0000; /* all filters are using mask 0 */ CAN_REG(CANbaseAddress, C_FMSKSEL2) = 0x0000; CAN_REG(CANbaseAddress, C_BUFPNT1) = 0xFFFF; /* use FIFO for all filters */ CAN_REG(CANbaseAddress, C_BUFPNT2) = 0xFFFF; CAN_REG(CANbaseAddress, C_BUFPNT3) = 0xFFFF; CAN_REG(CANbaseAddress, C_BUFPNT4) = 0xFFFF; /* set all filters to 0 */ pRXF = &CAN_REG(CANbaseAddress, C_RXF0SID); for(i=0; i<16; i++){ *pRXF = 0x0000; pRXF += 2; } if(CANmodule->useCANrxFilters){ /* CAN module filters are used, they will be configured with */ /* CO_CANrxBufferInit() functions, called by separate CANopen */ /* init functions. */ /* All mask bits are 1, so received message must match filter */ CAN_REG(CANbaseAddress, C_RXM0SID) = 0xFFE8; CAN_REG(CANbaseAddress, C_RXM1SID) = 0xFFE8; CAN_REG(CANbaseAddress, C_RXM2SID) = 0xFFE8; } else{ /* CAN module filters are not used, all messages with standard 11-bit */ /* identifier will be received */ /* Set masks so, that all messages with standard identifier are accepted */ CAN_REG(CANbaseAddress, C_RXM0SID) = 0x0008; CAN_REG(CANbaseAddress, C_RXM1SID) = 0x0008; CAN_REG(CANbaseAddress, C_RXM2SID) = 0x0008; } /* WIN = 0 - use buffer registers for default */ CAN_REG(CANbaseAddress, C_CTRL1) &= 0xFFFE; /* Configure DMA controller */ /* Set size of buffer in DMA RAM (FIFO Area Starts with Tx/Rx buffer TRB1 (FSA = 1)) */ /* Use maximum 16 buffers, because we have 16-bit system. */ if (CANmsgBuffSize >= 16) { CAN_REG(CANbaseAddress, C_FCTRL) = 0x8001; CANmodule->CANmsgBuffSize = 16; } else if(CANmsgBuffSize >= 12) { CAN_REG(CANbaseAddress, C_FCTRL) = 0x6001; CANmodule->CANmsgBuffSize = 12; } else if(CANmsgBuffSize >= 8) { CAN_REG(CANbaseAddress, C_FCTRL) = 0x4001; CANmodule->CANmsgBuffSize = 8; } else if(CANmsgBuffSize >= 6) { CAN_REG(CANbaseAddress, C_FCTRL) = 0x2001; CANmodule->CANmsgBuffSize = 6; } else if(CANmsgBuffSize >= 4) { CAN_REG(CANbaseAddress, C_FCTRL) = 0x0001; CANmodule->CANmsgBuffSize = 4; } else { return CO_ERROR_ILLEGAL_ARGUMENT; } /* DMA chanel initialization for ECAN reception */ DMA_REG(DMArxBaseAddress, DMA_CON) = 0x0020; DMA_REG(DMArxBaseAddress, DMA_PAD) = (volatile uint16_t) &CAN_REG(CANbaseAddress, C_RXD); DMA_REG(DMArxBaseAddress, DMA_CNT) = 7; DMA_REG(DMArxBaseAddress, DMA_REQ) = (CANbaseAddress==ADDR_CAN1) ? 34 : 55; #ifndef __HAS_EDS__ DMA_REG(DMArxBaseAddress, DMA_STA) = CANmsgBuffDMAoffset; #else DMA_REG(DMArxBaseAddress, DMA_STAL) = CANmsgBuffDMAoffset; DMA_REG(DMArxBaseAddress, DMA_STAH) = CANmsgBuffDMApage; #endif DMA_REG(DMArxBaseAddress, DMA_CON) = 0x8020; /* DMA chanel initialization for ECAN transmission */ DMA_REG(DMAtxBaseAddress, DMA_CON) = 0x2020; DMA_REG(DMAtxBaseAddress, DMA_PAD) = (volatile uint16_t) &CAN_REG(CANbaseAddress, C_TXD); DMA_REG(DMAtxBaseAddress, DMA_CNT) = 7; DMA_REG(DMAtxBaseAddress, DMA_REQ) = (CANbaseAddress==ADDR_CAN1) ? 70 : 71; #ifndef __HAS_EDS__ DMA_REG(DMAtxBaseAddress, DMA_STA) = CANmsgBuffDMAoffset; #else DMA_REG(DMAtxBaseAddress, DMA_STAL) = CANmsgBuffDMAoffset; DMA_REG(DMAtxBaseAddress, DMA_STAH) = CANmsgBuffDMApage; #endif DMA_REG(DMAtxBaseAddress, DMA_CON) = 0xA020; /* CAN interrupt registers */ /* clear interrupt flags */ CAN_REG(CANbaseAddress, C_INTF) = 0x0000; /* enable receive and transmit interrupt */ CAN_REG(CANbaseAddress, C_INTE) = 0x0003; /* CAN interrupt (combined) must be configured by application */ return CO_ERROR_NO; }
CO_ReturnError_t err = CO_ERROR_NO; uint16_t addr = CANmodule->CANbaseAddress; volatile uint16_t C_CTRL1old, C_TR01CONcopy; /* Verify overflow */ if(buffer->bufferFull){ if(!CANmodule->firstCANtxMessage){ /* don't set error, if bootup message is still on buffers */ CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, (buffer->ident >> 2) & 0x7FF); } err = CO_ERROR_TX_OVERFLOW; } CO_LOCK_CAN_SEND(); /* read C_TR01CON */ C_CTRL1old = CAN_REG(addr, C_CTRL1); CAN_REG(addr, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */ C_TR01CONcopy = CAN_REG(addr, C_TR01CON); CAN_REG(addr, C_CTRL1) = C_CTRL1old; /* if CAN TX buffer is free, copy message to it */ if((C_TR01CONcopy & 0x8) == 0 && CANmodule->CANtxCount == 0){ CANmodule->bufferInhibitFlag = buffer->syncFlag; CO_CANsendToModule(addr, CANmodule->CANmsgBuff, buffer); } /* if no buffer is free, message will be sent by interrupt */ else{ buffer->bufferFull = true; CANmodule->CANtxCount++; } CO_UNLOCK_CAN_SEND();
int can_tx_now(CAN_CHANNEL chan){ volatile unsigned long* base = can_tx_chan_cfgs[chan].base_addr; CAN_FRAME frame; int sent = 0; if (CAN_REG(base, CAN_SR) & (1<<2)) // buffer 1 is available { can_ring_pop(can_tx_chan_cfgs[chan].ring, &frame); CAN_REG(base, CAN_TFI1) = 1<<19; //Data length 8, FF = 0, RTR = 0, PRIO = 0 CAN_REG(base, CAN_TID1) = frame.addr; //get CAN_ID CAN_REG(base, CAN_TDA1) = frame.payload.w.w1; //load first data word CAN_REG(base, CAN_TDB1) = frame.payload.w.w2; //load second data word CAN_REG(base, CAN_CMR) = (1<<0) | (1<<5); // Select buffer 1, request transmission can_add_frame_count(chan); sent++; } else if (CAN_REG(base, CAN_SR) & (1<<10)) // buffer 2 is available { can_ring_pop(can_tx_chan_cfgs[chan].ring, &frame); CAN_REG(base, CAN_TFI2) = 1<<19; //Data length 8, FF = 0, RTR = 0, PRIO = 0 CAN_REG(base, CAN_TID2) = frame.addr; //get CAN_ID CAN_REG(base, CAN_TDA2) = frame.payload.w.w1; //load first data word CAN_REG(base, CAN_TDB2) = frame.payload.w.w2; //load second data word CAN_REG(base, CAN_CMR) = (1<<0) | (1<<6); // Select buffer 2, request transmission can_add_frame_count(chan); sent++; } return sent; }