Homepage GitHub

Static deque for CANFD ISR buffer


(Abraham Rodriguez) #1

Regarding the S32K driver layer for libuavcan, the current implementation uses an almost naive use of the deque STL for limiting the size of the RX queue as shown briefly next:

if (RX_ISRframeCount <= Frame_Capactiy )
{
RX_ISRframeCount++;

/* Insert the frame into the queue */ 
S32K_InterfaceManager::frame_ISRbuffer.push_back(FrameISR);
}

And in the read function it will be inverted as shown:

/* Check if the ISR buffer isn't empty */
if(!S32K_InterfaceManager::frame_ISRbuffer.empty())
{
/* Get the front element of the queue buffer */
out_frames[1] = FS32K_InterfaceManager::frame_ISRbuffer.front();

/* Pop the front element of the queue buffer */
S32K_InterfaceManager::frame_ISRbuffer.pop_front();

/* Decrease frame count */
RX_ISRframeCount--;
}

¿How can the deque STL be used while keeping a static deterministic ISR buffer?

Thank you in advance.


(Pavel Kirienko) #2

Hi Abraham. I am no @scottdixon, but if I were impersonating him I would have probably said:

std::deque<CAN::Frame, libuavcan::platform::memory::PoolAllocator<...>>

Replace the ellipsis with the appropriate parameters as needed. The second template parameter libuavcan::platform::memory::PoolAllocator comes from:

I assume here that the pool allocator is interrupt-safe. If you are uncomfortable with such assumptions, write your own queue instead, or just re-use this one:

(implementation: https://github.com/UAVCAN/libuavcan_stm32/blob/4e0a24756090d218b469f561d7e0d35e5f2f5427/driver/src/uc_stm32_can.cpp#L126-L183; you will need to ensure synchronized access).

I don’t think you need RX_ISRframeCount; use std::deque<>::size() instead or whatever queue class you’re using. Redundant state is bad.

I strongly recommend following a consistent naming style as described in the Zubax C++ Conventions.


(Scott Dixon) #3

The block allocator is ISR-safe (it uses an optimistic/lockless implementation to find free blocks) as long as you are not compiling with -fno-threadsafe-statics (which we are in our current example so we should change that).

In short, Pavel’s channeling of myself is correct.


(Abraham Rodriguez) #4

Thank you, the PoolAllocator fits as a plug & play custom allocator for the STL deque, the line would be as follows

/* Intermediate RX buffer for ISR reception with static memory pool */
static std::deque<FrameType, platform::PoolAllocator<S32K_FRAME_CAPACITY, sizeof(FrameType)> > frame_ISRbuffer;

This constant it’s a private member of S32K_InterfaceManager

/* Frame capacity for the intermediate ISR buffer */
constexpr static std::size_t S32K_FRAME_CAPACITY  = 500;

And substituted the CAN::Frame with the “using” directive from the class template parameter at interfaces.hpp which solves to CAN::Frame< CAN::TypeFD::MaxFrameSizeBytes>

    /**
    * The media-specific frame type exchanged across this interface.
    */
    using FrameType = FrameT;

The changes can be seen in https://github.com/noxuz/libuavcan_s32k/blob/master/S32K_libuavcan.hpp