1
1
// Software CANbus implementation for rp2040
2
2
//
3
- // Copyright (C) 2022 Kevin O'Connor <[email protected] >
3
+ // Copyright (C) 2022,2023 Kevin O'Connor <[email protected] >
4
4
//
5
5
// This file may be distributed under the terms of the GNU GPLv3 license.
6
6
@@ -318,6 +318,14 @@ pio_irq_set(struct can2040 *cd, uint32_t sm_irqs)
318
318
pio_hw -> inte0 = sm_irqs | SI_RX_DATA ;
319
319
}
320
320
321
+ // Completely disable host irqs
322
+ static void
323
+ pio_irq_disable (struct can2040 * cd )
324
+ {
325
+ pio_hw_t * pio_hw = cd -> pio_hw ;
326
+ pio_hw -> inte0 = 0 ;
327
+ }
328
+
321
329
// Return current host irq mask
322
330
static uint32_t
323
331
pio_irq_get (struct can2040 * cd )
@@ -662,6 +670,7 @@ tx_schedule_transmit(struct can2040 *cd)
662
670
pio_signal_set_txpending (cd );
663
671
}
664
672
cd -> tx_state = TS_QUEUED ;
673
+ cd -> stats .tx_attempt ++ ;
665
674
struct can2040_transmit * qt = & cd -> tx_queue [tx_qpos (cd , tx_pull_pos )];
666
675
pio_tx_send (cd , qt -> stuffed_data , qt -> stuffed_words );
667
676
return 0 ;
@@ -721,6 +730,7 @@ report_callback_error(struct can2040 *cd, uint32_t error_code)
721
730
static void
722
731
report_callback_rx_msg (struct can2040 * cd )
723
732
{
733
+ cd -> stats .rx_total ++ ;
724
734
cd -> rx_cb (cd , CAN2040_NOTIFY_RX , & cd -> parse_msg );
725
735
}
726
736
@@ -729,6 +739,7 @@ static void
729
739
report_callback_tx_msg (struct can2040 * cd )
730
740
{
731
741
writel (& cd -> tx_pull_pos , cd -> tx_pull_pos + 1 );
742
+ cd -> stats .tx_total ++ ;
732
743
cd -> rx_cb (cd , CAN2040_NOTIFY_TX , & cd -> parse_msg );
733
744
}
734
745
@@ -748,11 +759,11 @@ report_handle_eof(struct can2040 *cd)
748
759
pio_match_clear (cd );
749
760
}
750
761
751
- // Check if in an rx message is being processed
762
+ // Check if message being processed is an rx message (not self feedback from tx)
752
763
static int
753
- report_is_rx_eof_pending (struct can2040 * cd )
764
+ report_is_not_in_tx (struct can2040 * cd )
754
765
{
755
- return cd -> report_state == RS_NEED_RX_EOF ;
766
+ return !( cd -> report_state & RS_NEED_TX_ACK ) ;
756
767
}
757
768
758
769
// Parser found a new message start
@@ -817,7 +828,7 @@ report_note_eof_success(struct can2040 *cd)
817
828
818
829
// Parser found unexpected data on input
819
830
static void
820
- report_note_parse_error (struct can2040 * cd )
831
+ report_note_discarding (struct can2040 * cd )
821
832
{
822
833
if (cd -> report_state != RS_IDLE ) {
823
834
cd -> report_state = RS_IDLE ;
@@ -880,7 +891,7 @@ report_line_txpending(struct can2040 *cd)
880
891
return ;
881
892
}
882
893
// Tx request from can2040_transmit(), report_note_eof_success(),
883
- // or report_note_parse_error ().
894
+ // or report_note_discarding ().
884
895
uint32_t check_txpending = tx_schedule_transmit (cd );
885
896
pio_irq_set (cd , (pio_irqs & ~SI_TXPENDING ) | check_txpending );
886
897
}
@@ -896,6 +907,13 @@ enum {
896
907
MS_CRC , MS_ACK , MS_EOF0 , MS_EOF1 , MS_DISCARD
897
908
};
898
909
910
+ // Reset any bits in the incoming parsing state
911
+ static void
912
+ data_state_clear_bits (struct can2040 * cd )
913
+ {
914
+ cd -> raw_bit_count = cd -> unstuf .stuffed_bits = cd -> unstuf .count_stuff = 0 ;
915
+ }
916
+
899
917
// Transition to the next parsing state
900
918
static void
901
919
data_state_go_next (struct can2040 * cd , uint32_t state , uint32_t num_bits )
@@ -908,23 +926,35 @@ data_state_go_next(struct can2040 *cd, uint32_t state, uint32_t num_bits)
908
926
static void
909
927
data_state_go_discard (struct can2040 * cd )
910
928
{
911
- report_note_parse_error (cd );
912
-
913
929
if (pio_rx_check_stall (cd )) {
914
930
// CPU couldn't keep up for some read data - must reset pio state
915
- cd -> raw_bit_count = cd -> unstuf . count_stuff = 0 ;
931
+ data_state_clear_bits ( cd ) ;
916
932
pio_sm_setup (cd );
917
933
report_callback_error (cd , 0 );
918
934
}
919
935
920
936
data_state_go_next (cd , MS_DISCARD , 32 );
937
+
938
+ // Clear report state and update hw irqs after transition to MS_DISCARD
939
+ report_note_discarding (cd );
940
+ }
941
+
942
+ // Note a data parse error and transition to discard state
943
+ static void
944
+ data_state_go_error (struct can2040 * cd )
945
+ {
946
+ cd -> stats .parse_error ++ ;
947
+ data_state_go_discard (cd );
921
948
}
922
949
923
950
// Received six dominant bits on the line
924
951
static void
925
952
data_state_line_error (struct can2040 * cd )
926
953
{
927
- data_state_go_discard (cd );
954
+ if (cd -> parse_state == MS_DISCARD )
955
+ data_state_go_discard (cd );
956
+ else
957
+ data_state_go_error (cd );
928
958
}
929
959
930
960
// Received six unexpected passive bits on the line
@@ -933,16 +963,15 @@ data_state_line_passive(struct can2040 *cd)
933
963
{
934
964
if (cd -> parse_state != MS_DISCARD && cd -> parse_state != MS_START ) {
935
965
// Bitstuff error
936
- data_state_go_discard (cd );
966
+ data_state_go_error (cd );
937
967
return ;
938
968
}
939
969
940
970
uint32_t stuffed_bits = unstuf_get_raw (& cd -> unstuf );
941
971
uint32_t dom_bits = ~stuffed_bits ;
942
972
if (!dom_bits ) {
943
973
// Counter overflow in "sync" state machine - reset it
944
- cd -> unstuf .stuffed_bits = 0 ;
945
- cd -> raw_bit_count = cd -> unstuf .count_stuff = 0 ;
974
+ data_state_clear_bits (cd );
946
975
pio_sm_setup (cd );
947
976
data_state_go_discard (cd );
948
977
return ;
@@ -972,7 +1001,7 @@ data_state_go_crc(struct can2040 *cd)
972
1001
973
1002
int ret = report_note_crc_start (cd );
974
1003
if (ret ) {
975
- data_state_go_discard (cd );
1004
+ data_state_go_error (cd );
976
1005
return ;
977
1006
}
978
1007
data_state_go_next (cd , MS_CRC , 16 );
@@ -1065,7 +1094,7 @@ static void
1065
1094
data_state_update_crc (struct can2040 * cd , uint32_t data )
1066
1095
{
1067
1096
if (((cd -> parse_crc << 1 ) | 1 ) != data ) {
1068
- data_state_go_discard (cd );
1097
+ data_state_go_error (cd );
1069
1098
return ;
1070
1099
}
1071
1100
@@ -1083,7 +1112,7 @@ data_state_update_ack(struct can2040 *cd, uint32_t data)
1083
1112
// data_state_line_passive()
1084
1113
unstuf_restore_state (& cd -> unstuf , (cd -> parse_crc_bits << 2 ) | data );
1085
1114
1086
- data_state_go_discard (cd );
1115
+ data_state_go_error (cd );
1087
1116
return ;
1088
1117
}
1089
1118
report_note_ack_success (cd );
@@ -1095,7 +1124,7 @@ static void
1095
1124
data_state_update_eof0 (struct can2040 * cd , uint32_t data )
1096
1125
{
1097
1126
if (data != 0x0f || pio_rx_check_stall (cd )) {
1098
- data_state_go_discard (cd );
1127
+ data_state_go_error (cd );
1099
1128
return ;
1100
1129
}
1101
1130
unstuf_clear_state (& cd -> unstuf );
@@ -1106,14 +1135,17 @@ data_state_update_eof0(struct can2040 *cd, uint32_t data)
1106
1135
static void
1107
1136
data_state_update_eof1 (struct can2040 * cd , uint32_t data )
1108
1137
{
1109
- if (data >= 0x1c || ( data >= 0x18 && report_is_rx_eof_pending ( cd )))
1110
- // Message is considered fully transmitted
1138
+ if (data == 0x1f ) {
1139
+ // Success
1111
1140
report_note_eof_success (cd );
1112
-
1113
- if (data == 0x1f )
1114
1141
data_state_go_next (cd , MS_START , 1 );
1115
- else
1142
+ } else if (data >= 0x1c || (data >= 0x18 && report_is_not_in_tx (cd ))) {
1143
+ // Message fully transmitted - followed by "overload frame"
1144
+ report_note_eof_success (cd );
1116
1145
data_state_go_discard (cd );
1146
+ } else {
1147
+ data_state_go_error (cd );
1148
+ }
1117
1149
}
1118
1150
1119
1151
// Handle data received while in MS_DISCARD state
@@ -1310,13 +1342,28 @@ can2040_start(struct can2040 *cd, uint32_t sys_clock, uint32_t bitrate
1310
1342
{
1311
1343
cd -> gpio_rx = gpio_rx ;
1312
1344
cd -> gpio_tx = gpio_tx ;
1345
+ data_state_clear_bits (cd );
1313
1346
pio_setup (cd , sys_clock , bitrate );
1314
1347
data_state_go_discard (cd );
1315
1348
}
1316
1349
1317
- // API function to stop and uninitialize can2040 code
1350
+ // API function to stop can2040 code
1318
1351
void
1319
- can2040_shutdown (struct can2040 * cd )
1352
+ can2040_stop (struct can2040 * cd )
1320
1353
{
1321
- // XXX
1354
+ pio_irq_disable (cd );
1355
+ pio_sm_setup (cd );
1356
+ }
1357
+
1358
+ // API function to access can2040 statistics
1359
+ void
1360
+ can2040_get_statistics (struct can2040 * cd , struct can2040_stats * stats )
1361
+ {
1362
+ for (;;) {
1363
+ memcpy (stats , & cd -> stats , sizeof (* stats ));
1364
+ if (memcmp (stats , & cd -> stats , sizeof (* stats )) == 0 )
1365
+ // Successfully copied data
1366
+ return ;
1367
+ // Raced with irq handler update - retry copy
1368
+ }
1322
1369
}
0 commit comments