Browse Source

uavcan_stm32h7:can driver preserve ordering

Refering to the refernece manual:

     Tx queue operation is configured by programming FDCAN_TXBC.TFQM to 1. Messages
     stored in the Tx queue are transmitted starting with the message with the lowest message
     ID (highest priority). **In case that multiple queue buffers are configured with the same
     message ID, the queue buffer with the lowest buffer number is transmitted first**

    Tx FIFO operation is configured by programming FDCAN_TXBC.TFQM to 0. Messages
    stored in the Tx FIFO are transmitted starting with the message referenced by the get index
    FDCAN_TXFQS.TFGI. After each transmission the get index is incremented cyclically until
    the Tx FIFO is empty. The Tx FIFO enables transmission of messages with the same
    message ID from different Tx buffers in the order these messages have been written to the
    Tx FIFO

    The issue will be cancelation:

    The FDCAN supports transmit cancellation. To cancel a requested transmission from a
    dedicated Tx buffer or a Tx queue buffer the Host has to write a 1 to the corresponding bit
    position (= number of Tx buffer) of register FDCAN_TXBCR. Transmit cancellation is not
    intended for Tx FIFO operation.

    But there is nothing preventing it. This seems to indicate it will
    work. When a transmission request for the Tx buffer referenced by the get index is canceled, the
    get index is incremented to the next Tx buffer with pending transmission request and the Tx
    FIFO free level is recalculated. When transmission cancellation is applied to any other Tx
    buffer, the get index and the FIFO free level remain unchanged.
release/1.12
David Sidrane 4 years ago committed by Lorenz Meier
parent
commit
395519ac66
  1. 2
      src/drivers/uavcan/uavcan_drivers/stm32h7/driver/include/uavcan_stm32h7/can.hpp
  2. 22
      src/drivers/uavcan/uavcan_drivers/stm32h7/driver/src/uc_stm32h7_can.cpp

2
src/drivers/uavcan/uavcan_drivers/stm32h7/driver/include/uavcan_stm32h7/can.hpp

@ -112,7 +112,7 @@ class CanIface : public uavcan::ICanIface, uavcan::Noncopyable @@ -112,7 +112,7 @@ class CanIface : public uavcan::ICanIface, uavcan::Noncopyable
uavcan::uint32_t ExtIdFilterSA;
uavcan::uint32_t RxFIFO0SA;
uavcan::uint32_t RxFIFO1SA;
uavcan::uint32_t TxQueueSA;
uavcan::uint32_t TxFIFOSA;
} message_ram_;
enum { NumTxMailboxes = 32 }; // Should match the number of Tx FIFOs available in message RAM

22
src/drivers/uavcan/uavcan_drivers/stm32h7/driver/src/uc_stm32h7_can.cpp

@ -405,24 +405,24 @@ uavcan::int16_t CanIface::send(const uavcan::CanFrame &frame, uavcan::MonotonicT @@ -405,24 +405,24 @@ uavcan::int16_t CanIface::send(const uavcan::CanFrame &frame, uavcan::MonotonicT
* - Frames do not timeout on a properly functioning bus. Since frames do not timeout, the new
* frame can only have higher priority, which doesn't break the logic.
*
* - If high-priority frames are timing out in the TX queue, there's probably a lot of other
* - If high-priority frames are timing out in the TX FIFO, there's probably a lot of other
* issues to take care of before this one becomes relevant.
*
* - It takes CPU time. Not just CPU time, but critical section time, which is expensive.
*/
CriticalSectionLocker lock;
// First, check if there are any slots available in the queue
// First, check if there are any slots available in the FIFO
if ((can_->TXFQS & FDCAN_TXFQS_TFQF) > 0) {
// Tx FIFO / Queue is full
// Tx FIFO is full
return 0;
}
// Next, get the next available queue index from the controller
// Next, get the next available FIFO index from the controller
const uint8_t index = (can_->TXFQS & FDCAN_TXFQS_TFQPI) >> FDCAN_TXFQS_TFQPI_Pos;
// Now, we can copy the CAN frame to the queue (in message RAM)
uint32_t *txbuf = (uint32_t *)(message_ram_.TxQueueSA + (index * FIFO_ELEMENT_SIZE * WORD_LENGTH));
// Now, we can copy the CAN frame to the FIFO (in message RAM)
uint32_t *txbuf = (uint32_t *)(message_ram_.TxFIFOSA + (index * FIFO_ELEMENT_SIZE * WORD_LENGTH));
// Copy the ID; special case for standard ID frames
if (frame.isExtended()) {
@ -708,10 +708,10 @@ int CanIface::init(const uavcan::uint32_t bitrate, const OperatingMode mode) @@ -708,10 +708,10 @@ int CanIface::init(const uavcan::uint32_t bitrate, const OperatingMode mode)
can_->RXF0C |= n_fifo0 << FDCAN_RXF0C_F0S_Pos;
ram_offset += n_fifo0 * FIFO_ELEMENT_SIZE;
// Set Tx queue size (32 elements max)
message_ram_.TxQueueSA = gl_ram_base + ram_offset * WORD_LENGTH;
// Set Tx FIFO size (32 elements max)
message_ram_.TxFIFOSA = gl_ram_base + ram_offset * WORD_LENGTH;
can_->TXBC = 32U << FDCAN_TXBC_TFQS_Pos;
can_->TXBC |= FDCAN_TXBC_TFQM; // Queue mode (vs. FIFO)
can_->TXBC &= ~FDCAN_TXBC_TFQM; // Use FIFO
can_->TXBC |= ram_offset << FDCAN_TXBC_TBSA_Pos;
/*
@ -882,11 +882,11 @@ bool CanIface::canAcceptNewTxFrame(const uavcan::CanFrame &frame) const @@ -882,11 +882,11 @@ bool CanIface::canAcceptNewTxFrame(const uavcan::CanFrame &frame) const
{
// Check that we even _have_ a Tx FIFO allocated
if ((can_->TXBC & FDCAN_TXBC_TFQS) == 0) {
// Your queue size is 0, you did something wrong
// Your FIFO size is 0, you did something wrong
return false;
}
// Check if the Tx queue is full
// Check if the Tx FIFO is full
if ((can_->TXFQS & FDCAN_TXFQS_TFQF) == FDCAN_TXFQS_TFQF) {
// Sorry, out of room, try back later
return false;

Loading…
Cancel
Save