1 /*
2 * CAN module object for generic microcontroller.
3 *
4 * This file is a template for other microcontrollers.
5 *
6 * @file CO_driver.c
7 * @ingroup CO_driver
8 * @author Janez Paternoster
9 * @copyright 2004 - 2020 Janez Paternoster
10 *
11 * This file is part of CANopenNode, an opensource CANopen Stack.
12 * Project home page is <https://github.com/CANopenNode/CANopenNode>.
13 * For more information on CANopen see <http://www.can-cia.org/>.
14 *
15 * Licensed under the Apache License, Version 2.0 (the "License");
16 * you may not use this file except in compliance with the License.
17 * You may obtain a copy of the License at
18 *
19 * http://www.apache.org/licenses/LICENSE-2.0
20 *
21 * Unless required by applicable law or agreed to in writing, software
22 * distributed under the License is distributed on an "AS IS" BASIS,
23 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24 * See the License for the specific language governing permissions and
25 * limitations under the License.
26 */
27
28
29 #include "CO_driver.h"
30 #include "CO_Emergency.h"
31
32
33 /******************************************************************************/
CO_CANsetConfigurationMode(void * CANdriverState)34 void CO_CANsetConfigurationMode(void *CANdriverState){
35 /* Put CAN module in configuration mode */
36 }
37
38
39 /******************************************************************************/
CO_CANsetNormalMode(CO_CANmodule_t * CANmodule)40 void CO_CANsetNormalMode(CO_CANmodule_t *CANmodule){
41 /* Put CAN module in normal mode */
42
43 CANmodule->CANnormal = true;
44 }
45
46
47 /******************************************************************************/
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)48 CO_ReturnError_t CO_CANmodule_init(
49 CO_CANmodule_t *CANmodule,
50 void *CANdriverState,
51 CO_CANrx_t rxArray[],
52 uint16_t rxSize,
53 CO_CANtx_t txArray[],
54 uint16_t txSize,
55 uint16_t CANbitRate)
56 {
57 uint16_t i;
58
59 /* verify arguments */
60 if(CANmodule==NULL || rxArray==NULL || txArray==NULL){
61 return CO_ERROR_ILLEGAL_ARGUMENT;
62 }
63
64 /* Configure object variables */
65 CANmodule->CANdriverState = CANdriverState;
66 CANmodule->rxArray = rxArray;
67 CANmodule->rxSize = rxSize;
68 CANmodule->txArray = txArray;
69 CANmodule->txSize = txSize;
70 CANmodule->CANnormal = false;
71 CANmodule->useCANrxFilters = (rxSize <= 32U) ? true : false;/* microcontroller dependent */
72 CANmodule->bufferInhibitFlag = false;
73 CANmodule->firstCANtxMessage = true;
74 CANmodule->CANtxCount = 0U;
75 CANmodule->errOld = 0U;
76 CANmodule->em = NULL;
77
78 for(i=0U; i<rxSize; i++){
79 rxArray[i].ident = 0U;
80 rxArray[i].mask = (uint16_t)0xFFFFFFFFU;
81 rxArray[i].object = NULL;
82 rxArray[i].pFunct = NULL;
83 }
84 for(i=0U; i<txSize; i++){
85 txArray[i].bufferFull = false;
86 }
87
88
89 /* Configure CAN module registers */
90
91
92 /* Configure CAN timing */
93
94
95 /* Configure CAN module hardware filters */
96 if(CANmodule->useCANrxFilters){
97 /* CAN module filters are used, they will be configured with */
98 /* CO_CANrxBufferInit() functions, called by separate CANopen */
99 /* init functions. */
100 /* Configure all masks so, that received message must match filter */
101 }
102 else{
103 /* CAN module filters are not used, all messages with standard 11-bit */
104 /* identifier will be received */
105 /* Configure mask 0 so, that all messages with standard identifier are accepted */
106 }
107
108
109 /* configure CAN interrupt registers */
110
111
112 return CO_ERROR_NO;
113 }
114
115
116 /******************************************************************************/
CO_CANmodule_disable(CO_CANmodule_t * CANmodule)117 void CO_CANmodule_disable(CO_CANmodule_t *CANmodule){
118 /* turn off the module */
119 }
120
121
122 /******************************************************************************/
CO_CANrxMsg_readIdent(const CO_CANrxMsg_t * rxMsg)123 uint16_t CO_CANrxMsg_readIdent(const CO_CANrxMsg_t *rxMsg){
124 return (uint16_t) rxMsg->ident;
125 }
126
127
128 /******************************************************************************/
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))129 CO_ReturnError_t CO_CANrxBufferInit(
130 CO_CANmodule_t *CANmodule,
131 uint16_t index,
132 uint16_t ident,
133 uint16_t mask,
134 bool_t rtr,
135 void *object,
136 void (*pFunct)(void *object, const CO_CANrxMsg_t *message))
137 {
138 CO_ReturnError_t ret = CO_ERROR_NO;
139
140 if((CANmodule!=NULL) && (object!=NULL) && (pFunct!=NULL) && (index < CANmodule->rxSize)){
141 /* buffer, which will be configured */
142 CO_CANrx_t *buffer = &CANmodule->rxArray[index];
143
144 /* Configure object variables */
145 buffer->object = object;
146 buffer->pFunct = pFunct;
147
148 /* CAN identifier and CAN mask, bit aligned with CAN module. Different on different microcontrollers. */
149 buffer->ident = ident & 0x07FFU;
150 if(rtr){
151 buffer->ident |= 0x0800U;
152 }
153 buffer->mask = (mask & 0x07FFU) | 0x0800U;
154
155 /* Set CAN hardware module filter and mask. */
156 if(CANmodule->useCANrxFilters){
157
158 }
159 }
160 else{
161 ret = CO_ERROR_ILLEGAL_ARGUMENT;
162 }
163
164 return ret;
165 }
166
167
168 /******************************************************************************/
CO_CANtxBufferInit(CO_CANmodule_t * CANmodule,uint16_t index,uint16_t ident,bool_t rtr,uint8_t noOfBytes,bool_t syncFlag)169 CO_CANtx_t *CO_CANtxBufferInit(
170 CO_CANmodule_t *CANmodule,
171 uint16_t index,
172 uint16_t ident,
173 bool_t rtr,
174 uint8_t noOfBytes,
175 bool_t syncFlag)
176 {
177 CO_CANtx_t *buffer = NULL;
178
179 if((CANmodule != NULL) && (index < CANmodule->txSize)){
180 /* get specific buffer */
181 buffer = &CANmodule->txArray[index];
182
183 /* CAN identifier, DLC and rtr, bit aligned with CAN module transmit buffer.
184 * Microcontroller specific. */
185 buffer->ident = ((uint32_t)ident & 0x07FFU)
186 | ((uint32_t)(((uint32_t)noOfBytes & 0xFU) << 12U))
187 | ((uint32_t)(rtr ? 0x8000U : 0U));
188
189 buffer->bufferFull = false;
190 buffer->syncFlag = syncFlag;
191 }
192
193 return buffer;
194 }
195
196
197 /******************************************************************************/
CO_CANsend(CO_CANmodule_t * CANmodule,CO_CANtx_t * buffer)198 CO_ReturnError_t CO_CANsend(CO_CANmodule_t *CANmodule, CO_CANtx_t *buffer){
199 CO_ReturnError_t err = CO_ERROR_NO;
200
201 /* Verify overflow */
202 if(buffer->bufferFull){
203 if(!CANmodule->firstCANtxMessage){
204 /* don't set error, if bootup message is still on buffers */
205 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_CAN_TX_OVERFLOW, CO_EMC_CAN_OVERRUN, buffer->ident);
206 }
207 err = CO_ERROR_TX_OVERFLOW;
208 }
209
210 CO_LOCK_CAN_SEND();
211 /* if CAN TX buffer is free, copy message to it */
212 if(1 && CANmodule->CANtxCount == 0){
213 CANmodule->bufferInhibitFlag = buffer->syncFlag;
214 /* copy message and txRequest */
215 }
216 /* if no buffer is free, message will be sent by interrupt */
217 else{
218 buffer->bufferFull = true;
219 CANmodule->CANtxCount++;
220 }
221 CO_UNLOCK_CAN_SEND();
222
223 return err;
224 }
225
226
227 /******************************************************************************/
CO_CANclearPendingSyncPDOs(CO_CANmodule_t * CANmodule)228 void CO_CANclearPendingSyncPDOs(CO_CANmodule_t *CANmodule){
229 uint32_t tpdoDeleted = 0U;
230
231 CO_LOCK_CAN_SEND();
232 /* Abort message from CAN module, if there is synchronous TPDO.
233 * Take special care with this functionality. */
234 if(/*messageIsOnCanBuffer && */CANmodule->bufferInhibitFlag){
235 /* clear TXREQ */
236 CANmodule->bufferInhibitFlag = false;
237 tpdoDeleted = 1U;
238 }
239 /* delete also pending synchronous TPDOs in TX buffers */
240 if(CANmodule->CANtxCount != 0U){
241 uint16_t i;
242 CO_CANtx_t *buffer = &CANmodule->txArray[0];
243 for(i = CANmodule->txSize; i > 0U; i--){
244 if(buffer->bufferFull){
245 if(buffer->syncFlag){
246 buffer->bufferFull = false;
247 CANmodule->CANtxCount--;
248 tpdoDeleted = 2U;
249 }
250 }
251 buffer++;
252 }
253 }
254 CO_UNLOCK_CAN_SEND();
255
256
257 if(tpdoDeleted != 0U){
258 CO_errorReport((CO_EM_t*)CANmodule->em, CO_EM_TPDO_OUTSIDE_WINDOW, CO_EMC_COMMUNICATION, tpdoDeleted);
259 }
260 }
261
262
263 /******************************************************************************/
CO_CANverifyErrors(CO_CANmodule_t * CANmodule)264 void CO_CANverifyErrors(CO_CANmodule_t *CANmodule){
265 uint16_t rxErrors, txErrors, overflow;
266 CO_EM_t* em = (CO_EM_t*)CANmodule->em;
267 uint32_t err;
268
269 /* get error counters from module. Id possible, function may use different way to
270 * determine errors. */
271 rxErrors = CANmodule->txSize;
272 txErrors = CANmodule->txSize;
273 overflow = CANmodule->txSize;
274
275 err = ((uint32_t)txErrors << 16) | ((uint32_t)rxErrors << 8) | overflow;
276
277 if(CANmodule->errOld != err){
278 CANmodule->errOld = err;
279
280 if(txErrors >= 256U){ /* bus off */
281 CO_errorReport(em, CO_EM_CAN_TX_BUS_OFF, CO_EMC_BUS_OFF_RECOVERED, err);
282 }
283 else{ /* not bus off */
284 CO_errorReset(em, CO_EM_CAN_TX_BUS_OFF, err);
285
286 if((rxErrors >= 96U) || (txErrors >= 96U)){ /* bus warning */
287 CO_errorReport(em, CO_EM_CAN_BUS_WARNING, CO_EMC_NO_ERROR, err);
288 }
289
290 if(rxErrors >= 128U){ /* RX bus passive */
291 CO_errorReport(em, CO_EM_CAN_RX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err);
292 }
293 else{
294 CO_errorReset(em, CO_EM_CAN_RX_BUS_PASSIVE, err);
295 }
296
297 if(txErrors >= 128U){ /* TX bus passive */
298 if(!CANmodule->firstCANtxMessage){
299 CO_errorReport(em, CO_EM_CAN_TX_BUS_PASSIVE, CO_EMC_CAN_PASSIVE, err);
300 }
301 }
302 else{
303 bool_t isError = CO_isError(em, CO_EM_CAN_TX_BUS_PASSIVE);
304 if(isError){
305 CO_errorReset(em, CO_EM_CAN_TX_BUS_PASSIVE, err);
306 CO_errorReset(em, CO_EM_CAN_TX_OVERFLOW, err);
307 }
308 }
309
310 if((rxErrors < 96U) && (txErrors < 96U)){ /* no error */
311 CO_errorReset(em, CO_EM_CAN_BUS_WARNING, err);
312 }
313 }
314
315 if(overflow != 0U){ /* CAN RX bus overflow */
316 CO_errorReport(em, CO_EM_CAN_RXB_OVERFLOW, CO_EMC_CAN_OVERRUN, err);
317 }
318 }
319 }
320
321
322 /******************************************************************************/
CO_CANinterrupt(CO_CANmodule_t * CANmodule)323 void CO_CANinterrupt(CO_CANmodule_t *CANmodule){
324
325 /* receive interrupt */
326 if(1){
327 CO_CANrxMsg_t *rcvMsg; /* pointer to received message in CAN module */
328 uint16_t index; /* index of received message */
329 uint32_t rcvMsgIdent; /* identifier of the received message */
330 CO_CANrx_t *buffer = NULL; /* receive message buffer from CO_CANmodule_t object. */
331 bool_t msgMatched = false;
332
333 rcvMsg = 0; /* get message from module here */
334 rcvMsgIdent = rcvMsg->ident;
335 if(CANmodule->useCANrxFilters){
336 /* CAN module filters are used. Message with known 11-bit identifier has */
337 /* been received */
338 index = 0; /* get index of the received message here. Or something similar */
339 if(index < CANmodule->rxSize){
340 buffer = &CANmodule->rxArray[index];
341 /* verify also RTR */
342 if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){
343 msgMatched = true;
344 }
345 }
346 }
347 else{
348 /* CAN module filters are not used, message with any standard 11-bit identifier */
349 /* has been received. Search rxArray form CANmodule for the same CAN-ID. */
350 buffer = &CANmodule->rxArray[0];
351 for(index = CANmodule->rxSize; index > 0U; index--){
352 if(((rcvMsgIdent ^ buffer->ident) & buffer->mask) == 0U){
353 msgMatched = true;
354 break;
355 }
356 buffer++;
357 }
358 }
359
360 /* Call specific function, which will process the message */
361 if(msgMatched && (buffer != NULL) && (buffer->pFunct != NULL)){
362 buffer->pFunct(buffer->object, rcvMsg);
363 }
364
365 /* Clear interrupt flag */
366 }
367
368
369 /* transmit interrupt */
370 else if(0){
371 /* Clear interrupt flag */
372
373 /* First CAN message (bootup) was sent successfully */
374 CANmodule->firstCANtxMessage = false;
375 /* clear flag from previous message */
376 CANmodule->bufferInhibitFlag = false;
377 /* Are there any new messages waiting to be send */
378 if(CANmodule->CANtxCount > 0U){
379 uint16_t i; /* index of transmitting message */
380
381 /* first buffer */
382 CO_CANtx_t *buffer = &CANmodule->txArray[0];
383 /* search through whole array of pointers to transmit message buffers. */
384 for(i = CANmodule->txSize; i > 0U; i--){
385 /* if message buffer is full, send it. */
386 if(buffer->bufferFull){
387 buffer->bufferFull = false;
388 CANmodule->CANtxCount--;
389
390 /* Copy message to CAN buffer */
391 CANmodule->bufferInhibitFlag = buffer->syncFlag;
392 /* canSend... */
393 break; /* exit for loop */
394 }
395 buffer++;
396 }/* end of for loop */
397
398 /* Clear counter if no more messages */
399 if(i == 0U){
400 CANmodule->CANtxCount = 0U;
401 }
402 }
403 }
404 else{
405 /* some other interrupt reason */
406 }
407 }
408