STM32: Proper critical in CAN driver initialization

This commit is contained in:
Pavel Kirienko
2014-05-07 19:32:44 +04:00
parent cbf5450164
commit 7d2fccff77
2 changed files with 57 additions and 40 deletions
@@ -114,6 +114,8 @@ class CanIface : public uavcan::ICanIface, uavcan::Noncopyable
void handleTxMailboxInterrupt(uavcan::uint8_t mailbox_index, bool txok, uavcan::uint64_t utc_usec); void handleTxMailboxInterrupt(uavcan::uint8_t mailbox_index, bool txok, uavcan::uint64_t utc_usec);
bool waitMsrINakBitStateChange(bool target_state);
public: public:
enum { MaxRxQueueCapacity = 254 }; enum { MaxRxQueueCapacity = 254 };
@@ -135,7 +137,6 @@ public:
* Assumes: * Assumes:
* - Iface clock is enabled * - Iface clock is enabled
* - Iface has been resetted via RCC * - Iface has been resetted via RCC
* - Interrupts are disabled
* - Caller will configure NVIC by itself * - Caller will configure NVIC by itself
*/ */
int init(uavcan::uint32_t bitrate); int init(uavcan::uint32_t bitrate);
@@ -324,6 +324,27 @@ uavcan::int16_t CanIface::configureFilters(const uavcan::CanFilterConfig* filter
return -1; return -1;
} }
bool CanIface::waitMsrINakBitStateChange(bool target_state)
{
#if UAVCAN_STM32_NUTTX
const unsigned Timeout = 500;
#else
const unsigned Timeout = 2000000;
#endif
for (unsigned wait_ack = 0; wait_ack < Timeout; wait_ack++)
{
const bool state = (can_->MSR & bxcan::MSR_INAK) != 0;
if (state == target_state)
{
return true;
}
#if UAVCAN_STM32_NUTTX
::usleep(2000);
#endif
}
return false;
}
int CanIface::init(uavcan::uint32_t bitrate) int CanIface::init(uavcan::uint32_t bitrate)
{ {
int res = 0; int res = 0;
@@ -346,14 +367,7 @@ int CanIface::init(uavcan::uint32_t bitrate)
can_->MCR &= ~bxcan::MCR_SLEEP; // Exit sleep mode can_->MCR &= ~bxcan::MCR_SLEEP; // Exit sleep mode
can_->MCR |= bxcan::MCR_INRQ; // Request init can_->MCR |= bxcan::MCR_INRQ; // Request init
for (unsigned wait_ack = 0; wait_ack < 2000000; wait_ack++) if (!waitMsrINakBitStateChange(true))
{
if ((can_->MSR & bxcan::MSR_INAK) == bxcan::MSR_INAK)
{
break;
}
}
if ((can_->MSR & bxcan::MSR_INAK) != bxcan::MSR_INAK)
{ {
UAVCAN_STM32_LOG("MSR INAK not set"); UAVCAN_STM32_LOG("MSR INAK not set");
res = -1; res = -1;
@@ -375,14 +389,7 @@ int CanIface::init(uavcan::uint32_t bitrate)
can_->MCR &= ~bxcan::MCR_INRQ; // Leave init mode can_->MCR &= ~bxcan::MCR_INRQ; // Leave init mode
for (unsigned wait_ack = 0; wait_ack < 2000000; wait_ack++) if (!waitMsrINakBitStateChange(false))
{
if ((can_->MSR & bxcan::MSR_INAK) != bxcan::MSR_INAK)
{
break;
}
}
if ((can_->MSR & bxcan::MSR_INAK) == bxcan::MSR_INAK)
{ {
UAVCAN_STM32_LOG("MSR INAK not cleared"); UAVCAN_STM32_LOG("MSR INAK not cleared");
res = -1; res = -1;
@@ -636,20 +643,21 @@ int CanDriver::init(uavcan::uint32_t bitrate)
UAVCAN_STM32_LOG("Bitrate %lu", static_cast<unsigned long>(bitrate)); UAVCAN_STM32_LOG("Bitrate %lu", static_cast<unsigned long>(bitrate));
CriticalSectionLocker lock;
/* /*
* CAN1 * CAN1
*/ */
{
CriticalSectionLocker lock;
#if UAVCAN_STM32_NUTTX #if UAVCAN_STM32_NUTTX
modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_CAN1EN); modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_CAN1EN);
modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_CAN1RST); modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_CAN1RST);
modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST, 0); modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST, 0);
#else #else
RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; RCC->APB1ENR |= RCC_APB1ENR_CAN1EN;
RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST; RCC->APB1RSTR |= RCC_APB1RSTR_CAN1RST;
RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST;
#endif #endif
}
UAVCAN_STM32_LOG("Initing iface 0..."); UAVCAN_STM32_LOG("Initing iface 0...");
res = if0_.init(bitrate); res = if0_.init(bitrate);
@@ -664,15 +672,18 @@ int CanDriver::init(uavcan::uint32_t bitrate)
* CAN2 * CAN2
*/ */
#if UAVCAN_STM32_NUM_IFACES > 1 #if UAVCAN_STM32_NUM_IFACES > 1
{
CriticalSectionLocker lock;
# if UAVCAN_STM32_NUTTX # if UAVCAN_STM32_NUTTX
modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_CAN2EN); modifyreg32(STM32_RCC_APB1ENR, 0, RCC_APB1ENR_CAN2EN);
modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_CAN2RST); modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_CAN2RST);
modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST, 0); modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST, 0);
# else # else
RCC->APB1ENR |= RCC_APB1ENR_CAN2EN; RCC->APB1ENR |= RCC_APB1ENR_CAN2EN;
RCC->APB1RSTR |= RCC_APB1RSTR_CAN2RST; RCC->APB1RSTR |= RCC_APB1RSTR_CAN2RST;
RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN2RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN2RST;
#endif # endif
}
UAVCAN_STM32_LOG("Initing iface 1..."); UAVCAN_STM32_LOG("Initing iface 1...");
res = if1_.init(bitrate); res = if1_.init(bitrate);
@@ -710,16 +721,19 @@ int CanDriver::init(uavcan::uint32_t bitrate)
# endif # endif
# undef IRQ_ATTACH # undef IRQ_ATTACH
#else #else
nvicEnableVector(CAN1_TX_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); {
nvicEnableVector(CAN1_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); CriticalSectionLocker lock;
nvicEnableVector(CAN1_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); nvicEnableVector(CAN1_TX_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
nvicEnableVector(CAN1_SCE_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); nvicEnableVector(CAN1_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
nvicEnableVector(CAN1_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
nvicEnableVector(CAN1_SCE_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
# if UAVCAN_STM32_NUM_IFACES > 1 # if UAVCAN_STM32_NUM_IFACES > 1
nvicEnableVector(CAN2_TX_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); nvicEnableVector(CAN2_TX_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
nvicEnableVector(CAN2_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); nvicEnableVector(CAN2_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
nvicEnableVector(CAN2_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); nvicEnableVector(CAN2_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
nvicEnableVector(CAN2_SCE_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK); nvicEnableVector(CAN2_SCE_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
# endif # endif
}
#endif #endif
UAVCAN_STM32_LOG("CAN drv init OK"); UAVCAN_STM32_LOG("CAN drv init OK");
@@ -730,6 +744,8 @@ fail:
UAVCAN_STM32_LOG("CAN drv init failed %i", res); UAVCAN_STM32_LOG("CAN drv init failed %i", res);
assert(res < 0); assert(res < 0);
CriticalSectionLocker lock;
#if UAVCAN_STM32_NUTTX #if UAVCAN_STM32_NUTTX
// TODO: Unattach and disable all IRQs // TODO: Unattach and disable all IRQs
modifyreg32(STM32_RCC_APB1ENR, RCC_APB1ENR_CAN1EN, 0); modifyreg32(STM32_RCC_APB1ENR, RCC_APB1ENR_CAN1EN, 0);