Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds port for Arduino stm32 core. #45

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions LocoNet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ uint8_t eeprom_read_byte(const uint8_t* offset) {
void eeprom_write_byte(const uint8_t* offset, uint8_t value) {
EEPROM.write((int)offset, value);
}
#elif defined(STM32F1)
#elif defined(STM32F1)
# include <FreeRTOS.h>
# include <task.h>
# include <libopencm3/stm32/gpio.h>
# include <cstdint>
#elif defined(ARDUINO_ARCH_STM32)
# include <cstdint>
#else
# include <avr/eeprom.h>
# include <avr/wdt.h>
Expand Down Expand Up @@ -154,7 +156,7 @@ void LocoNetClass::setTxPin(uint8_t txPin)
LnPortRegisterType bitMaskTest = 0x01;
LnPortRegisterType bitNum = 0;

LnPortRegisterType port = digitalPinToPort(txPin);
auto port = digitalPinToPort(txPin);
LnPortAddrType out = portOutputRegister(port);

while (bitMask != bitMaskTest)
Expand Down Expand Up @@ -618,7 +620,7 @@ void LocoNetThrottleClass::updateState(TH_STATE State, uint8_t ForceNotify)

void LocoNetThrottleClass::updateStatus1(uint8_t Status, uint8_t ForceNotify)
{
register uint8_t Mask; // Temporary uint8_t Variable for bitwise AND to force
uint8_t Mask; // Temporary uint8_t Variable for bitwise AND to force
// the compiler to only do 8 bit operations not 16

if (ForceNotify || myStatus1 != Status)
Expand Down Expand Up @@ -1428,7 +1430,7 @@ void LocoNetFastClockClass::process66msActions(void)
}
}

#if defined(STM32F1)
#if defined(STM32F1) || defined(ARDUINO_ARCH_STM32)
// STM31F1 has no EEPROM.
#else

Expand Down Expand Up @@ -1760,7 +1762,7 @@ SV_STATUS LocoNetSystemVariableClass::doDeferredProcessing(void)
return SV_OK;
}

#endif // STM32F1
#endif // STM32F1 || ARDUINO_ARCH_STM32


/*****************************************************************************
Expand Down
4 changes: 2 additions & 2 deletions LocoNet.h
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ class LocoNetFastClockClass
/************************************************************************************
SV (System Variable Handling
************************************************************************************/
#if defined(STM32F1)
#if defined(STM32F1) || defined(ARDUINO_ARCH_STM32)
// STM31F1 has no flash.
#else

Expand Down Expand Up @@ -490,7 +490,7 @@ class LocoNetSystemVariableClass
SV_STATUS doDeferredProcessing(void);
};

#endif // STM32F1
#endif // STM32F1 || ARDUINO_ARCH_STM32

class LocoNetCVClass
{
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ It's known to work with:
- MEGA (ATmega2560)
- Leonardo, LeoStick, Arduino Pro Micro (ATmega32U4)
- Various AVRTiny Boards (ATTiny84, ATTiny84A, ATTiny841)
- Blue Pill (STM32F1 w/ libopencm3 and Arduino Stubs)
- Blue Pill (STM32F1 w/ libopencm3 and Arduino Stubs, or STM32F3 with stm32duino core)
- NodeMCU v1.0 (ESP8266 core for Arduino)

As of 2020-03-28 - Hans Tanner added the capability to change the polarity
Expand Down
24 changes: 22 additions & 2 deletions utility/ln_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
// figure out what board we are building

// Common defines
#if !defined(STM32F1) && !defined(ESP8266)
#if !defined(STM32F1) && !defined(ARDUINO_ARCH_STM32) && !defined(ESP8266)
# ifdef PINL // For the Mega 2560 (should work with 1280, etc)
# define _LNET_USE_MEGA
# else // For the UNO:
Expand All @@ -72,7 +72,7 @@
# endif
#endif

#if defined(STM32F1)
#if defined(STM32F1) || defined(ARDUINO_ARCH_STM32)
typedef uint32_t LnPortRegisterType;
typedef uint32_t LnCompareTargetType;
#else
Expand All @@ -97,6 +97,9 @@ typedef volatile LnPortRegisterType* LnPortAddrType;
#else
# if defined(STM32F1)
# define LN_BIT_PERIOD (rcc_apb1_frequency * 2 / 16666)
# elif defined(ARDUINO_ARCH_STM32)
// TMR2 runs at half the CPU clock on the STM32F3.
# define LN_BIT_PERIOD (36000000 / 16666)
# else
# define LN_BIT_PERIOD (F_CPU / 16666)
# endif
Expand Down Expand Up @@ -209,6 +212,23 @@ defined(__AVR_ATmega1284P__)
#define LN_TMR_CONTROL_REG TCCR1B // the code.
#define LN_INIT_COMPARATOR() { TCCR1A = 0; TCCR1B = 0x01; } // no prescaler, normal mode

#elif defined(ARDUINO_ARCH_STM32)
// This architecture is used for the stm32 core in Arduino (aka stm32duino,
// also present in the boards manager under 'stm32'. The default settings
// are for an STM32F303RE (nucleo).

#define LN_RX_PIN_NAME PB14
#define LN_RX_PORT (*portInputRegister(GPIOB))
#define LN_RX_BIT (14)
#define LN_RX_BITCFG LL_SYSCFG_EXTI_LINE14
#define LN_RX_GPIOSEL EXTI_GPIOB
#define LN_RX_GPIOCFG LL_SYSCFG_EXTI_PORTB
#define LN_SB_SIGNAL EXTI15_10_IRQHandler
#define LN_SB_IRQn EXTI15_10_IRQn
#define LN_TMR_SIGNAL TIM2_IRQHandler

#define ISR(name) extern "C" void name(void)

#elif defined(STM32F1)

#define LN_RX_PIN_NAME PB14
Expand Down
86 changes: 80 additions & 6 deletions utility/ln_sw_uart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ extern "C" {
# include <libopencm3/stm32/gpio.h>
# include <libopencm3/stm32/rcc.h>
# include <libopencm3/stm32/timer.h>
#elif defined(ARDUINO_ARCH_STM32)
#include <Arduino.h>
#include <stm32yyxx_ll_system.h>
#include <stm32yyxx_ll_exti.h>
#include <stm32yyxx_ll_tim.h>
/// @todo
#else
# include <avr/io.h>
# include <avr/interrupt.h>
Expand Down Expand Up @@ -84,7 +90,7 @@ volatile uint8_t lnTxSuccess; // this boolean flag as a message from timer in
volatile uint8_t lnLastTxBit;
#endif

#ifndef ESP8266
#if !defined(ESP8266) && !defined(ARDUINO_ARCH_STM32)
volatile uint8_t* txPort;
#else
LnPortAddrType txPort;
Expand Down Expand Up @@ -131,7 +137,7 @@ bool ICACHE_RAM_ATTR isLocoNetCollision()
}
#endif

#if defined(STM32F1)
#if defined(STM32F1) || defined(ARDUINO_ARCH_STM32)
# define bit_is_set(PORT, PIN) (((PORT >> PIN) & 0x01) != 0)
# define bit_is_clear(PORT, PIN) (((PORT >> PIN) & 0x01) == 0)
#endif
Expand Down Expand Up @@ -160,6 +166,12 @@ ISR(LN_SB_SIGNAL)
// Ignore any interrupt that is not EXTI14.
return;
}
#elif defined(ARDUINO_ARCH_STM32)
// Check if it really was EXTI14 that triggered this interrupt.
if (!LL_EXTI_IsActiveFlag_0_31(1u<<LN_RX_BIT)) {
// Ignore any interrupt that is not EXTI14.
return;
}
#endif

#if defined(ESP8266)
Expand All @@ -178,6 +190,10 @@ ISR(LN_SB_SIGNAL)
lnCompareTarget = timer_get_counter(TIM2) + LN_TIMER_RX_START_PERIOD;
/* Set the initual output compare value for OC1. */
timer_set_oc_value(TIM2, TIM_OC1, lnCompareTarget);
# elif defined(ARDUINO_ARCH_STM32)
lnCompareTarget = LL_TIM_GetCounter(TIM2) + LN_TIMER_RX_START_PERIOD;
/* Set the initual output compare value for OC1. */
LL_TIM_OC_SetCompareCH1(TIM2, lnCompareTarget & 0xffff);
# else // Get the Current Timer1 Count and Add the offset for the Compare target
lnCompareTarget = LN_TMR_INP_CAPT_REG + LN_TIMER_RX_START_PERIOD;
LN_TMR_OUTP_CAPT_REG = lnCompareTarget;
Expand Down Expand Up @@ -228,8 +244,11 @@ ISR(LN_TMR_SIGNAL) /* signal handler for timer0 overflow */
#else
LN_CLEAR_TIMER_FLAG();
lnCompareTarget += LN_TIMER_RX_RELOAD_PERIOD;
# if defined(STM32F1)
# if defined(STM32F1)
timer_set_oc_value(TIM2, TIM_OC1, lnCompareTarget);
# elif defined(ARDUINO_ARCH_STM32)
lnCompareTarget &= 0xffff;
LL_TIM_OC_SetCompareCH1(TIM2, lnCompareTarget & 0xffff);
# else
LN_TMR_OUTP_CAPT_REG = lnCompareTarget;
# endif
Expand Down Expand Up @@ -345,6 +364,9 @@ ISR(LN_TMR_SIGNAL) /* signal handler for timer0 overflow */
# if defined(STM32F1)
lnCompareTarget = timer_get_counter(TIM2) + LN_TIMER_TX_RELOAD_PERIOD - LN_TIMER_TX_RELOAD_ADJUST;
timer_set_oc_value(TIM2, TIM_OC1, lnCompareTarget);
# elif defined(ARDUINO_ARCH_STM32)
lnCompareTarget = LL_TIM_GetCounter(TIM2) + LN_TIMER_TX_RELOAD_PERIOD - LN_TIMER_TX_RELOAD_ADJUST;
LL_TIM_OC_SetCompareCH1(TIM2, lnCompareTarget & 0xffff);
# else
lnCompareTarget = LN_TMR_COUNT_REG + LN_TIMER_TX_RELOAD_PERIOD - LN_TIMER_TX_RELOAD_ADJUST;
LN_TMR_OUTP_CAPT_REG = lnCompareTarget;
Expand Down Expand Up @@ -425,7 +447,7 @@ void initLocoNetHardware(LnBuf * RxBuffer)
// Set the RX line to Input
#if defined(ESP8266)
pinMode(LN_RX_PORT, INPUT);
#elif defined(STM32F1)
#elif defined(STM32F1) || defined(ARDUINO_ARCH_STM32)
pinMode(LN_RX_PIN_NAME, INPUT);
#else
cbi(LN_RX_DDR, LN_RX_BIT);
Expand Down Expand Up @@ -496,7 +518,51 @@ void initLocoNetHardware(LnBuf * RxBuffer)
exti_reset_request(EXTI14);
exti_enable_request(EXTI14);
nvic_enable_irq(NVIC_EXTI15_10_IRQ);
#elif defined(ARDUINO_ARCH_STM32)

// === Setup the timer ===

// Enable TIM2 clock.
__HAL_RCC_TIM2_CLK_ENABLE();

// Enable TIM2 interrupt.
NVIC_SetPriority(TIM2_IRQn, 0);
NVIC_EnableIRQ(TIM2_IRQn);

// Reset TIM2 peripheral to defaults.
__HAL_RCC_TIM2_FORCE_RESET();
asm("nop ; nop ; nop; ");
__HAL_RCC_TIM2_RELEASE_RESET();

// Initializes TIM2 timer to count at max speed.
TIM_HandleTypeDef TimHandle;
memset(&TimHandle, 0, sizeof(TimHandle));
TimHandle.Instance = TIM2;
TimHandle.Init.Period = 65535;
TimHandle.Init.Prescaler = 1;
TimHandle.Init.ClockDivision = 0;
TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
TimHandle.Init.RepetitionCounter = 0;
HAL_TIM_Base_Init(&TimHandle);
HAL_TIM_Base_Start(&TimHandle);
// Disables all interrupts on the timer.
TIM2->DIER = 0;

// Sets up level change interrupt on RX pin.
LL_SYSCFG_SetEXTISource(LN_RX_GPIOCFG, LN_RX_BITCFG);
# ifdef LN_SW_UART_RX_INVERTED
LL_EXTI_EnableRisingTrig_0_31(LN_EXTI_FLAG);
# else
LL_EXTI_EnableFallingTrig_0_31(LN_EXTI_FLAG);
# endif

lnState = LN_ST_IDLE;

LN_CLEAR_START_BIT_FLAG();
LN_ENABLE_START_BIT_INTERRUPT();
NVIC_SetPriority(LN_SB_IRQn, 0);
NVIC_EnableIRQ(LN_SB_IRQn);

#else
# ifdef LN_INIT_COMPARATOR
LN_INIT_COMPARATOR();
Expand Down Expand Up @@ -525,6 +591,8 @@ void initLocoNetHardware(LnBuf * RxBuffer)
# else
attachInterrupt(digitalPinToInterrupt(LN_RX_PORT), ln_esp8266_pin_isr, FALLING);
# endif
#elif defined(ARDUINO_ARCH_STM32)
// all of these already done above
#else
//Clear StartBit Interrupt flag
LN_CLEAR_START_BIT_FLAG();
Expand All @@ -538,7 +606,7 @@ void initLocoNetHardware(LnBuf * RxBuffer)

// Set Timer Clock Source
LN_TMR_CONTROL_REG = (LN_TMR_CONTROL_REG & 0xF8) | LN_TMR_PRESCALER;
#endif // STM32F1
#endif // STM32F1 || ARDUINO_ARCH_STM32
}


Expand Down Expand Up @@ -609,8 +677,10 @@ LN_STATUS sendLocoNetPacketTry(lnMsg * TxData, unsigned char ucPrioDelay)
#else
// Before we do anything else - Disable StartBit Interrupt
LN_DISABLE_START_BIT_INTERRUPT();
# if defined(STM32F1)
# if defined(STM32F1)
if (exti_get_flag_status(EXTI14)) {
# elif defined(ARDUINO_ARCH_STM32)
if (LL_EXTI_IsActiveFlag_0_31(1u<<LN_RX_BIT)) {
# else
if (bit_is_set(LN_SB_INT_STATUS_REG, LN_SB_INT_STATUS_BIT)) {
# endif
Expand Down Expand Up @@ -640,6 +710,10 @@ LN_STATUS sendLocoNetPacketTry(lnMsg * TxData, unsigned char ucPrioDelay)
lnCompareTarget = timer_get_counter(TIM2) + LN_TIMER_TX_RELOAD_PERIOD - LN_TIMER_TX_RELOAD_ADJUST;
/* Set the initual output compare value for OC1. */
timer_set_oc_value(TIM2, TIM_OC1, lnCompareTarget);
# elif defined(ARDUINO_ARCH_STM32)
lnCompareTarget = LL_TIM_GetCounter(TIM2) + LN_TIMER_TX_RELOAD_PERIOD - LN_TIMER_TX_RELOAD_ADJUST;
/* Set the initual output compare value for OC1. */
LL_TIM_OC_SetCompareCH1(TIM2, lnCompareTarget & 0xffff);
# else
lnCompareTarget = LN_TMR_COUNT_REG + LN_TIMER_TX_RELOAD_PERIOD - LN_TIMER_TX_RELOAD_ADJUST;
LN_TMR_OUTP_CAPT_REG = lnCompareTarget;
Expand Down
26 changes: 24 additions & 2 deletions utility/ln_sw_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

#ifdef ESP8266
# include <Arduino.h>
#elif !defined(STM32F1)
#elif !defined(STM32F1) && !defined(ARDUINO_ARCH_STM32)
# include <avr/io.h>
# include <avr/interrupt.h>
#endif
Expand Down Expand Up @@ -100,7 +100,28 @@
# define LN_ENABLE_TIMER_INTERRUPT() (timer_enable_irq(TIM2, TIM_DIER_CC1IE))
// Disable Timer Compare Interrupt
# define LN_DISABLE_TIMER_INTERRUPT() (timer_disable_irq(TIM2, TIM_DIER_CC1IE))
#elif !defined(ESP8266)

#elif defined(ARDUINO_ARCH_STM32)

# define LN_EXTI_FLAG (1u << LN_RX_BIT)
//Clear StartBit Interrupt flag
# define LN_CLEAR_START_BIT_FLAG() (LL_EXTI_ClearFlag_0_31(LN_EXTI_FLAG))
//Enable StartBit Interrupt
# define LN_ENABLE_START_BIT_INTERRUPT() (LL_EXTI_EnableIT_0_31(LN_EXTI_FLAG))
//Disable StartBit Interrupt
# define LN_DISABLE_START_BIT_INTERRUPT() (LL_EXTI_DisableIT_0_31(LN_EXTI_FLAG))

// Clear Timer Interrupt Flag
# define LN_CLEAR_TIMER_FLAG() (LL_TIM_ClearFlag_CC1(TIM2))

// Enable Timer Compare Interrupt
# define LN_ENABLE_TIMER_INTERRUPT() (LL_TIM_EnableIT_CC1(TIM2))
// Disable Timer Compare Interrupt
# define LN_DISABLE_TIMER_INTERRUPT() (LL_TIM_DisableIT_CC1(TIM2))

#elif defined(ESP8266)
// No common definitions needed for the ESP.
#else // AVR
//Clear StartBit Interrupt flag
# define LN_CLEAR_START_BIT_FLAG() (sbi( LN_SB_INT_STATUS_REG, LN_SB_INT_STATUS_BIT ))
//Enable StartBit Interrupt
Expand All @@ -117,6 +138,7 @@
# define LN_DISABLE_TIMER_INTERRUPT() (cbi( LN_TMR_INT_ENABLE_REG, LN_TMR_INT_ENABLE_BIT ))
#endif


// For now we will simply check that TX and RX ARE NOT THE SAME as our circuit
// requires the TX signal to be INVERTED. If they are THE SAME then we have a
// Collision.
Expand Down