LCOV - code coverage report
Current view: top level - inc - onewire.h (source / functions) Coverage Total Hit
Test: stm32-async-1wire core coverage Lines: 100.0 % 2 2
Test Date: 2026-09-10 04:33:53 Functions: 100.0 % 1 1
Branches: 100.0 % 2 2

             Branch data     Line data    Source code
       1                 :             : /**
       2                 :             :  * @file onewire.h
       3                 :             :  * @brief Universal non-blocking 1-Wire bus layer for STM32
       4                 :             :  * @details The driver (ds18b20.c) and any other 1-Wire slave driver (DS2413,
       5                 :             :  *          DS2431, ...) are built on top of this layer. Every operation is
       6                 :             :  *          scheduled on TIM1/DMA and completes asynchronously: callers poll
       7                 :             :  *          onewire_bus_done() / onewire_search_poll() to advance, never wait.
       8                 :             :  */
       9                 :             : 
      10                 :             : #ifndef ONEWIRE_H
      11                 :             : #define ONEWIRE_H
      12                 :             : 
      13                 :             : #include <stdint.h>
      14                 :             : 
      15                 :             : /**
      16                 :             :  * @defgroup ONEWIRE_Protocol 1-Wire Protocol Constants
      17                 :             :  * @{
      18                 :             :  */
      19                 :             : 
      20                 :             : /** @brief Bytes in a device ROM address */
      21                 :             : #define ONEWIRE_ROM_BYTES 8
      22                 :             : /** @brief Bits in a device ROM address */
      23                 :             : #define ONEWIRE_ROM_BITS (ONEWIRE_ROM_BYTES * 8)
      24                 :             : /** @brief Bits per byte */
      25                 :             : #define ONEWIRE_BITS_PER_BYTE 8
      26                 :             : /** @brief Family selection: a single OW_PORT_FAMILY_* token resolved from
      27                 :             :  *  either the explicit OW_PORT_TARGET_* knob or the family macros
      28                 :             :  *  (STM32F1, STM32F0, STM32G0) that PlatformIO / STM32CubeMX define on their
      29                 :             :  *  own. ow_port.h picks the backend and app.c the device header/clock config
      30                 :             :  *  from the token — never from the individual spellings — so the backend and
      31                 :             :  *  the clock default cannot drift. To add a family, extend this chain (token
      32                 :             :  *  and default clock together in one branch), then add the #include branch in
      33                 :             :  *  ow_port.h, the app.c config, and a case in tests/test/test_sysclk_fallback.c. */
      34                 :             : #if defined(OW_PORT_TARGET_F1) || defined(STM32F1)
      35                 :             : #define OW_PORT_FAMILY_F1
      36                 :             : #elif defined(OW_PORT_TARGET_F0) || defined(STM32F0)
      37                 :             : #define OW_PORT_FAMILY_F0
      38                 :             : #elif defined(OW_PORT_TARGET_G0) || defined(STM32G0)
      39                 :             : #define OW_PORT_FAMILY_G0
      40                 :             : #endif
      41                 :             : /** @brief System clock frequency in MHz after application clock setup.
      42                 :             :  *  Single source of truth for the clock-dependent settings: the timer
      43                 :             :  *  prescaler (1µs ticks) and the input-capture filter selection below
      44                 :             :  *  derive from it; the bit-slot durations (ONEWIRE_ONE_PULSE and friends)
      45                 :             :  *  are fixed constants validated on every supported clock. Family defaults
      46                 :             :  *  are provided per OW_PORT_FAMILY_* above; override via
      47                 :             :  *  -DOWN_PORT_SYSCLK_MHZ=N (see app.c for the clock sources available
      48                 :             :  *  per family). */
      49                 :             : #if !defined(OW_PORT_SYSCLK_MHZ)
      50                 :             : #if defined(OW_PORT_FAMILY_F1)
      51                 :             : #define OW_PORT_SYSCLK_MHZ 72 /* STM32F103: HSE + PLL x9 */
      52                 :             : #elif defined(OW_PORT_FAMILY_F0)
      53                 :             : #define OW_PORT_SYSCLK_MHZ 48 /* STM32F030: HSI/2 + PLL x12 */
      54                 :             : #elif defined(OW_PORT_FAMILY_G0)
      55                 :             : #define OW_PORT_SYSCLK_MHZ 64 /* STM32G031: HSI16 + PLL */
      56                 :             : #endif
      57                 :             : #endif
      58                 :             : /** @brief Opt-in low-power WFE sleep: when defined, long hardware stages
      59                 :             :  *  (> 1 ms: conversion, scratchpad read, EEPROM hold-off, inter-cycle pause)
      60                 :             :  *  enable the TIM1 update interrupt (UIE) and SEVONPEND so that a pending
      61                 :             :  *  update event wakes the core from WFE without an ISR; short stages stay fully
      62                 :             :  *  polled. Long stages can sleep with ow_port_sleep_until_done(). Disabled by
      63                 :             :  *  default so non-low-power builds pay zero cost. Enable with -DOW_PORT_LOW_POWER.
      64                 :             :  *  @note No ISR is ever installed and NVIC_EnableIRQ is never called; the
      65                 :             :  *        pending bit is cleared explicitly in ow_port_bus_done() so WFE does
      66                 :             :  *        not degrade into a busy-loop. */
      67                 :             : #ifdef OW_PORT_LOW_POWER
      68                 :             : #if defined(OW_PORT_TARGET_F0) || defined(OW_PORT_TARGET_G0)
      69                 :             : #define OW_PORT_TIM1_UPD_IRQn TIM1_BRK_UP_TRG_COM_IRQn
      70                 :             : #else
      71                 :             : #define OW_PORT_TIM1_UPD_IRQn TIM1_UP_IRQn
      72                 :             : #endif
      73                 :             : #endif
      74                 :             : /** @brief Duration of a '1' bit write/read pulse in microseconds.
      75                 :             :  *  A single universal value for every clock: DS18B20 requires only ≥1µs and
      76                 :             :  *  samples the slot at ≥15µs after its start, and the read-slot capture
      77                 :             :  *  latency (bus RC rise + input filter + timer sync) stays far below the
      78                 :             :  *  ONEWIRE_SHORT_PULSE_MAX window on all supported clocks. Releases v1.6.0's
      79                 :             :  *  ≤16MHz compensation (2µs pulse): hardware on STM32F030@8MHz showed that a
      80                 :             :  *  2µs master pulse breaks the sensor's slot decoding outright — every
      81                 :             :  *  capture stretches past the threshold regardless of the answer — while a
      82                 :             :  *  plain 5µs pulse measures ~9µs there with every input-filter variant
      83                 :             :  *  swept (fCK_INT N=2/4/8 and fDTS/4 N=8). The short-pulse path was tuned on
      84                 :             :  *  F103@8MHz bench wiring whose slower rise is not reproduced by other
      85                 :             :  *  boards; re-validate per board before reintroducing anything similar.
      86                 :             :  *  @note Hardware-validated at 5µs on every supported clock:
      87                 :             :  *        STM32F030@48/8MHz, STM32F103@72/8MHz and STM32G031@64/16MHz. */
      88                 :             : #define ONEWIRE_ONE_PULSE 5
      89                 :             : #define ONEWIRE_ZERO_PULSE 60
      90                 :             : #define ONEWIRE_GUARD_BAND 5
      91                 :             : #define ONEWIRE_SHORT_PULSE_MAX 10
      92                 :             : 
      93                 :             : typedef enum {
      94                 :             :     ONEWIRE_TIMING_FAST = 0,
      95                 :             :     ONEWIRE_TIMING_STANDARD,
      96                 :             :     ONEWIRE_TIMING_SLOW,
      97                 :             :     ONEWIRE_TIMING_ROBUST,
      98                 :             :     ONEWIRE_TIMING_CUSTOM,
      99                 :             :     ONEWIRE_TIMING_COUNT
     100                 :             : } onewire_timing_profile_t;
     101                 :             : 
     102                 :             : typedef struct {
     103                 :             :     uint8_t one_pulse;
     104                 :             :     uint8_t zero_pulse;
     105                 :             :     uint8_t guard_band;
     106                 :             :     uint8_t parasite_guard_band;
     107                 :             :     uint8_t short_pulse_max;
     108                 :             : } onewire_timing_t;
     109                 :             : 
     110                 :             : #ifndef OW_TIMING_DEFAULT
     111                 :             : #define OW_TIMING_DEFAULT ONEWIRE_TIMING_STANDARD
     112                 :             : #endif
     113                 :             : #ifndef ONEWIRE_TIMING_PROFILE_DEFAULT
     114                 :             : #define ONEWIRE_TIMING_PROFILE_DEFAULT OW_TIMING_DEFAULT
     115                 :             : #endif
     116                 :             : 
     117                 :             : extern uint8_t ow_one_pulse_us;
     118                 :             : extern uint8_t ow_zero_pulse_us;
     119                 :             : extern uint8_t ow_guard_band_us;
     120                 :             : extern uint8_t ow_short_pulse_max_us;
     121                 :             : void ow_set_parasite_guard(uint8_t parasite);
     122                 :             : void onewire_set_timing_profile(onewire_timing_profile_t profile);
     123                 :             : onewire_timing_profile_t onewire_get_timing_profile(void);
     124                 :             : 
     125                 :             : /** @} */
     126                 :             : 
     127                 :             : /**
     128                 :             :  * @defgroup ONEWIRE_Init Init
     129                 :             :  * @{
     130                 :             :  */
     131                 :             : 
     132                 :             : /**
     133                 :             :  * @brief Initialize the shared 1-Wire timer/DMA/GPIO resources
     134                 :             :  * @note Enables GPIOA/TIM1/DMA1 clocks, sets the timer prescaler for 1µs
     135                 :             :  *       resolution, configures PA10 as alternate-function open-drain and marks
     136                 :             :  *       the search engine idle. Called once at startup, e.g. by the slave
     137                 :             :  *       driver's own init.
     138                 :             :  */
     139                 :             : void onewire_init(void);
     140                 :             : 
     141                 :             : /** @} */
     142                 :             : 
     143                 :             : /**
     144                 :             :  * @defgroup ONEWIRE_Bus Non-Blocking 1-Wire Bus Primitives
     145                 :             :  * @brief Each primitive schedules exactly one hardware-timed operation on
     146                 :             :  *        TIM1/DMA and returns immediately. Poll onewire_bus_done() to learn
     147                 :             :  *        when the operation finished, then decode the result.
     148                 :             :  * @{
     149                 :             :  */
     150                 :             : 
     151                 :             : /**
     152                 :             :  * @brief Non-blocking completion check for the scheduled bus operation
     153                 :             :  * @return 1 if finished (update flag cleared), 0 while still running
     154                 :             :  */
     155                 :             : uint8_t onewire_bus_done(void);
     156                 :             : 
     157                 :             : /**
     158                 :             :  * @brief Schedule a 1-Wire bus reset (presence pulse captured via DMA)
     159                 :             :  * @param[out] reset_pulses Buffer for the captured reset + presence pulse
     160                 :             :  *                          durations (2 x 16-bit)
     161                 :             :  * @note On completion, decode the presence pulse with onewire_present().
     162                 :             :  */
     163                 :             : void onewire_reset(volatile uint16_t* reset_pulses);
     164                 :             : 
     165                 :             : /**
     166                 :             :  * @brief Decode the presence pulse captured by onewire_reset()
     167                 :             :  * @param[in] pulses Reset + presence pulse durations captured by onewire_reset()
     168                 :             :  * @return 1 if at least one device answered, 0 otherwise
     169                 :             :  */
     170                 :             : uint8_t onewire_present(const volatile uint16_t* pulses);
     171                 :             : 
     172                 :             : /**
     173                 :             :  * @brief Schedule a write of `slots` bit slots
     174                 :             :  * @param[in] pulses Pulse buffer (one entry per slot); for `slots > 1` the
     175                 :             :  *                   entry at index `slots` must be 0 (hardware bus release)
     176                 :             :  * @param[in] slots Number of bit slots to transmit
     177                 :             :  * @note Non-blocking: the DMA feeds CCR3 from the buffer asynchronously, so
     178                 :             :  *       the buffer must stay valid until onewire_bus_done() reports completion.
     179                 :             :  */
     180                 :             : void onewire_write_slots(const uint8_t* pulses, uint16_t slots);
     181                 :             : 
     182                 :             : /**
     183                 :             :  * @brief Schedule a single-slot write of one raw bit
     184                 :             :  * @param[in] bit Bit value to write (0 or 1)
     185                 :             :  */
     186                 :             : void onewire_write_bit(uint8_t bit);
     187                 :             : 
     188                 :             : /**
     189                 :             :  * @brief Schedule a two-slot read of a Search ROM id/cmp bit pair
     190                 :             :  * @param[out] pair_pulses Buffer for the captured pulse durations (2 × 16-bit)
     191                 :             :  * @note On completion, decode the pair with onewire_pair_bits().
     192                 :             :  */
     193                 :             : void onewire_read_pair(volatile uint16_t* pair_pulses);
     194                 :             : 
     195                 :             : /**
     196                 :             :  * @brief Decode the id/cmp bits of a two-slot read pair
     197                 :             :  * @param[in] pair_pulses Pulses captured by onewire_read_pair()
     198                 :             :  * @param[out] id_bit Id bit (0 or 1)
     199                 :             :  * @param[out] cmp_bit Complement bit (0 or 1)
     200                 :             :  */
     201                 :             : void onewire_pair_bits(const volatile uint16_t* pair_pulses, uint8_t* id_bit, uint8_t* cmp_bit);
     202                 :             : 
     203                 :             : /**
     204                 :             :  * @brief Schedule a merged single-slot write followed by a two-slot read pair
     205                 :             :  * @param[in] bit Direction bit to write in slot 1 (0 or 1)
     206                 :             :  * @note One timer pass runs three slots: a write of `bit`, then a read of the
     207                 :             :  *       next id/cmp pair. Halves the timer passes per search bit compared to a
     208                 :             :  *       plain write plus a separate read pair. On completion, the internal
     209                 :             :  *       merged buffer holds [write-slot capture, id pulse, cmp pulse]: decode the
     210                 :             :  *       pair from entries 1 and 2 with onewire_bit_from_pulse(). Do not pass
     211                 :             :  *       this buffer to onewire_pair_bits(), which instead decodes entries 0 and
     212                 :             :  *       1 as produced by onewire_read_pair().
     213                 :             :  */
     214                 :             : void onewire_write_then_read(uint8_t bit);
     215                 :             : 
     216                 :             : /**
     217                 :             :  * @brief Schedule a read of `bytes` bytes from the bus
     218                 :             :  * @param[out] dst Buffer for the captured pulse durations (bytes × 8 × 8-bit)
     219                 :             :  * @param[in] bytes Number of bytes to read
     220                 :             :  * @note On completion, the caller decodes the 8-bit pulse durations (pulse
     221                 :             :  *       `<= ONEWIRE_SHORT_PULSE_MAX` reads as bit 1) into data bytes.
     222                 :             :  */
     223                 :             : void onewire_read_data(volatile uint8_t* dst, uint8_t bytes);
     224                 :             : 
     225                 :             : /**
     226                 :             :  * @brief Decode a single captured pulse duration into a 1-Wire bit
     227                 :             :  * @param[in] dur Pulse duration in microseconds
     228                 :             :  * @return 1 if the pulse is short (bit value '1'), 0 if long (bit value '0')
     229                 :             :  * @note A pulse duration `<= ONEWIRE_SHORT_PULSE_MAX` is the short ('1') slot.
     230                 :             :  */
     231                 :       50988 : static inline uint8_t onewire_bit_from_pulse(uint16_t dur) {
     232         [ +  + ]:       50988 :     return (dur <= ow_short_pulse_max_us) ? 1u : 0u;
     233                 :             : }
     234                 :             : 
     235                 :             : /**
     236                 :             :  * @brief Decode captured pulse durations into data bytes (LSB-first bits)
     237                 :             :  * @param[out] dst Decoded bytes
     238                 :             :  * @param[in] pulse Captured per-bit pulse durations (one entry per bit)
     239                 :             :  * @param[in] nbytes Number of bytes to decode (pulse must hold nbytes × 8 entries)
     240                 :             :  * @note Each bit is recovered with onewire_bit_from_pulse(); bit 0 maps to the
     241                 :             :  *       LSB of its byte. Recovers scratchpad / register bytes from the 1-Wire
     242                 :             :  *       read capture.
     243                 :             :  */
     244                 :             : void onewire_decode_pulses(uint8_t* dst, const volatile uint8_t* pulse, uint8_t nbytes);
     245                 :             : 
     246                 :             : /**
     247                 :             :  * @brief Encode a byte into write-pulse durations
     248                 :             :  * @param[out] out Output buffer (8 entries)
     249                 :             :  * @param[in] byte Byte value to encode
     250                 :             :  */
     251                 :             : void onewire_encode_byte(uint8_t* out, uint8_t byte);
     252                 :             : 
     253                 :             : /**
     254                 :             :  * @brief Start a hardware-timed wait with the shared one-pulse timer
     255                 :             :  * @param[in] arr Auto-reload value (one timer period in µs)
     256                 :             :  * @param[in] rcr Repetition counter (number of periods - 1)
     257                 :             :  * @note The timer update event fires after (RCR + 1) × ARR microseconds; used
     258                 :             :  *       for DS18B20 conversion waits and inter-measurement pauses.
     259                 :             :  */
     260                 :             : void onewire_start_timer(uint16_t arr, uint8_t rcr);
     261                 :             : 
     262                 :             : /**
     263                 :             :  * @brief Engage or release the parasite-power strong pull-up on the bus
     264                 :             :  * @param[in] on 1 drives the bus line HIGH actively (pin leaves the timer-
     265                 :             :  *                driven open-drain mode for a push-pull HIGH), 0 releases the
     266                 :             :  *                line back to the passive external pull-up
     267                 :             :  * @note Parasite-powered devices source their supply from the bus line and
     268                 :             :  *       need this active pull-up during energy-intensive phases: the whole
     269                 :             :  *       temperature conversion (tCONV, up to 750 ms) after Convert T and the
     270                 :             :  *       EEPROM programming window (tPROG) after Copy Scratchpad / Recall E².
     271                 :             :  *       Must only be called between hardware operations (bus idle), never
     272                 :             :  *       while a timed transaction is running.
     273                 :             :  */
     274                 :             : void onewire_strong_pullup(uint8_t on);
     275                 :             : 
     276                 :             : /** @} */
     277                 :             : 
     278                 :             : /**
     279                 :             :  * @defgroup ONEWIRE_Search Generic Non-Blocking Search ROM Engine
     280                 :             :  * @brief Implements the Maxim Search ROM (0xF0) / Alarm Search (0xEC)
     281                 :             :  *        algorithm as a polled state machine. The direction bit written at
     282                 :             :  *        position i determines which devices keep participating at position
     283                 :             :  *        i+1, so the transaction cannot be batched into one DMA pass; the
     284                 :             :  *        linear loop is decomposed into states with loop counters kept in the
     285                 :             :  *        context. Every state performs exactly one hardware-timed operation,
     286                 :             :  *        so a poll call never blocks.
     287                 :             :  * @{
     288                 :             :  */
     289                 :             : 
     290                 :             : /** @brief Per-device callback invoked by the search engine */
     291                 :             : typedef uint8_t (*onewire_search_sink_t)(const uint8_t* rom);
     292                 :             : 
     293                 :             : /**
     294                 :             :  * @brief Start a non-blocking search (Search ROM or Alarm Search)
     295                 :             :  * @param[in] sink Callback invoked per found device (may be NULL). A non-zero
     296                 :             :  *                 return value stops the search early.
     297                 :             :  * @param[in] max_devices Maximum number of devices to report (0 aborts)
     298                 :             :  * @param[in] command Search command byte (0xF0 Search ROM / 0xEC Alarm Search)
     299                 :             :  * @param[in] family 1-Wire family code to accept, or 0 to accept every family.
     300                 :             :  *                   Only accepted devices increment the found counter and
     301                 :             :  *                   reach the sink.
     302                 :             :  * @note Ignores the call while a search pass is already running. Arbitration
     303                 :             :  *       of the shared bus/timer against other 1-Wire operations lives in the
     304                 :             :  *       ds18b20_* layer, not here.
     305                 :             :  */
     306                 :             : void onewire_search_start(onewire_search_sink_t sink, uint8_t max_devices,
     307                 :             :                           uint8_t command, uint8_t family);
     308                 :             : 
     309                 :             : /**
     310                 :             :  * @brief Advance the non-blocking search by one hardware operation
     311                 :             :  * @return 1 when the search is finished, 0 while still running
     312                 :             :  */
     313                 :             : uint8_t onewire_search_poll(void);
     314                 :             : 
     315                 :             : /**
     316                 :             :  * @brief Number of devices found (valid once the search finished)
     317                 :             :  * @return Count of found devices
     318                 :             :  */
     319                 :             : uint8_t onewire_search_count(void);
     320                 :             : 
     321                 :             : /**
     322                 :             :  * @brief Check whether a search is currently running
     323                 :             :  * @return 1 while the search owns the timer, 0 when it is idle
     324                 :             :  */
     325                 :             : uint8_t onewire_search_active(void);
     326                 :             : 
     327                 :             : /** @} */
     328                 :             : 
     329                 :             : /**
     330                 :             :  * @defgroup ONEWIRE_CRC CRC-8
     331                 :             :  * @{
     332                 :             :  */
     333                 :             : 
     334                 :             : /**
     335                 :             :  * @brief Calculate the Dallas/Maxim 1-Wire CRC-8 over a byte buffer
     336                 :             :  * @param[in] data Input buffer
     337                 :             :  * @param[in] len Number of bytes to process
     338                 :             :  * @return CRC-8 checksum value
     339                 :             :  */
     340                 :             : uint8_t onewire_crc8(const uint8_t* data, uint8_t len);
     341                 :             : 
     342                 :             : /** @} */
     343                 :             : 
     344                 :             : #ifdef DS18B20_TEST_HARNESS
     345                 :             : /**
     346                 :             :  * @brief [TEST] Set the idle-HIGH gap injected between search slots
     347                 :             :  * @param[in] us Gap duration in microseconds (0 disables the injection)
     348                 :             :  * @note Temporary test hook for the RTOS-latency experiment only.
     349                 :             :  */
     350                 :             : void onewire_test_set_gap_us(uint16_t us);
     351                 :             : #endif
     352                 :             : 
     353                 :             : #endif /* ONEWIRE_H */
        

Generated by: LCOV version 2.0-1