Skip to content

Commit c48525f

Browse files
committed
cpu/samd5x/periph_can: fix RX
CAN required CLK_CANx_APB and CLK_CANx_APB to be running and will not request any clock by itself. We can ensure both clocks to be running by preventing the MCU from entering IDLE state. The SAMD5x/SAME5x Family Data Sheet says in Section "39.6.9 Sleep Mode Operation" says: > The CAN can be configured to operate in any idle sleep mode. The CAN > cannot operate in Standby sleep mode. > > [...] > > To leave low power mode, CLK_CANx_APB and GCLK_CANx must be active > before writing CCCR.CSR to '0'. The CAN will acknowledge this by > resetting CCCR.CSA = 0. Afterwards, the application can restart CAN > communication by resetting bit CCCR.INIT. tl;dr: At most SAM0_PM_IDLE is allowed while not shutting down the CAN controller, but even that will pause communication (including RX). Apparently, the CAN controller was never tested without also using the USB peripheral, which kept the clocks running as side effect.
1 parent 775f596 commit c48525f

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

cpu/samd5x/periph/can.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
#include <assert.h>
2121
#include <string.h>
2222

23+
#include "can/device.h"
2324
#include "periph/can.h"
2425
#include "periph/gpio.h"
25-
#include "can/device.h"
26+
#include "pm_layered.h"
2627

2728
#define ENABLE_DEBUG 0
2829
#include "debug.h"
@@ -107,6 +108,30 @@ static const struct can_bittiming_const bittiming_const = {
107108

108109
static int _power_on(can_t *dev)
109110
{
111+
/* CAN required CLK_CANx_APB and GCLK_CANx to be running and will not
112+
* request any clock by itself. We can ensure both clocks to be running
113+
* by preventing the MCU from entering IDLE state.
114+
*
115+
* The SAMD5x/SAME5x Family Data Sheet says in Section
116+
* "39.6.9 Sleep Mode Operation" says:
117+
*
118+
* > The CAN can be configured to operate in any idle sleep mode. The CAN
119+
* > cannot operate in Standby sleep mode.
120+
* >
121+
* > [...]
122+
* >
123+
* > To leave low power mode, CLK_CANx_APB and GCLK_CANx must be active
124+
* > before writing CCCR.CSR to '0'. The CAN will acknowledge this by
125+
* > resetting CCCR.CSA = 0. Afterwards, the application can restart CAN
126+
* > communication by resetting bit CCCR.INIT.
127+
*
128+
* tl;dr: At most SAM0_PM_IDLE is allowed while not shutting down the CAN
129+
* controller, but even that will pause communication (including RX).
130+
*/
131+
if (IS_USED(MODULE_PM_LAYERED)) {
132+
pm_block(SAM0_PM_IDLE);
133+
}
134+
110135
if (dev->conf->can == CAN0) {
111136
DEBUG_PUTS("CAN0 controller is used");
112137
MCLK->AHBMASK.reg |= MCLK_AHBMASK_CAN0;
@@ -125,6 +150,10 @@ static int _power_on(can_t *dev)
125150

126151
static int _power_off(can_t *dev)
127152
{
153+
if (IS_USED(MODULE_PM_LAYERED)) {
154+
pm_unblock(SAM0_PM_IDLE);
155+
}
156+
128157
if (dev->conf->can == CAN0) {
129158
DEBUG_PUTS("CAN0 controller is used");
130159
MCLK->AHBMASK.reg &= ~MCLK_AHBMASK_CAN0;

0 commit comments

Comments
 (0)