diff --git a/common/pimoroni_common.hpp b/common/pimoroni_common.hpp index 3a788732..b7b14aef 100644 --- a/common/pimoroni_common.hpp +++ b/common/pimoroni_common.hpp @@ -96,4 +96,18 @@ namespace pimoroni { pin_pair() : first(0), second(0) {} pin_pair(uint8_t first, uint8_t second) : first(first), second(second) {} }; + + struct bool_pair { + union { + bool first; + bool a; + }; + union { + bool second; + bool b; + }; + + bool_pair() : first(false), second(false) {} + bool_pair(bool first, bool second) : first(first), second(second) {} + }; } \ No newline at end of file diff --git a/drivers/encoder-pio/encoder.cpp b/drivers/encoder-pio/encoder.cpp index 653a534f..53e08d7b 100644 --- a/drivers/encoder-pio/encoder.cpp +++ b/drivers/encoder-pio/encoder.cpp @@ -2,13 +2,14 @@ #include #include #include "hardware/irq.h" +#include "hardware/clocks.h" #include "encoder.hpp" #include "encoder.pio.h" #define LAST_STATE(state) ((state) & 0b0011) #define CURR_STATE(state) (((state) & 0b1100) >> 2) -namespace pimoroni { +namespace encoder { //////////////////////////////////////////////////////////////////////////////////////////////////// // STATICS @@ -18,64 +19,64 @@ uint8_t Encoder::claimed_sms[] = { 0x0, 0x0 }; uint Encoder::pio_program_offset[] = { 0, 0 }; -Encoder::Snapshot::Snapshot() +Encoder::Capture::Capture() : captured_count(0), captured_delta(0), captured_frequency(0.0f), counts_per_rev(INT32_MAX) { } -Encoder::Snapshot::Snapshot(int32_t count, int32_t delta, float frequency, float counts_per_rev) +Encoder::Capture::Capture(int32_t count, int32_t delta, float frequency, float counts_per_rev) : captured_count(count), captured_delta(delta), captured_frequency(frequency) , counts_per_rev(MAX(counts_per_rev, FLT_EPSILON)) { //Clamp counts_per_rev to avoid potential NaN } -int32_t Encoder::Snapshot::count() const { +int32_t Encoder::Capture::count() const { return captured_count; } -int32_t Encoder::Snapshot::delta() const { +int32_t Encoder::Capture::delta() const { return captured_delta; } -float Encoder::Snapshot::frequency() const { +float Encoder::Capture::frequency() const { return captured_frequency; } -float Encoder::Snapshot::revolutions() const { +float Encoder::Capture::revolutions() const { return (float)captured_count / counts_per_rev; } -float Encoder::Snapshot::degrees() const { +float Encoder::Capture::degrees() const { return revolutions() * 360.0f; } -float Encoder::Snapshot::radians() const { +float Encoder::Capture::radians() const { return revolutions() * M_TWOPI; } -float Encoder::Snapshot::revolutions_delta() const { +float Encoder::Capture::revolutions_delta() const { return (float)captured_delta / counts_per_rev; } -float Encoder::Snapshot::degrees_delta() const { +float Encoder::Capture::degrees_delta() const { return revolutions_delta() * 360.0f; } -float Encoder::Snapshot::radians_delta() const { +float Encoder::Capture::radians_delta() const { return revolutions_delta() * M_TWOPI; } -float Encoder::Snapshot::revolutions_per_second() const { +float Encoder::Capture::revolutions_per_second() const { return captured_frequency / counts_per_rev; } -float Encoder::Snapshot::revolutions_per_minute() const { +float Encoder::Capture::revolutions_per_minute() const { return revolutions_per_second() * 60.0f; } -float Encoder::Snapshot::degrees_per_second() const { +float Encoder::Capture::degrees_per_second() const { return revolutions_per_second() * 360.0f; } -float Encoder::Snapshot::radians_per_second() const { +float Encoder::Capture::radians_per_second() const { return revolutions_per_second() * M_TWOPI; } @@ -249,7 +250,7 @@ void Encoder::zero() { step_dir = NO_DIR; // may not be wanted? last_count = 0; - last_snapshot_count = 0; + last_capture_count = 0; } int16_t Encoder::step() const { @@ -288,23 +289,23 @@ void Encoder::counts_per_revolution(float counts_per_rev) { enc_counts_per_rev = MAX(counts_per_rev, FLT_EPSILON); } -Encoder::Snapshot Encoder::take_snapshot() { - // Take a snapshot of the current values +Encoder::Capture Encoder::capture() { + // Take a capture of the current values int32_t count = enc_count; int32_t cumulative_time = enc_cumulative_time; enc_cumulative_time = 0; - // Determine the change in counts since the last snapshot was taken - int32_t change = count - last_snapshot_count; - last_snapshot_count = count; + // Determine the change in counts since the last capture was taken + int32_t change = count - last_capture_count; + last_capture_count = count; - // Calculate the average frequency of state transitions + // Calculate the average frequency of steps float frequency = 0.0f; if(change != 0 && cumulative_time != INT32_MAX) { frequency = (clocks_per_time * (float)change) / (float)cumulative_time; } - return Snapshot(count, change, frequency, enc_counts_per_rev); + return Capture(count, change, frequency, enc_counts_per_rev); } void Encoder::process_steps() { @@ -319,8 +320,8 @@ void Encoder::process_steps() { // Extract the time (in cycles) it has been since the last received int32_t time_received = (received & TIME_MASK) + ENC_DEBOUNCE_TIME; - // For rotary encoders, only every fourth transition is cared about, causing an inaccurate time value - // To address this we accumulate the times received and zero it when a transition is counted + // For rotary encoders, only every fourth step is cared about, causing an inaccurate time value + // To address this we accumulate the times received and zero it when a step is counted if(!count_microsteps) { if(time_received + microstep_time < time_received) // Check to avoid integer overflow time_received = INT32_MAX; @@ -331,7 +332,7 @@ void Encoder::process_steps() { bool up = (enc_direction == NORMAL); - // Determine what transition occurred + // Determine what step occurred switch(LAST_STATE(states)) { //-------------------------------------------------- case MICROSTEP_0: diff --git a/drivers/encoder-pio/encoder.hpp b/drivers/encoder-pio/encoder.hpp index daea37e0..2a3f3833 100644 --- a/drivers/encoder-pio/encoder.hpp +++ b/drivers/encoder-pio/encoder.hpp @@ -3,27 +3,15 @@ #include "hardware/pio.h" #include "common/pimoroni_common.hpp" -namespace pimoroni { +using namespace pimoroni; + +namespace encoder { enum Direction { NORMAL = 0, REVERSED = 1, }; - struct bool_pair { - union { - bool first; - bool a; - }; - union { - bool second; - bool b; - }; - - bool_pair() : first(false), second(false) {} - bool_pair(bool first, bool second) : first(first), second(second) {} - }; - class Encoder { //-------------------------------------------------- // Constants @@ -67,7 +55,7 @@ namespace pimoroni { // Substructures //-------------------------------------------------- public: - class Snapshot { + class Capture { //-------------------------------------------------- // Variables //-------------------------------------------------- @@ -82,8 +70,8 @@ namespace pimoroni { // Constructors //-------------------------------------------------- public: - Snapshot(); - Snapshot(int32_t count, int32_t delta, float frequency, float counts_per_rev); + Capture(); + Capture(int32_t count, int32_t delta, float frequency, float counts_per_rev); //-------------------------------------------------- @@ -137,7 +125,7 @@ namespace pimoroni { volatile StepDir step_dir = NO_DIR; int32_t last_count = 0; - int32_t last_snapshot_count = 0; + int32_t last_capture_count = 0; bool initialised = false; @@ -193,7 +181,7 @@ namespace pimoroni { float counts_per_revolution() const; void counts_per_revolution(float counts_per_rev); - Snapshot take_snapshot(); + Capture capture(); //-------------------------------------------------- private: diff --git a/drivers/encoder-pio/encoder.pio b/drivers/encoder-pio/encoder.pio index 0c124afb..630fa6a6 100644 --- a/drivers/encoder-pio/encoder.pio +++ b/drivers/encoder-pio/encoder.pio @@ -50,13 +50,13 @@ osr_dec: ; Read the state of both encoder pins and check ; if they are different from the last state - jmp pin encA_was_high + jmp pin enc_a_was_high mov isr, null - jmp read_encB -encA_was_high: + jmp read_enc_b +enc_a_was_high: set y, 1 mov isr, y -read_encB: +read_enc_b: in pins, 1 mov y, isr jmp x!=y state_changed [1] @@ -77,7 +77,7 @@ state_changed: ; Perform a delay to debounce switch inputs set y, (ITERATIONS - 1) [SET_CYCLES - 1] -debounce_loop: +debounce_loop: jmp y-- debounce_loop [JMP_CYCLES - 1] ; Initialise the timer, as an inverse, and decrement @@ -93,8 +93,6 @@ y_dec: ; Initialisation Code ; -------------------------------------------------- % c-sdk { -#include "hardware/clocks.h" - static const uint8_t ENC_LOOP_CYCLES = encoder_wrap - encoder_wrap_target; // The time that the debounce takes, as the number of wrap loops that the debounce is equivalent to diff --git a/examples/pico_explorer_encoder/demo.cpp b/examples/pico_explorer_encoder/demo.cpp index 26cc65fb..4ebfb7ae 100644 --- a/examples/pico_explorer_encoder/demo.cpp +++ b/examples/pico_explorer_encoder/demo.cpp @@ -6,14 +6,15 @@ #include "quadrature_out.pio.h" using namespace pimoroni; +using namespace encoder; //-------------------------------------------------- // Constants //-------------------------------------------------- -static const pin_pair ENCODER_PINS = {1, 0}; -static const uint ENCODER_PIN_C = PIN_UNUSED; -static const uint ENCODER_SWITCH_PIN = 4; +static const pin_pair ENCODER_PINS = {1, 0}; +static const uint ENCODER_PIN_C = PIN_UNUSED; +static const uint ENCODER_SWITCH_PIN = 4; static constexpr float COUNTS_PER_REVOLUTION = 24; // 24 is for rotary encoders. For motor magnetic encoders uses // 12 times the gear ratio (e.g. 12 * 20 with a 20:1 ratio motor @@ -54,7 +55,7 @@ enum DrawState { uint16_t buffer[PicoExplorer::WIDTH * PicoExplorer::HEIGHT]; PicoExplorer pico_explorer(buffer); -Encoder encoder(pio0, 0, ENCODER_PINS, ENCODER_PIN_C, NORMAL, COUNTS_PER_REVOLUTION, COUNT_MICROSTEPS, FREQ_DIVIDER); +Encoder enc(pio0, 0, ENCODER_PINS, ENCODER_PIN_C, NORMAL, COUNTS_PER_REVOLUTION, COUNT_MICROSTEPS, FREQ_DIVIDER); volatile bool encA_readings[READINGS_SIZE]; volatile bool encB_readings[READINGS_SIZE]; @@ -145,13 +146,13 @@ uint32_t draw_plot(Point p1, Point p2, volatile bool (&readings)[READINGS_SIZE], //////////////////////////////////////////////////////////////////////////////////////////////////// bool repeating_timer_callback(struct repeating_timer *t) { if(drawing_to_screen && next_scratch_index < SCRATCH_SIZE) { - encA_scratch[next_scratch_index] = encoder.state().a; - encB_scratch[next_scratch_index] = encoder.state().b; + encA_scratch[next_scratch_index] = enc.state().a; + encB_scratch[next_scratch_index] = enc.state().b; next_scratch_index++; } else { - encA_readings[next_reading_index] = encoder.state().a; - encB_readings[next_reading_index] = encoder.state().b; + encA_readings[next_reading_index] = enc.state().a; + encB_readings[next_reading_index] = enc.state().b; next_reading_index++; if(next_reading_index >= READINGS_SIZE) @@ -179,10 +180,10 @@ void setup() { pico_explorer.clear(); pico_explorer.update(); - encoder.init(); + enc.init(); - bool encA = encoder.state().a; - bool encB = encoder.state().b; + bool encA = enc.state().a; + bool encB = enc.state().b; for(uint i = 0; i < READINGS_SIZE; i++) { encA_readings[i] = encA; encB_readings[i] = encB; @@ -226,11 +227,11 @@ int main() { // If the user has wired up their encoder switch, and it is pressed, set the encoder count to zero if(ENCODER_SWITCH_PIN != PIN_UNUSED && gpio_get(ENCODER_SWITCH_PIN)) { - encoder.zero(); + enc.zero(); } - // Take a snapshot of the current encoder state - Encoder::Snapshot snapshot = encoder.take_snapshot(); + // Capture the encoder state + Encoder::Capture capture = enc.capture(); // Spin Motor 1 either clockwise or counterclockwise depending on if B or Y are pressed if(pico_explorer.is_pressed(PicoExplorer::B) && !pico_explorer.is_pressed(PicoExplorer::Y)) { @@ -316,21 +317,21 @@ int main() { { std::stringstream sstream; - sstream << snapshot.count(); + sstream << capture.count(); pico_explorer.set_pen(255, 255, 255); pico_explorer.text("Count:", Point(10, 150), 200, 3); pico_explorer.set_pen(255, 128, 255); pico_explorer.text(sstream.str(), Point(110, 150), 200, 3); } { std::stringstream sstream; - sstream << std::fixed << std::setprecision(1) << snapshot.frequency() << "hz"; + sstream << std::fixed << std::setprecision(1) << capture.frequency() << "hz"; pico_explorer.set_pen(255, 255, 255); pico_explorer.text("Freq: ", Point(10, 180), 220, 3); pico_explorer.set_pen(128, 255, 255); pico_explorer.text(sstream.str(), Point(90, 180), 220, 3); } { std::stringstream sstream; - sstream << std::fixed << std::setprecision(1) << snapshot.revolutions_per_minute(); + sstream << std::fixed << std::setprecision(1) << capture.revolutions_per_minute(); pico_explorer.set_pen(255, 255, 255); pico_explorer.text("RPM: ", Point(10, 210), 220, 3); pico_explorer.set_pen(255, 255, 128); pico_explorer.text(sstream.str(), Point(80, 210), 220, 3); } diff --git a/micropython/modules/encoder/encoder.cpp b/micropython/modules/encoder/encoder.cpp index 61d6ef78..fd7ffbb0 100644 --- a/micropython/modules/encoder/encoder.cpp +++ b/micropython/modules/encoder/encoder.cpp @@ -5,7 +5,7 @@ #define MP_OBJ_TO_PTR2(o, t) ((t *)(uintptr_t)(o)) using namespace pimoroni; -//using namespace encoder; +using namespace encoder; extern "C" { #include "encoder.h" @@ -304,22 +304,22 @@ extern mp_obj_t Encoder_counts_per_revolution(size_t n_args, const mp_obj_t *pos extern mp_obj_t Encoder_capture(mp_obj_t self_in) { _Encoder_obj_t *self = MP_OBJ_TO_PTR2(self_in, _Encoder_obj_t); - Encoder::Snapshot snapshot = self->encoder->take_snapshot(); + Encoder::Capture capture = self->encoder->capture(); mp_obj_t tuple[] = { - mp_obj_new_int(snapshot.count()), - mp_obj_new_int(snapshot.delta()), - mp_obj_new_float(snapshot.frequency()), - mp_obj_new_float(snapshot.revolutions()), - mp_obj_new_float(snapshot.degrees()), - mp_obj_new_float(snapshot.radians()), - mp_obj_new_float(snapshot.revolutions_delta()), - mp_obj_new_float(snapshot.degrees_delta()), - mp_obj_new_float(snapshot.radians_delta()), - mp_obj_new_float(snapshot.revolutions_per_second()), - mp_obj_new_float(snapshot.revolutions_per_minute()), - mp_obj_new_float(snapshot.degrees_per_second()), - mp_obj_new_float(snapshot.radians_per_second()), + mp_obj_new_int(capture.count()), + mp_obj_new_int(capture.delta()), + mp_obj_new_float(capture.frequency()), + mp_obj_new_float(capture.revolutions()), + mp_obj_new_float(capture.degrees()), + mp_obj_new_float(capture.radians()), + mp_obj_new_float(capture.revolutions_delta()), + mp_obj_new_float(capture.degrees_delta()), + mp_obj_new_float(capture.radians_delta()), + mp_obj_new_float(capture.revolutions_per_second()), + mp_obj_new_float(capture.revolutions_per_minute()), + mp_obj_new_float(capture.degrees_per_second()), + mp_obj_new_float(capture.radians_per_second()), }; STATIC const qstr tuple_fields[] = {