Skip to content

Commit

Permalink
[stm32] Add FDCAN support for H7 series
Browse files Browse the repository at this point in the history
  • Loading branch information
WasabiFan committed Sep 2, 2024
1 parent 5ae26dd commit 2f582ad
Show file tree
Hide file tree
Showing 14 changed files with 447 additions and 61 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">✕</td>
<td align="center">✕</td>
<td align="center">✅</td>
Expand Down
82 changes: 82 additions & 0 deletions examples/nucleo_h723zg/can/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2020, Raphael Lehmann
*
* 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<GpioA11::Rx, GpioA12::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 msg1(1, 1);
msg1.setExtended(true);
msg1.data[0] = 0x11;
Fdcan1::sendMessage(msg1);

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


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;
}
13 changes: 13 additions & 0 deletions examples/nucleo_h723zg/can/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<library>
<extends>modm:nucleo-h723zg</extends>
<options>
<option name="modm:build:build.path">../../../build/nucleo_h723zg/can</option>
</options>
<modules>
<module>modm:debug</module>
<module>modm:platform:can:1</module>
<module>modm:platform:can:2</module>
<module>modm:platform:can:3</module>
<module>modm:build:scons</module>
</modules>
</library>
4 changes: 2 additions & 2 deletions src/modm/board/nucleo_h723zg/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ struct SystemClock

static constexpr uint32_t LpUart1 = Apb4;

static constexpr uint32_t Can1 = Apb1;
static constexpr uint32_t Can2 = Apb1;
static constexpr uint32_t Fdcan1 = Apb1;
static constexpr uint32_t Fdcan2 = Apb1;

static constexpr uint32_t I2c1 = Apb1;
static constexpr uint32_t I2c2 = Apb1;
Expand Down
4 changes: 2 additions & 2 deletions src/modm/board/nucleo_h743zi/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ struct SystemClock

static constexpr uint32_t LpUart1 = Apb4;

static constexpr uint32_t Can1 = Apb1;
static constexpr uint32_t Can2 = Apb1;
static constexpr uint32_t Fdcan1 = Apb1;
static constexpr uint32_t Fdcan2 = Apb1;

static constexpr uint32_t I2c1 = Apb1;
static constexpr uint32_t I2c2 = Apb1;
Expand Down
70 changes: 66 additions & 4 deletions src/modm/platform/can/stm32-fdcan/can.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@

namespace {

using MessageRam = modm::platform::fdcan::MessageRam<{{ id - 1 }}>;
using MessageRam = modm::platform::fdcan::MessageRam<
{{ id - 1 }},
modm::platform::fdcan::Fdcan{{id}}MessageRamConfig,
modm::platform::fdcan::Fdcan{{id}}MessageRamBaseWords>;

%% if options["buffer.tx"] > 0
modm::atomic::Queue<modm::can::Message, {{ options["buffer.tx"] }}> txQueue;
Expand Down Expand Up @@ -192,13 +195,67 @@ modm::platform::Fdcan{{ id }}::initializeWithPrescaler(

configureInterrupts(interruptPriority);

// Select RX FIFO blocking/overwrite mode
%% if target["family"] == "h7"
{{ reg }}->RXF0C = overwriteOnOverrun ? FDCAN_RXF0C_F0OM : 0;
{{ reg }}->RXF1C = overwriteOnOverrun ? FDCAN_RXF1C_F1OM : 0;
%% else
{{ reg }}->RXGFC = overwriteOnOverrun ? (FDCAN_RXGFC_F1OM | FDCAN_RXGFC_F0OM) : 0;
%% endif

// reject non-matching frames
%% if target["family"] == "h7"
{{ reg }}->GFC |= FDCAN_GFC_ANFE | FDCAN_GFC_ANFS;
%% else
{{ reg }}->RXGFC |= FDCAN_RXGFC_ANFE | FDCAN_RXGFC_ANFS;
%% endif


// enable all filters, reject non-matching frames
{{ reg }}->RXGFC |= FDCAN_RXGFC_LSE | FDCAN_RXGFC_LSS | FDCAN_RXGFC_ANFE | FDCAN_RXGFC_ANFS;
%% if target["family"] == "h7"
// Configure number of elements in each RAM section
{{ reg }}->SIDFC |= MessageRam::Config.standardFilterCount << FDCAN_SIDFC_LSS_Pos;
{{ reg }}->XIDFC |= MessageRam::Config.extendedFilterCount << FDCAN_XIDFC_LSE_Pos;
{{ reg }}->RXF0C |= MessageRam::Config.rxFifo0Elements << FDCAN_RXF0C_F0S_Pos;
{{ reg }}->RXF1C |= MessageRam::Config.rxFifo1Elements << FDCAN_RXF1C_F1S_Pos;
// NB: RX buffer has no size configuration register; a write index is put
// into filter settings if desired. We don't support RX buffers.
{{ reg }}->TXEFC |= MessageRam::Config.txEventFifoElements << FDCAN_TXEFC_EFS_Pos;
{{ reg }}->TXBC |= (MessageRam::Config.txFifoElements << FDCAN_TXBC_TFQS_Pos) | (0 << FDCAN_TXBC_NDTB_Pos);
// Trigger memory elements unused, left at 0 (only supported on FDCAN1)
// {{ reg }}->TTTMC |= 0 << FDCAN_TTTMC_TME_Pos;

// Configure number of message data bytes stored in each message entry (maximum length)
{{ reg }}->TXESC |= static_cast<uint32_t>(MessageRam::Config.txBufferDataBytesMax) << FDCAN_TXESC_TBDS_Pos;
{{ reg }}->RXESC |=
(static_cast<uint32_t>(MessageRam::Config.rxBufferDataBytesMax) << FDCAN_RXESC_RBDS_Pos)
| (static_cast<uint32_t>(MessageRam::Config.rxFifo0DataBytesMax) << FDCAN_RXESC_F0DS_Pos)
| (static_cast<uint32_t>(MessageRam::Config.rxFifo1DataBytesMax) << FDCAN_RXESC_F1DS_Pos);

// Configure base address of each RAM section
{{ reg }}->SIDFC |= (MessageRam::Offset + MessageRam::Config.standardFilterListSectionOffset()) << FDCAN_SIDFC_FLSSA_Pos;
{{ reg }}->XIDFC |= (MessageRam::Offset + MessageRam::Config.extendedFilterListSectionOffset()) << FDCAN_XIDFC_FLESA_Pos;
{{ reg }}->RXF0C |= (MessageRam::Offset + MessageRam::Config.rxFifo0SectionOffset()) << FDCAN_RXF0C_F0SA_Pos;
{{ reg }}->RXF1C |= (MessageRam::Offset + MessageRam::Config.rxFifo1SectionOffset()) << FDCAN_RXF1C_F1SA_Pos;
// {{ reg }}->RXBC |= 0 << FDCAN_RXBC_RBSA_Pos;
{{ reg }}->TXEFC |= (MessageRam::Offset + MessageRam::Config.txEventSectionOffset()) << FDCAN_TXEFC_EFSA_Pos;
{{ reg }}->TXBC |= (MessageRam::Offset + MessageRam::Config.txFifoSectionOffset()) << FDCAN_TXBC_TBSA_Pos;
// {{ reg }}->TTTMC |= 0 << FDCAN_TTTMC_TMSA_Pos;

static_assert(MessageRam::Config.txFifoSectionOffset() + MessageRam::Config.txFifoSectionWords() == MessageRam::Config.totalSectionWords());
static_assert(MessageRam::Offset + MessageRam::Config.totalSectionWords() <= {{message_ram_length_words}});

%% else
%# Series other than STM32H7 have a fixed message RAM layout.

// NB: Before STM32H7, LSS and LSE determined the number of enabled filters;
// other filters were present but ignored. In STM32H7, LSS and LSE determine
// how many filters are present in the RAM. For pre-STM32H7 series we use
// the max value and zero out (disable) all filters on initialization.
{{ reg }}->RXGFC |= (MessageRam::Config.standardFilterCount << FDCAN_RXGFC_LSS_Pos) | (MessageRam::Config.extendedFilterCount << FDCAN_RXGFC_LSE_Pos);
%%endif

// Tx buffer: queue mode
{{ reg }}->TXBC = FDCAN_TXBC_TFQM;
{{ reg }}->TXBC |= FDCAN_TXBC_TFQM;

// Enable bit rate switching and CANFD frame format
if(fdDataTimings) {
Expand Down Expand Up @@ -344,7 +401,12 @@ modm::platform::Fdcan{{ id }}::configureInterrupts(uint32_t interruptPriority)
// enable both interrupts lines (0 and 1)
{{ reg }}->ILE = FDCAN_ILE_EINT1 | FDCAN_ILE_EINT0;
// assign receive interrupts to line 1

%% if target["family"] == "h7"
{{ reg }}->ILS = (FDCAN_ILS_RF0LL | FDCAN_ILS_RF0FL | FDCAN_ILS_RF0NL) | (FDCAN_ILS_RF1LL | FDCAN_ILS_RF1FL | FDCAN_ILS_RF1NL);
%% else
{{ reg }}->ILS = (FDCAN_ILS_RXFIFO0 | FDCAN_ILS_RXFIFO1);
%% endif

{{ reg }}->IE = 0;
%% if options["buffer.tx"] > 0
Expand Down
34 changes: 30 additions & 4 deletions src/modm/platform/can/stm32-fdcan/can.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "can_bit_timings.hpp"
#include "message_ram.hpp"
#include "can_message_ram_config.hpp"

namespace modm::platform
{
Expand All @@ -33,18 +34,43 @@ namespace modm::platform
* a shared Message RAM memory and a configuration block.
* The modules (FDCAN) are compliant with ISO 11898-1: 2015 (CAN protocol
* specification version 2.0 part A, B) and CAN FD protocol specification version 1.0.
* A 0.8 Kbyte Message RAM per FDCAN instance implements filters, receive FIFOs,
* transmit event FIFOs and transmit FIFOs.
* A Message RAM implements filters, receive FIFOs, transmit event FIFOs and
* transmit FIFOs. The RAM is 0.8 Kbyte per FDCAN instance, except for the H7
* series, which has 10 Kbytes of total message RAM arbitrarily split between
* FDCAN instances.
*
* This driver supports SW-managed/in-memory FIFOs which augment the hardware TX
* and RX FIFOs. Note that the HW TX queue is set to "queue mode" (not "FIFO mode").
* This means CAN messages are popped from the in-memory FIFO in order of addition
* but arbitrated according to ID priority within the HW queue.
*
* ## Filter
%% if target["family"] == "h7"
* Up to 28 filters can be defined for 11-bit IDs, up to 8 filters for 29-bit IDs.
%% else
* Up to 128 filters can be defined for 11-bit IDs, up to 64 filters for 29-bit IDs.
* Space for these filters must be allocated in the message RAM via the parameters
* described below.
%% endif
* The filter banks are not shared between the CAN instances.
*
* ## Configuration
* You can set the buffer size using the `tx_buffer` and `rx_buffer` parameters.
* You can set the in-memory (SW-managed) buffer size using the `tx_buffer` and
* `rx_buffer` parameters. If set to 0, filling a HW FIFO will immediately drop
* frames.
*
%% if target["family"] == "h7"
* You can configure the message RAM space allocation as follows:
* - `message_ram.standard_filter_count`: Maximum number of standard (11-bit ID) acceptance filters
* - `message_ram.extended_filter_count`: Maximum number of extended (29-bit ID) acceptance filters
* - `message_ram.rx_fifo_0_elements` and `message_ram.rx_fifo_1_elements`:
* Number of received frames which can be queued by hardware in each RX FIFO
* - `message_ram.tx_fifo_elements`: Number of frames pending transmit which can be queued in hardware
*
%% endif
* @author Raphael Lehmann <[email protected]>
* @author Christopher Durand <[email protected]>
* @author Kaelin Laundry <[email protected]>
* @ingroup modm_platform_can_{{ id }}
*/
class Fdcan{{ id }} : public ::modm::Can
Expand Down Expand Up @@ -74,7 +100,7 @@ public:
using ErrorCallback = void (*)();

private:
using MessageRam = fdcan::MessageRam<{{ id - 1 }}>;
using MessageRam = fdcan::MessageRam<{{ id - 1 }}, fdcan::Fdcan{{id}}MessageRamConfig, fdcan::Fdcan{{id}}MessageRamBaseWords>;

static inline volatile ErrorCallback errorCallback_ = nullptr;

Expand Down
46 changes: 46 additions & 0 deletions src/modm/platform/can/stm32-fdcan/can_message_ram_config.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2024, Kaelin Laundry
*
* 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/.
*/
// ----------------------------------------------------------------------------


#ifndef MODM_STM32_FDCAN_MESSAGE_RAM_CONFIG_HPP
#define MODM_STM32_FDCAN_MESSAGE_RAM_CONFIG_HPP

namespace modm::platform::fdcan
{
%% for instance in instances
static constexpr MessageRamConfig Fdcan{{instance}}MessageRamConfig
{
// TODO: support configuring message size on H7 (for better space utilization)
.txBufferDataBytesMax = DataFieldSize::Bytes64,
.rxBufferDataBytesMax = DataFieldSize::Bytes64,
.rxFifo0DataBytesMax = DataFieldSize::Bytes64,
.rxFifo1DataBytesMax = DataFieldSize::Bytes64,

.standardFilterCount = {{message_ram_options["fdcan"+(instance|string)+".message_ram.standard_filter_count"]}},
.extendedFilterCount = {{message_ram_options["fdcan"+(instance|string)+".message_ram.extended_filter_count"]}},
.rxFifo0Elements = {{message_ram_options["fdcan"+(instance|string)+".message_ram.rx_fifo_0_elements"]}},
.rxFifo1Elements = {{message_ram_options["fdcan"+(instance|string)+".message_ram.rx_fifo_1_elements"]}},
.txEventFifoElements = 3, // Currently unused but must be allocated for non-H7 series fixed layout
.txFifoElements = {{message_ram_options["fdcan"+(instance|string)+".message_ram.tx_fifo_elements"]}},
};
%% endfor


%% for instance in instances
%% if loop.first
static constexpr uint32_t Fdcan{{instance}}MessageRamBaseWords = 0;
%% else
static constexpr uint32_t Fdcan{{instance}}MessageRamBaseWords = Fdcan{{instance-1}}MessageRamBaseWords + Fdcan{{instance-1}}MessageRamConfig.totalSectionWords();
%% endif
%% endfor
} // modm::platform::fdcan

#endif // MODM_STM32_FDCAN_MESSAGE_RAM_CONFIG_HPP
Loading

0 comments on commit 2f582ad

Please sign in to comment.