mirror of
https://github.com/mysensors/MySensors.git
synced 2026-02-19 17:11:28 +01:00
Arduino_core_STM32 support (improved) (#1571)
* Arduino_core_STM32 support v1 after three previous attempts failed or were abandoned (#1422, #1437, #1486) * fixed compile warning on redefined (v)snprintf * add missing WDG reset, harden VREF and ATEMP to fail gracefully when not available
This commit is contained in:
@@ -73,6 +73,9 @@
|
||||
#elif defined(ARDUINO_ARCH_STM32F1)
|
||||
#include "hal/architecture/STM32F1/MyHwSTM32F1.cpp"
|
||||
#include "hal/crypto/generic/MyCryptoGeneric.cpp"
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#include "hal/architecture/STM32/MyHwSTM32.cpp"
|
||||
#include "hal/crypto/generic/MyCryptoGeneric.cpp"
|
||||
#elif defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_NRF52)
|
||||
#include "hal/architecture/NRF5/MyHwNRF5.cpp"
|
||||
#include "hal/crypto/generic/MyCryptoGeneric.cpp"
|
||||
@@ -336,7 +339,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
|
||||
#define MY_RAM_ROUTING_TABLE_ENABLED
|
||||
#elif defined(MY_RAM_ROUTING_TABLE_FEATURE) && defined(MY_REPEATER_FEATURE)
|
||||
// activate feature based on architecture
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_STM32F1) || defined(TEENSYDUINO) || defined(__linux__) || defined(__ASR6501__) || defined (__ASR6502__)
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_STM32F1) || defined(ARDUINO_ARCH_STM32) || defined(TEENSYDUINO) || defined(__linux__) || defined(__ASR6501__) || defined (__ASR6502__)
|
||||
#define MY_RAM_ROUTING_TABLE_ENABLED
|
||||
#elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
|
||||
#if defined(__avr_atmega1280__) || defined(__avr_atmega1284__) || defined(__avr_atmega2560__) || defined(__avr_attiny3224__) || defined(__avr_attiny3227__)
|
||||
@@ -474,6 +477,8 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs
|
||||
#include "hal/architecture/Linux/MyMainLinuxGeneric.cpp"
|
||||
#elif defined(ARDUINO_ARCH_STM32F1)
|
||||
#include "hal/architecture/STM32F1/MyMainSTM32F1.cpp"
|
||||
#elif defined(ARDUINO_ARCH_STM32)
|
||||
#include "hal/architecture/STM32/MyMainSTM32.cpp"
|
||||
#elif defined(__ASR6501__) || defined(__ASR6502__)
|
||||
#include "hal/architecture/ASR650x/MyMainASR650x.cpp"
|
||||
#elif defined(__arm__) && defined(TEENSYDUINO)
|
||||
|
||||
305
hal/architecture/STM32/MyHwSTM32.cpp
Normal file
305
hal/architecture/STM32/MyHwSTM32.cpp
Normal file
@@ -0,0 +1,305 @@
|
||||
/*
|
||||
* 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 <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2025 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file MyHwSTM32.cpp
|
||||
* @brief Hardware abstraction layer for STM32 microcontrollers using STM32duino core
|
||||
*
|
||||
* This implementation uses the official STM32duino Arduino core which provides
|
||||
* STM32Cube HAL underneath. It supports a wide range of STM32 families including
|
||||
* F0, F1, F4, L0, L4, G0, G4, H7, and more.
|
||||
*
|
||||
* Tested on:
|
||||
* - STM32F401CC/CE Black Pill
|
||||
* - STM32F411CE Black Pill
|
||||
*
|
||||
* Pin Mapping Example (STM32F4 Black Pill):
|
||||
*
|
||||
* nRF24L01+ Radio (SPI1):
|
||||
* - SCK: PA5
|
||||
* - MISO: PA6
|
||||
* - MOSI: PA7
|
||||
* - CSN: PA4
|
||||
* - CE: PB0 (configurable via MY_RF24_CE_PIN)
|
||||
*
|
||||
* RFM69/RFM95 Radio (SPI1):
|
||||
* - SCK: PA5
|
||||
* - MISO: PA6
|
||||
* - MOSI: PA7
|
||||
* - CS: PA4
|
||||
* - IRQ: PA3 (configurable)
|
||||
* - RST: PA2 (configurable)
|
||||
*/
|
||||
|
||||
#include "MyHwSTM32.h"
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
// Wait for serial port to connect (needed for native USB)
|
||||
while (!MY_SERIALDEVICE) {
|
||||
; // Wait for serial port connection
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// STM32duino EEPROM library auto-initializes on first use
|
||||
// No explicit initialization required
|
||||
return true;
|
||||
}
|
||||
|
||||
void hwReadConfigBlock(void *buf, void *addr, size_t length)
|
||||
{
|
||||
uint8_t *dst = static_cast<uint8_t *>(buf);
|
||||
int pos = reinterpret_cast<int>(addr);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
dst[i] = EEPROM.read(pos + i);
|
||||
}
|
||||
}
|
||||
|
||||
void hwWriteConfigBlock(void *buf, void *addr, size_t length)
|
||||
{
|
||||
uint8_t *src = static_cast<uint8_t *>(buf);
|
||||
int pos = reinterpret_cast<int>(addr);
|
||||
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
EEPROM.update(pos + i, src[i]);
|
||||
}
|
||||
|
||||
// Commit changes to flash (STM32duino EEPROM emulation)
|
||||
// Note: This happens automatically on next read or explicit commit
|
||||
}
|
||||
|
||||
uint8_t hwReadConfig(const int addr)
|
||||
{
|
||||
return EEPROM.read(addr);
|
||||
}
|
||||
|
||||
void hwWriteConfig(const int addr, uint8_t value)
|
||||
{
|
||||
EEPROM.update(addr, value);
|
||||
}
|
||||
|
||||
void hwWatchdogReset(void)
|
||||
{
|
||||
#if defined(HAL_IWDG_MODULE_ENABLED) && defined(IWDG)
|
||||
// Reset independent watchdog if enabled
|
||||
// Use direct register write to reload watchdog counter
|
||||
// This works whether IWDG was initialized by HAL or LL drivers
|
||||
IWDG->KR = IWDG_KEY_RELOAD;
|
||||
#endif
|
||||
// No-op if watchdog not enabled
|
||||
}
|
||||
|
||||
void hwReboot(void)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void hwRandomNumberInit(void)
|
||||
{
|
||||
// Use internal temperature sensor and ADC noise as entropy source
|
||||
// This provides reasonably good random seed values
|
||||
|
||||
#ifdef ADC1
|
||||
uint32_t seed = 0;
|
||||
|
||||
// Read multiple samples from different sources for entropy
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
uint32_t value = 0;
|
||||
|
||||
#ifdef TEMP_SENSOR_AVAILABLE
|
||||
// Try to read internal temperature sensor if available
|
||||
value ^= analogRead(ATEMP);
|
||||
#endif
|
||||
|
||||
#ifdef VREF_AVAILABLE
|
||||
// Mix in internal voltage reference reading
|
||||
value ^= analogRead(AVREF);
|
||||
#endif
|
||||
|
||||
// Mix in current time
|
||||
value ^= hwMillis();
|
||||
|
||||
// Mix in system tick
|
||||
value ^= micros();
|
||||
|
||||
// Accumulate into seed
|
||||
seed ^= (value & 0x7) << (i % 29);
|
||||
|
||||
// Small delay to ensure values change
|
||||
delayMicroseconds(100);
|
||||
}
|
||||
|
||||
randomSeed(seed);
|
||||
#else
|
||||
// Fallback: use millis as weak entropy source
|
||||
randomSeed(hwMillis());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
#ifdef UID_BASE
|
||||
// STM32 unique device ID is stored at a fixed address
|
||||
// Length is 96 bits (12 bytes) but we store 16 bytes for compatibility
|
||||
|
||||
uint32_t *id = (uint32_t *)UID_BASE;
|
||||
uint8_t *dst = (uint8_t *)uniqueID;
|
||||
|
||||
// Copy 12 bytes of unique ID
|
||||
for (uint8_t i = 0; i < 12; i++) {
|
||||
dst[i] = ((uint8_t *)id)[i];
|
||||
}
|
||||
|
||||
// Pad remaining bytes with zeros
|
||||
for (uint8_t i = 12; i < 16; i++) {
|
||||
dst[i] = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
// Unique ID not available on this variant
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage(void)
|
||||
{
|
||||
#if defined(VREF_AVAILABLE) && defined(AVREF) && defined(__HAL_RCC_ADC1_CLK_ENABLE)
|
||||
// Read internal voltage reference to calculate VDD
|
||||
// VREFINT is typically 1.2V (varies by STM32 family)
|
||||
|
||||
uint32_t vrefint = analogRead(AVREF);
|
||||
|
||||
if (vrefint > 0) {
|
||||
// Calculate VDD in millivolts
|
||||
// Formula: VDD = 3.3V * 4096 / ADC_reading
|
||||
// Adjusted: VDD = 1200mV * 4096 / vrefint_reading
|
||||
return (uint16_t)((1200UL * 4096UL) / vrefint);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Return typical 3.3V if measurement not available
|
||||
return 3300;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency(void)
|
||||
{
|
||||
// Return CPU frequency in 0.1 MHz units
|
||||
// F_CPU is defined by the build system (e.g., 84000000 for 84 MHz)
|
||||
return F_CPU / 100000UL;
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
#if defined(TEMP_SENSOR_AVAILABLE) && defined(ATEMP) && defined(__HAL_RCC_ADC1_CLK_ENABLE)
|
||||
// Read internal temperature sensor
|
||||
// Note: Requires calibration values for accurate results
|
||||
|
||||
int32_t temp_raw = analogRead(ATEMP);
|
||||
|
||||
#ifdef TEMP110_CAL_ADDR
|
||||
// Use factory calibration if available (STM32F4, L4, etc.)
|
||||
uint16_t *temp30_cal = (uint16_t *)TEMP30_CAL_ADDR;
|
||||
uint16_t *temp110_cal = (uint16_t *)TEMP110_CAL_ADDR;
|
||||
|
||||
if (temp30_cal && temp110_cal && *temp110_cal != *temp30_cal) {
|
||||
// Calculate temperature using two-point calibration
|
||||
// Formula: T = ((110-30) / (CAL_110 - CAL_30)) * (raw - CAL_30) + 30
|
||||
int32_t temp = 30 + ((110 - 30) * (temp_raw - *temp30_cal)) /
|
||||
(*temp110_cal - *temp30_cal);
|
||||
|
||||
// Apply user calibration
|
||||
temp = (temp - MY_STM32_TEMPERATURE_OFFSET) / MY_STM32_TEMPERATURE_GAIN;
|
||||
|
||||
return (int8_t)temp;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fallback: use typical values (less accurate)
|
||||
// Typical slope: 2.5 mV/°C, V25 = 0.76V for STM32F4
|
||||
// This is a rough approximation
|
||||
float voltage = (temp_raw * 3.3f) / 4096.0f;
|
||||
int32_t temp = 25 + (int32_t)((voltage - 0.76f) / 0.0025f);
|
||||
|
||||
return (int8_t)((temp - MY_STM32_TEMPERATURE_OFFSET) / MY_STM32_TEMPERATURE_GAIN);
|
||||
#else
|
||||
// Temperature sensor not available
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
// Calculate free heap memory
|
||||
// This uses newlib's mallinfo if available
|
||||
|
||||
#ifdef STACK_TOP
|
||||
extern char *__brkval;
|
||||
extern char __heap_start;
|
||||
|
||||
char *heap_end = __brkval ? __brkval : &__heap_start;
|
||||
char stack_var;
|
||||
|
||||
// Calculate space between heap and stack
|
||||
return (uint16_t)(&stack_var - heap_end);
|
||||
#else
|
||||
// Alternative method: try to allocate and measure
|
||||
// Not implemented to avoid fragmentation
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint32_t ms)
|
||||
{
|
||||
// TODO: Implement low-power sleep mode
|
||||
// For now, use simple delay
|
||||
// Future: Use STM32 STOP or STANDBY mode with RTC wakeup
|
||||
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
// TODO: Implement interrupt-based sleep
|
||||
// Future: Configure EXTI and enter STOP mode
|
||||
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1,
|
||||
const uint8_t interrupt2, const uint8_t mode2, uint32_t ms)
|
||||
{
|
||||
// TODO: Implement dual-interrupt sleep
|
||||
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
220
hal/architecture/STM32/MyHwSTM32.h
Normal file
220
hal/architecture/STM32/MyHwSTM32.h
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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 <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2025 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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 MyHwSTM32_h
|
||||
#define MyHwSTM32_h
|
||||
|
||||
#include <SPI.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
// Crypto endianness
|
||||
#define CRYPTO_LITTLE_ENDIAN
|
||||
|
||||
/**
|
||||
* @brief Default serial device for MySensors communication
|
||||
* @note Can be overridden in sketch before including MySensors.h
|
||||
*/
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE Serial
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Default debug output device
|
||||
*/
|
||||
#ifndef MY_DEBUGDEVICE
|
||||
#define MY_DEBUGDEVICE MY_SERIALDEVICE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Temperature sensor offset calibration
|
||||
* @note Adjust based on your specific STM32 chip calibration
|
||||
*/
|
||||
#ifndef MY_STM32_TEMPERATURE_OFFSET
|
||||
#define MY_STM32_TEMPERATURE_OFFSET (0.0f)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Temperature sensor gain calibration
|
||||
*/
|
||||
#ifndef MY_STM32_TEMPERATURE_GAIN
|
||||
#define MY_STM32_TEMPERATURE_GAIN (1.0f)
|
||||
#endif
|
||||
|
||||
// Printf format string compatibility
|
||||
// Note: STM32duino core already defines these in avr/pgmspace.h
|
||||
#ifndef snprintf_P
|
||||
#define snprintf_P(s, n, ...) snprintf((s), (n), __VA_ARGS__)
|
||||
#endif
|
||||
#ifndef vsnprintf_P
|
||||
#define vsnprintf_P(s, n, ...) vsnprintf((s), (n), __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// Digital I/O macros - wrap Arduino functions
|
||||
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
|
||||
#define hwDigitalRead(__pin) digitalRead(__pin)
|
||||
#define hwPinMode(__pin, __value) pinMode(__pin, __value)
|
||||
|
||||
// Timing functions
|
||||
#define hwMillis() millis()
|
||||
#define hwGetSleepRemaining() (0ul)
|
||||
|
||||
/**
|
||||
* @brief Initialize hardware
|
||||
* @return true if initialization successful
|
||||
*/
|
||||
bool hwInit(void);
|
||||
|
||||
/**
|
||||
* @brief Reset the watchdog timer
|
||||
*/
|
||||
void hwWatchdogReset(void);
|
||||
|
||||
/**
|
||||
* @brief Reboot the system
|
||||
*/
|
||||
void hwReboot(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize random number generator
|
||||
* @note Uses internal temperature sensor as entropy source
|
||||
*/
|
||||
void hwRandomNumberInit(void);
|
||||
|
||||
/**
|
||||
* @brief Read configuration block from EEPROM
|
||||
* @param buf Destination buffer
|
||||
* @param addr EEPROM address (as void pointer for compatibility)
|
||||
* @param length Number of bytes to read
|
||||
*/
|
||||
void hwReadConfigBlock(void *buf, void *addr, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Write configuration block to EEPROM
|
||||
* @param buf Source buffer
|
||||
* @param addr EEPROM address (as void pointer for compatibility)
|
||||
* @param length Number of bytes to write
|
||||
*/
|
||||
void hwWriteConfigBlock(void *buf, void *addr, size_t length);
|
||||
|
||||
/**
|
||||
* @brief Write single byte to EEPROM
|
||||
* @param addr EEPROM address
|
||||
* @param value Byte value to write
|
||||
*/
|
||||
void hwWriteConfig(const int addr, uint8_t value);
|
||||
|
||||
/**
|
||||
* @brief Read single byte from EEPROM
|
||||
* @param addr EEPROM address
|
||||
* @return Byte value read
|
||||
*/
|
||||
uint8_t hwReadConfig(const int addr);
|
||||
|
||||
/**
|
||||
* @brief Get unique chip ID
|
||||
* @param uniqueID Pointer to unique_id_t structure
|
||||
* @return true if successful
|
||||
*/
|
||||
bool hwUniqueID(unique_id_t *uniqueID);
|
||||
|
||||
/**
|
||||
* @brief Get CPU supply voltage
|
||||
* @return Voltage in millivolts
|
||||
*/
|
||||
uint16_t hwCPUVoltage(void);
|
||||
|
||||
/**
|
||||
* @brief Get CPU frequency
|
||||
* @return Frequency in 0.1 MHz units (e.g., 840 = 84 MHz)
|
||||
*/
|
||||
uint16_t hwCPUFrequency(void);
|
||||
|
||||
/**
|
||||
* @brief Get CPU temperature
|
||||
* @return Temperature in degrees Celsius
|
||||
*/
|
||||
int8_t hwCPUTemperature(void);
|
||||
|
||||
/**
|
||||
* @brief Get free memory (heap)
|
||||
* @return Free memory in bytes
|
||||
*/
|
||||
uint16_t hwFreeMem(void);
|
||||
|
||||
/**
|
||||
* @brief Sleep for specified milliseconds
|
||||
* @param ms Milliseconds to sleep
|
||||
* @return Actual sleep time or MY_SLEEP_NOT_POSSIBLE
|
||||
* @note Initial implementation returns MY_SLEEP_NOT_POSSIBLE
|
||||
*/
|
||||
int8_t hwSleep(uint32_t ms);
|
||||
|
||||
/**
|
||||
* @brief Sleep with interrupt wake
|
||||
* @param interrupt Pin number for interrupt
|
||||
* @param mode Interrupt mode (RISING, FALLING, CHANGE)
|
||||
* @param ms Maximum sleep time
|
||||
* @return Actual sleep time or MY_SLEEP_NOT_POSSIBLE
|
||||
* @note Initial implementation returns MY_SLEEP_NOT_POSSIBLE
|
||||
*/
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms);
|
||||
|
||||
/**
|
||||
* @brief Sleep with dual interrupt wake
|
||||
* @param interrupt1 First pin number
|
||||
* @param mode1 First interrupt mode
|
||||
* @param interrupt2 Second pin number
|
||||
* @param mode2 Second interrupt mode
|
||||
* @param ms Maximum sleep time
|
||||
* @return Actual sleep time or MY_SLEEP_NOT_POSSIBLE
|
||||
* @note Initial implementation returns MY_SLEEP_NOT_POSSIBLE
|
||||
*/
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1,
|
||||
const uint8_t interrupt2, const uint8_t mode2, uint32_t ms);
|
||||
|
||||
// SPI configuration
|
||||
#ifdef MY_SOFTSPI
|
||||
#error Soft SPI is not available on this architecture!
|
||||
#endif
|
||||
#define hwSPI SPI //!< Hardware SPI
|
||||
|
||||
/**
|
||||
* @brief Critical section implementation for STM32
|
||||
* @note Uses PRIMASK register to disable/restore interrupts
|
||||
*/
|
||||
static __inline__ uint8_t __disableIntsRetVal(void)
|
||||
{
|
||||
__disable_irq();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static __inline__ void __priMaskRestore(const uint32_t *priMask)
|
||||
{
|
||||
__set_PRIMASK(*priMask);
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION for ( uint32_t __savePriMask __attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), __ToDo = __disableIntsRetVal(); __ToDo ; __ToDo = 0 )
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif // MyHwSTM32_h
|
||||
57
hal/architecture/STM32/MyMainSTM32.cpp
Normal file
57
hal/architecture/STM32/MyMainSTM32.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 <henrik.ekblad@mysensors.org>
|
||||
* Copyright (C) 2013-2025 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/MySensors/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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file MyMainSTM32.cpp
|
||||
* @brief Main entry point implementation for STM32
|
||||
*
|
||||
* This file provides the main() function that integrates MySensors with the
|
||||
* STM32duino Arduino core. It overrides the default Arduino main() to inject
|
||||
* MySensors _begin() and _process() calls around the user's sketch functions.
|
||||
*/
|
||||
|
||||
#include "MyHwSTM32.h"
|
||||
|
||||
// Declare the sketch's setup() and loop() functions
|
||||
__attribute__((weak)) void setup(void);
|
||||
__attribute__((weak)) void loop(void);
|
||||
|
||||
// Override Arduino's main() function
|
||||
int main(void)
|
||||
{
|
||||
// Initialize Arduino core
|
||||
init();
|
||||
|
||||
#if defined(USBCON)
|
||||
// Initialize USB if available
|
||||
USBDevice.attach();
|
||||
#endif
|
||||
|
||||
_begin(); // Startup MySensors library
|
||||
|
||||
for(;;) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) {
|
||||
loop(); // Call sketch loop
|
||||
}
|
||||
// STM32duino doesn't use serialEventRun by default
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
340
hal/architecture/STM32/README.md
Normal file
340
hal/architecture/STM32/README.md
Normal file
@@ -0,0 +1,340 @@
|
||||
# MySensors STM32 Architecture Support
|
||||
|
||||
This directory contains the Hardware Abstraction Layer (HAL) implementation for STM32 microcontrollers using the official **STM32duino Arduino core**.
|
||||
|
||||
## Overview
|
||||
|
||||
The STM32 HAL enables MySensors to run on a wide range of STM32 microcontrollers, including:
|
||||
|
||||
- **STM32F0** series (Cortex-M0)
|
||||
- **STM32F1** series (Cortex-M3) - Note: This is separate from the old STM32F1 maple implementation
|
||||
- **STM32F4** series (Cortex-M4 with FPU)
|
||||
- **STM32L0/L4** series (Low-power Cortex-M0+/M4)
|
||||
- **STM32G0/G4** series (Cortex-M0+/M4)
|
||||
- **STM32H7** series (Cortex-M7)
|
||||
|
||||
## Supported Boards
|
||||
|
||||
Tested on:
|
||||
- **STM32F401CC Black Pill** (84 MHz, 256KB Flash, 64KB RAM)
|
||||
- **STM32F411CE Black Pill** (100 MHz, 512KB Flash, 128KB RAM)
|
||||
|
||||
Should work on any STM32 board supported by the STM32duino core.
|
||||
|
||||
## Features
|
||||
|
||||
### Implemented ✅
|
||||
- [x] Serial communication (USB CDC and Hardware UART)
|
||||
- [x] SPI interface for radios (nRF24L01+, RFM69, RFM95)
|
||||
- [x] EEPROM emulation using Flash memory
|
||||
- [x] Watchdog support (requires explicit initialization)
|
||||
- [x] System reboot
|
||||
- [x] Random number generation (using internal temperature sensor)
|
||||
- [x] Unique device ID (96-bit STM32 UID)
|
||||
- [x] CPU voltage reading (via VREFINT)
|
||||
- [x] CPU temperature reading (via internal sensor)
|
||||
- [x] CPU frequency reporting
|
||||
- [x] Critical section (interrupt disable/restore)
|
||||
- [x] RAM routing table support
|
||||
|
||||
### Planned 🔄
|
||||
- [ ] Low-power sleep modes (STOP, STANDBY)
|
||||
- [ ] RTC-based timekeeping
|
||||
- [ ] Interrupt-based wake from sleep
|
||||
- [ ] Free memory reporting (heap analysis)
|
||||
|
||||
## Pin Mapping
|
||||
|
||||
### STM32F4 Black Pill Example
|
||||
|
||||
#### nRF24L01+ Radio (SPI1)
|
||||
```
|
||||
nRF24 STM32
|
||||
----- -----
|
||||
VCC --> 3.3V
|
||||
GND --> GND
|
||||
CE --> PB0 (configurable via MY_RF24_CE_PIN)
|
||||
CSN --> PA4 (configurable via MY_RF24_CS_PIN)
|
||||
SCK --> PA5 (SPI1_SCK)
|
||||
MOSI --> PA7 (SPI1_MOSI)
|
||||
MISO --> PA6 (SPI1_MISO)
|
||||
IRQ --> PA3 (optional, configurable via MY_RF24_IRQ_PIN)
|
||||
```
|
||||
|
||||
#### RFM69/RFM95 Radio (SPI1)
|
||||
```
|
||||
RFM69 STM32
|
||||
----- -----
|
||||
VCC --> 3.3V
|
||||
GND --> GND
|
||||
NSS --> PA4 (configurable)
|
||||
SCK --> PA5 (SPI1_SCK)
|
||||
MOSI --> PA7 (SPI1_MOSI)
|
||||
MISO --> PA6 (SPI1_MISO)
|
||||
DIO0 --> PA3 (IRQ pin, configurable)
|
||||
RESET --> PA2 (configurable)
|
||||
```
|
||||
|
||||
#### Serial Communication
|
||||
```
|
||||
USB CDC: Serial (default, MY_SERIALDEVICE)
|
||||
UART1: PA9/PA10 (TX/RX)
|
||||
UART2: PA2/PA3 (TX/RX)
|
||||
```
|
||||
|
||||
#### Optional Status LEDs
|
||||
```
|
||||
On-board LED: PC13 (Blue Pill) or PA5 (Black Pill)
|
||||
RX LED: Configurable via MY_DEFAULT_RX_LED_PIN
|
||||
TX LED: Configurable via MY_DEFAULT_TX_LED_PIN
|
||||
ERR LED: Configurable via MY_DEFAULT_ERR_LED_PIN
|
||||
```
|
||||
|
||||
## PlatformIO Configuration
|
||||
|
||||
### platformio.ini Example
|
||||
|
||||
```ini
|
||||
[env:blackpill_f411ce]
|
||||
platform = ststm32
|
||||
framework = arduino
|
||||
board = blackpill_f411ce
|
||||
|
||||
; Upload configuration
|
||||
upload_protocol = stlink
|
||||
|
||||
; Build flags
|
||||
build_flags =
|
||||
-D MY_DEBUG
|
||||
-D MY_BAUD_RATE=115200
|
||||
-D MY_GATEWAY_SERIAL
|
||||
-D MY_RADIO_RF24
|
||||
-D MY_RF24_CE_PIN=PB0
|
||||
-D MY_RF24_CS_PIN=PA4
|
||||
-D MY_RF24_PA_LEVEL=RF24_PA_LOW
|
||||
|
||||
; Library dependencies
|
||||
lib_deps =
|
||||
mysensors/MySensors@^2.4.0
|
||||
; Add radio-specific libraries if needed
|
||||
|
||||
; Monitor configuration
|
||||
monitor_speed = 115200
|
||||
|
||||
; Debug configuration
|
||||
debug_tool = stlink
|
||||
```
|
||||
|
||||
### Supported Boards
|
||||
|
||||
Common `board` values for platformio.ini:
|
||||
- `blackpill_f401cc` - STM32F401CC Black Pill
|
||||
- `blackpill_f411ce` - STM32F411CE Black Pill (recommended)
|
||||
- `bluepill_f103c8` - STM32F103C8 Blue Pill (use old STM32F1 HAL instead)
|
||||
- `nucleo_f401re` - STM32F401RE Nucleo
|
||||
- `nucleo_f411re` - STM32F411RE Nucleo
|
||||
- `genericSTM32F103C8` - Generic F103C8
|
||||
- See [PlatformIO boards](https://docs.platformio.org/en/latest/boards/index.html#st-stm32) for complete list
|
||||
|
||||
### Upload Methods
|
||||
|
||||
Supported `upload_protocol` options:
|
||||
- `stlink` - ST-Link V2 programmer (recommended)
|
||||
- `dfu` - USB DFU bootloader (requires boot0 jumper)
|
||||
- `serial` - Serial bootloader (requires FTDI adapter)
|
||||
- `jlink` - Segger J-Link
|
||||
- `blackmagic` - Black Magic Probe
|
||||
|
||||
## Arduino IDE Configuration
|
||||
|
||||
1. Install STM32duino core:
|
||||
- Add board manager URL: `https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json`
|
||||
- Tools → Board → Boards Manager → Install "STM32 MCU based boards"
|
||||
|
||||
2. Select board:
|
||||
- Tools → Board → STM32 boards groups → Generic STM32F4 series
|
||||
- Tools → Board part number → BlackPill F411CE
|
||||
|
||||
3. Configure USB support:
|
||||
- Tools → USB support → CDC (generic 'Serial' supersede U(S)ART)
|
||||
|
||||
4. Select upload method:
|
||||
- Tools → Upload method → STM32CubeProgrammer (SWD)
|
||||
|
||||
## Sketch Configuration
|
||||
|
||||
### Basic Gateway Example
|
||||
|
||||
```cpp
|
||||
// Enable debug
|
||||
#define MY_DEBUG
|
||||
|
||||
// Gateway mode
|
||||
#define MY_GATEWAY_SERIAL
|
||||
|
||||
// Radio configuration
|
||||
#define MY_RADIO_RF24
|
||||
#define MY_RF24_CE_PIN PB0
|
||||
#define MY_RF24_CS_PIN PA4
|
||||
|
||||
#include <MySensors.h>
|
||||
|
||||
void setup() {
|
||||
// MySensors initializes automatically
|
||||
}
|
||||
|
||||
void presentation() {
|
||||
sendSketchInfo("STM32 Gateway", "1.0");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Add sensor reading code here
|
||||
}
|
||||
```
|
||||
|
||||
### Basic Sensor Node Example
|
||||
|
||||
```cpp
|
||||
#define MY_DEBUG
|
||||
#define MY_RADIO_RF24
|
||||
#define MY_RF24_CE_PIN PB0
|
||||
#define MY_RF24_CS_PIN PA4
|
||||
#define MY_NODE_ID 10
|
||||
|
||||
#include <MySensors.h>
|
||||
|
||||
#define CHILD_ID_TEMP 0
|
||||
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
|
||||
|
||||
void setup() {
|
||||
// Setup code
|
||||
}
|
||||
|
||||
void presentation() {
|
||||
sendSketchInfo("STM32 Sensor", "1.0");
|
||||
present(CHILD_ID_TEMP, S_TEMP);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float temperature = 22.5; // Read from sensor
|
||||
send(msgTemp.set(temperature, 1));
|
||||
sleep(60000); // Sleep for 1 minute
|
||||
}
|
||||
```
|
||||
|
||||
## EEPROM Emulation
|
||||
|
||||
The STM32 HAL uses the STM32duino EEPROM library, which provides Flash-based EEPROM emulation:
|
||||
|
||||
- **Size**: Configurable, typically 1-4KB
|
||||
- **Location**: Last Flash page(s)
|
||||
- **Wear leveling**: Implemented by STM32duino core
|
||||
- **Persistence**: Survives power cycles and resets
|
||||
- **Write cycles**: ~10,000 writes per page (Flash limitation)
|
||||
|
||||
Configuration is automatic. EEPROM size can be adjusted in the STM32duino menu or via build flags.
|
||||
|
||||
## Low-Power Considerations
|
||||
|
||||
### Current Status
|
||||
Sleep modes are **NOT YET IMPLEMENTED** in this initial release. Calling `sleep()` functions will return `MY_SLEEP_NOT_POSSIBLE`.
|
||||
|
||||
### Future Implementation
|
||||
The STM32 supports several low-power modes:
|
||||
- **Sleep mode**: ~10mA (CPU stopped, peripherals running)
|
||||
- **Stop mode**: ~10-100µA (CPU and most peripherals stopped)
|
||||
- **Standby mode**: ~1-10µA (only backup domain active)
|
||||
|
||||
Implementation will use:
|
||||
- RTC for timed wake-up
|
||||
- EXTI for interrupt wake-up
|
||||
- Backup SRAM for state retention
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Compilation Errors
|
||||
|
||||
**Error: `Hardware abstraction not defined`**
|
||||
- Solution: Ensure you're using STM32duino core, not Arduino STM32 (maple)
|
||||
- The platform should define `ARDUINO_ARCH_STM32`
|
||||
|
||||
**Error: `EEPROM.h not found`**
|
||||
- Solution: Update STM32duino core to latest version (2.0.0+)
|
||||
|
||||
**Error: Undefined reference to `__disable_irq`**
|
||||
- Solution: Ensure CMSIS is included (should be automatic with STM32duino)
|
||||
|
||||
### Upload Issues
|
||||
|
||||
**Upload fails with ST-Link**
|
||||
- Check ST-Link connections (SWDIO, SWCLK, GND, 3.3V)
|
||||
- Verify ST-Link firmware is up to date
|
||||
- Try: `st-flash reset` to reset the chip
|
||||
|
||||
**DFU mode not detected**
|
||||
- Set BOOT0 jumper to 1 (3.3V)
|
||||
- Press reset button
|
||||
- Verify with: `dfu-util -l`
|
||||
- After upload, set BOOT0 back to 0 (GND)
|
||||
|
||||
### Runtime Issues
|
||||
|
||||
**Serial monitor shows garbage**
|
||||
- Check baud rate matches (default 115200)
|
||||
- USB CDC may require driver on Windows
|
||||
- Try hardware UART instead
|
||||
|
||||
**Radio not working**
|
||||
- Verify 3.3V power supply (nRF24 needs clean power)
|
||||
- Check SPI pin connections
|
||||
- Add 10µF capacitor across radio VCC/GND
|
||||
- Verify CE and CS pin definitions
|
||||
|
||||
**EEPROM not persisting**
|
||||
- EEPROM emulation requires Flash write access
|
||||
- Check for debug mode preventing Flash writes
|
||||
- Verify sufficient Flash space for EEPROM pages
|
||||
|
||||
## Performance Characteristics
|
||||
|
||||
### STM32F411CE Black Pill
|
||||
- **CPU**: 100 MHz ARM Cortex-M4F
|
||||
- **Flash**: 512KB
|
||||
- **RAM**: 128KB
|
||||
- **Current**: ~50mA active, <1µA standby (when implemented)
|
||||
- **MySensors overhead**: ~30KB Flash, ~4KB RAM
|
||||
|
||||
### Benchmarks (preliminary)
|
||||
- **Radio message latency**: <10ms (similar to AVR)
|
||||
- **EEPROM read**: ~50µs per byte
|
||||
- **EEPROM write**: ~5ms per byte (Flash write)
|
||||
- **Temperature reading**: ~100µs
|
||||
|
||||
## Contributing
|
||||
|
||||
This STM32 HAL is designed for easy contribution to the main MySensors repository. When contributing:
|
||||
|
||||
1. Follow MySensors coding style
|
||||
2. Test on multiple STM32 variants if possible
|
||||
3. Document any chip-specific quirks
|
||||
4. Update this README with new features
|
||||
|
||||
## References
|
||||
|
||||
- [STM32duino Core](https://github.com/stm32duino/Arduino_Core_STM32)
|
||||
- [STM32duino Wiki](https://github.com/stm32duino/Arduino_Core_STM32/wiki)
|
||||
- [PlatformIO STM32 Platform](https://docs.platformio.org/en/latest/platforms/ststm32.html)
|
||||
- [MySensors Documentation](https://www.mysensors.org/download)
|
||||
- [STM32 Reference Manuals](https://www.st.com/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.html)
|
||||
|
||||
## License
|
||||
|
||||
This code is part of the MySensors project and is licensed under the GNU General Public License v2.0.
|
||||
|
||||
## Version History
|
||||
|
||||
- **v1.0.0** (2025-01-17) - Initial STM32 HAL implementation
|
||||
- Basic functionality (GPIO, SPI, EEPROM, Serial)
|
||||
- Tested on STM32F401/F411 Black Pill
|
||||
- Gateway and sensor node support
|
||||
- No sleep mode yet (planned for v1.1.0)
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "MySensors",
|
||||
"keywords": "framework, sensor, rf",
|
||||
"description": "Home Automation Framework. Create your own wireless sensor mesh using nRF24L01+, RFM69 and RFM95 radios running on AVR, ESP32, ESP8266, NRF5x, SAMD, STM32F1 and Teensyduino. Over-the-air updates and MySensors support by 20+ home automation controllers.",
|
||||
"description": "Home Automation Framework. Create your own wireless sensor mesh using nRF24L01+, RFM69 and RFM95 radios running on AVR, ESP32, ESP8266, NRF5x, SAMD, STM32, STM32F1 and Teensyduino. Over-the-air updates and MySensors support by 20+ home automation controllers.",
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
|
||||
@@ -3,7 +3,7 @@ version=2.4.0-alpha
|
||||
author=The MySensors Team
|
||||
maintainer=The MySensors Team
|
||||
sentence=Home Automation Framework
|
||||
paragraph=Create your own wireless sensor mesh using nRF24L01+, RFM69 and RFM95 radios running on AVR, ESP32, ESP8266, NRF5x, SAMD, STM32F1 and Teensyduino. Over-the-air updates and MySensors support by 20+ home automation controllers.
|
||||
paragraph=Create your own wireless sensor mesh using nRF24L01+, RFM69 and RFM95 radios running on AVR, ESP32, ESP8266, NRF5x, SAMD, STM32, STM32F1 and Teensyduino. Over-the-air updates and MySensors support by 20+ home automation controllers.
|
||||
category=Communication
|
||||
url=https://www.mysensors.org
|
||||
architectures=*
|
||||
|
||||
Reference in New Issue
Block a user