diff --git a/os/hal/dox/can.dox b/os/hal/dox/can.dox index 6c39a52b3..234cb2dc6 100644 --- a/os/hal/dox/can.dox +++ b/os/hal/dox/can.dox @@ -48,10 +48,9 @@ stop -> stop [label="\ncanStop()"]; stop -> ready [label="\ncanStart()\n(fast implementation)"]; stop -> starting [label="\ncanStart()\n(slow implementation)"]; - starting -> starting [label="\ncanStart()\n(other thread)"]; starting -> ready [label="\ninitialization complete\n(all threads)"]; ready -> stop [label="\ncanStop()"]; - ready -> ready [label="\ncanStart()\ncanReceive()\ncanTransmit()"]; + ready -> ready [label="\ncanReceive()\ncanTransmit()"]; ready -> sleep [label="\ncanSleep()"]; sleep -> sleep [label="\ncanSleep()"]; sleep -> ready [label="\ncanWakeup()"]; diff --git a/os/hal/ports/STM32/LLD/can_lld.c b/os/hal/ports/STM32/LLD/can_lld.c index 06294ab26..44cb95281 100644 --- a/os/hal/ports/STM32/LLD/can_lld.c +++ b/os/hal/ports/STM32/LLD/can_lld.c @@ -429,14 +429,11 @@ void can_lld_start(CANDriver *canp) { } #endif - /* Entering initialization mode. */ - canp->state = CAN_STARTING; + /* Configuring CAN. */ canp->can->MCR = CAN_MCR_INRQ; while ((canp->can->MSR & CAN_MSR_INAK) == 0) osalThreadSleepS(1); - /* BTR initialization.*/ canp->can->BTR = canp->config->btr; - /* MCR initialization.*/ canp->can->MCR = canp->config->mcr; /* Interrupt sources initialization.*/ diff --git a/os/hal/src/can.c b/os/hal/src/can.c index 08cdd5172..f6ef7011f 100644 --- a/os/hal/src/can.c +++ b/os/hal/src/can.c @@ -85,9 +85,9 @@ void canObjectInit(CANDriver *canp) { /** * @brief Configures and activates the CAN peripheral. - * @note Activating the CAN bus can be a slow operation this this function - * is not atomic, it waits internally for the initialization to - * complete. + * @note Activating the CAN bus can be a slow operation. + * @note Unlike other drivers it is not possible to restart the CAN + * driver without first stopping it using canStop(). * * @param[in] canp pointer to the @p CANDriver object * @param[in] config pointer to the @p CANConfig object. Depending on @@ -100,18 +100,18 @@ void canStart(CANDriver *canp, const CANConfig *config) { osalDbgCheck(canp != NULL); osalSysLock(); - osalDbgAssert((canp->state == CAN_STOP) || - (canp->state == CAN_STARTING) || - (canp->state == CAN_READY), - "invalid state"); - while (canp->state == CAN_STARTING) { - osalThreadSleepS((systime_t)1); - } - if (canp->state == CAN_STOP) { - canp->config = config; - can_lld_start(canp); - canp->state = CAN_READY; - } + osalDbgAssert(canp->state == CAN_STOP, "invalid state"); + + /* Entering initialization mode. */ + canp->state = CAN_STARTING; + canp->config = config; + + /* Low level initialization, could be a slow process and sleeps could + be performed inside.*/ + can_lld_start(canp); + + /* The driver finally goes into the ready state.*/ + canp->state = CAN_READY; osalSysUnlock(); } @@ -129,8 +129,13 @@ void canStop(CANDriver *canp) { osalSysLock(); osalDbgAssert((canp->state == CAN_STOP) || (canp->state == CAN_READY), "invalid state"); + + /* The low level driver is stopped.*/ can_lld_stop(canp); canp->state = CAN_STOP; + + /* Threads waiting on CAN APIs are notified that the driver has been + stopped in order to not have stuck threads.*/ osalThreadDequeueAllI(&canp->rxqueue, MSG_RESET); osalThreadDequeueAllI(&canp->txqueue, MSG_RESET); osalOsRescheduleS();