diff --git a/drivers/pwm/pwm_cluster.cpp b/drivers/pwm/pwm_cluster.cpp index 6016d18d..e6a080ab 100644 --- a/drivers/pwm/pwm_cluster.cpp +++ b/drivers/pwm/pwm_cluster.cpp @@ -150,9 +150,22 @@ PWMCluster::~PWMCluster() { if(initialised) { pio_sm_set_enabled(pio, sm, false); - dma_channel_abort(dma_channel); - dma_channel_set_irq0_enabled(dma_channel, false); - //dma_channel_unclaim(dma_channel); // This does not seem to work + // Tear down the DMA channel. + // This is copied from: https://github.com/raspberrypi/pico-sdk/pull/744/commits/5e0e8004dd790f0155426e6689a66e08a83cd9fc + uint32_t irq0_save = dma_hw->inte0 & (1u << dma_channel); + hw_clear_bits(&dma_hw->inte0, irq0_save); + + dma_hw->abort = 1u << dma_channel; + + // To fence off on in-flight transfers, the BUSY bit should be polled + // rather than the ABORT bit, because the ABORT bit can clear prematurely. + while (dma_hw->ch[dma_channel].ctrl_trig & DMA_CH0_CTRL_TRIG_BUSY_BITS) tight_loop_contents(); + + // Clear the interrupt (if any) and restore the interrupt masks. + dma_hw->ints0 = 1u << dma_channel; + hw_set_bits(&dma_hw->inte0, irq0_save); + + dma_channel_unclaim(dma_channel); // This works now the teardown behaves correctly clusters[dma_channel] = nullptr; pio_sm_unclaim(pio, sm); diff --git a/micropython/examples/servo2040/current_meter.py b/micropython/examples/servo2040/current_meter.py index 9dd87409..868ddd44 100644 --- a/micropython/examples/servo2040/current_meter.py +++ b/micropython/examples/servo2040/current_meter.py @@ -1,3 +1,4 @@ +import gc import time from machine import Pin from pimoroni import Analog, AnalogMux, Button @@ -21,6 +22,9 @@ MAX_CURRENT = 3.0 # The maximum current, in amps, to show on the meter SAMPLES = 50 # The number of current measurements to take per reading TIME_BETWEEN = 0.001 # The time between each current measurement +# Free up hardware resources ahead of creating a new ServoCluster +gc.collect() + # Create the user button user_sw = Button(servo2040.USER_SW) diff --git a/micropython/examples/servo2040/servo_cluster.py b/micropython/examples/servo2040/servo_cluster.py index aaa0d38b..400e364d 100644 --- a/micropython/examples/servo2040/servo_cluster.py +++ b/micropython/examples/servo2040/servo_cluster.py @@ -1,3 +1,4 @@ +import gc import time import math from servo import ServoCluster, servo2040 @@ -10,6 +11,9 @@ such may have problems when running code multiple times. If you encounter issues, try resetting your board. """ +# Free up hardware resources ahead of creating a new ServoCluster +gc.collect() + # Create a servo cluster for pins 0 to 3, using PIO 0 and State Machine 0 START_PIN = servo2040.SERVO_1 END_PIN = servo2040.SERVO_4 diff --git a/micropython/examples/servo2040/servo_wave.py b/micropython/examples/servo2040/servo_wave.py index 31963f10..cba9c360 100644 --- a/micropython/examples/servo2040/servo_wave.py +++ b/micropython/examples/servo2040/servo_wave.py @@ -1,3 +1,4 @@ +import gc import time import math from pimoroni import Button @@ -19,6 +20,9 @@ BRIGHTNESS = 0.4 # The brightness of the LEDs UPDATES = 50 # How many times to update LEDs and Servos per second SERVO_EXTENT = 80.0 # How far from zero to move the servos +# Free up hardware resources ahead of creating a new ServoCluster +gc.collect() + # Create a servo cluster for pins 0 to 7, using PIO 0 and State Machine 0 START_PIN = servo2040.SERVO_1 END_PIN = servo2040.SERVO_8 diff --git a/micropython/modules/servo/servo.cpp b/micropython/modules/servo/servo.cpp index 5ba0d880..26ad6c60 100644 --- a/micropython/modules/servo/servo.cpp +++ b/micropython/modules/servo/servo.cpp @@ -1365,7 +1365,7 @@ mp_obj_t ServoCluster_make_new(const mp_obj_type_t *type, size_t n_args, size_t delete cluster; m_del(PWMCluster::Sequence, seq_buffer, PWMCluster::NUM_BUFFERS * 2); m_del(PWMCluster::TransitionData, dat_buffer, PWMCluster::BUFFER_SIZE * 2); - mp_raise_msg(&mp_type_RuntimeError, "unable to allocate the hardware resources needed to initialise this ServoCluster");//. Try running `import gc` followed by `gc.collect()`, then create this ServoCluster"); + mp_raise_msg(&mp_type_RuntimeError, "unable to allocate the hardware resources needed to initialise this ServoCluster. Try running `import gc` followed by `gc.collect()` before creating it"); } self = m_new_obj_with_finaliser(_ServoCluster_obj_t);