drivers/pulse_counter: Use C11 atomics & bugfix
- Previously the pulse counter used GCC's built-in functions for atomic memory
access. This PR changes this to use C11 atomics instead:
- Use of C11 atomics instead of atomic build-in functions makes the code
more portable and readable.
- Previously pulse_counter_reset() did not use an atomic function, so that
resets would be racy. (E.g. on the 8-bit AVR platform an 16-bit store is
not atomic, unless special care (like using C11 atomics) is taken.)
This commit is contained in:
parent
743d7170e2
commit
2d81738cb9
@ -26,6 +26,11 @@
|
||||
#define PULSE_COUNTER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#ifdef __cplusplus
|
||||
#include "c11_atomics_compat.hpp"
|
||||
#else
|
||||
#include <stdatomic.h>
|
||||
#endif
|
||||
#include "periph/gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -44,7 +49,7 @@ typedef struct {
|
||||
* @brief Device descriptor for a pulse counter device
|
||||
*/
|
||||
typedef struct {
|
||||
int16_t pulse_count; /**< pulse counter */
|
||||
atomic_uint_least16_t pulse_count; /**< pulse counter */
|
||||
} pulse_counter_t;
|
||||
|
||||
/**
|
||||
@ -74,7 +79,7 @@ int16_t pulse_counter_read_with_reset(pulse_counter_t *dev);
|
||||
*
|
||||
* @return Accumulated pulse counts
|
||||
*/
|
||||
int16_t pulse_counter_read_without_reset(const pulse_counter_t *dev);
|
||||
int16_t pulse_counter_read_without_reset(pulse_counter_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Reset pulse counter value
|
||||
|
||||
@ -19,9 +19,8 @@
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "pulse_counter_params.h"
|
||||
#include "pulse_counter.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
@ -31,8 +30,8 @@ static void pulse_counter_trigger(void *arg)
|
||||
{
|
||||
pulse_counter_t *dev = (pulse_counter_t *)arg;
|
||||
|
||||
/* Use atomic operations to avoid messing with IRQ flags */
|
||||
__atomic_fetch_add(&(dev->pulse_count), 1, __ATOMIC_SEQ_CST);
|
||||
/* Use C11 atomic operations to avoid messing with IRQ flags */
|
||||
atomic_fetch_add(&(dev->pulse_count), 1);
|
||||
}
|
||||
|
||||
/* Initialize pulse counter */
|
||||
@ -50,29 +49,24 @@ int pulse_counter_init(pulse_counter_t *dev, const pulse_counter_params_t *param
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->pulse_count = 0;
|
||||
atomic_init(&dev->pulse_count, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return the accumulated pulse counts and reset the count to zero */
|
||||
int16_t pulse_counter_read_with_reset(pulse_counter_t *dev)
|
||||
{
|
||||
int16_t pulse_count_output = 0;
|
||||
int16_t reset_value = 0;
|
||||
|
||||
/* Use atomic operations to avoid messing with IRQ flags */
|
||||
__atomic_exchange(&(dev->pulse_count), &reset_value, &pulse_count_output, __ATOMIC_SEQ_CST);
|
||||
return pulse_count_output;
|
||||
return atomic_exchange(&(dev->pulse_count), 0);
|
||||
}
|
||||
|
||||
/* Return the accumulated pulse counts */
|
||||
int16_t pulse_counter_read_without_reset(const pulse_counter_t *dev)
|
||||
int16_t pulse_counter_read_without_reset(pulse_counter_t *dev)
|
||||
{
|
||||
return dev->pulse_count;
|
||||
return atomic_load(&dev->pulse_count);
|
||||
}
|
||||
|
||||
/* Reset the pulse count value to zero */
|
||||
void pulse_counter_reset(pulse_counter_t *dev)
|
||||
{
|
||||
dev->pulse_count = 0;
|
||||
atomic_store(&(dev->pulse_count), 0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user