diff --git a/drivers/motor/motor_cluster.cpp b/drivers/motor/motor_cluster.cpp index 736d16d7..92d3981c 100644 --- a/drivers/motor/motor_cluster.cpp +++ b/drivers/motor/motor_cluster.cpp @@ -10,21 +10,21 @@ namespace motor { MotorCluster::MotorCluster(PIO pio, uint sm, uint pin_base, uint pin_pair_count, Direction direction, float speed_scale, float zeropoint, float deadzone, float freq, DecayMode mode, bool auto_phase, PWMCluster::Sequence *seq_buffer, PWMCluster::TransitionData *dat_buffer) - : pwms(pio, sm, pin_base, (pin_pair_count * 2), seq_buffer, dat_buffer), pwm_frequency(freq) { + : pwms(pio, sm, pin_base, (pin_pair_count * 2), seq_buffer, dat_buffer, false), pwm_frequency(freq) { create_motor_states(direction, speed_scale, zeropoint, deadzone, mode, auto_phase); } MotorCluster::MotorCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t length, Direction direction, float speed_scale, float zeropoint, float deadzone, float freq, DecayMode mode, bool auto_phase, PWMCluster::Sequence *seq_buffer, PWMCluster::TransitionData *dat_buffer) - : pwms(pio, sm, pin_pairs, length, seq_buffer, dat_buffer), pwm_frequency(freq) { + : pwms(pio, sm, pin_pairs, length, seq_buffer, dat_buffer, false), pwm_frequency(freq) { create_motor_states(direction, speed_scale, zeropoint, deadzone, mode, auto_phase); } MotorCluster::MotorCluster(PIO pio, uint sm, std::initializer_list pin_pairs, Direction direction, float speed_scale, float zeropoint, float deadzone, float freq, DecayMode mode, bool auto_phase, PWMCluster::Sequence *seq_buffer, PWMCluster::TransitionData *dat_buffer) - : pwms(pio, sm, pin_pairs, seq_buffer, dat_buffer), pwm_frequency(freq) { + : pwms(pio, sm, pin_pairs, seq_buffer, dat_buffer, false), pwm_frequency(freq) { create_motor_states(direction, speed_scale, zeropoint, deadzone, mode, auto_phase); } @@ -289,7 +289,7 @@ namespace motor { success = true; } - } + //} return success; } diff --git a/drivers/motor/motor_state.hpp b/drivers/motor/motor_state.hpp index 1a7f9cba..e182fe77 100644 --- a/drivers/motor/motor_state.hpp +++ b/drivers/motor/motor_state.hpp @@ -24,7 +24,7 @@ namespace motor { static const DecayMode DEFAULT_DECAY_MODE = SLOW_DECAY; // The standard motor decay behaviour static constexpr float DEFAULT_FREQUENCY = 25000.0f; // The standard motor update rate static constexpr float MIN_FREQUENCY = 10.0f; - static constexpr float MAX_FREQUENCY = 50000.0f; + static constexpr float MAX_FREQUENCY = 400000.0f; static constexpr float ZERO_PERCENT = 0.0f; static constexpr float ONEHUNDRED_PERCENT = 1.0f; diff --git a/drivers/pwm/pwm_cluster.cpp b/drivers/pwm/pwm_cluster.cpp index c691d039..0765b46c 100644 --- a/drivers/pwm/pwm_cluster.cpp +++ b/drivers/pwm/pwm_cluster.cpp @@ -22,13 +22,14 @@ uint8_t PWMCluster::claimed_sms[] = { 0x0, 0x0 }; uint PWMCluster::pio_program_offset = 0; -PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_mask, Sequence *seq_buffer, TransitionData *dat_buffer) +PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_mask, Sequence *seq_buffer, TransitionData *dat_buffer, bool loading_zone) : pio(pio) , sm(sm) , pin_mask(pin_mask & ((1u << NUM_BANK0_GPIOS) - 1)) , channel_count(0) , channels(nullptr) -, wrap_level(0) { +, wrap_level(0) +, loading_zone(loading_zone) { // Create the channel mapping for(uint pin = 0; pin < NUM_BANK0_GPIOS; pin++) { @@ -42,13 +43,14 @@ PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_mask, Sequence *seq_buffer, Tr } -PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_base, uint pin_count, Sequence *seq_buffer, TransitionData *dat_buffer) +PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_base, uint pin_count, Sequence *seq_buffer, TransitionData *dat_buffer, bool loading_zone) : pio(pio) , sm(sm) , pin_mask(0x00000000) , channel_count(0) , channels(nullptr) -, wrap_level(0) { +, wrap_level(0) +, loading_zone(loading_zone) { // Create the pin mask and channel mapping uint pin_end = MIN(pin_count + pin_base, NUM_BANK0_GPIOS); @@ -61,13 +63,14 @@ PWMCluster::PWMCluster(PIO pio, uint sm, uint pin_base, uint pin_count, Sequence constructor_common(seq_buffer, dat_buffer); } -PWMCluster::PWMCluster(PIO pio, uint sm, const uint8_t *pins, uint32_t length, Sequence *seq_buffer, TransitionData *dat_buffer) +PWMCluster::PWMCluster(PIO pio, uint sm, const uint8_t *pins, uint32_t length, Sequence *seq_buffer, TransitionData *dat_buffer, bool loading_zone) : pio(pio) , sm(sm) , pin_mask(0x00000000) , channel_count(0) , channels(nullptr) -, wrap_level(0) { +, wrap_level(0) +, loading_zone(loading_zone) { // Create the pin mask and channel mapping for(uint i = 0; i < length; i++) { @@ -82,13 +85,14 @@ PWMCluster::PWMCluster(PIO pio, uint sm, const uint8_t *pins, uint32_t length, S constructor_common(seq_buffer, dat_buffer); } -PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pins, Sequence *seq_buffer, TransitionData *dat_buffer) +PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pins, Sequence *seq_buffer, TransitionData *dat_buffer, bool loading_zone) : pio(pio) , sm(sm) , pin_mask(0x00000000) , channel_count(0) , channels(nullptr) -, wrap_level(0) { +, wrap_level(0) +, loading_zone(loading_zone) { // Create the pin mask and channel mapping for(auto pin : pins) { @@ -102,13 +106,14 @@ PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pins, Se constructor_common(seq_buffer, dat_buffer); } -PWMCluster::PWMCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t length, Sequence *seq_buffer, TransitionData *dat_buffer) +PWMCluster::PWMCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t length, Sequence *seq_buffer, TransitionData *dat_buffer, bool loading_zone) : pio(pio) , sm(sm) , pin_mask(0x00000000) , channel_count(0) , channels(nullptr) -, wrap_level(0) { +, wrap_level(0) +, loading_zone(loading_zone) { // Create the pin mask and channel mapping for(uint i = 0; i < length; i++) { @@ -127,13 +132,14 @@ PWMCluster::PWMCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t len constructor_common(seq_buffer, dat_buffer); } -PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pin_pairs, Sequence *seq_buffer, TransitionData *dat_buffer) +PWMCluster::PWMCluster(PIO pio, uint sm, std::initializer_list pin_pairs, Sequence *seq_buffer, TransitionData *dat_buffer, bool loading_zone) : pio(pio) , sm(sm) , pin_mask(0x00000000) , channel_count(0) , channels(nullptr) -, wrap_level(0) { +, wrap_level(0) +, loading_zone(loading_zone) { // Create the pin mask and channel mapping for(auto pair : pin_pairs) { @@ -535,12 +541,14 @@ void PWMCluster::load_pwm() { gpio_put(WRITE_GPIO, false); #endif - // Introduce "Loading Zone" transitions to the end of the sequence to - // prevent the DMA interrupt firing many milliseconds before the sequence ends. - uint32_t zone_inserts = MIN(LOADING_ZONE_SIZE, wrap_level - LOADING_ZONE_POSITION); - for(uint32_t i = zone_inserts + LOADING_ZONE_POSITION; i > LOADING_ZONE_POSITION; i--) { - PWMCluster::sorted_insert(transitions, data_size, TransitionData(wrap_level - i)); - PWMCluster::sorted_insert(looping_transitions, looping_data_size, TransitionData(wrap_level - i)); + if(loading_zone) { + // Introduce "Loading Zone" transitions to the end of the sequence to + // prevent the DMA interrupt firing many milliseconds before the sequence ends. + uint32_t zone_inserts = MIN(LOADING_ZONE_SIZE, wrap_level - LOADING_ZONE_POSITION); + for(uint32_t i = zone_inserts + LOADING_ZONE_POSITION; i > LOADING_ZONE_POSITION; i--) { + PWMCluster::sorted_insert(transitions, data_size, TransitionData(wrap_level - i)); + PWMCluster::sorted_insert(looping_transitions, looping_data_size, TransitionData(wrap_level - i)); + } } #ifdef DEBUG_MULTI_PWM diff --git a/drivers/pwm/pwm_cluster.hpp b/drivers/pwm/pwm_cluster.hpp index e60f2969..0d0cc403 100644 --- a/drivers/pwm/pwm_cluster.hpp +++ b/drivers/pwm/pwm_cluster.hpp @@ -15,11 +15,12 @@ namespace pimoroni { // Constants //-------------------------------------------------- private: - static const uint64_t MAX_PWM_CLUSTER_WRAP = UINT16_MAX; // UINT32_MAX works too, but seems to produce less accurate counters - static const uint32_t LOADING_ZONE_SIZE = 3; // The number of dummy transitions to insert into the data to delay the DMA interrupt (if zero then no zone is used) - static const uint32_t LOADING_ZONE_POSITION = 55; // The number of levels before the wrap level to insert the load zone - // Smaller values will make the DMA interrupt trigger closer to the time the data is needed, - // but risks stalling the PIO if the interrupt takes longer due to other processes + static const uint64_t MAX_PWM_CLUSTER_WRAP = UINT16_MAX; // UINT32_MAX works too, but seems to produce less accurate counters + static const uint32_t LOADING_ZONE_SIZE = 3; // The number of dummy transitions to insert into the data to delay the DMA interrupt (if zero then no zone is used) + static const uint32_t LOADING_ZONE_POSITION = 55; // The number of levels before the wrap level to insert the load zone + // Smaller values will make the DMA interrupt trigger closer to the time the data is needed, + // but risks stalling the PIO if the interrupt takes longer due to other processes + static const bool DEFAULT_USE_LOADING_ZONE = true; // Whether or not the default behaviour of PWMCluster is to use the loading zone public: static const uint BUFFER_SIZE = 64; // Set to 64, the maximum number of single rises and falls for 32 channels within a looping time period static const uint NUM_BUFFERS = 3; @@ -119,6 +120,7 @@ namespace pimoroni { volatile uint last_written_index = 0; bool initialised = false; + bool loading_zone = true; //-------------------------------------------------- @@ -134,13 +136,13 @@ namespace pimoroni { // Constructors/Destructor //-------------------------------------------------- public: - PWMCluster(PIO pio, uint sm, uint pin_mask, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr); - PWMCluster(PIO pio, uint sm, uint pin_base, uint pin_count, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr); - PWMCluster(PIO pio, uint sm, const uint8_t *pins, uint32_t length, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr); - PWMCluster(PIO pio, uint sm, std::initializer_list pins, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr); + PWMCluster(PIO pio, uint sm, uint pin_mask, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr, bool loading_zone = DEFAULT_USE_LOADING_ZONE); + PWMCluster(PIO pio, uint sm, uint pin_base, uint pin_count, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr, bool loading_zone = DEFAULT_USE_LOADING_ZONE); + PWMCluster(PIO pio, uint sm, const uint8_t *pins, uint32_t length, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr, bool loading_zone = DEFAULT_USE_LOADING_ZONE); + PWMCluster(PIO pio, uint sm, std::initializer_list pins, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr, bool loading_zone = DEFAULT_USE_LOADING_ZONE); - PWMCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t length, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr); - PWMCluster(PIO pio, uint sm, std::initializer_list pin_pairs, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr); + PWMCluster(PIO pio, uint sm, const pin_pair *pin_pairs, uint32_t length, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr, bool loading_zone = DEFAULT_USE_LOADING_ZONE); + PWMCluster(PIO pio, uint sm, std::initializer_list pin_pairs, Sequence *seq_buffer = nullptr, TransitionData *dat_buffer = nullptr, bool loading_zone = DEFAULT_USE_LOADING_ZONE); ~PWMCluster(); private: diff --git a/micropython/modules/motor/motor.cpp b/micropython/modules/motor/motor.cpp index 8a7f5f6f..8f2db642 100644 --- a/micropython/modules/motor/motor.cpp +++ b/micropython/modules/motor/motor.cpp @@ -302,9 +302,8 @@ extern mp_obj_t Motor_frequency(size_t n_args, const mp_obj_t *pos_args, mp_map_ float freq = mp_obj_get_float(args[ARG_freq].u_obj); - // TODO confirm frequency range if(!self->motor->frequency(freq)) { - mp_raise_ValueError("freq out of range. Expected 10Hz to 350Hz"); //TODO + mp_raise_ValueError("freq out of range. Expected 10Hz to 400KHz"); } return mp_const_none; } @@ -1442,7 +1441,7 @@ extern mp_obj_t MotorCluster_frequency(size_t n_args, const mp_obj_t *pos_args, float freq = mp_obj_get_float(args[ARG_freq].u_obj); if(!self->cluster->frequency(freq)) - mp_raise_ValueError("freq out of range. Expected 10Hz to 350Hz"); + mp_raise_ValueError("freq out of range. Expected 10Hz to 400KHz"); else return mp_const_none; }