I don't know, I did my own, not for all data types at once, but on as required basis. It wasn't a daunting task. Can't post the full code but I'm sure no one gets mad at me if I just give the few structs for cross reference so you can compare to your own implementation:
#define TO_SHORT_ID(x) ((x)<<18)
#define FROM_SHORT_ID(x) ((x)>>18)
typedef struct PACK
{
union
{
struct PACK
{
uint32_t id : 29; // CAN ID. 11-bit ID goes into [28..18], use TO_SHORT_ID(0x123) macro for ID 0x123
uint32_t rtr : 1; // 1 = remote frame
uint32_t xtd : 1; // 1 = use 29-bit ID. 0 = use 11-bit ID
uint32_t esi : 1; // Error state indicator, no idea what this does
uint32_t reserved : 16;
uint32_t dlc : 4; // Data length 0-8. For CAN FD frames over 8 bytes, use macros DLC_
uint32_t brs : 1; // Set to 1 to switch to higher CAN FD baudrate
uint32_t fdf : 1; // Set to 1 to send CAN FD frame
uint32_t res : 1;
uint32_t efc : 1; // Set to 1 to store TX event
uint32_t mm : 8; // Marker copied to TX event fifo, if enabled
};
uint64_t header_u64;
};
union
{
uint8_t u8[TX_BUF_ELEM_BYTES];
uint16_t u16[TX_BUF_ELEM_BYTES/2];
uint32_t u32[TX_BUF_ELEM_BYTES/4];
uint64_t u64[TX_BUF_ELEM_BYTES/8];
};
} can_tx_elem_t;
typedef struct PACK
{
union
{
struct PACK
{
uint32_t id : 29; // CAN ID. 11-bit ID goes into [28..18], use FROM_SHORT_ID(0x123) macro for ID 0x123
uint32_t rtr : 1; // 1 = remote frame
uint32_t xtd : 1; // 1 = use 29-bit ID. 0 = use 11-bit ID
uint32_t esi : 1; // Error state indicator, no idea what this does
uint32_t rxts : 16; // RX timestamp
uint32_t dlc : 4; // Data length 0-8. For CAN FD frames over 8 bytes, use macros DLC_
uint32_t brs : 1; // Received with CAN FD baud rate switching
uint32_t fdf : 1; // Received as CAN FD frame
uint32_t res : 1;
uint32_t fidx : 7; // Matching filter index
uint32_t amf : 1; // If '1', didn't match any filters (but accepting non-matching is globally enabled). fidx is then invalid.
};
uint64_t header_u64;
};
union
{
uint8_t u8[RX_BUF_ELEM_BYTES];
uint16_t u16[RX_BUF_ELEM_BYTES/2];
uint32_t u32[RX_BUF_ELEM_BYTES/4];
uint64_t u64[RX_BUF_ELEM_BYTES/8];
};
} can_rx_elem_t;
#define FLT_TYPE_RANGE 0b00
#define FLT_TYPE_DUALOR 0b01
#define FLT_TYPE_MASKED 0b10
#define FLT_TYPE_OFF 0b11
#define DEST_OFF 0b00
#define DEST_FIFO0 0b01
#define DEST_FIFO1 0b10
#define DEST_REJECT 0b11
// Combining DEST_REJECT and prio='1' isn't supported, this combo results in a special mode in FDCAN we don't support now.
typedef struct PACK
{
uint32_t id2 : 11; // mask when FLT_TYPE_MASKED
uint32_t res : 5;
uint32_t id1 : 11;
uint32_t dest : 2;
uint32_t prio : 1; // if '1', HPM interrupt is generated
uint32_t flt_type : 2;
} flt11b_elem_t;
// Combining DEST_REJECT and prio='1' isn't supported, this combo results in a special mode in FDCAN we don't support now.
typedef struct PACK
{
uint32_t id1 : 29;
uint32_t dest : 2;
uint32_t prio : 1; // if '1', HPM interrupt is generated
uint32_t id2 : 29;
uint32_t res : 1;
uint32_t flt_type : 2;
} flt29b_elem_t;
I had some weird behavior when trying read-modify-write operations on message RAM, or smaller than 32-bit accesses. I didn't look at it further, just transitioned to doing full 32- or 64-bit self-aligned read/write accesses.