Internal Interface Wrap
API reference
Loading...
Searching...
No Matches
Public Member Functions | Static Public Member Functions | Static Public Attributes | Private Attributes | Friends | List of all members
StmSpiBus Class Reference

One MCU SPI peripheral + its soft-CS device collection. More...

#include <StmSpi.h>

Collaboration diagram for StmSpiBus:
[legend]

Public Member Functions

 StmSpiBus (const hf_spi_bus_config_t &config) noexcept
 
 StmSpiBus (SPI_HandleTypeDef *hal_handle, hf_u32_t timeout_ms=1000) noexcept
 Convenience: construct directly from a CubeMX HAL handle.
 
 ~StmSpiBus () noexcept
 
bool Initialize () noexcept
 
bool IsInitialized () const noexcept
 
bool Deinitialize () noexcept
 
int CreateDevice (const hf_spi_device_config_t &device_config) noexcept
 Register a soft-CS device on this bus.
 
BaseSpi * GetDevice (int device_index) noexcept
 
const BaseSpi * GetDevice (int device_index) const noexcept
 
std::size_t GetDeviceCount () const noexcept
 
bool RemoveDevice (int device_index) noexcept
 
const hf_spi_bus_config_t & GetConfig () const noexcept
 
SPI_HandleTypeDef * GetHalHandle () const noexcept
 Underlying CubeMX SPI handle (platform wiring only).
 
bool ApplyDeviceMode (hf_stm32_spi_mode_t mode, bool io_swap=false, hf_u8_t midi_cycles=15, hf_u32_t clock_speed_hz=0, bool *reconfigured=nullptr) noexcept
 Apply mode (CPOL/CPHA), midi_cycles (CFG2.MIDI) and clock_speed_hz (CFG1.MBR) if they differ from the last applied values. Safe to call with SPE briefly cleared.
 
hf_u32_t GetKernelClockHz () const noexcept
 Kernel clock feeding this SPI peripheral, in Hz (0 if unknown).
 
hf_u32_t GetEffectiveClockHz () const noexcept
 Effective SCK in Hz for the prescaler currently programmed.
 
void IdleAllChipSelects () noexcept
 Drive every registered soft-CS to idle (active-low → HIGH).
 
hf_u8_t ProbeMisoLine (void *miso_port, hf_u8_t miso_pin_pos, const BaseSpi *device) noexcept
 Bring-up probe of the shared MISO/SDO net — no scope required.
 
uint8_t * ScratchTx () noexcept
 
uint8_t * ScratchRx () noexcept
 
bool LockBus (hf_u32_t timeout_ms) noexcept
 Exclusive bus lock for mode + FIFO + CS + HAL transfer.
 
void UnlockBus () noexcept
 

Static Public Member Functions

static hf_u8_t ResolveBaudMbr (hf_u32_t kernel_hz, hf_u32_t requested_hz) noexcept
 Smallest CFG1.MBR whose SCK does not exceed requested_hz.
 

Static Public Attributes

static constexpr hf_u16_t kScratchBytes = 32
 

Private Attributes

hf_spi_bus_config_t config_
 
bool initialized_ {false}
 
bool mode_applied_ {false}
 
hf_stm32_spi_mode_t last_mode_ {hf_stm32_spi_mode_t::MODE_0}
 
bool last_io_swap_ {false}
 
hf_u8_t last_midi_cycles_ {15}
 
hf_u8_t last_baud_mbr_ {0xFFU}
 
PlatformMutex bus_mutex_ {}
 
std::vector< std::unique_ptr< StmSpiDevice > > devices_
 
uint8_t scratch_tx_ [kScratchBytes] {}
 
uint8_t scratch_rx_ [kScratchBytes] {}
 

Friends

class StmSpiDevice
 
class StmSpiBusLock
 

Detailed Description

One MCU SPI peripheral + its soft-CS device collection.

Applies per-device SPI mode on transfer so soft-CS multi-slave buses (e.g. MAX Mode 0 + TLE Mode 1) work despite a single CubeMX SPI Init block. Transfers are serialized with PlatformMutex via StmSpiBusLock. Opt-in bench register-poke paths must take the same lock.

Note
Soft-CS multi-slave contract (this MCU binding):
  • Stage short payloads through D1 AXI when the caller buffer may sit in external FMC SDRAM (byte-access hazard class shared with StmI2c).
  • Flush RX FIFO + clear EOT/TXTF before each soft-CS frame (and after HAL errors so the next peer does not see stale bytes).
  • CS is SoftChipSelectGuard-scoped per frame; software GPIO already exceeds datasheet tCSS — short settle only.
  • Clear HW NSS-pulse (SSOM) so multi-byte transfers are one continuous stream under the asserted CS line.

Constructor & Destructor Documentation

◆ StmSpiBus() [1/2]

StmSpiBus::StmSpiBus ( const hf_spi_bus_config_t &  config)
explicitnoexcept

◆ StmSpiBus() [2/2]

StmSpiBus::StmSpiBus ( SPI_HandleTypeDef *  hal_handle,
hf_u32_t  timeout_ms = 1000 
)
explicitnoexcept

Convenience: construct directly from a CubeMX HAL handle.

◆ ~StmSpiBus()

StmSpiBus::~StmSpiBus ( )
noexcept

Member Function Documentation

◆ ApplyDeviceMode()

bool StmSpiBus::ApplyDeviceMode ( hf_stm32_spi_mode_t  mode,
bool  io_swap = false,
hf_u8_t  midi_cycles = 15,
hf_u32_t  clock_speed_hz = 0,
bool *  reconfigured = nullptr 
)
noexcept

Apply mode (CPOL/CPHA), midi_cycles (CFG2.MIDI) and clock_speed_hz (CFG1.MBR) if they differ from the last applied values. Safe to call with SPE briefly cleared.

Parameters
midi_cyclesSCK idle cycles between data frames (0–15). See hf_spi_device_config_t::inter_data_idle_cycles for why this is per-device: FIFO-serviced slaves want the pause, shift-register slaves (TLE92466ED) need a continuous 32-bit stream.
clock_speed_hzTarget SCK in Hz; 0 keeps whatever prescaler is already programmed (CubeMX default). See hf_spi_device_config_t::clock_speed_hz.
reconfiguredOptional out-flag: true when CFG1/CFG2 were actually rewritten. Callers use this to decide whether the post-mode CPOL settle is needed — an unchanged peripheral cannot have glitched SCK, so the settle is pure WCET on a same-device repeat frame.
Note
Caller must hold StmSpiBusLock and have every soft-CS idle (see IdleAllChipSelects) — SPE toggle must not clock a selected slave.

◆ CreateDevice()

int StmSpiBus::CreateDevice ( const hf_spi_device_config_t &  device_config)
noexcept

Register a soft-CS device on this bus.

Returns
Device index ≥ 0, or negative on failure.

◆ Deinitialize()

bool StmSpiBus::Deinitialize ( )
noexcept

◆ GetConfig()

const hf_spi_bus_config_t & StmSpiBus::GetConfig ( ) const
noexcept

◆ GetDevice() [1/2]

const BaseSpi * StmSpiBus::GetDevice ( int  device_index) const
noexcept

◆ GetDevice() [2/2]

BaseSpi * StmSpiBus::GetDevice ( int  device_index)
noexcept

◆ GetDeviceCount()

std::size_t StmSpiBus::GetDeviceCount ( ) const
noexcept

◆ GetEffectiveClockHz()

hf_u32_t StmSpiBus::GetEffectiveClockHz ( ) const
noexcept

Effective SCK in Hz for the prescaler currently programmed.

Returns
0 when the kernel clock cannot be resolved.

◆ GetHalHandle()

SPI_HandleTypeDef * StmSpiBus::GetHalHandle ( ) const
noexcept

Underlying CubeMX SPI handle (platform wiring only).

◆ GetKernelClockHz()

hf_u32_t StmSpiBus::GetKernelClockHz ( ) const
noexcept

Kernel clock feeding this SPI peripheral, in Hz (0 if unknown).

Resolved from RCC at call time, so a clock-tree change cannot silently invalidate a hard-coded assumption. SPI1/2/3 share RCC_PERIPHCLK_SPI123, SPI4/5 share SPI45, SPI6 stands alone.

◆ IdleAllChipSelects()

void StmSpiBus::IdleAllChipSelects ( )
noexcept

Drive every registered soft-CS to idle (active-low → HIGH).

Note
Caller must hold StmSpiBusLock. Called before every mode change.

◆ Initialize()

bool StmSpiBus::Initialize ( )
noexcept

◆ IsInitialized()

bool StmSpiBus::IsInitialized ( ) const
noexcept

◆ LockBus()

bool StmSpiBus::LockBus ( hf_u32_t  timeout_ms)
noexcept

Exclusive bus lock for mode + FIFO + CS + HAL transfer.

Returns
false on timeout / lock failure.
Note
Prefer StmSpiBusLock RAII over raw Lock/Unlock pairs.

◆ ProbeMisoLine()

hf_u8_t StmSpiBus::ProbeMisoLine ( void *  miso_port,
hf_u8_t  miso_pin_pos,
const BaseSpi *  device 
)
noexcept

Bring-up probe of the shared MISO/SDO net — no scope required.

Retargets miso_port bit miso_pin_pos to a plain input, samples it with the internal pull-up and then the pull-down — first with every soft-CS idle, then with only device selected — and restores the original MODER/PUPDR. A slave that drives SDO overpowers the ~40 kΩ internal pull; a high-Z net simply follows it.

Returns
0 if the probe could not run, otherwise bit7 plus: bit0 = CS idle + pull-up reads HIGH, bit1 = CS idle + pull-down reads HIGH, bit2 = device selected + pull-up reads HIGH, bit3 = device selected + pull-down reads HIGH.

Decode: 0x81 idle high-Z and driven LOW when selected — slave is alive and answering zeros. 0x85 high-Z even when selected — slave never drives SDO (unpowered, held in reset, or MISO not landed). 0x80 held LOW with all CS high — short to GND or a peer driving the shared net.

Note
Takes StmSpiBusLock internally; do not call while holding it.

◆ RemoveDevice()

bool StmSpiBus::RemoveDevice ( int  device_index)
noexcept

◆ ResolveBaudMbr()

hf_u8_t StmSpiBus::ResolveBaudMbr ( hf_u32_t  kernel_hz,
hf_u32_t  requested_hz 
)
staticnoexcept

Smallest CFG1.MBR whose SCK does not exceed requested_hz.

Parameters
kernel_hzPeripheral kernel clock.
requested_hzTarget SCK.
Returns
MBR field value 0–7 (divisor 2^(MBR+1)); 7 when requested_hz is below kernel/256, so the bus never runs faster than asked.

◆ ScratchRx()

uint8_t * StmSpiBus::ScratchRx ( )
inlinenoexcept

◆ ScratchTx()

uint8_t * StmSpiBus::ScratchTx ( )
inlinenoexcept

◆ UnlockBus()

void StmSpiBus::UnlockBus ( )
noexcept

Friends And Related Symbol Documentation

◆ StmSpiBusLock

◆ StmSpiDevice

Member Data Documentation

◆ bus_mutex_

PlatformMutex StmSpiBus::bus_mutex_ {}
mutableprivate

◆ config_

hf_spi_bus_config_t StmSpiBus::config_
private

◆ devices_

std::vector<std::unique_ptr<StmSpiDevice> > StmSpiBus::devices_
private

◆ initialized_

bool StmSpiBus::initialized_ {false}
private

◆ kScratchBytes

constexpr hf_u16_t StmSpiBus::kScratchBytes = 32
staticconstexpr

Per-bus internal-SRAM staging for short transfers. Must only be touched under StmSpiBusLock. A single process-wide scratch raced when two buses transferred concurrently (SensorAcquisition ADS pump vs actuator SPI2) and spliced peer bytes into TMC9660 TMCL frames.

◆ last_baud_mbr_

hf_u8_t StmSpiBus::last_baud_mbr_ {0xFFU}
private

Last CFG1.MBR written by ApplyDeviceMode; 0xFF = never written, so the CubeMX prescaler stands until a device asks for a specific clock.

◆ last_io_swap_

bool StmSpiBus::last_io_swap_ {false}
private

◆ last_midi_cycles_

hf_u8_t StmSpiBus::last_midi_cycles_ {15}
private

◆ last_mode_

hf_stm32_spi_mode_t StmSpiBus::last_mode_ {hf_stm32_spi_mode_t::MODE_0}
private

◆ mode_applied_

bool StmSpiBus::mode_applied_ {false}
private

◆ scratch_rx_

uint8_t StmSpiBus::scratch_rx_[kScratchBytes] {}
private

◆ scratch_tx_

uint8_t StmSpiBus::scratch_tx_[kScratchBytes] {}
private

The documentation for this class was generated from the following files: