2017-08-14 08:00 PM
Hi,
has anyone ever managed to send a standard CAN overload frame on an stm32?
So far, I could only find error handling for incoming frames but no way to send one myself.
#can #overload2017-10-25 08:48 PM
Ok, so I found a workaround:
/**
* @brief A bus blocker message with ID=0 and DLC=8 -> prevents any other node from accessing the bus
*/
static const CanTxMsgTypeDef CAN_blockerMsg = { 0, 0, CAN_ID_EXT, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0 };
/**
* Receive interrupt handler
* -> pushes received CAN message into CAN_Reader rx_fifo for further processing
* @param hcanCAN peripheral handle
*
elates imed::helmbus::io::subclasses::CANReader
* \link HAL_CAN_RxCpltCallback \endlink
*/
extern 'C' void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan) {
using namespace imed::helmbus::io;
/* construct can_message struct */
const auto msg = static_cast<CAN_message_CPP>(std::move(HAL_CAN_ReadRxMsg(hcan->pRxMsg)));
auto const& bus = CANBus::get_instance(*hcan);
bus->reader.led.startFlashing();
const uint8_t fifo = (__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_FMP1));
if (HAL_CAN_rxFiFoUsed(hcan, fifo) > 1 || bus->getUsedFiFoSlots() > 1) {
/* queue filled > 1 */
imed::CritGuard crit;
if (HAL_CAN_txRdy(hcan)) {
const CanTxMsgTypeDef* const backup = hcan->pTxMsg;
hcan->pTxMsg = (CanTxMsgTypeDef*) &CAN_blockerMsg;
/* transmit */
uint8_t ret = static_cast<uint8_t>(HAL_CAN_Transmit_IT(hcan));
if (!ret) /* ret == HAL_OK */
HAL_CAN_Transmit_IT(hcan);
if (!ret) /* ret == HAL_OK */
HAL_CAN_Transmit_IT(hcan);
hcan->pTxMsg = (CanTxMsgTypeDef*) backup;
}
}
bus->push(msg, 0, true);
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
Basically, this callback does one extra check:
If the hardware RX fifo in the CAN controller is 2/3 filled OR if the software fifo has a backlog, the ISR sends 3 long blocker messages to the bus (ID=0, DLC=8, IDE=1). Because of this message being max priority, this keeps the bus free for about ~1ms @ 500K and gives me some time to work through the fifo.
Luckily, the actual transmit is done in hardware, so the three calls to Transmit_IT return immediately after copying the blocker message into the TX mailboxes.
I can do this because the code is working in a 1:n configuration on the bus, this being the 1.