-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathcan_pic32.c
1110 lines (1017 loc) · 27.9 KB
/
can_pic32.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* @file can_pic32.c
* @author Sebastien CAUX (sebcaux)
* @copyright UniSwarm 2017-2023
*
* @date December 8 2017, 09:10 AM
*
* @brief CAN support for udevkit for PIC32MK, PIC32MX, PIC32MZDA,
* PIC32MZEC and PIC32MZEF
*
* Implementation based on Microchip document DS61154C :
* http://ww1.microchip.com/downloads/en/DeviceDoc/61154C.pdf
*/
#include "can.h"
#include <archi.h>
#include <driver/sysclock.h>
enum
{
CAN_FLAG_UNUSED = 0x00
};
typedef struct
{
union
{
struct
{
unsigned used : 1;
unsigned enabled : 1;
unsigned : 6;
};
uint8_t val;
};
} can_status;
struct can_dev
{
CAN_MODE mode;
uint32_t bitRate;
uint8_t propagSeg;
uint8_t s1Seg;
uint8_t s2Seg;
can_status flags;
};
#ifdef UDEVKIT_HAVE_CONFIG
# include "udevkit_config.h"
#endif
#if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
# ifndef CAN1_FIFO_SIZE
# define CAN1_FIFO_SIZE (32 * (CAN_MESSAGE_HEADER_SIZE + 8U)) // 32 messages of 8 bytes
# endif
static uint8_t __attribute__((aligned(4), noload, section(".can1_fifos"))) _can1_fifo_buffer[CAN1_FIFO_SIZE];
#endif
#if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
# ifndef CAN2_FIFO_SIZE
# define CAN2_FIFO_SIZE (32 * (CAN_MESSAGE_HEADER_SIZE + 8U)) // 32 messages of 8 bytes
# endif
static uint8_t __attribute__((aligned(4), noload, section(".can2_fifos"))) _can2_fifo_buffer[CAN2_FIFO_SIZE];
#endif
#if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
# ifndef CAN3_FIFO_SIZE
# define CAN3_FIFO_SIZE (32 * (CAN_MESSAGE_HEADER_SIZE + 8U)) // 32 messages of 8 bytes
# endif
static uint8_t __attribute__((aligned(4), noload, section(".can3_fifos"))) _can3_fifo_buffer[CAN3_FIFO_SIZE];
#endif
#if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
# ifndef CAN4_FIFO_SIZE
# define CAN4_FIFO_SIZE (32 * (CAN_MESSAGE_HEADER_SIZE + 8U)) // 32 messages of 8 bytes
# endif
static uint8_t __attribute__((aligned(4), noload, section(".can4_fifos"))) _can4_fifo_buffer[CAN4_FIFO_SIZE];
#endif
static struct can_dev _cans[] = {
#if CAN_COUNT >= 1
{.bitRate = 0, .flags = {{.val = CAN_FLAG_UNUSED}}},
#endif
#if CAN_COUNT >= 2
{.bitRate = 0, .flags = {{.val = CAN_FLAG_UNUSED}}},
#endif
#if CAN_COUNT >= 3
{.bitRate = 0, .flags = {{.val = CAN_FLAG_UNUSED}}},
#endif
#if CAN_COUNT >= 4
{.bitRate = 0, .flags = {{.val = CAN_FLAG_UNUSED}}},
#endif
};
/**
* @brief Gives a free CAN bus number and open it
* @return CAN bus number
*/
rt_dev_t can_getFreeDevice(void)
{
#if CAN_COUNT >= 1
uint8_t i;
rt_dev_t device;
for (i = 0; i < CAN_COUNT; i++)
{
if (_cans[i].flags.used == 0)
{
break;
}
}
if (i == CAN_COUNT)
{
return NULLDEV;
}
device = MKDEV(DEV_CLASS_CAN, i);
can_open(device);
return device;
#else
return NULLDEV;
#endif
}
/**
* @brief Opens a CAN bus
* @param can CAN bus id
* @return 0 if ok, -1 in case of error
*/
int can_open(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return -1;
}
if (_cans[can].flags.used == 1)
{
return -1;
}
_cans[can].flags.used = 1;
return 0;
#else
return -1;
#endif
}
/**
* @brief Closes and release a CAN bus
* @param device CAN bus number
* @return 0 if ok, -1 in case of error
*/
int can_close(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return -1;
}
can_disable(device);
_cans[can].flags.val = CAN_FLAG_UNUSED;
return 0;
#else
return -1;
#endif
}
/**
* @brief CAN sdk state
* @param device can device number
* @return true if can was openned by can_open function
*/
bool can_isOpened(rt_dev_t device)
{
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return -1;
}
return (_cans[can].flags.used == 1);
}
/**
* @brief Enables the specified CAN bus
* @param device CAN bus number
* @return 0 if ok, -1 in case of error
*/
int can_enable(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return -1;
}
_cans[can].flags.enabled = 1;
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
// assign memory
C1FIFOBA = KVA_TO_PA(_can1_fifo_buffer);
// fifo 0 (transmit)
C1FIFOCON0bits.FSIZE = 15;
C1FIFOCON0SET = 0x80;
// fifo 1 (receive)
C1FIFOCON1bits.FSIZE = 15;
C1FIFOCON1CLR = 0x80;
// filter 1
C1FLTCON0bits.FSEL1 = 1; // Store messages in FIFO1
C1FLTCON0bits.MSEL1 = 1; // Use Mask 1
C1RXF1bits.SID = 0x000; // Filter 1 EID
C1RXF1bits.EID = 0x00000; // Filter 1 SID
C1RXF1bits.EXID = 1; // Filter EID messages
C1FLTCON0bits.FLTEN1 = 1; // Enable the filter
// mask 1
C1RXM1bits.SID = 0x000; // Ignore all bits in comparison
C1RXM1bits.EID = 0x00000; // Ignore all bits in comparison
C1RXM1bits.MIDE = 0; // Match all message types.
break;
# endif
# if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
case CAN2_ID:
// assign memory
C2FIFOBA = KVA_TO_PA(_can2_fifo_buffer);
// fifo 0 (transmit)
C2FIFOCON0bits.FSIZE = 15;
C2FIFOCON0SET = 0x80;
// fifo 1 (receive)
C2FIFOCON1bits.FSIZE = 15;
C2FIFOCON1CLR = 0x80;
// filter 1
C2FLTCON0bits.FSEL1 = 1; // Store messages in FIFO1
C2FLTCON0bits.MSEL1 = 1; // Use Mask 1
C2RXF1bits.SID = 0x000; // Filter 1 EID
C2RXF1bits.EID = 0x00000; // Filter 1 SID
C2RXF1bits.EXID = 1; // Filter EID messages
C2FLTCON0bits.FLTEN1 = 1; // Enable the filter
// mask 1
C2RXM1bits.SID = 0x000; // Ignore all bits in comparison
C2RXM1bits.EID = 0x00000; // Ignore all bits in comparison
C2RXM1bits.MIDE = 0; // Match all message types.
break;
# endif
# if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
case CAN3_ID:
// assign memory
C3FIFOBA = KVA_TO_PA(_can3_fifo_buffer);
// fifo 0 (transmit)
C3FIFOCON0bits.FSIZE = 15;
C3FIFOCON0SET = 0x80;
// fifo 1 (receive)
C3FIFOCON1bits.FSIZE = 15;
C3FIFOCON1CLR = 0x80;
// filter 1
C3FLTCON0bits.FSEL1 = 1; // Store messages in FIFO1
C3FLTCON0bits.MSEL1 = 1; // Use Mask 1
C3RXF1bits.SID = 0x000; // Filter 1 EID
C3RXF1bits.EID = 0x00000; // Filter 1 SID
C3RXF1bits.EXID = 1; // Filter only EID messages
C3FLTCON0bits.FLTEN1 = 1; // Enable the filter
// mask 1
C3RXM1bits.SID = 0x000; // Ignore all bits in comparison
C3RXM1bits.EID = 0x00000; // Ignore all bits in comparison
C3RXM1bits.MIDE = 1; // Match only message types.
break;
# endif
# if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
case CAN4_ID:
// assign memory
C4FIFOBA = KVA_TO_PA(_can4_fifo_buffer);
// fifo 0 (transmit)
C4FIFOCON0bits.FSIZE = 15;
C4FIFOCON0SET = 0x80;
// fifo 1 (receive)
C4FIFOCON1bits.FSIZE = 15;
C4FIFOCON1CLR = 0x80;
// filter 1
C4FLTCON0bits.FSEL1 = 1; // Store messages in FIFO1
C4FLTCON0bits.MSEL1 = 1; // Use Mask 1
C4RXF1bits.SID = 0x000; // Filter 1 EID
C4RXF1bits.EID = 0x00000; // Filter 1 SID
C4RXF1bits.EXID = 1; // Filter only EID messages
C4FLTCON0bits.FLTEN1 = 1; // Enable the filter
// mask 1
C4RXM1bits.SID = 0x000; // Ignore all bits in comparison
C4RXM1bits.EID = 0x00000; // Ignore all bits in comparison
C4RXM1bits.MIDE = 1; // Match only message types.
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* @brief Disables the specified CAN bus
* @param device CAN bus number
* @return 0 if ok, -1 in case of error
*/
int can_disable(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return -1;
}
_cans[can].flags.enabled = 0;
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
_CAN1IE = 0; // disable can global interrupt
C1CONbits.REQOP = 4;
while (C1CONbits.OPMOD != 4)
{
;
}
C1CONbits.ON = 0; // disable can
while (C1CONbits.CANBUSY == 1)
{
;
}
break;
# endif
# if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
case CAN2_ID:
_CAN2IE = 0; // disable can global interrupt
C2CONbits.REQOP = 4;
while (C2CONbits.OPMOD != 4)
{
;
}
C2CONbits.ON = 0; // disable can
while (C2CONbits.CANBUSY == 1)
{
;
}
break;
# endif
# if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
case CAN3_ID:
_CAN3IE = 0; // disable can global interrupt
C3CONbits.REQOP = 4;
while (C3CONbits.OPMOD != 4)
{
;
}
C3CONbits.ON = 0; // disable can
while (C3CONbits.CANBUSY == 1)
{
;
}
break;
# endif
# if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
case CAN4_ID:
_CAN4IE = 0; // disable can global interrupt
C4CONbits.REQOP = 4;
while (C4CONbits.OPMOD != 4)
{
;
}
C4CONbits.ON = 0; // disable can
while (C4CONbits.CANBUSY == 1)
{
;
}
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* @brief Can sdk enabled state
* @param device can device number
* @return true if can was enabled by can_enable function
*/
bool can_isEnabled(rt_dev_t device)
{
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return -1;
}
return (_cans[can].flags.enabled == 1);
}
/**
* @brief Sets configuration (can version and mode) of the specified CAN bus
* @param device CAN bus number
* @param mode CAN mode of operation
* @return 0 if ok, -1 in case of error
*/
int can_setMode(rt_dev_t device, CAN_MODE mode)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
uint8_t modeBits;
if (can >= CAN_COUNT)
{
return 0;
}
// check parameters
switch (mode)
{
case CAN_MODE_NORMAL:
modeBits = 0b000;
break;
case CAN_MODE_LISTENONLY:
modeBits = 0b011;
break;
case CAN_MODE_LISTENALL:
modeBits = 0b111;
break;
case CAN_MODE_LOOPBACK:
modeBits = 0b010;
break;
case CAN_MODE_DISABLED:
modeBits = 0b001;
break;
case CAN_MODE_CONFIGURATION:
modeBits = 0b100;
break;
default:
return -1;
}
_cans[can].mode = mode;
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
C1CONbits.ON = 1;
C1CONbits.REQOP = modeBits;
while (C1CONbits.OPMOD != modeBits)
{
;
}
break;
# endif
# if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
case CAN2_ID:
C2CONbits.ON = 1;
C2CONbits.REQOP = modeBits;
while (C2CONbits.OPMOD != modeBits)
{
;
}
break;
# endif
# if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
case CAN3_ID:
C3CONbits.ON = 1;
C3CONbits.REQOP = modeBits;
while (C3CONbits.OPMOD != modeBits)
{
;
}
break;
# endif
# if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
case CAN4_ID:
C4CONbits.ON = 1;
C4CONbits.REQOP = modeBits;
while (C4CONbits.OPMOD != modeBits)
{
;
}
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* @brief Returns the current bus mode of operation
* @param device CAN device number
* @return current mode of operation
*/
CAN_MODE can_mode(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return 0;
}
return _cans[can].mode;
#else
return 0;
#endif
}
/**
* @brief Sets bit rate and segments timing
*
* Sum of all segments (propagSeg, s1Seg, s2Seg) + 1 must be contained in
* the range of 8 to 25 quantums.
*
* CAN Bit Timing (8-25 Tq) segments computation
*
* | Sync | Propag seg | Phase seg 1 |Phase seg 2 |
*
* | 1 Tq | 1-8 Tq | 1-8 Tq | 1-8 Tq |
*
* sample point
*
* @param device CAN device number
* @param bitRate bit rate speed in bit/s
* @param propagSeg propagation segment duration in number of quantum (1-8)
* @param s1Seg segment 1 duration in number of quantum (1-8)
* @param s2Seg segment 2 duration in number of quantum (1-8)
* @return 0 if ok, -1 in case of error
*/
int can_setBitTiming(rt_dev_t device, uint32_t bitRate, uint8_t propagSeg, uint8_t s1Seg, uint8_t s2Seg)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
uint8_t bitRateDiv;
uint8_t quantum;
if (can >= CAN_COUNT)
{
return 0;
}
if (propagSeg > 8 || s1Seg > 8 || s2Seg > 8)
{
return -1;
}
if (propagSeg < 1 || s1Seg < 1 || s2Seg < 1)
{
return -1;
}
quantum = propagSeg + s1Seg + s2Seg + 1;
if (quantum < 8 || quantum > 25)
{
return -1;
}
_cans[can].bitRate = bitRate;
_cans[can].propagSeg = propagSeg;
_cans[can].s1Seg = s1Seg;
_cans[can].s2Seg = s2Seg;
/* possible work arround for PIC32MK
if (can == 2 || can == 3)
{
quantum -= 2;
}*/
bitRateDiv = sysclock_periphFreq(SYSCLOCK_CLOCK_CAN) / (bitRate * quantum * 2);
if (bitRateDiv > 64)
{
bitRateDiv = 64;
}
bitRateDiv--;
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
C1CONbits.ON = 1;
C1CONbits.REQOP = 4;
while (C1CONbits.OPMOD != 4)
{
;
}
C1CFGbits.SJW = 0; // Synchronization Jump Width (1-4)
C1CFGbits.PRSEG = propagSeg - 1; // Propagation Time Segment (1-8)
C1CFGbits.SEG1PH = s1Seg - 1; // Phase Buffer Segment 1 (1-8)
C1CFGbits.SEG2PHTS = 1; // Phase Buffer Segment 2 is freely programmable
C1CFGbits.SEG2PH = s2Seg - 1; // Phase Buffer Segment 2 (1-8) SEG2PH >= SEG1PH
C1CFGbits.BRP = bitRateDiv; // bit rate divisor (1-64) * 2
break;
# endif
# if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
case CAN2_ID:
C2CONbits.ON = 1;
C2CONbits.REQOP = 4;
while (C2CONbits.OPMOD != 4)
{
;
}
C2CFGbits.SJW = 0; // Synchronization Jump Width (1-4)
C2CFGbits.PRSEG = propagSeg - 1; // Propagation Time Segment (1-8)
C2CFGbits.SEG1PH = s1Seg - 1; // Phase Buffer Segment 1 (1-8)
C2CFGbits.SEG2PHTS = 1; // Phase Buffer Segment 2 is freely programmable
C2CFGbits.SEG2PH = s2Seg - 1; // Phase Buffer Segment 2 (1-8) SEG2PH >= SEG1PH
C2CFGbits.BRP = bitRateDiv; // bit rate divisor (1-64) * 2
break;
# endif
# if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
case CAN3_ID:
C3CONbits.ON = 1;
C3CONbits.REQOP = 4;
while (C3CONbits.OPMOD != 4)
{
;
}
C3CFGbits.SJW = 0; // Synchronization Jump Width (1-4)
C3CFGbits.PRSEG = propagSeg - 1; // Propagation Time Segment (1-8)
C3CFGbits.SEG1PH = s1Seg - 1; // Phase Buffer Segment 1 (1-8)
C3CFGbits.SEG2PHTS = 1; // Phase Buffer Segment 2 is freely programmable
C3CFGbits.SEG2PH = s2Seg - 1; // Phase Buffer Segment 2 (1-8) SEG2PH >= SEG1PH
C3CFGbits.BRP = bitRateDiv; // bit rate divisor (1-64) * 2
break;
# endif
# if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
case CAN4_ID:
C4CONbits.ON = 1;
C4CONbits.REQOP = 4;
while (C4CONbits.OPMOD != 4)
{
;
}
C4CFGbits.SJW = 0; // Synchronization Jump Width (1-4)
C4CFGbits.PRSEG = propagSeg - 1; // Propagation Time Segment (1-8)
C4CFGbits.SEG1PH = s1Seg - 1; // Phase Buffer Segment 1 (1-8)
C4CFGbits.SEG2PHTS = 1; // Phase Buffer Segment 2 is freely programmable
C4CFGbits.SEG2PH = s2Seg - 1; // Phase Buffer Segment 2 (1-8) SEG2PH >= SEG1PH
C4CFGbits.BRP = bitRateDiv; // bit rate divisor (1-64) * 2
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* @brief Returns the current bit rate in bits/s
* @param device CAN device number
* @return bit rate in bits/s if OK, 0 in case of error
*/
uint32_t can_bitRate(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return 0;
}
return _cans[can].bitRate;
#else
return 0;
#endif
}
/**
* @brief Gets the effective bit rate in hertz
* @param device CAN device number
* @return speed of receive and transmit in bits/s, 0 in case of error
*/
uint32_t can_effectiveBitRate(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return 0;
}
uint16_t bitRateDiv = 1;
uint8_t quantums = _cans[can].propagSeg + _cans[can].s1Seg + _cans[can].s2Seg + 1;
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
bitRateDiv = (C1CFGbits.BRP + 1) << 1; // bit rate divisor (1-64) * 2
break;
# endif
# if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
case CAN2_ID:
bitRateDiv = (C2CFGbits.BRP + 1) << 1; // bit rate divisor (1-64) * 2
break;
# endif
# if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
case CAN3_ID:
bitRateDiv = (C3CFGbits.BRP + 1) << 1; // bit rate divisor (1-64) * 2
break;
# endif
# if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
case CAN4_ID:
bitRateDiv = (C4CFGbits.BRP + 1) << 1; // bit rate divisor (1-64) * 2
break;
# endif
}
return sysclock_periphFreq(SYSCLOCK_CLOCK_CAN) / (bitRateDiv * quantums);
#else
return 0;
#endif
}
/**
* @brief Gets propagation segment duration in quantums
* @param device CAN device number
* @return propagation segment duration in quantums, 0 in case of error
*/
uint8_t can_propagSeg(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return 0;
}
return _cans[can].propagSeg;
#else
return 0;
#endif
}
/**
* @brief Gets segment 1 duration in quantums
* @param device CAN device number
* @return segment 1 duration in quantums, 0 in case of error
*/
uint8_t can_s1Seg(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return 0;
}
return _cans[can].s1Seg;
#else
return 0;
#endif
}
/**
* @brief Gets segment 2 duration in quantums
* @param device CAN device number
* @return segment 2 duration in quantums, 0 in case of error
*/
uint8_t can_s2Seg(rt_dev_t device)
{
#if CAN_COUNT >= 1
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return 0;
}
return _cans[can].s2Seg;
#else
return 0;
#endif
}
/**
* @brief Write a can message to fifo
* @param device CAN device number
* @param fifo fifo number to put the message
* @param header CAN message header struct (id, flags, data size)
* @return 0 if message is successfully putted inside fifo, -1 in case of error
*/
int can_send(rt_dev_t device, uint8_t fifo, CAN_MSG_HEADER *header, const char *data)
{
UDK_UNUSED(fifo);
#if CAN_COUNT >= 1
unsigned int i;
uint8_t can = MINOR(device);
if (can >= CAN_COUNT)
{
return 0;
}
CAN_TxMsgBuffer *buffer = NULL;
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
if (C1FIFOINT0bits.TXNFULLIF == 0)
{
buffer = NULL;
}
else
{
buffer = (CAN_TxMsgBuffer *)(PA_TO_KVA1(C1FIFOUA0));
}
break;
# endif
# if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
case CAN2_ID:
if (C2FIFOINT0bits.TXNFULLIF == 0)
{
buffer = NULL;
}
else
{
buffer = (CAN_TxMsgBuffer *)(PA_TO_KVA1(C2FIFOUA0));
}
break;
# endif
# if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
case CAN3_ID:
if (C3FIFOINT0bits.TXNFULLIF == 0)
{
buffer = NULL;
}
else
{
buffer = (CAN_TxMsgBuffer *)(PA_TO_KVA1(C3FIFOUA0));
}
break;
# endif
# if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
case CAN4_ID:
if (C4FIFOINT0bits.TXNFULLIF == 0)
{
buffer = NULL;
}
else
{
buffer = (CAN_TxMsgBuffer *)(PA_TO_KVA1(C4FIFOUA0));
}
break;
# endif
}
if (buffer != NULL)
{
// clear the message header
buffer->messageWord[0] = 0;
buffer->messageWord[1] = 0;
// set can id
if ((header->flags & CAN_VERS2BA) == CAN_VERS2BA)
{
buffer->msgEID.IDE = 1; // extended id
buffer->msgEID.EID = header->id & 0x3FFFF; // Message EID
buffer->msgSID.SID = header->id >> 18; // Message EID
}
else
{
buffer->msgSID.SID = header->id; // Message EID
}
// RTR
if (header->flags & CAN_RTR)
{
buffer->msgEID.RTR = 1;
header->size = 0;
buffer->msgEID.DLC = 0;
}
else
{
// set data and data size
if (header->size > 8)
{
header->size = 8;
}
buffer->msgEID.DLC = header->size; // Data Length
for (i = 0; i < header->size; i++)
{
buffer->data[i] = data[i];
}
}
}
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
if (buffer != NULL)
{
C1FIFOCON0SET = 0x2008; // Set the UINC and TXREQ bit
}
else
{
C1FIFOCON0SET = 0x0008; // Set the TXREQ bit
}
break;
# endif
# if (CAN_COUNT >= 2) && !defined(CAN2_DISABLE)
case CAN2_ID:
if (buffer != NULL)
{
C2FIFOCON0SET = 0x2008; // Set the UINC and TXREQ bit
}
else
{
C2FIFOCON0SET = 0x0008; // Set the TXREQ bit
}
break;
# endif
# if (CAN_COUNT >= 3) && !defined(CAN3_DISABLE)
case CAN3_ID:
if (buffer != NULL)
{
C3FIFOCON0SET = 0x2008; // Set the UINC and TXREQ bit
}
else
{
C3FIFOCON0SET = 0x0008; // Set the TXREQ bit
}
break;
# endif
# if (CAN_COUNT >= 4) && !defined(CAN4_DISABLE)
case CAN4_ID:
if (buffer != NULL)
{
C4FIFOCON0SET = 0x2008; // Set the UINC and TXREQ bit
}
else
{
C4FIFOCON0SET = 0x0008; // Set the TXREQ bit
}
break;
# endif
}
return 0;
#else
return -1;
#endif
}
/**
* @brief Read a can message from fifo
* @param device CAN device number
* @param fifo fifo number to read the message
* @param header CAN message header struct (id, flags, data size)
* @return 0 if message no readen, -1 in case of error, 1 if a message is readen
*/
int can_rec(rt_dev_t device, uint8_t fifo, CAN_MSG_HEADER *header, char *data)
{
UDK_UNUSED(fifo);
#if CAN_COUNT >= 1
int i;
uint8_t can = MINOR(device);
CAN_FLAGS flagValue = 0;
CAN_RxMsgBuffer *buffer = NULL;
switch (can)
{
# if (CAN_COUNT >= 1) && !defined(CAN1_DISABLE)
case CAN1_ID:
if (C1FIFOINT1bits.RXNEMPTYIF != 1)
{
return 0;