From dc139d68ca3281797543e3de62df64be1fb204c9 Mon Sep 17 00:00:00 2001 From: Philipp Erhardt Date: Thu, 21 May 2026 17:25:33 +0000 Subject: [PATCH 1/2] Fix FIFO queue size --- machine/cortex-m/st/stm32l4/interface/spi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/machine/cortex-m/st/stm32l4/interface/spi.c b/machine/cortex-m/st/stm32l4/interface/spi.c index 8edb63d..9236f1b 100644 --- a/machine/cortex-m/st/stm32l4/interface/spi.c +++ b/machine/cortex-m/st/stm32l4/interface/spi.c @@ -317,6 +317,13 @@ static int spi_select_device(void *bus, const spi_device_cfg_t *dev_cfg) LL_SPI_SetClockPolarity(hspi->Instance, polarity); LL_SPI_SetClockPhase(hspi->Instance, phase); LL_SPI_SetDataWidth(hspi->Instance, datasize); + /* FRXTH must track the data width, or RXNE fires at the wrong FIFO + * level and >8-bit reads return corrupt data: half-full for >8-bit + * words, quarter-full otherwise. */ + LL_SPI_SetRxFIFOThreshold( + hspi->Instance, + dev_cfg->bits_per_word > 8 ? LL_SPI_RX_FIFO_TH_HALF + : LL_SPI_RX_FIFO_TH_QUARTER); LL_SPI_SetTransferBitOrder(hspi->Instance, bit_order); __HAL_SPI_ENABLE(hspi); From 042e8a9a78c42dc293fde586332363406adee070 Mon Sep 17 00:00:00 2001 From: Philipp Erhardt Date: Thu, 21 May 2026 23:33:01 +0000 Subject: [PATCH 2/2] MCU Temp --- machine/cortex-m/src/native.rs | 1 + machine/cortex-m/src/native/mcu_temp.rs | 16 +++ machine/cortex-m/src/stub.rs | 1 + machine/cortex-m/src/stub/mcu_temp.rs | 8 ++ .../cortex-m/st/stm32l4/interface/export.h | 7 + .../cortex-m/st/stm32l4/interface/mcu_temp.c | 130 ++++++++++++++++++ .../cortex-m/st/stm32l4/interface/mcu_temp.h | 11 ++ 7 files changed, 174 insertions(+) create mode 100644 machine/cortex-m/src/native/mcu_temp.rs create mode 100644 machine/cortex-m/src/stub/mcu_temp.rs create mode 100644 machine/cortex-m/st/stm32l4/interface/mcu_temp.c create mode 100644 machine/cortex-m/st/stm32l4/interface/mcu_temp.h diff --git a/machine/cortex-m/src/native.rs b/machine/cortex-m/src/native.rs index 4e51b59..546400f 100644 --- a/machine/cortex-m/src/native.rs +++ b/machine/cortex-m/src/native.rs @@ -8,6 +8,7 @@ pub mod debug; pub mod excep; pub mod gpio; pub mod i2c; +pub mod mcu_temp; pub mod panic; pub mod sched; pub mod spi; diff --git a/machine/cortex-m/src/native/mcu_temp.rs b/machine/cortex-m/src/native/mcu_temp.rs new file mode 100644 index 0000000..04d0244 --- /dev/null +++ b/machine/cortex-m/src/native/mcu_temp.rs @@ -0,0 +1,16 @@ +//! MCU internal junction-temperature sensor. + +use hal_api::{PosixError, Result}; + +use super::bindings; + +/// Read the MCU die temperature in degrees Celsius. +/// +/// Returns `EIO` if ADC init or conversion failed. +pub fn read() -> Result { + let millidegc = unsafe { bindings::hal_mcu_temp_millidegc() }; + if millidegc == i32::MIN { + return Err(PosixError::EIO); + } + Ok(millidegc as f32 / 1000.0) +} diff --git a/machine/cortex-m/src/stub.rs b/machine/cortex-m/src/stub.rs index f89334b..214e5d6 100644 --- a/machine/cortex-m/src/stub.rs +++ b/machine/cortex-m/src/stub.rs @@ -6,6 +6,7 @@ pub mod can; pub mod device_tree; pub mod gpio; pub mod i2c; +pub mod mcu_temp; pub mod sched; pub mod spi; pub mod system; diff --git a/machine/cortex-m/src/stub/mcu_temp.rs b/machine/cortex-m/src/stub/mcu_temp.rs new file mode 100644 index 0000000..8878d8f --- /dev/null +++ b/machine/cortex-m/src/stub/mcu_temp.rs @@ -0,0 +1,8 @@ +//! MCU internal junction-temperature sensor (host stub). + +use hal_api::Result; + +/// Return a fixed dummy temperature on the host build. +pub fn read() -> Result { + Ok(25.0) +} diff --git a/machine/cortex-m/st/stm32l4/interface/export.h b/machine/cortex-m/st/stm32l4/interface/export.h index f8c4102..8446a09 100644 --- a/machine/cortex-m/st/stm32l4/interface/export.h +++ b/machine/cortex-m/st/stm32l4/interface/export.h @@ -253,3 +253,10 @@ unsigned long long monotonic_freq(void); void delay_us(uint32_t delay_us); void do_tick(void); void tim2_hndlr(void); + +// mcu_temp.c +// Sentinel returned on init/conversion failure. +#define HAL_MCU_TEMP_ERROR INT32_MIN +// Reads the MCU internal junction temperature, in milli-degrees Celsius, +// or HAL_MCU_TEMP_ERROR on failure. +int32_t hal_mcu_temp_millidegc(void); diff --git a/machine/cortex-m/st/stm32l4/interface/mcu_temp.c b/machine/cortex-m/st/stm32l4/interface/mcu_temp.c new file mode 100644 index 0000000..3f14c16 --- /dev/null +++ b/machine/cortex-m/st/stm32l4/interface/mcu_temp.c @@ -0,0 +1,130 @@ +/* + * STM32L4 internal junction-temperature-sensor reading. + * + * Reads ADC1 channel 17 (ADC_CHANNEL_TEMPSENSOR), the on-die temperature + * sensor, and converts the raw code to a temperature using the factory + * calibration values. + * + * Reference: RM0432 (STM32L4+ reference manual) section 21.4.32 + * "Temperature sensor". The sensor needs a long ADC sampling time + * (640.5 cycles here) for its high output impedance to settle. + * + * Conversion formula (applied by __HAL_ADC_CALC_TEMPERATURE): + * + * T = (TS_CAL2_TEMP - TS_CAL1_TEMP) + * --------------------------------- * (TS_DATA - TS_CAL1) + TS_CAL1_TEMP + * (TS_CAL2 - TS_CAL1) + * + * where TS_CAL1/TS_CAL2 are the factory-programmed ADC codes at the two + * calibration temperatures, read from CMSIS-defined addresses. The macro + * also rescales TS_DATA for VREF+ (calibration was performed at 3.0 V) and + * for ADC resolution. The typical-slope (Avg_Slope / V25) formula is NOT + * used: it is inaccurate on STM32L4. + */ + +#include "mcu_temp.h" + +#include "stm32l4xx_hal.h" +#include "stm32l4xx_hal_adc.h" +#include "stm32l4xx_hal_adc_ex.h" + +/* Nucleo VREF+ in millivolts; the temperature macro scales for it. */ +#define MCU_TEMP_VDDA_MV 3300U + +/* Samples averaged per read to reduce noise. */ +#define MCU_TEMP_SAMPLES 16U + +/* Per-conversion poll timeout, milliseconds. */ +#define MCU_TEMP_CONV_TIMEOUT_MS 10U + +int32_t hal_mcu_temp_millidegc(void) +{ + ADC_HandleTypeDef hadc = {0}; + ADC_ChannelConfTypeDef chan = {0}; + + __HAL_RCC_ADC_CLK_ENABLE(); + + /* ADC1, single conversion, software trigger, 12-bit right-aligned. + * Synchronous clock from PCLK2 divided by 4: 80 MHz / 4 = 20 MHz, + * within the STM32L4 datasheet ADC clock maximum. */ + hadc.Instance = ADC1; + hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; + hadc.Init.Resolution = ADC_RESOLUTION_12B; + hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; + hadc.Init.ScanConvMode = ADC_SCAN_DISABLE; + hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV; + hadc.Init.LowPowerAutoWait = DISABLE; + hadc.Init.ContinuousConvMode = DISABLE; + hadc.Init.NbrOfConversion = 1; + hadc.Init.DiscontinuousConvMode = DISABLE; + hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; + hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; + hadc.Init.DMAContinuousRequests = DISABLE; + hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; + hadc.Init.OversamplingMode = DISABLE; + + if (HAL_ADC_Init(&hadc) != HAL_OK) + { + return HAL_MCU_TEMP_ERROR; + } + + /* Internal temperature sensor on regular rank 1. The longest sample + * time available is required for the sensor's settling (RM0432 + * section 21.4.32). */ + chan.Channel = ADC_CHANNEL_TEMPSENSOR; + chan.Rank = ADC_REGULAR_RANK_1; + chan.SamplingTime = ADC_SAMPLETIME_640CYCLES_5; + chan.SingleDiff = ADC_SINGLE_ENDED; + chan.OffsetNumber = ADC_OFFSET_NONE; + chan.Offset = 0; + + if (HAL_ADC_ConfigChannel(&hadc, &chan) != HAL_OK) + { + HAL_ADC_DeInit(&hadc); + return HAL_MCU_TEMP_ERROR; + } + + /* Calibrate the ADC once before the first conversion. */ + if (HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED) != HAL_OK) + { + HAL_ADC_DeInit(&hadc); + return HAL_MCU_TEMP_ERROR; + } + + /* Average MCU_TEMP_SAMPLES conversions. */ + uint32_t accum = 0; + for (uint32_t i = 0; i < MCU_TEMP_SAMPLES; i++) + { + if (HAL_ADC_Start(&hadc) != HAL_OK) + { + HAL_ADC_DeInit(&hadc); + return HAL_MCU_TEMP_ERROR; + } + if (HAL_ADC_PollForConversion(&hadc, MCU_TEMP_CONV_TIMEOUT_MS) != HAL_OK) + { + HAL_ADC_Stop(&hadc); + HAL_ADC_DeInit(&hadc); + return HAL_MCU_TEMP_ERROR; + } + accum += HAL_ADC_GetValue(&hadc); + HAL_ADC_Stop(&hadc); + } + + HAL_ADC_DeInit(&hadc); + + uint32_t adc_data = accum / MCU_TEMP_SAMPLES; + + /* Guard the divide-by-zero in the conversion (TS_CAL2 == TS_CAL1). + * This cannot happen on real silicon but keeps the shim defensive. */ + if ((int32_t)*TEMPSENSOR_CAL2_ADDR == (int32_t)*TEMPSENSOR_CAL1_ADDR) + { + return HAL_MCU_TEMP_ERROR; + } + + /* __HAL_ADC_CALC_TEMPERATURE yields whole degrees Celsius; scale to + * milli-degrees for the integer interface. */ + int32_t degc = __HAL_ADC_CALC_TEMPERATURE(MCU_TEMP_VDDA_MV, adc_data, + ADC_RESOLUTION_12B); + + return degc * 1000; +} diff --git a/machine/cortex-m/st/stm32l4/interface/mcu_temp.h b/machine/cortex-m/st/stm32l4/interface/mcu_temp.h new file mode 100644 index 0000000..d746770 --- /dev/null +++ b/machine/cortex-m/st/stm32l4/interface/mcu_temp.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +/* Sentinel returned on init/conversion failure (see export.h). */ +#define HAL_MCU_TEMP_ERROR INT32_MIN + +/* Read the STM32L4 internal junction temperature sensor. + * Returns the die temperature in milli-degrees Celsius, or + * HAL_MCU_TEMP_ERROR on failure. */ +int32_t hal_mcu_temp_millidegc(void);