From cde5d8f7c3e56e5a65ed5f3b4f7c575734cabfa5 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 25 Mar 2017 19:01:31 +0000 Subject: [PATCH] Add STM32F1 HW support (#795) --- MyConfig.h | 25 +++--- MySensors.h | 4 + core/MyHwSTM32F1.cpp | 174 ++++++++++++++++++++++++++++++++++++++++ core/MyHwSTM32F1.h | 69 ++++++++++++++++ core/MyMainSTM32F1.cpp | 45 +++++++++++ drivers/RFM69/RFM69.cpp | 5 +- drivers/RFM69/RFM69.h | 29 ++++++- library.properties | 2 +- 8 files changed, 339 insertions(+), 14 deletions(-) create mode 100644 core/MyHwSTM32F1.cpp create mode 100644 core/MyHwSTM32F1.h create mode 100644 core/MyMainSTM32F1.cpp diff --git a/MyConfig.h b/MyConfig.h index 512d193..5c2d1e7 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -529,6 +529,8 @@ #define MY_RF24_CS_PIN 3 #elif defined(LINUX_ARCH_RASPBERRYPI) #define MY_RF24_CS_PIN 24 +#elif defined(ARDUINO_ARCH_STM32F1) +#define MY_RF24_CS_PIN SS #else #define MY_RF24_CS_PIN 10 #endif @@ -679,6 +681,14 @@ #define MY_RF69_IRQ_PIN RF69_IRQ_PIN #endif +/** +* @def MY_RF69_IRQ_NUM +* @brief RF69 IRQ pin number. +*/ +#ifndef MY_RF69_IRQ_NUM +#define MY_RF69_IRQ_NUM RF69_IRQ_NUM +#endif + /** * @def MY_RF69_SPI_CS * @brief RF69 SPI chip select pin. @@ -687,16 +697,13 @@ #define MY_RF69_SPI_CS RF69_SPI_CS #endif + /** - * @def MY_RF69_IRQ_NUM - * @brief RF69 IRQ pin number. - */ -#ifndef MY_RF69_IRQ_NUM -#if defined(ARDUINO_ARCH_ESP8266) -#define MY_RF69_IRQ_NUM RF69_IRQ_PIN -#else -#define MY_RF69_IRQ_NUM RF69_IRQ_NUM -#endif +* @def MY_RF69_SPI_CLOCK_DIV +* @brief RF69 SPI Clock divider. +*/ +#ifndef MY_RF69_SPI_CLOCK_DIV +#define MY_RF69_SPI_CLOCK_DIV RF69_SPI_CLOCK_DIV #endif // Enables RFM69 encryption (all nodes and gateway must have this enabled, and all must be personalized with the same AES key) diff --git a/MySensors.h b/MySensors.h index 86834ce..bb67f22 100644 --- a/MySensors.h +++ b/MySensors.h @@ -66,6 +66,8 @@ #elif defined(ARDUINO_ARCH_SAMD) #include "drivers/extEEPROM/extEEPROM.cpp" #include "core/MyHwSAMD.cpp" +#elif defined(ARDUINO_ARCH_STM32F1) +#include "core/MyHwSTM32F1.cpp" #elif defined(__linux__) #include "core/MyHwLinuxGeneric.cpp" #endif @@ -341,6 +343,8 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #include "core/MyMainESP8266.cpp" #elif defined(__linux__) #include "core/MyMainLinux.cpp" +#elif defined(ARDUINO_ARCH_STM32F1) +#include "core/MyMainSTM32F1.cpp" #else #include "core/MyMainDefault.cpp" #endif diff --git a/core/MyHwSTM32F1.cpp b/core/MyHwSTM32F1.cpp new file mode 100644 index 0000000..9c93cc4 --- /dev/null +++ b/core/MyHwSTM32F1.cpp @@ -0,0 +1,174 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyHwSTM32F1.h" +#include + + +/* +* Pinout STM32F103C8 dev board: +* http://wiki.stm32duino.com/images/a/ae/Bluepillpinout.gif +* +* Wiring RFM69 radio / SPI1 +* -------------------------------------------------- +* CLK PA5 +* MISO PA6 +* MOSI PA7 +* CSN PA4 +* CE NA +* IRQ PA3 (default) +* +* Wiring RFM69 radio / SPI1 +* -------------------------------------------------- +* CLK PA5 +* MISO PA6 +* MOSI PA7 +* CSN PA4 +* CE PB0 (default) +* IRQ NA +* +*/ +bool hwInit(void) +{ +#if !defined(MY_DISABLED_SERIAL) + Serial.begin(MY_BAUD_RATE); +#endif + if (EEPROM.init() == EEPROM_OK) { + + uint16 cnt; + EEPROM.count(&cnt); + if(cnt>=EEPROM.maxcount()) { + // tmp, WIP: format eeprom if full + EEPROM.format(); + } + return true; + } + return false; +} + +void hwReadConfigBlock(void* buf, void* addr, size_t length) +{ + uint8_t* dst = static_cast(buf); + int pos = reinterpret_cast(addr); + while (length-- > 0) { + *dst++ = EEPROM.read(pos++); + } +} + +void hwWriteConfigBlock(void* buf, void* addr, size_t length) +{ + uint8_t* src = static_cast(buf); + int pos = reinterpret_cast(addr); + while (length-- > 0) { + EEPROM.write(pos++, *src++); + } +} + +uint8_t hwReadConfig(const int addr) +{ + uint8_t value; + hwReadConfigBlock(&value, reinterpret_cast(addr), 1); + return value; +} + +void hwWriteConfig(const int addr, uint8_t value) +{ + hwWriteConfigBlock(&value, reinterpret_cast(addr), 1); +} + +int8_t hwSleep(unsigned long ms) +{ + // TODO: Not supported! + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; +} + +int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) +{ + // TODO: Not supported! + (void)interrupt; + (void)mode; + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; +} + +int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, + unsigned long ms) +{ + // TODO: Not supported! + (void)interrupt1; + (void)mode1; + (void)interrupt2; + (void)mode2; + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; +} + +bool hwUniqueID(unique_id_t* uniqueID) +{ + (void)memcpy((uint8_t*)uniqueID, (uint32_t*)0x1FFFF7E0, 16); + return true; +} + +uint16_t hwCPUVoltage() +{ + adc_reg_map *regs = ADC1->regs; + regs->CR2 |= ADC_CR2_TSVREFE; // enable VREFINT and temp sensor + regs->SMPR1 = ADC_SMPR1_SMP17; // sample rate for VREFINT ADC channel + return 1200 * 4096 / adc_read(ADC1, 17); +} + +uint16_t hwCPUFrequency() +{ + return F_CPU/100000UL; +} + +uint16_t hwFreeMem() +{ + //Not yet implemented + return 0; +} + +void hwDebugPrint(const char *fmt, ...) +{ + char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; +#ifdef MY_GATEWAY_FEATURE + // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) + snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;%lu "), C_INTERNAL, I_LOG_MESSAGE, + hwMillis()); + MY_SERIALDEVICE.print(fmtBuffer); +#else + // prepend timestamp + MY_SERIALDEVICE.print(hwMillis()); + MY_SERIALDEVICE.print(" "); +#endif + va_list args; + va_start(args, fmt); +#ifdef MY_GATEWAY_FEATURE + // Truncate message if this is gateway node + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); + fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; + fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; +#else + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); +#endif + va_end(args); + MY_SERIALDEVICE.print(fmtBuffer); + MY_SERIALDEVICE.flush(); +} \ No newline at end of file diff --git a/core/MyHwSTM32F1.h b/core/MyHwSTM32F1.h new file mode 100644 index 0000000..43d0f77 --- /dev/null +++ b/core/MyHwSTM32F1.h @@ -0,0 +1,69 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyHwSTM32F1_h +#define MyHwSTM32F1_h + +#include "MyHw.h" + +#include +#include + +#ifdef __cplusplus +#include +#endif + +// mapping +#define snprintf_P snprintf +#define vsnprintf_P vsnprintf + + +// emulated EEPROM (experimental) +#define EEPROM_PAGE_SIZE (uint16_t)1024 +#define EEPROM_SIZE (uint16_t)2048 +#define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 128 * EEPROM_PAGE_SIZE - 2 * EEPROM_PAGE_SIZE)) + + +#ifndef MY_SERIALDEVICE +#define MY_SERIALDEVICE Serial +#endif + +// Define these as macros to save valuable space +#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) +#define hwDigitalRead(__pin) digitalRead(__pin) +#define hwPinMode(__pin, __value) pinMode(__pin, __value) +#define hwWatchdogReset() iwdg_feed() +#define hwReboot() nvic_sys_reset() +#define hwMillis() millis() +void (*serialEventRun)() = NULL; + +bool hwInit(void); +void hwReadConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfig(const int addr, uint8_t value); +uint8_t hwReadConfig(const int addr); + + +#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) + +#ifndef DOXYGEN +#define MY_CRITICAL_SECTION +#endif /* DOXYGEN */ + +#endif diff --git a/core/MyMainSTM32F1.cpp b/core/MyMainSTM32F1.cpp new file mode 100644 index 0000000..c529f64 --- /dev/null +++ b/core/MyMainSTM32F1.cpp @@ -0,0 +1,45 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +// Initialize library and handle sketch functions like we want to + +extern "C" void __libc_init_array(void); + +// Force init to be called *first*, i.e. before static object allocation. +// Otherwise, statically allocated objects that need libmaple may fail. +__attribute__(( constructor (101))) void premain() +{ + init(); +} + +int main(void) +{ + _begin(); + + for(;;) { + _process(); + if (loop) { + loop(); + } + if (serialEventRun) { + serialEventRun(); + } + } + return 0; +} \ No newline at end of file diff --git a/drivers/RFM69/RFM69.cpp b/drivers/RFM69/RFM69.cpp index a9520a9..d4de967 100644 --- a/drivers/RFM69/RFM69.cpp +++ b/drivers/RFM69/RFM69.cpp @@ -90,6 +90,8 @@ bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) hwDigitalWrite(_slaveSelectPin, HIGH); hwPinMode(_slaveSelectPin, OUTPUT); + hwPinMode(_interruptPin, INPUT); + SPI.begin(); unsigned long start = millis(); uint8_t timeout = 50; @@ -500,8 +502,7 @@ void RFM69::select() // set RFM69 SPI settings SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); - SPI.setClockDivider( - SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present + SPI.setClockDivider(MY_RF69_SPI_CLOCK_DIV); hwDigitalWrite(_slaveSelectPin, LOW); } diff --git a/drivers/RFM69/RFM69.h b/drivers/RFM69/RFM69.h index cb6c697..c18659d 100644 --- a/drivers/RFM69/RFM69.h +++ b/drivers/RFM69/RFM69.h @@ -31,6 +31,7 @@ #ifndef RFM69_h #define RFM69_h #include // assumes Arduino IDE v1.0 or greater +#include #define RF69_MAX_DATA_LEN 61 // to take advantage of the built in AES/CRC we want to limit the frame size to the internal FIFO size (66 bytes - 3 bytes overhead - 2 bytes crc) #define RF69_SPI_CS SS // SS is the SPI slave select pin, for instance D10 on ATmega328 @@ -45,14 +46,39 @@ #elif defined(__AVR_ATmega32U4__) #define RF69_IRQ_PIN 3 #define RF69_IRQ_NUM 0 -#elif defined(__arm__)//Use pin 10 or any pin you want +#elif defined(__STM32F1__) +#define RF69_IRQ_PIN PA3 +#define RF69_IRQ_NUM PA3 +#elif defined(__arm__) //generic ARM #define RF69_IRQ_PIN 10 #define RF69_IRQ_NUM 10 +#elif defined(ARDUINO_ARCH_ESP8266) +#define RF69_IRQ_PIN 2 +#define RF69_IRQ_NUM 2 #else #define RF69_IRQ_PIN 2 #define RF69_IRQ_NUM 0 #endif +// SPI clock@2-4Mhz +#if (F_CPU>=512000000) +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV256 +#elif (F_CPU>=256000000) +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV128 +#elif (F_CPU>=128000000) +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV64 +#elif (F_CPU>=64000000) +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV32 +#elif (F_CPU>=32000000) +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV16 +#elif (F_CPU>=16000000) +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV8 +#elif (F_CPU>=8000000) +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV4 +#else +#define RF69_SPI_CLOCK_DIV SPI_CLOCK_DIV2 +#endif + #define CSMA_LIMIT -90 // upper RX signal sensitivity threshold in dBm for carrier sense access #define RF69_MODE_SLEEP 0 // XTAL OFF @@ -148,7 +174,6 @@ public: uint8_t readReg(uint8_t addr); //!< readReg void writeReg(uint8_t addr, uint8_t val); //!< writeReg void readAllRegs(); //!< readAllRegs - protected: static void isr0(); //!< isr0 void virtual interruptHandler(); //!< interruptHandler diff --git a/library.properties b/library.properties index b3ccbfa..6458fce 100644 --- a/library.properties +++ b/library.properties @@ -6,4 +6,4 @@ sentence=Home Automation Framework paragraph=Create your own wireless sensor mesh using NRF24L01+, RFM69 and RFM95 radios running on Arduino, SAMD and ESP8266. Allows over-the-air updates of nodes. Supported by 20+ home automation controllers. category=Communication url=https://www.mysensors.org -architectures=avr,esp8266,samd +architectures=*