1 /*
2 * CAN module object for Microchip dsPIC33F or PIC24H microcontroller.
3 *
4 * @file CO_driver.c
5 * @author Janez Paternoster
6 * @author Peter Rozsahegyi (EDS)
7 * @author Jens Nielsen (CAN receive)
8 * @copyright 2004 - 2020 Janez Paternoster
9 *
10 * This file is part of CANopenNode, an opensource CANopen Stack.
11 * Project home page is <https://github.com/CANopenNode/CANopenNode>.
12 * For more information on CANopen see <http://www.can-cia.org/>.
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 */
26
27
28 #include "CO_driver.h"
29 #include "CO_Emergency.h"
30
31
32 /* Globals */
33 extern const CO_CANbitRateData_t CO_CANbitRateData[8];
34
35 #if CO_CAN1msgBuffSize > 0
36 __eds__ CO_CANrxMsg_t CO_CAN1msg[CO_CAN1msgBuffSize] __eds __dma __attribute__((aligned(128)));
37 #endif
38 #if CO_CAN2msgBuffSize > 0
39 __eds__ CO_CANrxMsg_t CO_CAN2msg[CO_CAN1msgBuffSize] __eds __dma __attribute__((aligned(128)));
40 #endif
41
42
43 /* Macro and Constants - CAN module registers and DMA registers - offset. */
44 #define CAN_REG(base, offset) (*((volatile uint16_t *) (((uintptr_t) base) + offset)))
45
46 #define C_CTRL1 0x00
47 #define C_CTRL2 0x02
48 #define C_VEC 0x04
49 #define C_FCTRL 0x06
50 #define C_FIFO 0x08
51 #define C_INTF 0x0A
52 #define C_INTE 0x0C
53 #define C_EC 0x0E
54 #define C_CFG1 0x10
55 #define C_CFG2 0x12
56 #define C_FEN1 0x14
57 #define C_FMSKSEL1 0x18
58 #define C_FMSKSEL2 0x1A
59
60 /* WIN == 0 */
61 #define C_RXFUL1 0x20
62 #define C_RXFUL2 0x22
63 #define C_RXOVF1 0x28
64 #define C_RXOVF2 0x2A
65 #define C_TR01CON 0x30
66 #define C_TR23CON 0x32
67 #define C_TR45CON 0x34
68 #define C_TR67CON 0x36
69 #define C_RXD 0x40
70 #define C_TXD 0x42
71
72 /* WIN == 1 */
73 #define C_BUFPNT1 0x20
74 #define C_BUFPNT2 0x22
75 #define C_BUFPNT3 0x24
76 #define C_BUFPNT4 0x26
77 #define C_RXM0SID 0x30
78 #define C_RXM1SID 0x34
79 #define C_RXM2SID 0x38
80 #define C_RXF0SID 0x40 /* filter1 = +4, ...., filter 15 = +4*15 */
81
82
83 #define DMA_REG(base, offset) (*((volatile uint16_t *) (base + offset)))
84
85 #define DMA_CON 0x0
86 #define DMA_REQ 0x2
87 #ifndef __HAS_EDS__
88 #define DMA_STA 0x4
89 #define DMA_STB 0x6
90 #define DMA_PAD 0x8
91 #define DMA_CNT 0xA
92 #else
93 #define DMA_STAL 0x4
94 #define DMA_STAH 0x6
95 #define DMA_STBL 0x8
96 #define DMA_STBH 0xA
97 #define DMA_PAD 0xC
98 #define DMA_CNT 0xE
99 #endif
100
101
102 /******************************************************************************/
CO_CANsetConfigurationMode(void * CANdriverState)103 void CO_CANsetConfigurationMode(void *CANdriverState){
104 uint16_t C_CTRL1copy = CAN_REG(CANdriverState, C_CTRL1);
105
106 /* set REQOP = 0x4 */
107 C_CTRL1copy &= 0xFCFF;
108 C_CTRL1copy |= 0x0400;
109 CAN_REG(CANdriverState, C_CTRL1) = C_CTRL1copy;
110
111 /* while OPMODE != 4 */
112 while((CAN_REG(CANdriverState, C_CTRL1) & 0x00E0) != 0x0080);
113 }
114
115
116 /******************************************************************************/
CO_CANsetNormalMode(CO_CANmodule_t * CANmodule)117 void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){
118 uint16_t C_CTRL1copy = CAN_REG(CANmodule->CANdriverState, C_CTRL1);
119
120 /* set REQOP = 0x0 */
121 C_CTRL1copy &= 0xF8FF;
122 CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1copy;
123
124 /* while OPMODE != 0 */
125 while((CAN_REG(CANmodule->CANdriverState, C_CTRL1) & 0x00E0) != 0x0000);
126
127 CANmodule->CANnormal = true;
128 }
129
130
131 /******************************************************************************/
CO_CANmodule_init(CO_CANmodule_t * CANmodule,void * CANdriverState,CO_CANrx_t rxArray[],uint16_t rxSize,CO_CANtx_t txArray[],uint16_t txSize,uint16_t CANbitRate)132 CO_ReturnError_t CO_CANmodule_init(
133 CO_CANmodule_t *CANmodule,
134 void *CANdriverState,
135 CO_CANrx_t rxArray[],
136 uint16_t rxSize,
137 CO_CANtx_t txArray[],
138 uint16_t txSize,
139 uint16_t CANbitRate)
140 {
141 uint16_t i;
142 volatile uint16_t *pRXF;
143
144 uint16_t DMArxBaseAddress;
145 uint16_t DMAtxBaseAddress;
146 __eds__ CO_CANrxMsg_t *CANmsgBuff;
147 uint8_t CANmsgBuffSize;
148 uint16_t CANmsgBuffDMAoffset;
149 #if defined(__HAS_EDS__)
150 uint16_t CANmsgBuffDMApage;
151 #endif
152
153 /* verify arguments */
154 if(CANmodule==NULL || rxArray==NULL || txArray==NULL){
155 return CO_ERROR_ILLEGAL_ARGUMENT;
156 }
157
158 /* Get global addresses for CAN module 1 or 2. */
159 if(CANdriverState == ADDR_CAN1) {
160 DMArxBaseAddress = CO_CAN1_DMA0;
161 DMAtxBaseAddress = CO_CAN1_DMA1;
162 CANmsgBuff = &CO_CAN1msg[0];
163 CANmsgBuffSize = CO_CAN1msgBuffSize;
164 CANmsgBuffDMAoffset = __builtin_dmaoffset(&CO_CAN1msg[0]);
165 #if defined(__HAS_EDS__)
166 CANmsgBuffDMApage = __builtin_dmapage(&CO_CAN1msg[0]);
167 #endif
168 }
169 #if CO_CAN2msgBuffSize > 0
170 else if(((uintptr_t) CANdriverState) == ADDR_CAN2) {
171 DMArxBaseAddress = CO_CAN2_DMA0;
172 DMAtxBaseAddress = CO_CAN2_DMA1;
173 CANmsgBuff = &CO_CAN2msg[0];
174 CANmsgBuffSize = CO_CAN2msgBuffSize;
175 CANmsgBuffDMAoffset = __builtin_dmaoffset(&CO_CAN2msg[0]);
176 #if defined(__HAS_EDS__)
177 CANmsgBuffDMApage = __builtin_dmapage(&CO_CAN2msg[0]);
178 #endif
179 }
180 #endif
181 else {
182 return CO_ERROR_ILLEGAL_ARGUMENT;
183 }
184
185 /* Configure object variables */
186 CANmodule->CANdriverState = CANdriverState;
187 CANmodule->CANmsgBuff = CANmsgBuff;
188 CANmodule->rxArray = rxArray;
189 CANmodule->rxSize = rxSize;
190 CANmodule->txArray = txArray;
191 CANmodule->txSize = txSize;
192 CANmodule->CANnormal = false;
193 CANmodule->useCANrxFilters = (rxSize <= 16U) ? true : false;
194 CANmodule->bufferInhibitFlag = false;
195 CANmodule->firstCANtxMessage = true;
196 CANmodule->CANtxCount = 0U;
197 CANmodule->errOld = 0U;
198 CANmodule->em = NULL;
199
200 for(i=0U; i<rxSize; i++){
201 rxArray[i].ident = 0U;
202 rxArray[i].pFunct = NULL;
203 }
204 for(i=0U; i<txSize; i++){
205 txArray[i].bufferFull = false;
206 }
207
208
209 /* Configure control registers */
210 CAN_REG(CANdriverState, C_CTRL1) = 0x0400;
211 CAN_REG(CANdriverState, C_CTRL2) = 0x0000;
212
213
214 /* Configure CAN timing */
215 switch(CANbitRate){
216 case 10: i=0; break;
217 case 20: i=1; break;
218 case 50: i=2; break;
219 default:
220 case 125: i=3; break;
221 case 250: i=4; break;
222 case 500: i=5; break;
223 case 800: i=6; break;
224 case 1000: i=7; break;
225 }
226
227 if(CO_CANbitRateData[i].scale == 2)
228 CAN_REG(CANdriverState, C_CTRL1) |= 0x0800;
229
230 CAN_REG(CANdriverState, C_CFG1) = (CO_CANbitRateData[i].SJW - 1) << 6 |
231 (CO_CANbitRateData[i].BRP - 1);
232
233 CAN_REG(CANdriverState, C_CFG2) = ((uint16_t)(CO_CANbitRateData[i].phSeg2 - 1)) << 8 |
234 0x0080 |
235 (CO_CANbitRateData[i].phSeg1 - 1) << 3 |
236 (CO_CANbitRateData[i].PROP - 1);
237
238
239 /* setup RX and TX control registers */
240 CAN_REG(CANdriverState, C_CTRL1) &= 0xFFFE; /* WIN = 0 - use buffer registers */
241 CAN_REG(CANdriverState, C_RXFUL1) = 0x0000;
242 CAN_REG(CANdriverState, C_RXFUL2) = 0x0000;
243 CAN_REG(CANdriverState, C_RXOVF1) = 0x0000;
244 CAN_REG(CANdriverState, C_RXOVF2) = 0x0000;
245 CAN_REG(CANdriverState, C_TR01CON) = 0x0080; /* use one buffer for transmission */
246 CAN_REG(CANdriverState, C_TR23CON) = 0x0000;
247 CAN_REG(CANdriverState, C_TR45CON) = 0x0000;
248 CAN_REG(CANdriverState, C_TR67CON) = 0x0000;
249
250
251 /* CAN module hardware filters */
252 CAN_REG(CANdriverState, C_CTRL1) |= 0x0001; /* WIN = 1 - use filter registers */
253 CAN_REG(CANdriverState, C_FEN1) = 0xFFFF; /* enable all 16 filters */
254 CAN_REG(CANdriverState, C_FMSKSEL1) = 0x0000; /* all filters are using mask 0 */
255 CAN_REG(CANdriverState, C_FMSKSEL2) = 0x0000;
256 CAN_REG(CANdriverState, C_BUFPNT1) = 0xFFFF; /* use FIFO for all filters */
257 CAN_REG(CANdriverState, C_BUFPNT2) = 0xFFFF;
258 CAN_REG(CANdriverState, C_BUFPNT3) = 0xFFFF;
259 CAN_REG(CANdriverState, C_BUFPNT4) = 0xFFFF;
260 /* set all filters to 0 */
261 pRXF = &CAN_REG(CANdriverState, C_RXF0SID);
262 for(i=0; i<16; i++){
263 *pRXF = 0x0000;
264 pRXF += 2;
265 }
266 if(CANmodule->useCANrxFilters){
267 /* CAN module filters are used, they will be configured with */
268 /* CO_CANrxBufferInit() functions, called by separate CANopen */
269 /* init functions. */
270 /* All mask bits are 1, so received message must match filter */
271 CAN_REG(CANdriverState, C_RXM0SID) = 0xFFE8;
272 CAN_REG(CANdriverState, C_RXM1SID) = 0xFFE8;
273 CAN_REG(CANdriverState, C_RXM2SID) = 0xFFE8;
274 }
275 else{
276 /* CAN module filters are not used, all messages with standard 11-bit */
277 /* identifier will be received */
278 /* Set masks so, that all messages with standard identifier are accepted */
279 CAN_REG(CANdriverState, C_RXM0SID) = 0x0008;
280 CAN_REG(CANdriverState, C_RXM1SID) = 0x0008;
281 CAN_REG(CANdriverState, C_RXM2SID) = 0x0008;
282 }
283
284 /* WIN = 0 - use buffer registers for default */
285 CAN_REG(CANdriverState, C_CTRL1) &= 0xFFFE;
286
287
288 /* Configure DMA controller */
289 /* Set size of buffer in DMA RAM (FIFO Area Starts with Tx/Rx buffer TRB1 (FSA = 1)) */
290 /* Use maximum 16 buffers, because we have 16-bit system. */
291 if (CANmsgBuffSize >= 16) {
292 CAN_REG(CANdriverState, C_FCTRL) = 0x8001;
293 CANmodule->CANmsgBuffSize = 16;
294 }
295 else if(CANmsgBuffSize >= 12) {
296 CAN_REG(CANdriverState, C_FCTRL) = 0x6001;
297 CANmodule->CANmsgBuffSize = 12;
298 }
299 else if(CANmsgBuffSize >= 8) {
300 CAN_REG(CANdriverState, C_FCTRL) = 0x4001;
301 CANmodule->CANmsgBuffSize = 8;
302 }
303 else if(CANmsgBuffSize >= 6) {
304 CAN_REG(CANdriverState, C_FCTRL) = 0x2001;
305 CANmodule->CANmsgBuffSize = 6;
306 }
307 else if(CANmsgBuffSize >= 4) {
308 CAN_REG(CANdriverState, C_FCTRL) = 0x0001;
309 CANmodule->CANmsgBuffSize = 4;
310 }
311 else {
312 return CO_ERROR_ILLEGAL_ARGUMENT;
313 }
314
315 /* DMA chanel initialization for ECAN reception */
316 DMA_REG(DMArxBaseAddress, DMA_CON) = 0x0020;
317 DMA_REG(DMArxBaseAddress, DMA_PAD) = (volatile uint16_t) &CAN_REG(CANdriverState, C_RXD);
318 DMA_REG(DMArxBaseAddress, DMA_CNT) = 7;
319 DMA_REG(DMArxBaseAddress, DMA_REQ) = (CANdriverState==ADDR_CAN1) ? 34 : 55;
320
321 #ifndef __HAS_EDS__
322 DMA_REG(DMArxBaseAddress, DMA_STA) = CANmsgBuffDMAoffset;
323 #else
324 DMA_REG(DMArxBaseAddress, DMA_STAL) = CANmsgBuffDMAoffset;
325 DMA_REG(DMArxBaseAddress, DMA_STAH) = CANmsgBuffDMApage;
326 #endif
327
328 DMA_REG(DMArxBaseAddress, DMA_CON) = 0x8020;
329
330 /* DMA chanel initialization for ECAN transmission */
331 DMA_REG(DMAtxBaseAddress, DMA_CON) = 0x2020;
332 DMA_REG(DMAtxBaseAddress, DMA_PAD) = (volatile uint16_t) &CAN_REG(CANdriverState, C_TXD);
333 DMA_REG(DMAtxBaseAddress, DMA_CNT) = 7;
334 DMA_REG(DMAtxBaseAddress, DMA_REQ) = (CANdriverState==ADDR_CAN1) ? 70 : 71;
335
336 #ifndef __HAS_EDS__
337 DMA_REG(DMAtxBaseAddress, DMA_STA) = CANmsgBuffDMAoffset;
338 #else
339 DMA_REG(DMAtxBaseAddress, DMA_STAL) = CANmsgBuffDMAoffset;
340 DMA_REG(DMAtxBaseAddress, DMA_STAH) = CANmsgBuffDMApage;
341 #endif
342
343 DMA_REG(DMAtxBaseAddress, DMA_CON) = 0xA020;
344
345
346 /* CAN interrupt registers */
347 /* clear interrupt flags */
348 CAN_REG(CANdriverState, C_INTF) = 0x0000;
349 /* enable receive and transmit interrupt */
350 CAN_REG(CANdriverState, C_INTE) = 0x0003;
351 /* CAN interrupt (combined) must be configured by application */
352
353 return CO_ERROR_NO;
354 }
355
356
357 /******************************************************************************/
CO_CANmodule_disable(CO_CANmodule_t * CANmodule)358 void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){
359 CO_CANsetConfigurationMode(CANmodule->CANdriverState);
360 }
361
362
363 /******************************************************************************/
CO_CANrxMsg_readIdent(const CO_CANrxMsg_t * rxMsg)364 uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){
365 return (rxMsg->ident >> 2) & 0x7FF;
366 }
367
368
369 /******************************************************************************/
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))370 CO_ReturnError_t CO_CANrxBufferInit(
371 CO_CANmodule_t *CANmodule,
372 uint16_t index,
373 uint16_t ident,
374 uint16_t mask,
375 bool_t rtr,
376 void *object,
377 void (*pFunct)(void *object, const CO_CANrxMsg_t *message))
378 {
379 CO_ReturnError_t ret = CO_ERROR_NO;
380
381 if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){
382 /* buffer, which will be configured */
383 CO_CANrx_t *buffer = &CANmodule->rxArray[index];
384 uint16_t RXF, RXM;
385 uint16_t addr = CANmodule->CANdriverState;
386
387 /* Configure object variables */
388 buffer->object = object;
389 buffer->pFunct = pFunct;
390
391
392 /* CAN identifier and CAN mask, bit aligned with CAN module registers (in DMA RAM) */
393 RXF = (ident & 0x07FF) << 2;
394 if(rtr){
395 RXF |= 0x02;
396 }
397 RXM = (mask & 0x07FF) << 2;
398 RXM |= 0x02;
399
400 /* configure filter and mask */
401 if(RXF != buffer->ident || RXM != buffer->mask){
402 volatile uint16_t C_CTRL1old = CAN_REG(addr, C_CTRL1);
403 CAN_REG(addr, C_CTRL1) = C_CTRL1old | 0x0001; /* WIN = 1 - use filter registers */
404 buffer->ident = RXF;
405 buffer->mask = RXM;
406
407 /* Set CAN hardware module filter and mask. */
408 if(CANmodule->useCANrxFilters){
409 volatile uint16_t *pRXF;
410 volatile uint16_t *pRXM0, *pRXM1, *pRXM2;
411 uint16_t selectMask;
412
413 /* align RXF and RXM with C_RXF_SID and C_RXM_SID registers */
414 RXF &= 0xFFFD; RXF <<= 3;
415 RXM &= 0xFFFD; RXM <<= 3; RXM |= 0x0008;
416
417 /* write to filter */
418 pRXF = &CAN_REG(addr, C_RXF0SID); /* pointer to first filter register */
419 pRXF += index * 2; /* now points to C_RXFiSID (i == index) */
420 *pRXF = RXF; /* write value to filter */
421
422 /* configure mask (There are three masks, each of them can be asigned to any filter. */
423 /* First mask has always the value 0xFFE8 - all 11 bits must match). */
424 pRXM0 = &CAN_REG(addr, C_RXM0SID);
425 pRXM1 = &CAN_REG(addr, C_RXM1SID);
426 pRXM2 = &CAN_REG(addr, C_RXM2SID);
427 if(RXM == 0xFFE8){
428 selectMask = 0;
429 }
430 else if(RXM == *pRXM1 || *pRXM1 == 0xFFE8){
431 /* RXM is equal to mask 1 or mask 1 was not yet configured. */
432 *pRXM1 = RXM;
433 selectMask = 1;
434 }
435 else if(RXM == *pRXM2 || *pRXM2 == 0xFFE8){
436 /* RXM is equal to mask 2 or mask 2 was not yet configured. */
437 *pRXM2 = RXM;
438 selectMask = 2;
439 }
440 else{
441 /* not enough masks */
442 ret = CO_ERROR_OUT_OF_MEMORY;
443 selectMask = 0;
444 }
445 if(ret == CO_ERROR_NO){
446 /* now write to appropriate mask select register */
447 if(index<8){
448 uint16_t clearMask = ~(0x0003 << (index << 1));
449 selectMask = selectMask << (index << 1);
450 CAN_REG(addr, C_FMSKSEL1) =
451 (CAN_REG(addr, C_FMSKSEL1) & clearMask) | selectMask;
452 }
453 else{
454 uint16_t clearMask = ~(0x0003 << ((index-8) << 1));
455 selectMask = selectMask << ((index-8) << 1);
456 CAN_REG(addr, C_FMSKSEL2) =
457 (CAN_REG(addr, C_FMSKSEL2) & clearMask) | selectMask;
458 }
459 }
460 }
461 CAN_REG(addr, C_CTRL1) = C_CTRL1old;
462 }
463 }
464 else{
465 ret = CO_ERROR_ILLEGAL_ARGUMENT;
466 }
467
468 return ret;
469 }
470
471
472 /******************************************************************************/
CO_CANtxBufferInit(CO_CANmodule_t * CANmodule,uint16_t index,uint16_t ident,bool_t rtr,uint8_t noOfBytes,bool_t syncFlag)473 CO_CANtx_t *CO_CANtxBufferInit(
474 CO_CANmodule_t *CANmodule,
475 uint16_t index,
476 uint16_t ident,
477 bool_t rtr,
478 uint8_t noOfBytes,
479 bool_t syncFlag)
480 {
481 CO_CANtx_t *buffer = NULL;
482
483 if((CANmodule != NULL) && (index < CANmodule->txSize)){
484 /* get specific buffer */
485 buffer = &CANmodule->txArray[index];
486
487 /* CAN identifier, bit aligned with CAN module registers */
488 uint16_t TXF;
489 TXF = (ident & 0x07FF) << 2;
490 if(rtr){
491 TXF |= 0x02;
492 }
493
494 /* write to buffer */
495 buffer->ident = TXF;
496 buffer->DLC = noOfBytes;
497 buffer->bufferFull = false;
498 buffer->syncFlag = syncFlag;
499 }
500
501 return buffer;
502 }
503
504
505 /* Copy message to CAN module - internal usage only.
506 *
507 * @param CANdriverState CAN module base address
508 * @param dest Pointer to CAN module transmit buffer
509 * @param src Pointer to source message
510 */
CO_CANsendToModule(void * CANdriverState,__eds__ CO_CANrxMsg_t * dest,CO_CANtx_t * src)511 static void CO_CANsendToModule(void *CANdriverState, __eds__ CO_CANrxMsg_t *dest, CO_CANtx_t *src){
512 uint8_t DLC;
513 __eds__ uint8_t *CANdataBuffer;
514 uint8_t *pData;
515 volatile uint16_t C_CTRL1old;
516
517 /* CAN-ID + RTR */
518 dest->ident = src->ident;
519
520 /* Data lenght */
521 DLC = src->DLC;
522 if(DLC > 8) DLC = 8;
523 dest->DLC = DLC;
524
525 /* copy data */
526 CANdataBuffer = &(dest->data[0]);
527 pData = src->data;
528 for(; DLC>0; DLC--) *(CANdataBuffer++) = *(pData++);
529
530 /* control register, transmit request */
531 C_CTRL1old = CAN_REG(CANdriverState, C_CTRL1);
532 CAN_REG(CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */
533 CAN_REG(CANdriverState, C_TR01CON) |= 0x08;
534 CAN_REG(CANdriverState, C_CTRL1) = C_CTRL1old;
535 }
536
537
538 /******************************************************************************/
CO_CANsend(CO_CANmodule_t * CANmodule,CO_CANtx_t * buffer)539 CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){
540 CO_ReturnError_t err = CO_ERROR_NO;
541 uint16_t addr = CANmodule->CANdriverState;
542 volatile uint16_t C_CTRL1old, C_TR01CONcopy;
543
544 /* Verify overflow */
545 if(buffer->bufferFull){
546 if(!CANmodule->firstCANtxMessage){
547 /* don't set error, if bootup message is still on buffers */
548 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, (buffer->ident >> 2) & 0x7FF);
549 }
550 err = CO_ERROR_TX_OVERFLOW;
551 }
552
553 CO_LOCK_CAN_SEND();
554 /* read C_TR01CON */
555 C_CTRL1old = CAN_REG(addr, C_CTRL1);
556 CAN_REG(addr, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */
557 C_TR01CONcopy = CAN_REG(addr, C_TR01CON);
558 CAN_REG(addr, C_CTRL1) = C_CTRL1old;
559
560 /* if CAN TX buffer is free, copy message to it */
561 if((C_TR01CONcopy & 0x8) == 0 && CANmodule->CANtxCount == 0){
562 CANmodule->bufferInhibitFlag = buffer->syncFlag;
563 CO_CANsendToModule(addr, CANmodule->CANmsgBuff, buffer);
564 }
565 /* if no buffer is free, message will be sent by interrupt */
566 else{
567 buffer->bufferFull = true;
568 CANmodule->CANtxCount++;
569 }
570 CO_UNLOCK_CAN_SEND();
571
572 return err;
573 }
574
575
576 /******************************************************************************/
CO_CANclearPendingSyncPDOs(CO_CANmodule_t * CANmodule)577 void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){
578 uint32_t tpdoDeleted = 0U;
579
580 CO_LOCK_CAN_SEND();
581 /* Abort message from CAN module, if there is synchronous TPDO.
582 * Take special care with this functionality. */
583 if(CANmodule->bufferInhibitFlag){
584 volatile uint16_t C_CTRL1old = CAN_REG(CANmodule->CANdriverState, C_CTRL1);
585 CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */
586 CAN_REG(CANmodule->CANdriverState, C_TR01CON) &= 0xFFF7; /* clear TXREQ */
587 CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old;
588 CANmodule->bufferInhibitFlag = false;
589 tpdoDeleted = 1U;
590 }
591 /* delete also pending synchronous TPDOs in TX buffers */
592 if(CANmodule->CANtxCount != 0U){
593 uint16_t i;
594 CO_CANtx_t *buffer = &CANmodule->txArray[0];
595 for(i = CANmodule->txSize; i > 0U; i--){
596 if(buffer->bufferFull){
597 if(buffer->syncFlag){
598 buffer->bufferFull = false;
599 CANmodule->CANtxCount--;
600 tpdoDeleted = 2U;
601 }
602 }
603 buffer++;
604 }
605 }
606 CO_UNLOCK_CAN_SEND();
607
608
609 if(tpdoDeleted != 0U){
610 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted);
611 }
612 }
613
614
615 /******************************************************************************/
CO_CANverifyErrors(CO_CANmodule_t * CANmodule)616 void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){
617 uint16_t err;
618 CO_EM_t* em = (CO_EM_t*)CANmodule->em;
619
620 err = CAN_REG(CANmodule->CANdriverState, C_INTF) >> 8;
621 if(CAN_REG(CANmodule->CANdriverState, C_INTF) & 4){
622 err |= 0x80;
623 }
624
625 if(CANmodule->errOld != err){
626 CANmodule->errOld = err;
627
628 /* CAN RX bus overflow */
629 if(err & 0xC0){
630 CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err);
631 CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFB;/* clear bits */
632 }
633
634 /* CAN TX bus off */
635 if(err & 0x20){
636 CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err);
637 }
638 else{
639 CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err);
640 }
641
642 /* CAN TX bus passive */
643 if(err & 0x10){
644 if(!CANmodule->firstCANtxMessage) CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err);
645 }
646 else{
647 int8_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE);
648 if(isError){
649 CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err);
650 CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err);
651 }
652 }
653
654 /* CAN RX bus passive */
655 if(err & 0x08){
656 CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err);
657 }
658 else{
659 CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err);
660 }
661
662 /* CAN TX or RX bus warning */
663 if(err & 0x19){
664 CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err);
665 }
666 else{
667 CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err);
668 }
669 }
670 }
671
672
673 /******************************************************************************/
CO_CANinterrupt(CO_CANmodule_t * CANmodule)674 void CO_CANinterrupt(CO_CANmodule_t *CANmodule) {
675
676 /* receive interrupt (New CAN message is available in RX FIFO buffer) */
677 if(CAN_REG(CANmodule->CANdriverState, C_INTF) & 0x02) {
678 uint16_t C_CTRL1old;
679 uint16_t C_RXFUL1copy;
680 uint16_t C_FIFOcopy;
681 uint8_t FNRB, FBP;
682
683 CO_DISABLE_INTERRUPTS();
684 C_CTRL1old = CAN_REG(CANmodule->CANdriverState, C_CTRL1);
685 CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */
686 C_RXFUL1copy = CAN_REG(CANmodule->CANdriverState, C_RXFUL1);
687 CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old;
688
689 /* We will service the buffers indicated by RXFUL copy, clear interrupt
690 * flag now and let interrupt hit again if more messages are received */
691 CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFD;
692 C_FIFOcopy = CAN_REG(CANmodule->CANdriverState, C_FIFO);
693 CO_ENABLE_INTERRUPTS();
694
695 /* FNRB tells us which buffer to read in FIFO */
696 FNRB = C_FIFOcopy & 0x3F;
697 /* FBP tells us the next FIFO entry that will be written */
698 FBP = C_FIFOcopy >> 8;
699
700 while(C_RXFUL1copy != 0) {
701 __eds__ CO_CANrxMsg_t *rcvMsg;/* pointer to received message in CAN module */
702 uint16_t index; /* index of received message */
703 uint16_t rcvMsgIdent; /* identifier of the received message */
704 CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */
705 bool_t msgMatched = false;
706 uint16_t mask;
707
708 mask = 1 << FNRB;
709
710 if((C_RXFUL1copy & mask) == 0) {
711 /* This should not happen. However, if it does happen
712 * (in case of debugging), get FNRB from loop. */
713 for(FNRB=1; FNRB<CANmodule->CANmsgBuffSize; FNRB++) {
714 mask = 1 << FNRB;
715 if((C_RXFUL1copy & mask)) {
716 break;
717 }
718 }
719 }
720
721 /* RXFUL is set for this buffer, service it */
722 rcvMsg = &CANmodule->CANmsgBuff[FNRB];
723 rcvMsgIdent = rcvMsg->ident;
724 if(CANmodule->useCANrxFilters) {
725 /* CAN module filters are used. Message with known 11-bit identifier has */
726 /* been received */
727 index = rcvMsg->FILHIT;
728 if(index < CANmodule->rxSize) {
729 buffer = &CANmodule->rxArray[index];
730 /* verify also RTR */
731 if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) {
732 msgMatched = true;
733 }
734 }
735 }
736 else {
737 /* CAN module filters are not used, message with any standard 11-bit identifier */
738 /* has been received. Search rxArray form CANmodule for the same CAN-ID. */
739 buffer = &CANmodule->rxArray[0];
740 for(index = CANmodule->rxSize; index > 0U; index--) {
741 if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U) {
742 msgMatched = true;
743 break;
744 }
745 buffer++;
746 }
747 }
748
749 /* Call specific function, which will process the message */
750 if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)) {
751 #ifdef __HAS_EDS__
752 CO_CANrxMsg_t _rcvMsg = *rcvMsg;
753 buffer->pFunct(buffer->object, &_rcvMsg);
754 #else
755 buffer->pFunct(buffer->object, rcvMsg);
756 #endif
757 }
758
759 /* Clear RXFUL flag */
760 CO_DISABLE_INTERRUPTS();
761 C_CTRL1old = CAN_REG(CANmodule->CANdriverState, C_CTRL1);
762 CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old & 0xFFFE; /* WIN = 0 - use buffer registers */
763 CAN_REG(CANmodule->CANdriverState, C_RXFUL1) &= ~(mask);
764 CAN_REG(CANmodule->CANdriverState, C_CTRL1) = C_CTRL1old;
765 CO_ENABLE_INTERRUPTS();
766 C_RXFUL1copy &= ~(mask);
767
768 /* Now update FNRB, it will point to a new buffer after RXFUL was cleared */
769 FNRB = (CAN_REG(CANmodule->CANdriverState, C_FIFO) & 0x3F);
770 }
771 }
772
773 /* transmit interrupt (TX buffer is free) */
774 if(CAN_REG(CANmodule->CANdriverState, C_INTF) & 0x01) {
775
776 /* Clear interrupt flag */
777 CAN_REG(CANmodule->CANdriverState, C_INTF) &= 0xFFFE;
778 /* First CAN message (bootup) was sent successfully */
779 CANmodule->firstCANtxMessage = false;
780 /* clear flag from previous message */
781 CANmodule->bufferInhibitFlag = false;
782 /* Are there any new messages waiting to be send */
783 if(CANmodule->CANtxCount > 0U){
784 uint16_t i; /* index of transmitting message */
785
786 /* first buffer */
787 CO_CANtx_t *buffer = &CANmodule->txArray[0];
788 /* search through whole array of pointers to transmit message buffers. */
789 for(i = CANmodule->txSize; i > 0U; i--){
790 /* if message buffer is full, send it. */
791 if(buffer->bufferFull){
792 buffer->bufferFull = false;
793 CANmodule->CANtxCount--;
794
795 /* Copy message to CAN buffer */
796 CANmodule->bufferInhibitFlag = buffer->syncFlag;
797 CO_CANsendToModule(CANmodule->CANdriverState, CANmodule->CANmsgBuff, buffer);
798 break; /* exit for loop */
799 }
800 buffer++;
801 }/* end of for loop */
802
803 /* Clear counter if no more messages */
804 if(i == 0U){
805 CANmodule->CANtxCount = 0U;
806 }
807 }
808 }
809 }
810