3535
3636#define I2C_INST i2c0
3737
38+ // How long a low pulse must be to be counted.
39+ #ifdef CONFIG_MIN_PULSE_WIDTH_US
40+ #define MIN_PULSE_WIDTH_US (int64_t (CONFIG_MIN_PULSE_WIDTH_US))
41+ #else
42+ #define MIN_PULSE_WIDTH_US (100'000ULL )
43+ #endif // CONFIG_MIN_PULSE_WIDTH_US
44+
45+ static_assert (MIN_PULSE_WIDTH_US >= 10ULL ,
46+ " Minimum pulse width must be at least 10us!" );
47+
3848static constexpr std::uint32_t kDeviceInfoAddr {0x0 };
39- static constexpr std::uint32_t kEdgeCountAddr {0x800 };
49+ static constexpr std::uint32_t kPulseCountAddr {0x800 };
4050
4151// Board ID (this is set only once and stored here).
4252static char board_id[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1 ];
@@ -47,9 +57,8 @@ static DeviceInfoBlock data;
4757// EEPROM peripheral.
4858static AT24CM02 eeprom{I2C_INST, true };
4959
50- static volatile std::uint32_t edgecount;
51- static std::uint32_t last_edgecount;
52- static volatile ::absolute_time_t last_edge_time;
60+ static volatile std::uint32_t pulsecount;
61+ static std::uint32_t last_pulsecount;
5362
5463[[noreturn]] static void Panic () noexcept {
5564 while (1 ) {
@@ -82,20 +91,20 @@ static void ValidateDeviceInfo() noexcept {
8291 }
8392}
8493
85- static void StoreEdgeCount (std::uint32_t ec ) noexcept {
86- if (!eeprom.Write (kEdgeCountAddr , reinterpret_cast <const std::uint8_t *>(&ec ),
87- sizeof (ec ))) {
94+ static void StorePulseCount (std::uint32_t pc ) noexcept {
95+ if (!eeprom.Write (kPulseCountAddr , reinterpret_cast <const std::uint8_t *>(&pc ),
96+ sizeof (pc ))) {
8897 Panic ();
8998 }
9099}
91100
92- static void LoadEdgeCount () noexcept {
93- std::uint32_t ec ;
94- if (!eeprom.Read (kEdgeCountAddr , reinterpret_cast <std::uint8_t *>(&ec ),
95- sizeof (ec ))) {
101+ static void LoadPulseCount () noexcept {
102+ std::uint32_t pc ;
103+ if (!eeprom.Read (kPulseCountAddr , reinterpret_cast <std::uint8_t *>(&pc ),
104+ sizeof (pc ))) {
96105 Panic ();
97106 }
98- edgecount = ec ;
107+ pulsecount = pc ;
99108}
100109
101110[[nodiscard]] static bool WriteLockEnabled () noexcept {
@@ -147,8 +156,8 @@ static void HandleSerialMessage(std::string_view message) noexcept {
147156 } else {
148157 std::printf (" ERR\n " );
149158 }
150- } else if (header == " EDGECOUNT " sv) {
151- std::printf (" %u\n " , edgecount );
159+ } else if (header == " PULSECOUNT " sv) {
160+ std::printf (" %u\n " , pulsecount );
152161 }
153162 }
154163 } else {
@@ -159,9 +168,9 @@ static void HandleSerialMessage(std::string_view message) noexcept {
159168 StoreDeviceInfo ();
160169 }
161170 } else if (header == " RESETCOUNT" sv) {
162- StoreEdgeCount (0 );
163- edgecount = 0 ;
164- last_edgecount = 0 ;
171+ StorePulseCount (0 );
172+ pulsecount = 0 ;
173+ last_pulsecount = 0 ;
165174 }
166175 }
167176}
@@ -203,28 +212,37 @@ int main(void) {
203212 LoadDeviceInfo ();
204213 ValidateDeviceInfo ();
205214
206- LoadEdgeCount ();
215+ LoadPulseCount ();
207216 // check for blank EEPROM
208- if (edgecount == 0xFFFFFFFF ) {
209- edgecount = 0 ;
210- StoreEdgeCount (0 );
217+ if (pulsecount == 0xFFFFFFFF ) {
218+ pulsecount = 0 ;
219+ StorePulseCount (0 );
211220 }
212221
213222 // Get the board ID (we only need to do this once)
214223 ::pico_get_unique_board_id_string (board_id, sizeof (board_id));
215224
216- last_edgecount = edgecount;
217- last_edge_time = ::get_absolute_time ();
225+ last_pulsecount = pulsecount;
226+ static volatile ::absolute_time_t falling_edge_time = ::get_absolute_time ();
227+ static volatile bool pulse_started = false ;
218228
219- // Falling edges increase the edge count.
229+ // When we see a falling edge, store the time that happened. When we see
230+ // a rising edge, see how long the pulse was, and if it was long enough,
231+ // increment the edge count. Else, we wait for the next falling edge.
220232 ::gpio_set_irq_enabled_with_callback (
221- PIN_SWITCH, GPIO_IRQ_EDGE_FALL, true , [](::uint, std::uint32_t ) {
233+ PIN_SWITCH, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true ,
234+ [](::uint, std::uint32_t event_mask) {
222235 const auto now = ::get_absolute_time ();
223- const auto diff = ::absolute_time_diff_us (last_edge_time, now);
224- // 50ms debounce
225- if (diff >= 50'000 ) {
226- last_edge_time = now;
227- edgecount = edgecount + 1 ;
236+ if (!pulse_started && (event_mask & GPIO_IRQ_EDGE_FALL)) {
237+ pulse_started = true ;
238+ falling_edge_time = now;
239+ } else if (pulse_started && (event_mask & GPIO_IRQ_EDGE_RISE)) {
240+ const auto diff = ::absolute_time_diff_us (falling_edge_time, now);
241+ // Look for low pulses wide enough to be counted.
242+ if (diff >= MIN_PULSE_WIDTH_US) {
243+ pulse_started = false ;
244+ pulsecount = pulsecount + 1 ;
245+ }
228246 }
229247 });
230248
@@ -234,8 +252,8 @@ int main(void) {
234252 while (1 ) {
235253 c = ::getchar_timeout_us (10 );
236254 if (c == PICO_ERROR_TIMEOUT) {
237- if (edgecount != last_edgecount ) {
238- StoreEdgeCount (last_edgecount = edgecount );
255+ if (pulsecount != last_pulsecount ) {
256+ StorePulseCount (last_pulsecount = pulsecount );
239257 }
240258 continue ;
241259 }
0 commit comments