Skip to content

Commit 58212be

Browse files
Merge pull request #315 from marckleinebudde/bus-off-handling
add software based CAN bus off handling
2 parents 9f4c4a0 + b1ddc95 commit 58212be

6 files changed

Lines changed: 96 additions & 45 deletions

File tree

include/can.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#include "led.h"
3535
#include "list.h"
3636

37+
#define CAN_CHANNEL_BUS_OFF_RESTART_DISABLED 0
38+
3739
typedef struct can_channel {
3840
#if defined (CONFIG_BXCAN)
3941
CAN_TypeDef *instance;
@@ -42,6 +44,7 @@ typedef struct can_channel {
4244
led_data_t leds;
4345
uint32_t feature;
4446
enum gs_can_state state;
47+
uint32_t bus_off_restart;
4548
#if defined (CONFIG_BXCAN)
4649
struct gs_device_filter filter;
4750
uint32_t btr;
@@ -78,8 +81,6 @@ static inline void can_set_filter(can_data_t __maybe_unused *channel, const stru
7881
}
7982
#endif
8083

81-
bool can_is_enabled(can_data_t *channel);
82-
8384
bool can_receive(can_data_t *channel, struct gs_host_frame *rx_frame);
8485
bool can_is_rx_pending(can_data_t *channel);
8586

include/can_common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static inline bool can_is_lec_error(const uint8_t lec)
8080
return true;
8181
}
8282

83+
bool can_is_enabled(const struct can_channel *channel);
8384
void can_enable(struct can_channel *channel, uint32_t mode);
8485
void can_disable(USBD_GS_CAN_HandleTypeDef *hcan, struct can_channel *channel);
8586
void can_get_device_state(const struct can_channel *channel, struct gs_device_state *state);
@@ -89,6 +90,8 @@ uint8_t gs_can_tx_state_to_frame(const enum gs_can_state state);
8990
uint8_t gs_can_rx_state_to_frame(const enum gs_can_state state);
9091
void can_lec_error_to_frame(struct gs_host_frame *frame, const uint8_t lec);
9192

93+
void can_schedule_bus_off_recovery(struct can_channel *channel, uint32_t delay_ms);
94+
9295
void CAN_SendFrame(USBD_GS_CAN_HandleTypeDef *hcan, can_data_t *channel);
9396
void CAN_ReceiveFrame(USBD_GS_CAN_HandleTypeDef *hcan, can_data_t *channel);
9497
void CAN_HandleError(USBD_GS_CAN_HandleTypeDef *hcan, can_data_t *channel);

include/can_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,5 @@ bool can_drv_handle_bus_error(const struct can_channel *channel, struct gs_host_
4343
enum gs_can_state can_drv_get_state(const uint32_t reg);
4444
void can_drv_get_device_state(const struct can_channel *channel, struct gs_device_state *state, const uint32_t reg);
4545
void can_drv_handle_state_change(const struct can_channel *channel, struct gs_host_frame *frame, const uint32_t reg);
46+
47+
void can_drv_handle_bus_off_recovery(struct can_channel *channel);

include/util.h

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
/*
2-
3-
The MIT License (MIT)
4-
5-
Copyright (c) 2016, 2019 Hubert Denkmair
6-
7-
Permission is hereby granted, free of charge, to any person obtaining a copy
8-
of this software and associated documentation files (the "Software"), to deal
9-
in the Software without restriction, including without limitation the rights
10-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11-
copies of the Software, and to permit persons to whom the Software is
12-
furnished to do so, subject to the following conditions:
13-
14-
The above copyright notice and this permission notice shall be included in
15-
all copies or substantial portions of the Software.
16-
17-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23-
THE SOFTWARE.
24-
25-
*/
2+
* The MIT License (MIT)
3+
*
4+
* Copyright (c) 2016, 2019 Hubert Denkmair
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*
24+
*/
2625

2726
#pragma once
2827

2928
#include <stdint.h>
3029
#include <stdbool.h>
3130
#include <cmsis_device.h>
3231

32+
#define time_after(a, b) ((int)((b) - (a)) < 0)
33+
3334
void hex32(char *out, uint32_t val);
3435

3536
// ARM's

src/can/bxcan.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
*
2525
*/
2626

27-
#include "board.h"
2827
#include "can.h"
2928
#include "can_common.h"
3029
#include "can_drv.h"
@@ -154,7 +153,7 @@ void can_drv_enable(struct can_channel *channel)
154153
const uint32_t feature = channel->feature;
155154
CAN_TypeDef *can = channel->instance;
156155

157-
uint32_t mcr = CAN_MCR_INRQ | CAN_MCR_ABOM | CAN_MCR_TXFP;
156+
uint32_t mcr = CAN_MCR_INRQ | CAN_MCR_TXFP;
158157

159158
if (feature & GS_CAN_FEATURE_ONE_SHOT) {
160159
mcr |= CAN_MCR_NART;
@@ -188,25 +187,15 @@ void can_drv_enable(struct can_channel *channel)
188187

189188
can->MCR &= ~CAN_MCR_INRQ;
190189
while ((can->MSR & CAN_MSR_INAK) != 0);
191-
192-
board_phy_power_set(channel, true);
193190
}
194191

195192
void can_drv_disable(struct can_channel *channel)
196193
{
197194
CAN_TypeDef *can = channel->instance;
198195

199-
board_phy_power_set(channel, false);
200196
can->MCR |= CAN_MCR_INRQ; // send can controller into initialization mode
201197
}
202198

203-
bool can_is_enabled(can_data_t *channel)
204-
{
205-
CAN_TypeDef *can = channel->instance;
206-
207-
return (can->MCR & CAN_MCR_INRQ) == 0;
208-
}
209-
210199
bool can_is_rx_pending(can_data_t *channel)
211200
{
212201
CAN_TypeDef *can = channel->instance;
@@ -396,3 +385,9 @@ void can_drv_handle_state_change(const struct can_channel __maybe_unused *channe
396385
frame->classic_can->data[1] |= gs_can_rx_state_to_frame(rx_state);
397386
}
398387
}
388+
389+
void can_drv_handle_bus_off_recovery(struct can_channel *channel)
390+
{
391+
can_drv_disable(channel);
392+
can_drv_enable(channel);
393+
}

src/can_common.c

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,19 @@
2424
*
2525
*/
2626

27-
#include <string.h>
28-
27+
#include "board.h"
2928
#include "can_common.h"
3029
#include "can_drv.h"
3130
#include "host_frame.h"
3231
#include "led.h"
3332
#include "timer.h"
3433
#include "usbd_gs_can.h"
3534

36-
#define CAN_ERROR_WARNING_THRESHOLD 96
37-
#define CAN_ERROR_PASSIVE_THRESHOLD 128
38-
#define CAN_BUS_OFF_THRESHOLD 256
35+
#define CAN_ERROR_WARNING_THRESHOLD 96
36+
#define CAN_ERROR_PASSIVE_THRESHOLD 128
37+
#define CAN_BUS_OFF_THRESHOLD 256
38+
39+
#define CAN_BUS_OFF_RESTART_DELAY_MS 100
3940

4041
#ifndef CONFIG_CANFD
4142
const struct gs_device_bt_const_extended CAN_btconst_ext;
@@ -69,20 +70,29 @@ bool can_check_filter_ok(const struct gs_device_filter *filter)
6970
}
7071
#endif
7172

73+
bool can_is_enabled(const struct can_channel *channel)
74+
{
75+
return channel->state < GS_CAN_STATE_STOPPED;
76+
}
77+
7278
void can_enable(struct can_channel *channel, const uint32_t feature)
7379
{
7480
channel->feature = feature;
7581

7682
led_set_mode(&channel->leds, LED_MODE_NORMAL);
7783
channel->state = GS_CAN_STATE_ERROR_ACTIVE;
84+
board_phy_power_set(channel, true);
7885
can_drv_enable(channel);
7986
}
8087

8188
void can_disable(USBD_GS_CAN_HandleTypeDef *hcan, struct can_channel *channel)
8289
{
8390
can_drv_disable(channel);
91+
board_phy_power_set(channel, false);
8492
usbd_gs_can_purge_from_host_list_by_channel(hcan, channel);
8593
usbd_gs_can_purge_to_host_list_by_channel(hcan, channel);
94+
95+
channel->bus_off_restart = CAN_CHANNEL_BUS_OFF_RESTART_DISABLED;
8696
channel->state = GS_CAN_STATE_STOPPED;
8797
led_set_mode(&channel->leds, LED_MODE_OFF);
8898
}
@@ -167,7 +177,7 @@ static void can_prepare_error_frame(const struct can_channel *channel,
167177
frame->channel = can_channel_get_nr(channel);
168178
frame->flags = 0;
169179
frame->reserved = 0;
170-
memset(frame->classic_can->data, 0x0, sizeof(frame->classic_can->data));
180+
*frame->classic_can = (struct classic_can){ 0 };
171181

172182
frame->classic_can_ts->timestamp_us = timer_get();
173183
}
@@ -265,6 +275,14 @@ static bool can_bus_error_pending(const struct can_channel *channel, const uint3
265275
return can_drv_bus_error_pending(reg_status);
266276
}
267277

278+
void can_schedule_bus_off_recovery(struct can_channel *channel, const uint32_t delay_ms)
279+
{
280+
channel->bus_off_restart = HAL_GetTick() + delay_ms;
281+
282+
if (channel->bus_off_restart == CAN_CHANNEL_BUS_OFF_RESTART_DISABLED)
283+
channel->bus_off_restart++;
284+
}
285+
268286
static void can_handle_state_change(USBD_GS_CAN_HandleTypeDef *hcan, struct can_channel *channel,
269287
const uint32_t reg_status)
270288
{
@@ -277,6 +295,7 @@ static void can_handle_state_change(USBD_GS_CAN_HandleTypeDef *hcan, struct can_
277295

278296
if (channel->state == GS_CAN_STATE_BUS_OFF) {
279297
frame->can_id |= CAN_ERR_BUSOFF;
298+
can_schedule_bus_off_recovery(channel, CAN_BUS_OFF_RESTART_DELAY_MS);
280299
} else {
281300
frame->can_id |= CAN_ERR_CRTL | CAN_ERR_CNT;
282301
can_drv_handle_state_change(channel, frame, reg_status);
@@ -288,7 +307,7 @@ static void can_handle_state_change(USBD_GS_CAN_HandleTypeDef *hcan, struct can_
288307

289308
static bool can_state_change_pending(struct can_channel *channel, const uint32_t reg_status)
290309
{
291-
if (channel->state >= GS_CAN_STATE_STOPPED)
310+
if (!can_is_enabled(channel))
292311
return false;
293312

294313
const enum gs_can_state new_state = can_drv_get_state(reg_status);
@@ -300,6 +319,34 @@ static bool can_state_change_pending(struct can_channel *channel, const uint32_t
300319
return true;
301320
}
302321

322+
static void can_handle_bus_off_recovery(USBD_GS_CAN_HandleTypeDef *hcan, struct can_channel *channel)
323+
{
324+
can_drv_handle_bus_off_recovery(channel);
325+
326+
channel->bus_off_restart = CAN_CHANNEL_BUS_OFF_RESTART_DISABLED;
327+
328+
struct gs_host_frame_object *frame_object = gs_host_frame_object_get_locked(hcan);
329+
if (!frame_object)
330+
return;
331+
332+
struct gs_host_frame *frame = &frame_object->frame;
333+
can_prepare_error_frame(channel, frame);
334+
335+
frame->can_id |= CAN_ERR_RESTARTED;
336+
337+
list_add_tail_locked(&frame_object->list, &hcan->list_to_host);
338+
}
339+
340+
static bool can_bus_off_recovery_pending(const struct can_channel *channel)
341+
{
342+
if (channel->bus_off_restart == CAN_CHANNEL_BUS_OFF_RESTART_DISABLED)
343+
return false;
344+
345+
const uint32_t now = HAL_GetTick();
346+
347+
return time_after(now, channel->bus_off_restart);
348+
}
349+
303350
// If there are frames to receive, don't report any error frames. The
304351
// best we can localize the errors to is "after the last successfully
305352
// received frame", so wait until we get there. LEC will hold some error
@@ -316,5 +363,7 @@ void CAN_HandleError(USBD_GS_CAN_HandleTypeDef *hcan, can_data_t *channel)
316363
can_handle_state_change(hcan, channel, reg_status);
317364
} else if (can_bus_error_pending(channel, reg_status)) {
318365
can_handle_bus_error(hcan, channel, reg_status);
366+
} else if (can_bus_off_recovery_pending(channel)) {
367+
can_handle_bus_off_recovery(hcan, channel);
319368
}
320369
}

0 commit comments

Comments
 (0)