From 05e5d614fffe9e4cb82d03b7593a41123ca3d55f Mon Sep 17 00:00:00 2001 From: Balazs Racz Date: Mon, 2 Aug 2021 22:17:00 +0200 Subject: [PATCH] Adds driver and hooks for sending railcom data out. (#551) This PR enables the dcc_decoder code to interact with a RailCom driver in a way that allows sending railcom data back to the track. - Adds the ability to adjust what timing the railcom driver gets called. This is expectedto change when we generate a cutout versus when we trigger the UART to send data. - adds calls to the RailcomDriver to specify the feedback to be sent - Ensures that railcom data only gets sent for the packet that it belongs to - Adds an STM32 implementation for the railcom send driver, which is derived from the Stm32Uart driver. - Adds a hook in the dcc_decode interrupt that calls an application provided module to compute what railcom feedback we should be sending. ==== * Adds a delta capability for tuning the railcom cutout timing. * Fixes up the compilation of the Tiva DCC decoder target. * Adds API for railcom sender implementation. * Adds railcom sender implementation for STM32. * Adds a call in the DCC interrupt to fill in the railcom feedback. * Adds the send functions to the railcom driver. * Fixes bugs in the stm32 railcom sender. * Removes unneeded forward declaration. --- .../HwInit.cxx | 18 +++ .../freertos.armv7m.ek-tm4c123gxl/HwInit.cxx | 17 +++ src/dcc/PacketProcessor.hxx | 54 ++++++++ src/freertos_drivers/common/DccDecoder.hxx | 33 ++++- src/freertos_drivers/common/RailcomDriver.hxx | 25 ++++ src/freertos_drivers/st/Stm32DCCDecoder.hxx | 18 +++ .../st/Stm32RailcomSender.cxx | 88 ++++++++++++ .../st/Stm32RailcomSender.hxx | 126 ++++++++++++++++++ src/freertos_drivers/st/Stm32Uart.hxx | 3 +- src/freertos_drivers/ti/TivaDCCDecoder.hxx | 18 +++ .../freertos_drivers/stm32cubef091xc/sources | 3 +- 11 files changed, 398 insertions(+), 5 deletions(-) create mode 100644 src/dcc/PacketProcessor.hxx create mode 100644 src/freertos_drivers/st/Stm32RailcomSender.cxx create mode 100644 src/freertos_drivers/st/Stm32RailcomSender.hxx diff --git a/applications/dcc_decoder/targets/freertos.armv6m.st-stm32f091rc-nucleo/HwInit.cxx b/applications/dcc_decoder/targets/freertos.armv6m.st-stm32f091rc-nucleo/HwInit.cxx index 2e7664bbd..d7811a4af 100644 --- a/applications/dcc_decoder/targets/freertos.armv6m.st-stm32f091rc-nucleo/HwInit.cxx +++ b/applications/dcc_decoder/targets/freertos.armv6m.st-stm32f091rc-nucleo/HwInit.cxx @@ -122,6 +122,24 @@ struct DccDecoderHW /// driver to take a feedback sample. static inline void after_feedback_hook() {} + /// How many usec later/earlier should the railcom cutout start happen. + static int time_delta_railcom_pre_usec() + { + return 0; + } + + /// How many usec later/earlier should the railcom cutout middle happen. + static int time_delta_railcom_mid_usec() + { + return 0; + } + + /// How many usec later/earlier should the railcom cutout end happen. + static int time_delta_railcom_end_usec() + { + return 0; + } + /// Second timer resource that will be used to measure microseconds for the /// railcom cutout. May be the same as the Capture Timer, if there are at /// least two channels on that timer resource. diff --git a/applications/dcc_decoder/targets/freertos.armv7m.ek-tm4c123gxl/HwInit.cxx b/applications/dcc_decoder/targets/freertos.armv7m.ek-tm4c123gxl/HwInit.cxx index 6471746e0..47389cb34 100644 --- a/applications/dcc_decoder/targets/freertos.armv7m.ek-tm4c123gxl/HwInit.cxx +++ b/applications/dcc_decoder/targets/freertos.armv7m.ek-tm4c123gxl/HwInit.cxx @@ -167,6 +167,23 @@ struct DCCDecode static inline void dcc_before_cutout_hook() {} static inline void dcc_packet_finished_hook() {} static inline void after_feedback_hook() {} + /// How many usec later/earlier should the railcom cutout start happen. + static int time_delta_railcom_pre_usec() + { + return 0; + } + + /// How many usec later/earlier should the railcom cutout middle happen. + static int time_delta_railcom_mid_usec() + { + return 0; + } + + /// How many usec later/earlier should the railcom cutout end happen. + static int time_delta_railcom_end_usec() + { + return 0; + } }; // Dummy implementation because we are not a railcom detector. diff --git a/src/dcc/PacketProcessor.hxx b/src/dcc/PacketProcessor.hxx new file mode 100644 index 000000000..96448cd2f --- /dev/null +++ b/src/dcc/PacketProcessor.hxx @@ -0,0 +1,54 @@ +/** \copyright + * Copyright (c) 2021, Balazs Racz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \file PacketProcessor.hxx + * + * Interface used for processing DCC packets to generate the feedback data. + * + * @author Balazs Racz + * @date 10 July 2021 + */ + +#include "dcc/packet.h" + +class RailcomDriver; + +namespace dcc +{ + +/// Abstract class that is used as a plugin in the DCC decoder. The application +/// logic can implement this class and it will be called from the +/// interrupt. This is necessary to correctly generate the RailCom feedback to +/// be sent back. +class PacketProcessor +{ +public: + /// Called in an OS interrupt with the arrived packet. + virtual void packet_arrived( + const DCCPacket *pkt, RailcomDriver *railcom) = 0; +}; + +} // namespace dcc diff --git a/src/freertos_drivers/common/DccDecoder.hxx b/src/freertos_drivers/common/DccDecoder.hxx index 6bd0d69ff..f66bc266b 100644 --- a/src/freertos_drivers/common/DccDecoder.hxx +++ b/src/freertos_drivers/common/DccDecoder.hxx @@ -35,6 +35,7 @@ #include "RailcomDriver.hxx" // for debug pins #include "dcc/Receiver.hxx" +#include "dcc/PacketProcessor.hxx" #include "dcc/packet.h" /** @@ -95,6 +96,14 @@ public: inputData_->destroy(); } + /// Installs a hook that will be called in the interrupt context for each + /// incoming packet. + /// @param p the hook interface to be called. + void set_packet_processor(dcc::PacketProcessor *p) + { + packetProcessor_ = p; + } + /** Handles a raw interrupt. */ inline void interrupt_handler() __attribute__((always_inline)); @@ -212,12 +221,17 @@ private: bool prepCutout_ = false; /// Which window of the cutout we are in. uint32_t cutoutState_; + /// Counts unique identifiers for DCC packets to be returned. + uint32_t packetId_ = 0; /// How many times did we lose a DCC packet due to no buffer available. //uint32_t overflowCount_ {0}; /// notified for cutout events. RailcomDriver *railcomDriver_; + /// notified for every arrived DCC / MM packet within the interrupt. + dcc::PacketProcessor* packetProcessor_ = nullptr; + /// DCC packet decoder state machine and internal state. dcc::DccDecoder decoder_ {Module::get_ticks_per_usec()}; @@ -302,6 +316,12 @@ __attribute__((optimize("-O3"))) void DccDecoder::interrupt_handler() if (decoder_.before_dcc_cutout()) { prepCutout_ = true; + auto* p = decoder_.pkt(); + if (p) + { + p->feedback_key = ++packetId_; + } + railcomDriver_->set_feedback_key(packetId_); Module::dcc_before_cutout_hook(); } // If we are at the second half of the last 1 bit and the @@ -314,7 +334,8 @@ __attribute__((optimize("-O3"))) void DccDecoder::interrupt_handler() { //Debug::RailcomDriverCutout::set(true); Module::set_cap_timer_time(); - Module::set_cap_timer_delay_usec(RAILCOM_CUTOUT_PRE); + Module::set_cap_timer_delay_usec( + RAILCOM_CUTOUT_PRE + Module::time_delta_railcom_pre_usec()); inCutout_ = true; cutoutState_ = 0; if (decoder_.pkt()) @@ -365,14 +386,16 @@ DccDecoder::rcom_interrupt_handler() { case 0: { - Module::set_cap_timer_delay_usec(RAILCOM_CUTOUT_MID); + Module::set_cap_timer_delay_usec( + RAILCOM_CUTOUT_MID + Module::time_delta_railcom_mid_usec()); railcomDriver_->start_cutout(); cutoutState_ = 1; break; } case 1: { - Module::set_cap_timer_delay_usec(RAILCOM_CUTOUT_END); + Module::set_cap_timer_delay_usec( + RAILCOM_CUTOUT_END + Module::time_delta_railcom_end_usec()); railcomDriver_->middle_cutout(); cutoutState_ = 2; break; @@ -396,6 +419,10 @@ __attribute__((optimize("-O3"))) void DccDecoder::os_interrupt_handler() unsigned woken = 0; if (nextPacketFilled_) { + if (packetProcessor_) + { + packetProcessor_->packet_arrived(decoder_.pkt(), railcomDriver_); + } inputData_->advance(1); nextPacketFilled_ = false; inputData_->signal_condition_from_isr(); diff --git a/src/freertos_drivers/common/RailcomDriver.hxx b/src/freertos_drivers/common/RailcomDriver.hxx index c09bbec3a..44a0f8a34 100644 --- a/src/freertos_drivers/common/RailcomDriver.hxx +++ b/src/freertos_drivers/common/RailcomDriver.hxx @@ -36,6 +36,11 @@ #ifndef _FREERTOS_DRIVERS_COMMON_RAILCOMDRIVER_HXX_ #define _FREERTOS_DRIVERS_COMMON_RAILCOMDRIVER_HXX_ +#include + +#include "utils/macros.h" +#include "dcc/railcom.h" + /// Abstract base class for railcom drivers. This interface is used to /// communicate when the railcom cutout happens. The railcom cutout is produced /// or detected in the DCC generator or DCC parser driver, but the railcom @@ -67,6 +72,26 @@ public: * shall be called before start_cutout. The feedback key set here is used * until this method is called again. @param key is the new feedback key. */ virtual void set_feedback_key(uint32_t key) = 0; + + /** Specifies what packet should be sent for the channel1 cutout. It is + * okay to specify the same packet pointer for ch1 and ch2 cutout. + * @param ch1_pkt the RailCom packet. Only the ch1 data will be read from + * this packet. This pointer must stay alive until the next DCC packet + * comes. The FeedbackKey in this packet must be correct for the current + * DCC packet or else the data will not be sent. */ + virtual void send_ch1(const DCCFeedback *ch1_pkt) + { + } + + /** Specifies what packet should be sent for the channel2 cutout. It is + * okay to specify the same packet pointer for ch1 and ch2 cutout. + * @param ch2_pkt the RailCom packet. Only the ch2 data will be read from + * this packet. This pointer must stay alive until the next DCC packet + * comes. The FeedbackKey in this packet must be correct for the current + * DCC packet or else the data will not be sent. */ + virtual void send_ch2(const DCCFeedback *ch2_pkt) + { + } }; diff --git a/src/freertos_drivers/st/Stm32DCCDecoder.hxx b/src/freertos_drivers/st/Stm32DCCDecoder.hxx index 79d9df173..c981901fe 100644 --- a/src/freertos_drivers/st/Stm32DCCDecoder.hxx +++ b/src/freertos_drivers/st/Stm32DCCDecoder.hxx @@ -175,6 +175,24 @@ public: HW::after_feedback_hook(); } + /// How many usec later should the railcom cutout start happen. + static int time_delta_railcom_pre_usec() + { + return HW::time_delta_railcom_pre_usec(); + } + + /// How many usec later should the railcom cutout middle happen. + static int time_delta_railcom_mid_usec() + { + return HW::time_delta_railcom_mid_usec(); + } + + /// How many usec later should the railcom cutout middle happen. + static int time_delta_railcom_end_usec() + { + return HW::time_delta_railcom_end_usec(); + } + /// Called from the capture interrupt handler. Checks interrupt status, /// clears interrupt. /// @return true if the interrupt was generated by a capture event. diff --git a/src/freertos_drivers/st/Stm32RailcomSender.cxx b/src/freertos_drivers/st/Stm32RailcomSender.cxx new file mode 100644 index 000000000..d90f5a667 --- /dev/null +++ b/src/freertos_drivers/st/Stm32RailcomSender.cxx @@ -0,0 +1,88 @@ +/** \copyright + * Copyright (c) 2021, Balazs Racz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \file Stm32RailcomSender.hxx + * + * Implements a RailcomDriver that sends outgoing railcom data through a UART + * TX on an STM32 target. Designed to be invoked from the priority zero + * interrupt of the DCC decoder. + * + * @author Balazs Racz + * @date July 10, 2021 + */ + +#include "freertos_drivers/st/Stm32RailcomSender.hxx" + +#include "stm32f_hal_conf.hxx" + +/// Called at the beginning of the first window. +void Stm32RailcomSender::start_cutout() +{ + const auto* pkt = ch1Pkt_; + if (!pkt || pkt->feedbackKey != expectedFeedbackKey_) + { + // Nothing to send or came too late and should not be sent. + return; + } + if (!__HAL_UART_GET_IT(&uartHandle, UART_IT_TXE)) { + // Transmission is not complete yet. That's weird. + return; + } + if (pkt->ch1Size == 0) { + // Nothing to send. + return; + } + uartHandle.Instance->TDR = pkt->ch1Data[0]; + if (pkt->ch1Size > 1) + { + txBuf->put(pkt->ch1Data + 1, 1); + __HAL_UART_ENABLE_IT(&uartHandle, UART_IT_TXE); + } +} + +void Stm32RailcomSender::middle_cutout() +{ + const auto* pkt = ch2Pkt_; + if (!pkt || pkt->feedbackKey != expectedFeedbackKey_) + { + // Nothing to send or came too late and should not be sent. + return; + } + if (!__HAL_UART_GET_IT(&uartHandle, UART_IT_TXE)) { + // Transmission is not complete yet. That's weird. + return; + } + if (pkt->ch2Size == 0) { + // Nothing to send. + return; + } + uartHandle.Instance->TDR = pkt->ch2Data[0]; + if (pkt->ch2Size > 1) + { + txBuf->put(pkt->ch2Data + 1, pkt->ch2Size - 1); + __HAL_UART_ENABLE_IT(&uartHandle, UART_IT_TXE); + } +} diff --git a/src/freertos_drivers/st/Stm32RailcomSender.hxx b/src/freertos_drivers/st/Stm32RailcomSender.hxx new file mode 100644 index 000000000..eeff2291b --- /dev/null +++ b/src/freertos_drivers/st/Stm32RailcomSender.hxx @@ -0,0 +1,126 @@ +/** \copyright + * Copyright (c) 2021, Balazs Racz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \file Stm32RailcomSender.hxx + * + * Implements a RailcomDriver that sends outgoing railcom data through a UART + * TX on an STM32 target. Designed to be invoked from the priority zero + * interrupt of the DCC decoder. + * + * @author Balazs Racz + * @date July 10, 2021 + */ + +#include "freertos_drivers/common/RailcomDriver.hxx" +#include "dcc/railcom.h" +#include "freertos_drivers/st/Stm32Uart.hxx" + +class Stm32RailcomSender : public RailcomDriver, protected Stm32Uart +{ +public: + Stm32RailcomSender( + const char *name, USART_TypeDef *base, IRQn_Type interrupt) + : Stm32Uart(name, base, interrupt) + { + } + +public: + /// Specifies what packet should be sent for the channel1 cutout. It is + /// okay to specify the same packet pointer for ch1 and ch2 cutout. + /// @param ch1_pkt the RailCom packet. Only the ch1 data will be read from + /// this packet. This pointer must stay alive until the next DCC packet + /// comes. The FeedbackKey in this packet must be correct for the current + /// DCC packet or else the data will not be sent. + void send_ch1(const DCCFeedback *ch1_pkt) override + { + ch1Pkt_ = ch1_pkt; + } + + /// Specifies what packet should be sent for the channel2 cutout. It is + /// okay to specify the same packet pointer for ch1 and ch2 cutout. + /// @param ch2_pkt the RailCom packet. Only the ch2 data will be read from + /// this packet. This pointer must stay alive until the next DCC packet + /// comes. The FeedbackKey in this packet must be correct for the current + /// DCC packet or else the data will not be sent. + void send_ch2(const DCCFeedback *ch2_pkt) override + { + ch2Pkt_ = ch2_pkt; + } + + ssize_t write(File *file, const void *buf, size_t count) override + { + // We do not support writing through the regular posix API. + return -EIO; + } + + ssize_t read(File *file, void *buf, size_t count) override + { + // We do not support reading through the regular posix API. + return -EIO; + } + +private: + // ======= DCC driver API ======== + /// No implementation needed. + void feedback_sample() override + { + } + /// Called at the beginning of the first window. + void start_cutout() override; + /// Called at the beginning of the middle window. + void middle_cutout() override; + /// Called after the cutout is over. + void end_cutout() override { + // We throw away the packets that we got given. + //ch1Pkt_ = nullptr; + //ch2Pkt_ = nullptr; + } + /// Called instead of start/mid/end-cutout at the end of the current packet + /// if there was no cutout requested. + void no_cutout() override + { + // We throw away the packets that we got given. + //ch1Pkt_ = nullptr; + //ch2Pkt_ = nullptr; + } + /// Feedback key is set by the DCC decoder driver. The feedback packet must + /// carry the same feedback key or else it will not be transmitted. + void set_feedback_key(uint32_t key) override + { + expectedFeedbackKey_ = key; + } + +private: + /// What should be the feedback key in the packet. This value comes from + /// the DCC driver and is compared to the RailCom packets we should be + /// sending at the beginning of the cutout windows. + uintptr_t expectedFeedbackKey_ = 0; + + /// The packet to send in channel 1. Externally owned. + const DCCFeedback *ch1Pkt_ = nullptr; + /// The packet to send in channel 2. Externally owned. + const DCCFeedback *ch2Pkt_ = nullptr; +}; diff --git a/src/freertos_drivers/st/Stm32Uart.hxx b/src/freertos_drivers/st/Stm32Uart.hxx index 0ff8c87a9..aa403d9c8 100644 --- a/src/freertos_drivers/st/Stm32Uart.hxx +++ b/src/freertos_drivers/st/Stm32Uart.hxx @@ -67,7 +67,7 @@ public: * include/freertos/tc_ioctl.h */ int ioctl(File *file, unsigned long int key, unsigned long data) override; -private: +protected: void enable() override; /**< function to enable device */ void disable() override; /**< function to disable device */ @@ -115,6 +115,7 @@ private: static Stm32Uart *instances[8]; #endif +private: /** Default constructor. */ Stm32Uart(); diff --git a/src/freertos_drivers/ti/TivaDCCDecoder.hxx b/src/freertos_drivers/ti/TivaDCCDecoder.hxx index 4b762d49a..74203105a 100644 --- a/src/freertos_drivers/ti/TivaDCCDecoder.hxx +++ b/src/freertos_drivers/ti/TivaDCCDecoder.hxx @@ -136,6 +136,24 @@ public: HW::after_feedback_hook(); } + /// How many usec later should the railcom cutout start happen. + static int time_delta_railcom_pre_usec() + { + return HW::time_delta_railcom_pre_usec(); + } + + /// How many usec later should the railcom cutout middle happen. + static int time_delta_railcom_mid_usec() + { + return HW::time_delta_railcom_mid_usec(); + } + + /// How many usec later should the railcom cutout middle happen. + static int time_delta_railcom_end_usec() + { + return HW::time_delta_railcom_end_usec(); + } + /// Called from the capture interrupt handler. Checks interrupt status, /// clears interrupt. /// @return true if the interrupt was generated by a capture event. diff --git a/targets/freertos.armv6m/freertos_drivers/stm32cubef091xc/sources b/targets/freertos.armv6m/freertos_drivers/stm32cubef091xc/sources index e7308f35f..6f2189d68 100644 --- a/targets/freertos.armv6m/freertos_drivers/stm32cubef091xc/sources +++ b/targets/freertos.armv6m/freertos_drivers/stm32cubef091xc/sources @@ -49,7 +49,8 @@ CSRCS += stm32f0xx_hal.c \ CXXSRCS += Stm32Can.cxx \ Stm32Uart.cxx \ Stm32SPI.cxx \ - Stm32EEPROMEmulation.cxx + Stm32EEPROMEmulation.cxx \ + Stm32RailcomSender.cxx # for some reason, -0s changes the behavior of HAL_FLASHEx_Erase() and # doesn't perform the erase.