36#ifndef _FREERTOS_DRIVERS_ST_STM32RAILCOM_HXX_
37#define _FREERTOS_DRIVERS_ST_STM32RAILCOM_HXX_
41#include "freertos_drivers/common/RailcomImpl.hxx"
43#if defined(STM32F072xB) || defined(STM32F091xC)
44#include "stm32f0xx_ll_dma.h"
45#include "stm32f0xx_ll_usart.h"
46#elif defined(STM32F103xB)
47#include "stm32f1xx_ll_dma.h"
48#include "stm32f1xx_ll_usart.h"
49#elif defined(STM32F303xC) || defined(STM32F303xE)
50#include "stm32f3xx_ll_dma.h"
51#include "stm32f3xx_ll_usart.h"
52#elif defined(STM32L431xx) || defined(STM32L432xx)
53#include "stm32l4xx_ll_dma.h"
54#include "stm32l4xx_ll_usart.h"
55#elif defined(STM32F767xx)
56#include "stm32f7xx_ll_dma.h"
57#include "stm32f7xx_ll_usart.h"
59#error Dont know what STM32 chip you have.
135 static uint8_t sample() {
137 if (!CH1_Pin::get()) ret |= 1;
138 if (!CH2_Pin::get()) ret |= 2;
139 if (!CH3_Pin::get()) ret |= 4;
140 if (!CH4_Pin::get()) ret |= 8;
145// The weak attribute is needed if the definition is put into a header file.
146const uint32_t RailcomHw::UART[] __attribute__((weak)) = { USART4_BASE,
147USART1_BASE, USART3_BASE, USART2_BASE };
149const RailcomDmaChannel RailcomHw::DMA[] __attribute__((weak)) = {
150DMA1_Channel1_BASE, DMA1_Channel3_BASE, DMA1_Channel6_BASE, DMA1_Channel5_BASE
153In hw_preinit(), we have this for DMA channel routing:
154 //DMA channel routing for railcom UARTs
155 MODIFY_REG(DMA1->CSELR, DMA_CSELR_C1S_Msk, DMA1_CSELR_CH1_USART4_RX);
156 MODIFY_REG(DMA1->CSELR, DMA_CSELR_C3S_Msk, DMA1_CSELR_CH3_USART1_RX);
157 MODIFY_REG(DMA1->CSELR, DMA_CSELR_C6S_Msk, DMA1_CSELR_CH3_USART3_RX);
158 MODIFY_REG(DMA1->CSELR, DMA_CSELR_C5S_Msk, DMA1_CSELR_CH3_USART2_RX);
174 SetInterruptPriority(HW::OS_INTERRUPT, configKERNEL_INTERRUPT_PRIORITY);
176 SetInterruptPriority(HW::OS_INTERRUPT, 0xff);
178 HAL_NVIC_EnableIRQ(HW::OS_INTERRUPT);
183 HAL_NVIC_DisableIRQ(HW::OS_INTERRUPT);
194 static constexpr USART_TypeDef *
uart(
unsigned i)
196 return HW::UART[i].Instance;
201 static constexpr DMA_Channel_TypeDef *
dma_ch(
unsigned i)
203 return HW::DMA[i].Instance;
210 HAL_NVIC_SetPendingIRQ((IRQn_Type)int_nr);
216 for (
unsigned i = 0; i < HW::CHANNEL_COUNT; ++i)
218 UART_HandleTypeDef uart_handle;
219 memset(&uart_handle, 0,
sizeof(uart_handle));
220 uart_handle.Init.BaudRate = 250000;
221 uart_handle.Init.WordLength = UART_WORDLENGTH_8B;
222 uart_handle.Init.StopBits = UART_STOPBITS_1;
223 uart_handle.Init.Parity = UART_PARITY_NONE;
224 uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
225 uart_handle.Init.Mode = UART_MODE_RX;
226 uart_handle.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
227 uart_handle.Instance =
uart(i);
228 HAL_UART_DeInit(&uart_handle);
229 volatile auto ret = HAL_UART_Init(&uart_handle);
233 LL_USART_SetTransferDirection(
uart(i), LL_USART_DIRECTION_NONE);
245 uint32_t config = LL_DMA_DIRECTION_PERIPH_TO_MEMORY |
246 LL_DMA_MODE_NORMAL | LL_DMA_PERIPH_NOINCREMENT |
247 LL_DMA_MEMORY_INCREMENT | LL_DMA_PDATAALIGN_BYTE |
248 LL_DMA_MDATAALIGN_BYTE | LL_DMA_PRIORITY_HIGH;
249 MODIFY_REG(
dma_ch(i)->CCR,
250 DMA_CCR_DIR | DMA_CCR_MEM2MEM | DMA_CCR_CIRC | DMA_CCR_PINC |
251 DMA_CCR_MINC | DMA_CCR_PSIZE | DMA_CCR_MSIZE | DMA_CCR_PL |
252 DMA_CCR_TCIE | DMA_CCR_HTIE | DMA_CCR_TEIE,
255 LL_USART_Enable(
uart(i));
260 for (
unsigned i = 0; i < HW::CHANNEL_COUNT; ++i)
262 LL_USART_Disable(
uart(i));
269 HW::enable_measurement(
true);
271 HW::disable_measurement();
276 HW::enable_measurement(
false);
277 const bool need_ch1_cutout =
279 Debug::RailcomRxActivate::set(
true);
280 for (
unsigned i = 0; i < HW::CHANNEL_COUNT; ++i)
282 while (LL_USART_IsActiveFlag_RXNE(
uart(i)))
284 uint8_t data =
uart(i)->RDR;
290 LL_USART_EnableDMAReq_RX(
uart(i));
291 LL_USART_SetTransferDirection(
uart(i), LL_USART_DIRECTION_RX);
292 LL_USART_ClearFlag_FE(
uart(i));
293 LL_USART_Enable(
uart(i));
297 dma_ch(i)->CCR |= DMA_CCR_EN;
300 Debug::RailcomDriverCutout::set(
true);
305 Debug::RailcomDriverCutout::set(
false);
306 for (
unsigned i = 0; i < HW::CHANNEL_COUNT; ++i)
312 LL_USART_Disable(
uart(i));
313 CLEAR_BIT(
dma_ch(i)->CCR, DMA_CCR_EN);
318 Debug::RailcomError::toggle();
322 Debug::RailcomDataReceived::toggle();
323 Debug::RailcomAnyData::set(
true);
326 if (LL_USART_IsActiveFlag_FE(
uart(i)))
336 LL_USART_SetTransferDirection(
uart(i), LL_USART_DIRECTION_NONE);
337 LL_USART_ClearFlag_FE(
uart(i));
338 Debug::RailcomError::toggle();
347 dma_ch(i)->CCR |= DMA_CCR_EN;
349 LL_USART_SetTransferDirection(
uart(i), LL_USART_DIRECTION_RX);
350 LL_USART_ClearFlag_FE(
uart(i));
351 LL_USART_Enable(
uart(i));
353 HW::middle_cutout_hook();
354 Debug::RailcomDriverCutout::set(
true);
359 HW::disable_measurement();
360 bool have_packets =
false;
361 for (
unsigned i = 0; i < HW::CHANNEL_COUNT; ++i)
363 LL_USART_Disable(
uart(i));
368 CLEAR_BIT(
dma_ch(i)->CCR, DMA_CCR_EN);
373 Debug::RailcomDataReceived::toggle();
374 Debug::RailcomAnyData::set(
true);
375 Debug::RailcomCh2Data::set(
true);
377 if (LL_USART_IsActiveFlag_FE(
uart(i)))
379 Debug::RailcomError::toggle();
380 LL_USART_ClearFlag_FE(
uart(i));
387 LL_USART_SetTransferDirection(
uart(i), LL_USART_DIRECTION_NONE);
389 Debug::RailcomPackets::toggle();
393 HAL_NVIC_SetPendingIRQ(HW::OS_INTERRUPT);
395 Debug::RailcomRxActivate::set(
false);
404 Debug::RailcomPackets::toggle();
405 HAL_NVIC_SetPendingIRQ(HW::OS_INTERRUPT);
408 Debug::RailcomCh2Data::set(
false);
409 Debug::RailcomDriverCutout::set(
false);
420 Debug::RailcomPackets::toggle();
421 HAL_NVIC_SetPendingIRQ(HW::OS_INTERRUPT);
void commit_back()
Commits the oldest entry reserved by noncommit_back.
Base class for railcom drivers.
dcc::Feedback * returnedPackets_[HW::CHANNEL_COUNT]
Stores pointers to packets we are filling right now, one for each channel.
uint32_t feedbackKey_
Stores the key for the next packets to read.
dcc::Feedback * alloc_new_packet(uint8_t channel)
Takes a new empty packet at the front of the queue, fills in feedback key and channel information.
void add_sample(int sample)
Adds a sample for a preamble bit.
FixedQueue< dcc::Feedback, HW::Q_SIZE > feedbackQueue_
The packets we have read so far.
Railcom driver for STM32-class microcontrollers using the HAL middleware library.
bool inCutout_
True when we are currently within a cutout.
static constexpr DMA_Channel_TypeDef * dma_ch(unsigned i)
void disable() override
This will be called when reference count goes from non-zero to 0.
void int_set_pending(unsigned int_nr) override
Sets a given software interrupt pending.
void no_cutout() override
Called instead of start/mid/end-cutout at the end of the current packet if there was no cutout reques...
void feedback_sample() override
Call to the driver for sampling the current sensors.
static constexpr USART_TypeDef * uart(unsigned i)
void middle_cutout() override
Notifies the driver that the railcom cutout has reached the middle point, i.e., the first window is p...
void start_cutout() override
Instructs the driver that the railcom cutout is starting now.
void end_cutout() override
Instructs the driver that the railcom cutout is over now.
Stm32RailcomDriver(const char *path)
Constructor.
void enable() OVERRIDE
This will be called once when reference-count goes from 0 to positive.
#define OVERRIDE
Function attribute for virtual functions declaring that this funciton is overriding a funciton that s...
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
uint8_t ch2Size
Number of bytes in channel two.
uint8_t ch1Size
Number of bytes in channel one.
uint8_t ch1Data[2]
Payload of channel 1.
This struct helps casting the DMA channel base addresses to the appropriate type.
DMA_Channel_TypeDef * Instance
Use this to access the registers.
uint32_t baseAddress
Initialized by the constants from the processor header like USART1_BASE.
This struct helps casting the UART base addresses to the appropriate type.
USART_TypeDef * Instance
Use this to access the registers.
uint32_t baseAddress
Initialized by the constants from the processor header like USART1_BASE.
void add_ch2_data(uint8_t data)
Appends a byte to the channel 2 payload.