diff --git a/drivers/encoder-pio/CMakeLists.txt b/drivers/encoder-pio/CMakeLists.txt index 3acea382..9dce7452 100644 --- a/drivers/encoder-pio/CMakeLists.txt +++ b/drivers/encoder-pio/CMakeLists.txt @@ -1,13 +1 @@ -add_library(encoder-pio INTERFACE) - -target_sources(encoder-pio INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/encoder.cpp - ${CMAKE_CURRENT_LIST_DIR}/capture.cpp -) - -pico_generate_pio_header(encoder-pio ${CMAKE_CURRENT_LIST_DIR}/encoder.pio) - -target_include_directories(encoder-pio INTERFACE ${CMAKE_CURRENT_LIST_DIR}) - -# Pull in pico libraries that we need -target_link_libraries(encoder-pio INTERFACE pico_stdlib hardware_pio) \ No newline at end of file +include(encoder-pio.cmake) \ No newline at end of file diff --git a/drivers/encoder-pio/capture.hpp b/drivers/encoder-pio/capture.hpp index 2aa6edaf..458daebe 100644 --- a/drivers/encoder-pio/capture.hpp +++ b/drivers/encoder-pio/capture.hpp @@ -10,7 +10,7 @@ namespace pimoroni { //-------------------------------------------------- private: const int32_t captured_count = 0; - const int32_t count_change = 0; + const int32_t count_change = 0; const float average_frequency = 0.0f; const float counts_per_revolution = 1; @@ -34,7 +34,7 @@ namespace pimoroni { int32_t get_count_change() const; - float get_frequency() const; + float get_frequency() const; float get_revolutions_per_second() const; float get_revolutions_per_minute() const; float get_degrees_per_second() const; diff --git a/drivers/encoder-pio/encoder-pio.cmake b/drivers/encoder-pio/encoder-pio.cmake index 37b3959a..74737526 100644 --- a/drivers/encoder-pio/encoder-pio.cmake +++ b/drivers/encoder-pio/encoder-pio.cmake @@ -1,12 +1,17 @@ -add_library(encoder-pio INTERFACE) +set(DRIVER_NAME encoder-pio) +add_library(${DRIVER_NAME} INTERFACE) -target_sources(encoder-pio INTERFACE - ${CMAKE_CURRENT_LIST_DIR}/msa301.cpp +target_sources(${DRIVER_NAME} INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/encoder.cpp + ${CMAKE_CURRENT_LIST_DIR}/capture.cpp ) -pico_generate_pio_header(encoder-pio ${CMAKE_CURRENT_LIST_DIR}/encoder.pio) +pico_generate_pio_header(${DRIVER_NAME} ${CMAKE_CURRENT_LIST_DIR}/encoder.pio) -target_include_directories(encoder-pio INTERFACE ${CMAKE_CURRENT_LIST_DIR}) +target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR}) # Pull in pico libraries that we need -target_link_libraries(encoder-pio INTERFACE pico_stdlib hardware_i2c) \ No newline at end of file +target_link_libraries(${DRIVER_NAME} INTERFACE + pico_stdlib + hardware_pio + ) \ No newline at end of file diff --git a/drivers/encoder-pio/encoder.cpp b/drivers/encoder-pio/encoder.cpp index 730b74df..908472d7 100644 --- a/drivers/encoder-pio/encoder.cpp +++ b/drivers/encoder-pio/encoder.cpp @@ -17,7 +17,7 @@ namespace pimoroni { //////////////////////////////////////////////////////////////////////////////////////////////////// void Encoder::pio0_interrupt_callback() { - //Go through each of encoders on this PIO to see which triggered this interrupt + // Go through each of encoders on this PIO to see which triggered this interrupt for(uint8_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { if(pio_encoders[0][sm] != nullptr) { pio_encoders[0][sm]->check_for_transition(); @@ -27,7 +27,7 @@ namespace pimoroni { //////////////////////////////////////////////////////////////////////////////////////////////////// void Encoder::pio1_interrupt_callback() { - //Go through each of encoders on this PIO to see which triggered this interrupt + // Go through each of encoders on this PIO to see which triggered this interrupt for(uint8_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { if(pio_encoders[1][sm] != nullptr) { pio_encoders[1][sm]->check_for_transition(); @@ -41,7 +41,7 @@ namespace pimoroni { // CONSTRUCTORS / DESTRUCTOR //////////////////////////////////////////////////////////////////////////////////////////////////// Encoder::Encoder(PIO pio, uint8_t pinA, uint8_t pinB, uint8_t pinC, - float counts_per_revolution, bool count_microsteps, + float counts_per_revolution, bool count_microsteps, uint16_t freq_divider) : enc_pio(pio), pinA(pinA), pinB(pinB), pinC(pinC), counts_per_revolution(counts_per_revolution), count_microsteps(count_microsteps), @@ -50,13 +50,13 @@ namespace pimoroni { //////////////////////////////////////////////////////////////////////////////////////////////////// Encoder::~Encoder() { - //Clean up our use of the SM associated with this encoder + // Clean up our use of the SM associated with this encoder encoder_program_release(enc_pio, enc_sm); uint index = pio_get_index(enc_pio); pio_encoders[index][enc_sm] = nullptr; pio_claimed_sms[index] &= ~(1u << enc_sm); - //If there are no more SMs using the encoder program, then we can remove it from the PIO + // If there are no more SMs using the encoder program, then we can remove it from the PIO if(pio_claimed_sms[index] == 0) { pio_remove_program(enc_pio, &encoder_program, enc_offset); } @@ -70,10 +70,10 @@ namespace pimoroni { bool Encoder::init() { bool initialised = false; - //Are the pins we want to use actually valid? + // Are the pins we want to use actually valid? if((pinA < NUM_BANK0_GPIOS) && (pinB < NUM_BANK0_GPIOS)) { - //If a Pin C was defined, and valid, set it as a GND to pull the other two pins down + // If a Pin C was defined, and valid, set it as a GND to pull the other two pins down if((pinC != PIN_UNUSED) && (pinC < NUM_BANK0_GPIOS)) { gpio_init(pinC); gpio_set_dir(pinC, GPIO_OUT); @@ -83,9 +83,9 @@ namespace pimoroni { enc_sm = pio_claim_unused_sm(enc_pio, true); uint pio_idx = pio_get_index(enc_pio); - //Is this the first time using an encoder on this PIO? + // Is this the first time using an encoder on this PIO? if(pio_claimed_sms[pio_idx] == 0) { - //Add the program to the PIO memory and enable the appropriate interrupt + // Add the program to the PIO memory and enable the appropriate interrupt enc_offset = pio_add_program(enc_pio, &encoder_program); encoder_program_init(enc_pio, enc_sm, enc_offset, pinA, pinB, freq_divider); hw_set_bits(&enc_pio->inte0, PIO_IRQ0_INTE_SM0_RXNEMPTY_BITS << enc_sm); @@ -99,11 +99,11 @@ namespace pimoroni { } } - //Keep a record of this encoder for the interrupt callback + // Keep a record of this encoder for the interrupt callback pio_encoders[pio_idx][enc_sm] = this; pio_claimed_sms[pio_idx] |= 1u << enc_sm; - //Read the current state of the encoder pins and start the PIO program on the SM + // Read the current state of the encoder pins and start the PIO program on the SM stateA = gpio_get(pinA); stateB = gpio_get(pinB); encoder_program_start(enc_pio, enc_sm, stateA, stateB); @@ -175,18 +175,18 @@ namespace pimoroni { //////////////////////////////////////////////////////////////////////////////////////////////////// Capture Encoder::perform_capture() { - //Capture the current values - int32_t captured_count = count; - int32_t captured_cumulative_time = cumulative_time; - cumulative_time = 0; + // Capture the current values + int32_t captured_count = count; + int32_t captured_cumulative_time = cumulative_time; + cumulative_time = 0; - //Determine the change in counts since the last capture was performed - int32_t count_change = captured_count - last_captured_count; - last_captured_count = captured_count; + // Determine the change in counts since the last capture was performed + int32_t count_change = captured_count - last_captured_count; + last_captured_count = captured_count; - //Calculate the average frequency of state transitions + // Calculate the average frequency of state transitions float average_frequency = 0.0f; - if(count_change != 0 && captured_cumulative_time != INT_MAX) { + if(count_change != 0 && captured_cumulative_time != INT_MAX) { average_frequency = (clocks_per_time * (float)count_change) / (float)captured_cumulative_time; } @@ -233,7 +233,7 @@ namespace pimoroni { // 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 if(!count_microsteps) { - if(time_received + microstep_time < time_received) //Check to avoid integer overflow + if(time_received + microstep_time < time_received) // Check to avoid integer overflow time_received = INT32_MAX; else time_received += microstep_time; @@ -256,7 +256,7 @@ namespace pimoroni { // B ____|‾‾‾‾ case MICROSTEP_3: if(count_microsteps) - microstep_down(time_received); + microstep_down(time_received); break; } break; @@ -270,7 +270,7 @@ namespace pimoroni { if(count_microsteps || last_travel_dir == CLOCKWISE) microstep_up(time_received); - last_travel_dir = NO_DIR; //Finished turning clockwise + last_travel_dir = NO_DIR; // Finished turning clockwise break; // A ‾‾‾‾|____ @@ -291,7 +291,7 @@ namespace pimoroni { if(count_microsteps) microstep_up(time_received); - last_travel_dir = CLOCKWISE; //Started turning clockwise + last_travel_dir = CLOCKWISE; // Started turning clockwise break; // A ‾‾‾‾‾‾‾‾‾ @@ -300,7 +300,7 @@ namespace pimoroni { if(count_microsteps) microstep_down(time_received); - last_travel_dir = COUNTERCLOCK; //Started turning counter-clockwise + last_travel_dir = COUNTERCLOCK; // Started turning counter-clockwise break; } break; @@ -320,8 +320,8 @@ namespace pimoroni { case MICROSTEP_2: if(count_microsteps || last_travel_dir == COUNTERCLOCK) microstep_down(time_received); - - last_travel_dir = NO_DIR; //Finished turning counter-clockwise + + last_travel_dir = NO_DIR; // Finished turning counter-clockwise break; } break; diff --git a/drivers/encoder-pio/encoder.hpp b/drivers/encoder-pio/encoder.hpp index a3f27df5..535db71c 100644 --- a/drivers/encoder-pio/encoder.hpp +++ b/drivers/encoder-pio/encoder.hpp @@ -12,7 +12,7 @@ namespace pimoroni { public: static constexpr float DEFAULT_COUNTS_PER_REV = 24; static const uint16_t DEFAULT_COUNT_MICROSTEPS = false; - static const uint16_t DEFAULT_FREQ_DIVIDER = 1; + static const uint16_t DEFAULT_FREQ_DIVIDER = 1; static const uint8_t PIN_UNUSED = UINT8_MAX; private: @@ -58,7 +58,7 @@ namespace pimoroni { const float clocks_per_time = 0; //-------------------------------------------------- - + uint enc_sm = 0; uint enc_offset = 0; @@ -108,7 +108,7 @@ namespace pimoroni { float get_angle_degrees() const; float get_angle_radians() const; - float get_frequency() const; + float get_frequency() const; float get_revolutions_per_second() const; float get_revolutions_per_minute() const; float get_degrees_per_second() const; diff --git a/examples/pico_explorer_encoder/demo.cpp b/examples/pico_explorer_encoder/demo.cpp index 1f434c94..fbf17dff 100644 --- a/examples/pico_explorer_encoder/demo.cpp +++ b/examples/pico_explorer_encoder/demo.cpp @@ -16,24 +16,24 @@ static const uint8_t ENCODER_PIN_B = 0; static const uint8_t ENCODER_PIN_C = Encoder::PIN_UNUSED; static const uint8_t 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 -static const bool COUNT_MICROSTEPS = false; //Set to true for motor magnetic encoders +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 +static const bool COUNT_MICROSTEPS = false; // Set to true for motor magnetic encoders -static const uint16_t FREQ_DIVIDER = 1; //Increase this to deal with switch bounce. 250 Gives a 1ms debounce +static const uint16_t FREQ_DIVIDER = 1; // Increase this to deal with switch bounce. 250 Gives a 1ms debounce -static const int32_t TIME_BETWEEN_SAMPLES_US = 100; //Time between each sample, in microseconds -static const int32_t WINDOW_DURATION_US = 1000000; //The full time window that will be stored +static const int32_t TIME_BETWEEN_SAMPLES_US = 100; // Time between each sample, in microseconds +static const int32_t WINDOW_DURATION_US = 1000000; // The full time window that will be stored static const int32_t READINGS_SIZE = WINDOW_DURATION_US / TIME_BETWEEN_SAMPLES_US; -static const int32_t SCRATCH_SIZE = READINGS_SIZE / 10; //A smaller value, for temporarily storing readings during screen drawing +static const int32_t SCRATCH_SIZE = READINGS_SIZE / 10; // A smaller value, for temporarily storing readings during screen drawing static const bool QUADRATURE_OUT_ENABLED = true; -static constexpr float QUADRATURE_OUT_FREQ = 800; //The frequency the quadrature output will run at (note that counting microsteps will show 4x this value) -static const float QUADRATURE_OUT_1ST_PIN = 6; //Which first pin to output the quadrature signal to (e.g. pins 6 and 7) +static constexpr float QUADRATURE_OUT_FREQ = 800; // The frequency the quadrature output will run at (note that counting microsteps will show 4x this value) +static const float QUADRATURE_OUT_1ST_PIN = 6; // Which first pin to output the quadrature signal to (e.g. pins 6 and 7) -static const uint64_t MAIN_LOOP_TIME_US = 50000; //How long there should be in microseconds between each screen refresh -static const uint16_t EDGE_ALIGN_ABOVE_ZOOM = 4; //The zoom level beyond which edge alignment will be enabled to ma +static const uint64_t MAIN_LOOP_TIME_US = 50000; // How long there should be in microseconds between each screen refresh +static const uint16_t EDGE_ALIGN_ABOVE_ZOOM = 4; // The zoom level beyond which edge alignment will be enabled to ma @@ -71,136 +71,131 @@ uint16_t current_zoom_level = 1; //////////////////////////////////////////////////////////////////////////////////////////////////// // FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////////// -uint32_t draw_plot(Point p1, Point p2, volatile bool (&readings)[READINGS_SIZE], uint32_t readingPos, bool edge_align) -{ - uint32_t reading_window = READINGS_SIZE / current_zoom_level; - uint32_t start_index_no_modulus = (readingPos + (READINGS_SIZE - reading_window)); - uint32_t start_index = start_index_no_modulus % READINGS_SIZE; - int32_t screen_window = std::min(p2.x, (int32_t)PicoExplorer::WIDTH) - p1.x; +uint32_t draw_plot(Point p1, Point p2, volatile bool (&readings)[READINGS_SIZE], uint32_t readingPos, bool edge_align) { + uint32_t reading_window = READINGS_SIZE / current_zoom_level; + uint32_t start_index_no_modulus = (readingPos + (READINGS_SIZE - reading_window)); + uint32_t start_index = start_index_no_modulus % READINGS_SIZE; + int32_t screen_window = std::min(p2.x, (int32_t)PicoExplorer::WIDTH) - p1.x; - bool last_reading = readings[start_index % READINGS_SIZE]; + bool last_reading = readings[start_index % READINGS_SIZE]; - uint32_t alignment_offset = 0; - if(edge_align) { - //Perform edge alignment by first seeing if there is a window of readings available (will be at anything other than x1 zoom) - uint32_t align_window = (start_index_no_modulus - readingPos); + uint32_t alignment_offset = 0; + if(edge_align) { + // Perform edge alignment by first seeing if there is a window of readings available (will be at anything other than x1 zoom) + uint32_t align_window = (start_index_no_modulus - readingPos); - //Then go backwards through that window - for(uint32_t i = 1; i < align_window; i++) { - uint32_t align_index = (start_index + (READINGS_SIZE - i)) % READINGS_SIZE; - bool align_reading = readings[align_index]; + // Then go backwards through that window + for(uint32_t i = 1; i < align_window; i++) { + uint32_t align_index = (start_index + (READINGS_SIZE - i)) % READINGS_SIZE; + bool align_reading = readings[align_index]; - //Has a transition from high to low been detected? - if(!align_reading && align_reading != last_reading) { - //Set the new start index from which to draw from and break out of the search - start_index = align_index; - alignment_offset = i; - break; - } - last_reading = align_reading; - } - - last_reading = readings[start_index % READINGS_SIZE]; + // Has a transition from high to low been detected? + if(!align_reading && align_reading != last_reading) { + // Set the new start index from which to draw from and break out of the search + start_index = align_index; + alignment_offset = i; + break; + } + last_reading = align_reading; } - //Go through each X pixel within the screen window - uint32_t reading_window_start = 0; - for(int32_t x = 0; x < screen_window; x++) - { - uint32_t reading_window_end = ((x + 1) * reading_window) / screen_window; + last_reading = readings[start_index % READINGS_SIZE]; + } - //Set the draw state to be whatever the last reading was - DrawState draw_state = last_reading ? DRAW_HIGH : DRAW_LOW; + // Go through each X pixel within the screen window + uint32_t reading_window_start = 0; + for(int32_t x = 0; x < screen_window; x++) { + uint32_t reading_window_end = ((x + 1) * reading_window) / screen_window; - //Go through the readings in this window to see if a transition from low to high or high to low occurs - if(reading_window_end > reading_window_start) { - for(uint32_t i = reading_window_start; i < reading_window_end; i++) { - bool reading = readings[(i + start_index) % READINGS_SIZE]; - if(reading != last_reading) { - draw_state = DRAW_TRANSITION; - break; //A transition occurred, so no need to continue checking readings - } - last_reading = reading; - } - last_reading = readings[((reading_window_end - 1) + start_index) % READINGS_SIZE]; - } - reading_window_start = reading_window_end; - - //Draw a pixel in a high or low position, or a line between the two if a transition - switch(draw_state) - { - case DRAW_TRANSITION: - for(uint8_t y = p1.y; y < p2.y; y++) - pico_explorer.pixel(Point(x + p1.x, y)); - break; - case DRAW_HIGH: - pico_explorer.pixel(Point(x + p1.x, p1.y)); - break; - case DRAW_LOW: - pico_explorer.pixel(Point(x + p1.x, p2.y - 1)); - break; + // Set the draw state to be whatever the last reading was + DrawState draw_state = last_reading ? DRAW_HIGH : DRAW_LOW; + + // Go through the readings in this window to see if a transition from low to high or high to low occurs + if(reading_window_end > reading_window_start) { + for(uint32_t i = reading_window_start; i < reading_window_end; i++) { + bool reading = readings[(i + start_index) % READINGS_SIZE]; + if(reading != last_reading) { + draw_state = DRAW_TRANSITION; + break; // A transition occurred, so no need to continue checking readings } + last_reading = reading; + } + last_reading = readings[((reading_window_end - 1) + start_index) % READINGS_SIZE]; } + reading_window_start = reading_window_end; - //Return the alignment offset so subsequent encoder channel plots can share the alignment - return alignment_offset; + // Draw a pixel in a high or low position, or a line between the two if a transition + switch(draw_state) { + case DRAW_TRANSITION: + for(uint8_t y = p1.y; y < p2.y; y++) + pico_explorer.pixel(Point(x + p1.x, y)); + break; + case DRAW_HIGH: + pico_explorer.pixel(Point(x + p1.x, p1.y)); + break; + case DRAW_LOW: + pico_explorer.pixel(Point(x + p1.x, p2.y - 1)); + break; + } + } + + // Return the alignment offset so subsequent encoder channel plots can share the alignment + return alignment_offset; } //////////////////////////////////////////////////////////////////////////////////////////////////// bool repeating_timer_callback(struct repeating_timer *t) { - if(drawing_to_screen && next_scratch_index < SCRATCH_SIZE) { - encA_scratch[next_scratch_index] = encoder.get_state_a(); - encB_scratch[next_scratch_index] = encoder.get_state_b(); - next_scratch_index++; - } - else { - encA_readings[next_reading_index] = encoder.get_state_a(); - encB_readings[next_reading_index] = encoder.get_state_b(); + if(drawing_to_screen && next_scratch_index < SCRATCH_SIZE) { + encA_scratch[next_scratch_index] = encoder.get_state_a(); + encB_scratch[next_scratch_index] = encoder.get_state_b(); + next_scratch_index++; + } + else { + encA_readings[next_reading_index] = encoder.get_state_a(); + encB_readings[next_reading_index] = encoder.get_state_b(); - next_reading_index++; - if(next_reading_index >= READINGS_SIZE) - next_reading_index = 0; - } + next_reading_index++; + if(next_reading_index >= READINGS_SIZE) + next_reading_index = 0; + } - return true; + return true; } void setup() { - stdio_init_all(); + stdio_init_all(); - gpio_init(PICO_DEFAULT_LED_PIN); - gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); + gpio_init(PICO_DEFAULT_LED_PIN); + gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); - if(ENCODER_SWITCH_PIN != Encoder::PIN_UNUSED) { - gpio_init(ENCODER_SWITCH_PIN); - gpio_set_dir(ENCODER_SWITCH_PIN, GPIO_IN); - gpio_pull_down(ENCODER_SWITCH_PIN); - } + if(ENCODER_SWITCH_PIN != Encoder::PIN_UNUSED) { + gpio_init(ENCODER_SWITCH_PIN); + gpio_set_dir(ENCODER_SWITCH_PIN, GPIO_IN); + gpio_pull_down(ENCODER_SWITCH_PIN); + } - pico_explorer.init(); - pico_explorer.set_pen(0); - pico_explorer.clear(); - pico_explorer.update(); + pico_explorer.init(); + pico_explorer.set_pen(0); + pico_explorer.clear(); + pico_explorer.update(); - encoder.init(); + encoder.init(); - bool encA = encoder.get_state_a(); - bool encB = encoder.get_state_b(); - for(uint i = 0; i < READINGS_SIZE; i++) { - encA_readings[i] = encA; - encB_readings[i] = encB; - } + bool encA = encoder.get_state_a(); + bool encB = encoder.get_state_b(); + for(uint i = 0; i < READINGS_SIZE; i++) { + encA_readings[i] = encA; + encB_readings[i] = encB; + } - if(QUADRATURE_OUT_ENABLED) { - //Set up the quadrature encoder output - PIO pio = pio1; - uint offset = pio_add_program(pio, &quadrature_out_program); - uint sm = pio_claim_unused_sm(pio, true); - quadrature_out_program_init(pio, sm, offset, QUADRATURE_OUT_1ST_PIN, QUADRATURE_OUT_FREQ); - } - - pico_explorer.set_backlight(255); + if(QUADRATURE_OUT_ENABLED) { + // Set up the quadrature encoder output + PIO pio = pio1; + uint offset = pio_add_program(pio, &quadrature_out_program); + uint sm = pio_claim_unused_sm(pio, true); + quadrature_out_program_init(pio, sm, offset, QUADRATURE_OUT_1ST_PIN, QUADRATURE_OUT_FREQ); + } } @@ -210,136 +205,139 @@ void setup() { //////////////////////////////////////////////////////////////////////////////////////////////////// int main() { - //Perform the main setup for the demo - setup(); + // Perform the main setup for the demo + setup(); - //Begin the timer that will take readings of the coder at regular intervals - struct repeating_timer timer; - add_repeating_timer_us(-TIME_BETWEEN_SAMPLES_US, repeating_timer_callback, NULL, &timer); + // Begin the timer that will take readings of the coder at regular intervals + struct repeating_timer timer; + add_repeating_timer_us(-TIME_BETWEEN_SAMPLES_US, repeating_timer_callback, NULL, &timer); - bool aPressedLatch = false; - bool xPressedLatch = false; - uint64_t last_time = time_us_64(); + bool aPressedLatch = false; + bool xPressedLatch = false; + uint64_t last_time = time_us_64(); - while(true) { - - //Has enough time elapsed since we last refreshed the screen? - uint64_t current_time = time_us_64(); - if(current_time > last_time + MAIN_LOOP_TIME_US) { - last_time = current_time; - - gpio_put(PICO_DEFAULT_LED_PIN, true); //Show the screen refresh has stated + while(true) { - //If the user has wired up their encoder switch, and it is pressed, set the encoder count to zero - if(ENCODER_SWITCH_PIN != Encoder::PIN_UNUSED && gpio_get(ENCODER_SWITCH_PIN)) { - encoder.zero_count(); - } + // Has enough time elapsed since we last refreshed the screen? + uint64_t current_time = time_us_64(); + if(current_time > last_time + MAIN_LOOP_TIME_US) { + last_time = current_time; - //Take a capture, or snapshot of the current encoder state - Capture capture = encoder.perform_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)) - pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::FORWARD, 1.0f); - else if(pico_explorer.is_pressed(PicoExplorer::Y) && !pico_explorer.is_pressed(PicoExplorer::B)) - pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::REVERSE, 0.2f); - else - pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::STOP); - + gpio_put(PICO_DEFAULT_LED_PIN, true); // Show the screen refresh has stated - //If A has been pressed, zoom the view out to a min of x1 - if(pico_explorer.is_pressed(PicoExplorer::A)) { - if(!aPressedLatch) { - aPressedLatch = true; - current_zoom_level = std::max(current_zoom_level / 2, 1); - } - } - else { - aPressedLatch = false; - } + // If the user has wired up their encoder switch, and it is pressed, set the encoder count to zero + if(ENCODER_SWITCH_PIN != Encoder::PIN_UNUSED && gpio_get(ENCODER_SWITCH_PIN)) { + encoder.zero_count(); + } - //If X has been pressed, zoom the view in to the max of x512 - if(pico_explorer.is_pressed(PicoExplorer::X)) { - if(!xPressedLatch) { - xPressedLatch = true; - current_zoom_level = std::min(current_zoom_level * 2, 512); - } - } - else { - xPressedLatch = false; - } + // Take a capture, or snapshot of the current encoder state + Capture capture = encoder.perform_capture(); - //-------------------------------------------------- - // Draw the encoder readings to the screen as a signal plot + // 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)) { + pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::FORWARD, 1.0f); + } + else if(pico_explorer.is_pressed(PicoExplorer::Y) && !pico_explorer.is_pressed(PicoExplorer::B)) { + pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::REVERSE, 0.2f); + } + else { + pico_explorer.set_motor(PicoExplorer::MOTOR1, PicoExplorer::STOP); + } - pico_explorer.set_pen(0, 0, 0); - pico_explorer.clear(); - - drawing_to_screen = true; - - pico_explorer.set_pen(255, 255, 0); - uint32_t localPos = next_reading_index; - uint32_t alignment_offset = draw_plot(Point(0, 10), Point(PicoExplorer::WIDTH, 10 + 50), encA_readings, localPos, current_zoom_level > EDGE_ALIGN_ABOVE_ZOOM); - - pico_explorer.set_pen(0, 255, 255); - draw_plot(Point(0, 80), Point(PicoExplorer::WIDTH, 80 + 50), encB_readings, (localPos + (READINGS_SIZE - alignment_offset)) % READINGS_SIZE, false); - - //Copy values that may have been stored in the scratch buffers, back into the main buffers - for(uint16_t i = 0; i < next_scratch_index; i++) { - encA_readings[next_reading_index] = encA_scratch[i]; - encB_readings[next_reading_index] = encB_scratch[i]; - - next_reading_index++; - if(next_reading_index >= READINGS_SIZE) - next_reading_index = 0; - } - drawing_to_screen = false; - next_scratch_index = 0; - - pico_explorer.set_pen(255, 255, 255); - pico_explorer.character('A', Point(5, 10 + 15), 3); - pico_explorer.character('B', Point(5, 80 + 15), 3); - - if(current_zoom_level < 10) - pico_explorer.text("x" + std::to_string(current_zoom_level), Point(220, 62), 200, 2); - else if(current_zoom_level < 100) - pico_explorer.text("x" + std::to_string(current_zoom_level), Point(210, 62), 200, 2); - else - pico_explorer.text("x" + std::to_string(current_zoom_level), Point(200, 62), 200, 2); - - - //-------------------------------------------------- - // Write out the count, frequency and rpm of the encoder - - pico_explorer.set_pen(8, 8, 8); - pico_explorer.rectangle(Rect(0, 140, PicoExplorer::WIDTH, PicoExplorer::HEIGHT - 140)); - - pico_explorer.set_pen(64, 64, 64); - pico_explorer.rectangle(Rect(0, 140, PicoExplorer::WIDTH, 2)); - - { - std::stringstream sstream; - sstream << capture.get_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) << capture.get_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) << capture.get_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); - } - - pico_explorer.update(); //Refresh the screen - gpio_put(PICO_DEFAULT_LED_PIN, false); //Show the screen refresh has ended + // If A has been pressed, zoom the view out to a min of x1 + if(pico_explorer.is_pressed(PicoExplorer::A)) { + if(!aPressedLatch) { + aPressedLatch = true; + current_zoom_level = std::max(current_zoom_level / 2, 1); } + } + else { + aPressedLatch = false; + } + + // If X has been pressed, zoom the view in to the max of x512 + if(pico_explorer.is_pressed(PicoExplorer::X)) { + if(!xPressedLatch) { + xPressedLatch = true; + current_zoom_level = std::min(current_zoom_level * 2, 512); + } + } + else { + xPressedLatch = false; + } + + //-------------------------------------------------- + // Draw the encoder readings to the screen as a signal plot + + pico_explorer.set_pen(0, 0, 0); + pico_explorer.clear(); + + drawing_to_screen = true; + + pico_explorer.set_pen(255, 255, 0); + uint32_t localPos = next_reading_index; + uint32_t alignment_offset = draw_plot(Point(0, 10), Point(PicoExplorer::WIDTH, 10 + 50), encA_readings, localPos, current_zoom_level > EDGE_ALIGN_ABOVE_ZOOM); + + pico_explorer.set_pen(0, 255, 255); + draw_plot(Point(0, 80), Point(PicoExplorer::WIDTH, 80 + 50), encB_readings, (localPos + (READINGS_SIZE - alignment_offset)) % READINGS_SIZE, false); + + // Copy values that may have been stored in the scratch buffers, back into the main buffers + for(uint16_t i = 0; i < next_scratch_index; i++) { + encA_readings[next_reading_index] = encA_scratch[i]; + encB_readings[next_reading_index] = encB_scratch[i]; + + next_reading_index++; + if(next_reading_index >= READINGS_SIZE) + next_reading_index = 0; + } + + drawing_to_screen = false; + next_scratch_index = 0; + + pico_explorer.set_pen(255, 255, 255); + pico_explorer.character('A', Point(5, 10 + 15), 3); + pico_explorer.character('B', Point(5, 80 + 15), 3); + + if(current_zoom_level < 10) + pico_explorer.text("x" + std::to_string(current_zoom_level), Point(220, 62), 200, 2); + else if(current_zoom_level < 100) + pico_explorer.text("x" + std::to_string(current_zoom_level), Point(210, 62), 200, 2); + else + pico_explorer.text("x" + std::to_string(current_zoom_level), Point(200, 62), 200, 2); + + + //-------------------------------------------------- + // Write out the count, frequency and rpm of the encoder + + pico_explorer.set_pen(8, 8, 8); + pico_explorer.rectangle(Rect(0, 140, PicoExplorer::WIDTH, PicoExplorer::HEIGHT - 140)); + + pico_explorer.set_pen(64, 64, 64); + pico_explorer.rectangle(Rect(0, 140, PicoExplorer::WIDTH, 2)); + + { + std::stringstream sstream; + sstream << capture.get_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) << capture.get_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) << capture.get_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); + } + + pico_explorer.update(); // Refresh the screen + gpio_put(PICO_DEFAULT_LED_PIN, false); // Show the screen refresh has ended } + } } \ No newline at end of file