Skip to content

Commit

Permalink
[platform] Add CANFD large frame support
Browse files Browse the repository at this point in the history
  • Loading branch information
rasmuskleist authored and twast92 committed Feb 4, 2023
1 parent c347f00 commit e4b1a4a
Show file tree
Hide file tree
Showing 17 changed files with 258 additions and 56 deletions.
2 changes: 1 addition & 1 deletion examples/avr/can/mcp2515_uart/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ main()
}
stream << modm::endl;

stream << " dlc = " << message.getLength() << modm::endl;
stream << " dlc = " << message.getDataLengthCode() << modm::endl;
if (!message.isRemoteTransmitRequest())
{
stream << " data = ";
Expand Down
2 changes: 1 addition & 1 deletion examples/generic/ros/can_bridge/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ messageRosToModm(const can_msgs::Frame& source, modm::can::Message& destination)
bool
messageModmToRos(const modm::can::Message& source, can_msgs::Frame& destination) {
destination.id = source.getIdentifier();
destination.dlc = source.getLength();
destination.dlc = source.getDataLengthCode();
destination.is_rtr = source.isRemoteTransmitRequest();
destination.is_extended = source.isExtended();
memcpy(destination.data, source.data, source.getLength());
Expand Down
93 changes: 93 additions & 0 deletions examples/nucleo_g474re/fdcan/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* Copyright (c) 2022, Rasmus Kleist Hørlyck Sørensen
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

#include <modm/board.hpp>
#include <modm/debug/logger.hpp>
#include <modm/board.hpp>

using namespace modm::literals;

// Set the log level
#undef MODM_LOG_LEVEL
#define MODM_LOG_LEVEL modm::log::INFO

int
main()
{
Board::initialize();

MODM_LOG_INFO << "CAN Test Program" << modm::endl;

MODM_LOG_INFO << "Initializing Fdcan1..." << modm::endl;
// Initialize Fdcan1
Fdcan1::connect<GpioB8::Rx, GpioB9::Tx>(Gpio::InputType::PullUp);
Fdcan1::initialize<Board::SystemClock, 125_kbps, 1_pct, 500_kbps>(9);

MODM_LOG_INFO << "Setting up Filter for Fdcan1..." << modm::endl;
// Receive every extended id message
Fdcan1::setExtendedFilter(0, Fdcan1::FilterConfig::Fifo0,
modm::can::ExtendedIdentifier(0),
modm::can::ExtendedMask(0));

MODM_LOG_INFO << "Initializing Fdcan2..." << modm::endl;
// Initialize Fdcan2
Fdcan2::connect<GpioB5::Rx, GpioB6::Tx>(Gpio::InputType::PullUp);
Fdcan2::initialize<Board::SystemClock, 125_kbps, 1_pct, 500_kbps>(12);

MODM_LOG_INFO << "Setting up Filter for Fdcan2..." << modm::endl;
// Receive every message
Fdcan2::setExtendedFilter(0, Fdcan2::FilterConfig::Fifo0,
modm::can::ExtendedIdentifier(0),
modm::can::ExtendedMask(0));

// Send a message
MODM_LOG_INFO << "Sending message on Fdcan1..." << modm::endl;
modm::can::Message msg(1, 1);
msg.setExtended(true);
msg.data[0] = 0x11;
Fdcan1::sendMessage(msg);

// Send a message
MODM_LOG_INFO << "Sending message on Fdcan2..." << modm::endl;
msg.data[0] = 0x22;
Fdcan2::sendMessage(msg);

// Send a message
MODM_LOG_INFO << "Sending message on Fdcan1..." << modm::endl;
modm::can::Message longMsg(2, 32);
longMsg.setExtended(true);
for (uint8_t i = 0; i < 32; i++) longMsg.data[i] = i;
Fdcan1::sendMessage(longMsg);

// Send a message
MODM_LOG_INFO << "Sending message on Fdcan2..." << modm::endl;
longMsg.data[0] = 0x22;
Fdcan2::sendMessage(longMsg);

while (true)
{
if (Fdcan1::isMessageAvailable())
{
MODM_LOG_INFO << "Fdcan1: Message is available..." << modm::endl;
modm::can::Message message;
Fdcan1::getMessage(message);
MODM_LOG_INFO << message << modm::endl;
}
if (Fdcan2::isMessageAvailable())
{
MODM_LOG_INFO << "Fdcan2: Message is available..." << modm::endl;
modm::can::Message message;
Fdcan2::getMessage(message);
MODM_LOG_INFO << message << modm::endl;
}
}

return 0;
}
15 changes: 15 additions & 0 deletions examples/nucleo_g474re/fdcan/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<library>
<extends>modm:nucleo-g474re</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_g474re/fdcan</option>
<option name="modm:architecture:can:message.buffer">64</option>
</options>
<modules>
<module>modm:debug</module>
<module>modm:platform:can:1</module>
<module>modm:platform:can:2</module>
<module>modm:platform:gpio</module>
<module>modm:platform:uart:2</module>
<module>modm:build:scons</module>
</modules>
</library>
3 changes: 2 additions & 1 deletion examples/stm32f072_discovery/can/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ displayMessage(const modm::can::Message& message)
}
MODM_LOG_INFO<< modm::endl;

MODM_LOG_INFO<< "dlc =" << message.getLength() << modm::endl;
MODM_LOG_INFO<< "dlc =" << message.getDataLengthCode() << modm::endl;
MODM_LOG_INFO<< "length =" << message.getLength() << modm::endl;
if (!message.isRemoteTransmitRequest())
{
MODM_LOG_INFO << "data=";
Expand Down
3 changes: 2 additions & 1 deletion examples/stm32f3_discovery/can/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ displayMessage(const modm::can::Message& message)
}
MODM_LOG_INFO<< modm::endl;

MODM_LOG_INFO<< "dlc =" << message.getLength() << modm::endl;
MODM_LOG_INFO<< "dlc =" << message.getDataLengthCode() << modm::endl;
MODM_LOG_INFO<< "length =" << message.getLength() << modm::endl;
if (!message.isRemoteTransmitRequest())
{
MODM_LOG_INFO << "data=";
Expand Down
3 changes: 2 additions & 1 deletion examples/stm32f469_discovery/can/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ displayMessage(const modm::can::Message& message)
}
MODM_LOG_INFO<< modm::endl;

MODM_LOG_INFO<< "dlc =" << message.getLength() << modm::endl;
MODM_LOG_INFO<< "dlc =" << message.getDataLengthCode() << modm::endl;
MODM_LOG_INFO<< "length =" << message.getLength() << modm::endl;
if (!message.isRemoteTransmitRequest())
{
MODM_LOG_INFO << "data=";
Expand Down
3 changes: 2 additions & 1 deletion examples/stm32f4_discovery/can/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ displayMessage(const modm::can::Message& message)
}
MODM_LOG_INFO<< modm::endl;

MODM_LOG_INFO<< "dlc =" << message.getLength() << modm::endl;
MODM_LOG_INFO<< "dlc =" << message.getDataLengthCode() << modm::endl;
MODM_LOG_INFO<< "length =" << message.getLength() << modm::endl;
if (!message.isRemoteTransmitRequest())
{
MODM_LOG_INFO << "data=";
Expand Down
3 changes: 2 additions & 1 deletion examples/stm32f4_discovery/can2/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ displayMessage(const modm::can::Message& message)
}
MODM_LOG_INFO<< modm::endl;

MODM_LOG_INFO<< "dlc =" << message.getLength() << modm::endl;
MODM_LOG_INFO<< "dlc =" << message.getDataLengthCode() << modm::endl;
MODM_LOG_INFO<< "length =" << message.getLength() << modm::endl;
if (!message.isRemoteTransmitRequest())
{
MODM_LOG_INFO << "data=";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2014, 2016, Niklas Hauser
* Copyright (c) 2015-2016, Sascha Schade
* Copyright (c) 2022, Rasmus Kleist Hørlyck Sørensen
*
* This file is part of the modm project.
*
Expand All @@ -16,30 +17,38 @@
#include <stdint.h>
#include <string.h> // strlen
#include <algorithm>
#include <array>
#include <modm/architecture/utils.hpp>

namespace modm::can
{

/// Representation of a CAN message
/// @ingroup modm_architecture_can
struct Message
{
inline Message(uint32_t inIdentifier = 0, uint8_t inLength = 0) :
identifier(inIdentifier), flags(), length(inLength)
identifier(inIdentifier), flags()
{
setLength(inLength);
}

// Create CAN message from long data in Network Order.
inline Message(uint32_t inIdentifier, uint8_t inLength, const uint64_t &inData, bool extended=false) :
identifier(inIdentifier), length(std::min(inLength, uint8_t(8)))
inline Message(uint32_t inIdentifier, uint8_t inLength, const uint64_t &inData, bool extended = false) :
Message(inIdentifier, std::min(inLength, uint8_t(8)))
{
flags.extended = extended;
const uint8_t *inDataB = reinterpret_cast<const uint8_t *>(&inData);
for (uint8_t ii = 0; ii < length; ++ii)
data[ii] = inDataB[length - ii - 1];
}

inline Message(uint32_t inIdentifier, uint8_t inLength, const uint8_t *inData, bool extended = false) :
Message(inIdentifier, inLength)
{
flags.extended = extended;
for (uint8_t ii = 0; ii < length; ++ii)
data[ii] = inData[ii];
}

inline uint32_t
getIdentifier() const
{
Expand All @@ -52,6 +61,30 @@ struct Message
identifier = id;
}

inline constexpr uint8_t
getCapacity() const
{
return capacity;
}

inline void
setFlexibleData(bool fd = true)
{
flags.fd = fd;
}

inline bool
isFlexibleData() const
{
return (flags.fd != 0);
}

inline bool
isBitRateSwitching() const
{
return (flags.brs != 0);
}

inline void
setExtended(bool extended = true)
{
Expand All @@ -76,42 +109,89 @@ struct Message
return (flags.rtr != 0);
}

inline void
setDataLengthCode(uint8_t inDlc)
{
while (dlcConversionTable[inDlc] > capacity) inDlc--;

dlc = inDlc;
length = dlcConversionTable[inDlc];
if (dlc > 8) setFlexibleData();
}

inline void
setLength(uint8_t inLength)
{
if constexpr (capacity <= 8)
{
length = dlc = std::min<uint8_t>(inLength, capacity);
}
else
{
uint8_t inDlc = 0;
while (dlcConversionTable[inDlc] < std::min<uint8_t>(inLength, capacity)) inDlc++;
setDataLengthCode(inDlc);
}
}

inline uint8_t
getLength() const
{
return length;
}

inline void
setLength(uint8_t len)
inline uint8_t
getDataLengthCode() const
{
length = len;
return dlc;
}

public:
static constexpr uint8_t capacity = {{ options["message.buffer"] }};
static constexpr uint8_t dlcConversionTable[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48, 64};
public:
uint32_t identifier;
uint8_t modm_aligned(4) data[8];
struct Flags
{
Flags() :
rtr(0), extended(1)
fd(0), brs(0), rtr(0), extended(1)
{
}

bool fd : 1;
bool brs : 1;
bool rtr : 1;
bool extended : 1;
} flags;
uint8_t dlc;
uint8_t length;
uint8_t modm_aligned(4) data[capacity];

public:
inline bool
operator == (const modm::can::Message& rhs) const
{
return ((this->identifier == rhs.identifier) and
(this->dlc == rhs.dlc) and
(this->length == rhs.length) and
(this->flags.fd == rhs.flags.fd) and
(this->flags.brs == rhs.flags.brs) and
(this->flags.rtr == rhs.flags.rtr) and
(this->flags.extended == rhs.flags.extended) and
std::equal(data, data + length, rhs.data));
std::equal(data, data + getLength(), rhs.data));
}

inline void
operator = (const modm::can::Message& rhs)
{
this->identifier = rhs.identifier;
this->dlc = rhs.dlc;
this->length = rhs.length;
this->flags.fd = rhs.flags.fd;
this->flags.brs = rhs.flags.brs;
this->flags.rtr = rhs.flags.rtr;
this->flags.extended = rhs.flags.extended;
std::copy(std::begin(rhs.data), std::end(rhs.data), std::begin(this->data));
}

inline bool
Expand All @@ -120,9 +200,10 @@ struct Message
return (this->identifier << (this->flags.extended ? 0 : 18))
< (rhs.identifier << (rhs.flags.extended ? 0 : 18));
}

};

} // namespace modm::can
} // namespace modm::can

#if MODM_HAS_IOSTREAM
#include <inttypes.h>
Expand All @@ -135,20 +216,23 @@ namespace modm
inline modm::IOStream&
operator << (modm::IOStream& s, const modm::can::Message& m)
{
s.printf("id = %04" PRIx32 ", len = ", m.identifier);
s << m.length;
s.printf(", flags = %c%c, data = ",
s.printf("id = %04" PRIx32 ", len = %u, dlc = %u", m.identifier, m.length, m.dlc);
s.printf(", flags = %c%c%c%c",
m.flags.fd ? 'F' : 'f',
m.flags.brs ? 'B' : 'b',
m.flags.rtr ? 'R' : 'r',
m.flags.extended ? 'E' : 'e');
if (not m.isRemoteTransmitRequest()) {
for (uint_fast8_t ii = 0; ii < m.length; ++ii) {
s.printf(", data = ");
for (uint_fast8_t ii = 0; ii < m.getLength(); ++ii) {
s.printf("%02x ", m.data[ii]);
}
}
return s;
}

} // modm namespace

#endif

#endif // MODM_CAN_MESSAGE_HPP
Loading

0 comments on commit e4b1a4a

Please sign in to comment.