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