kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			More progress on Servo PIO
							rodzic
							
								
									aca98ca747
								
							
						
					
					
						commit
						de3cb52931
					
				| 
						 | 
				
			
			@ -2,6 +2,8 @@
 | 
			
		|||
#include "common/pimoroni_common.hpp"
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include "hardware/gpio.h"
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
namespace servo {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -16,50 +18,47 @@ struct alignas(8) Transition {
 | 
			
		|||
    Transition() : mask(0), delay(0) {};
 | 
			
		||||
};
 | 
			
		||||
static const uint NUM_BUFFERS = 3;
 | 
			
		||||
static const uint LOADING_ZONE_SIZE = 3;
 | 
			
		||||
struct Sequence {
 | 
			
		||||
    uint32_t size;
 | 
			
		||||
    Transition data[BUFFER_SIZE];
 | 
			
		||||
    Sequence() : size(1), data({Transition()}) {};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Sequence sequences[NUM_BUFFERS];
 | 
			
		||||
uint sequence_index = 0;
 | 
			
		||||
 | 
			
		||||
//Sequence loading_zone = {3, {Transition(), Transition(), Transition()}}; //Need 6 words to create loading zone behaviour with normal FIFO
 | 
			
		||||
Sequence loading_zone = {5, {Transition(), Transition(), Transition(), Transition(), Transition()}}; //Need 6 words to create loading zone behaviour with normal FIFO
 | 
			
		||||
bool enter_loading_zone = false;
 | 
			
		||||
const bool use_loading_zone = true;
 | 
			
		||||
uint loading_zone_size = 3;
 | 
			
		||||
volatile uint read_index = 0;
 | 
			
		||||
volatile uint last_written_index = 0;
 | 
			
		||||
 | 
			
		||||
uint gpio = 15;
 | 
			
		||||
//Sequence loading_zone = {3, {Transition(), Transition(), Transition()}}; //Need 6 words to create loading zone behaviour with normal FIFO
 | 
			
		||||
//Sequence loading_zone = {5, {Transition(), Transition(), Transition(), Transition(), Transition()}}; //Need 6 words to create loading zone behaviour with normal FIFO
 | 
			
		||||
const bool use_loading_zone = true;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
uint irq_gpio = 15;
 | 
			
		||||
uint write_gpio = 16;
 | 
			
		||||
uint sideset_gpio = 17;
 | 
			
		||||
 | 
			
		||||
void __isr pwm_dma_handler() {
 | 
			
		||||
    // Clear the interrupt request.
 | 
			
		||||
    dma_hw->ints0 = 1u << data_dma_channel;
 | 
			
		||||
 | 
			
		||||
    // if(enter_loading_zone) {
 | 
			
		||||
    //     gpio_put(gpio+1, 1);
 | 
			
		||||
    //     uint32_t transitions = loading_zone.size * 2;
 | 
			
		||||
    //     uint32_t* buffer = (uint32_t *)loading_zone.data;
 | 
			
		||||
    //     dma_channel_set_trans_count(data_dma_channel, transitions, false);
 | 
			
		||||
    //     dma_channel_set_read_addr(data_dma_channel, buffer, true);
 | 
			
		||||
    gpio_put(irq_gpio, 1); //TOREMOVE Just for debug
 | 
			
		||||
 | 
			
		||||
    //     enter_loading_zone = false;
 | 
			
		||||
    //     gpio_put(gpio+1, 0);
 | 
			
		||||
    // }
 | 
			
		||||
    // else {
 | 
			
		||||
    gpio_put(gpio, 1);
 | 
			
		||||
    uint32_t transitions = sequences[sequence_index].size * 2;
 | 
			
		||||
    uint32_t* buffer = (uint32_t *)sequences[sequence_index].data;
 | 
			
		||||
    // If new data been written since the last time, switch to reading that buffer
 | 
			
		||||
    if(last_written_index != read_index) {
 | 
			
		||||
        read_index = last_written_index;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t transitions = sequences[read_index].size * 2;
 | 
			
		||||
    uint32_t* buffer = (uint32_t *)sequences[read_index].data;
 | 
			
		||||
 | 
			
		||||
    dma_channel_set_trans_count(data_dma_channel, transitions, false);
 | 
			
		||||
    dma_channel_set_read_addr(data_dma_channel, buffer, true);
 | 
			
		||||
 | 
			
		||||
    // For some reason sequence 0 is output to the PIO twice, rather than once, despite the below line shifting the index along...
 | 
			
		||||
    // ^ Seemed related to filling an 8 long fifo buffer. Reducing to 4 removed it.
 | 
			
		||||
    sequence_index = (sequence_index + 1) % NUM_BUFFERS;
 | 
			
		||||
 | 
			
		||||
    gpio_put(gpio, 0);
 | 
			
		||||
    //}
 | 
			
		||||
    gpio_put(irq_gpio, 0); //TOREMOVE Just for debug
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    /***
 | 
			
		||||
| 
						 | 
				
			
			@ -76,27 +75,37 @@ interrupt is fired, and the handler reconfigures channel A so that it is ready f
 | 
			
		|||
     * */
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
MultiPWM::MultiPWM(PIO pio, uint sm, uint pin) : pio(pio), sm(sm) {
 | 
			
		||||
MultiPWM::MultiPWM(PIO pio, uint sm, uint pin_mask) : pio(pio), sm(sm), pin_mask(pin_mask) {
 | 
			
		||||
    pio_program_offset = pio_add_program(pio, &multi_pwm_program);
 | 
			
		||||
 | 
			
		||||
    gpio_init(gpio);
 | 
			
		||||
    gpio_set_dir(gpio, GPIO_OUT);
 | 
			
		||||
    gpio_init(gpio+1);
 | 
			
		||||
    gpio_set_dir(gpio+1, GPIO_OUT);
 | 
			
		||||
    gpio_init(irq_gpio);
 | 
			
		||||
    gpio_set_dir(irq_gpio, GPIO_OUT);
 | 
			
		||||
    gpio_init(write_gpio);
 | 
			
		||||
    gpio_set_dir(write_gpio, GPIO_OUT);
 | 
			
		||||
 | 
			
		||||
    for(uint i = pin; i < pin + 15; i++)
 | 
			
		||||
        pio_gpio_init(pio, i);
 | 
			
		||||
    if(pin_mask != 0) {
 | 
			
		||||
        // Initialise all the pins this PWM will control
 | 
			
		||||
        for(uint pin = 0; pin < 32; pin++) { // 32 is number of bits
 | 
			
		||||
            if((pin_mask & (1u << pin)) != 0) {
 | 
			
		||||
                pio_gpio_init(pio, pin);
 | 
			
		||||
                pin_duty[pin] = 0u;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    pio_gpio_init(pio, 17);
 | 
			
		||||
    pio_sm_set_consecutive_pindirs(pio, sm, pin, 17, true);
 | 
			
		||||
    pio_sm_set_consecutive_pindirs(pio, sm, 17, 1, true);
 | 
			
		||||
        // Set their default state and direction
 | 
			
		||||
        pio_sm_set_pins_with_mask(pio, sm, 0x00, pin_mask);
 | 
			
		||||
        pio_sm_set_pindirs_with_mask(pio, sm, pin_mask, pin_mask);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pio_gpio_init(pio, sideset_gpio);
 | 
			
		||||
    pio_sm_set_consecutive_pindirs(pio, sm, sideset_gpio, 1, true);
 | 
			
		||||
 | 
			
		||||
    pio_sm_config c = multi_pwm_program_get_default_config(pio_program_offset);
 | 
			
		||||
    sm_config_set_out_pins(&c, pin, 17);
 | 
			
		||||
    sm_config_set_sideset_pins(&c, 17);
 | 
			
		||||
    sm_config_set_out_pins(&c, 0, irq_gpio); //TODO change this to be 32
 | 
			
		||||
    sm_config_set_sideset_pins(&c, sideset_gpio);
 | 
			
		||||
    sm_config_set_out_shift(&c, false, true, 32);
 | 
			
		||||
    //sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); // Joining the FIFOs makes the DMA interrupts occur earlier than we would like
 | 
			
		||||
    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_NONE);
 | 
			
		||||
    sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_NONE); // We actively do not want a joined FIFO even though we are not needing the RX
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    float div = clock_get_hz(clk_sys) / 5000000;
 | 
			
		||||
    sm_config_set_clkdiv(&c, div);
 | 
			
		||||
| 
						 | 
				
			
			@ -154,93 +163,19 @@ MultiPWM::MultiPWM(PIO pio, uint sm, uint pin) : pio(pio), sm(sm) {
 | 
			
		|||
    irq_set_exclusive_handler(DMA_IRQ_0, pwm_dma_handler);
 | 
			
		||||
    irq_set_enabled(DMA_IRQ_0, true);
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        Sequence& seq = sequences[0];
 | 
			
		||||
        Transition* trans = seq.data;
 | 
			
		||||
        trans[0].mask = (1u << 0);
 | 
			
		||||
        trans[0].delay = 1000 - 1;
 | 
			
		||||
 | 
			
		||||
        trans[1].mask = (1u << 1);
 | 
			
		||||
        trans[1].delay = 1000 - 1;
 | 
			
		||||
 | 
			
		||||
        trans[2].mask = (1u << 1);
 | 
			
		||||
        trans[2].delay = 1000 - 1;
 | 
			
		||||
 | 
			
		||||
        trans[3].mask = 0;
 | 
			
		||||
        trans[3].delay = (20000 - 3000) - 1;
 | 
			
		||||
 | 
			
		||||
        //if(use_loading_zone)
 | 
			
		||||
            //trans[4].delay -= loading_zone.size;
 | 
			
		||||
 | 
			
		||||
        seq.size = 4;
 | 
			
		||||
 | 
			
		||||
        if(use_loading_zone){
 | 
			
		||||
            trans[seq.size - 1].delay -= loading_zone_size;
 | 
			
		||||
            for(uint i = 0; i < loading_zone_size; i++) {
 | 
			
		||||
                trans[seq.size].mask = 0;
 | 
			
		||||
                trans[seq.size].delay = 0;
 | 
			
		||||
                seq.size += 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        Sequence& seq = sequences[1];
 | 
			
		||||
        Transition* trans = seq.data;
 | 
			
		||||
        trans[0].mask = (1u << 5);
 | 
			
		||||
        trans[0].delay = 10000 - 1;
 | 
			
		||||
 | 
			
		||||
        trans[1].mask = 0;
 | 
			
		||||
        trans[1].delay = (20000 - 10000) - 1;
 | 
			
		||||
 | 
			
		||||
        //if(use_loading_zone)
 | 
			
		||||
            //trans[1].delay -= loading_zone.size;
 | 
			
		||||
 | 
			
		||||
        seq.size = 2;
 | 
			
		||||
 | 
			
		||||
        if(use_loading_zone){
 | 
			
		||||
            trans[seq.size - 1].delay -= loading_zone_size;
 | 
			
		||||
            for(uint i = 0; i < loading_zone_size; i++) {
 | 
			
		||||
                trans[seq.size].mask = 0;
 | 
			
		||||
                trans[seq.size].delay = 0;
 | 
			
		||||
                seq.size += 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        Sequence& seq = sequences[2];
 | 
			
		||||
        Transition* trans = seq.data;
 | 
			
		||||
 | 
			
		||||
        uint count = 0;
 | 
			
		||||
        uint last = 14;
 | 
			
		||||
        for(uint i = 0; i < last; i++) {
 | 
			
		||||
            trans[i].mask = (1u << i);
 | 
			
		||||
            trans[i].delay = 1000 - 1;
 | 
			
		||||
            count += 1000;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        trans[last].mask = 0;
 | 
			
		||||
        trans[last].delay = (20000 - count) - 1;
 | 
			
		||||
 | 
			
		||||
        //if(use_loading_zone)
 | 
			
		||||
        //    trans[last].delay -= loading_zone.size;
 | 
			
		||||
 | 
			
		||||
        seq.size = last + 1;
 | 
			
		||||
 | 
			
		||||
        if(use_loading_zone){
 | 
			
		||||
            trans[seq.size - 1].delay -= loading_zone_size;
 | 
			
		||||
            for(uint i = 0; i < loading_zone_size; i++) {
 | 
			
		||||
                trans[seq.size].mask = 0;
 | 
			
		||||
                trans[seq.size].delay = 0;
 | 
			
		||||
                seq.size += 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    // Set up the transition buffers
 | 
			
		||||
    for(uint i = 0; i < NUM_BUFFERS; i++) {
 | 
			
		||||
        Sequence& seq = sequences[i];
 | 
			
		||||
        seq = Sequence();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Manually call the handler once, to trigger the first transfer
 | 
			
		||||
    pwm_dma_handler();
 | 
			
		||||
 | 
			
		||||
    for(uint i = 0; i < 32; i++) {
 | 
			
		||||
        pin_duty[i] = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //dma_start_channel_mask(1u << ctrl_dma_channel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -255,13 +190,260 @@ MultiPWM::~MultiPWM() {
 | 
			
		|||
    // pio_sm_unclaim seems to hardfault in MicroPython
 | 
			
		||||
    pio_sm_unclaim(pio, sm);
 | 
			
		||||
#endif
 | 
			
		||||
    // Reset all the pins this PWM will control back to an unused state
 | 
			
		||||
    for(uint pin = 0; pin < 32; pin++) { // 32 is number of bits
 | 
			
		||||
        if((1u << pin) != 0) {
 | 
			
		||||
            gpio_set_function(pin, GPIO_FUNC_NULL);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MultiPWM::start(uint fps) {
 | 
			
		||||
    //add_repeating_timer_ms(-(1000 / fps), dma_timer_callback, (void*)this, &timer);
 | 
			
		||||
bool MultiPWM::start(uint sequence_num) {
 | 
			
		||||
    gpio_put(write_gpio, 1);
 | 
			
		||||
    // Read | Last W = Write
 | 
			
		||||
    // 0    | 0      = 1 (or 2)
 | 
			
		||||
    // 0    | 1      = 2
 | 
			
		||||
    // 0    | 2      = 1
 | 
			
		||||
    // 1    | 0      = 2
 | 
			
		||||
    // 1    | 1      = 2 (or 0)
 | 
			
		||||
    // 1    | 2      = 0
 | 
			
		||||
    // 2    | 0      = 1
 | 
			
		||||
    // 2    | 1      = 0
 | 
			
		||||
    // 2    | 2      = 0 (or 1)
 | 
			
		||||
 | 
			
		||||
    // Choose the write index based on the last index
 | 
			
		||||
    // There's probably a single equation for this, but I couldn't work it out
 | 
			
		||||
    uint write_index = (read_index + 1) % NUM_BUFFERS;
 | 
			
		||||
    if(write_index == last_written_index) {
 | 
			
		||||
        write_index = (write_index + 1) % NUM_BUFFERS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch(sequence_num) {
 | 
			
		||||
        case 0:
 | 
			
		||||
        {
 | 
			
		||||
            Sequence& seq = sequences[write_index];
 | 
			
		||||
            Transition* trans = seq.data;
 | 
			
		||||
            trans[0].mask = (1u << 0);
 | 
			
		||||
            trans[0].delay = 1000 - 1;
 | 
			
		||||
 | 
			
		||||
            trans[1].mask = (1u << 1);
 | 
			
		||||
            trans[1].delay = 1000 - 1;
 | 
			
		||||
 | 
			
		||||
            trans[2].mask = (1u << 1);
 | 
			
		||||
            trans[2].delay = 1000 - 1;
 | 
			
		||||
 | 
			
		||||
            trans[3].mask = 0;
 | 
			
		||||
            trans[3].delay = (20000 - 3000) - 1;
 | 
			
		||||
            seq.size = 4;
 | 
			
		||||
 | 
			
		||||
            if(use_loading_zone){
 | 
			
		||||
                trans[seq.size - 1].delay -= LOADING_ZONE_SIZE;
 | 
			
		||||
                for(uint i = 0; i < LOADING_ZONE_SIZE; i++) {
 | 
			
		||||
                    trans[seq.size].mask = 0;
 | 
			
		||||
                    trans[seq.size].delay = 0;
 | 
			
		||||
                    seq.size += 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
        case 1:
 | 
			
		||||
        {
 | 
			
		||||
            Sequence& seq = sequences[write_index];
 | 
			
		||||
            Transition* trans = seq.data;
 | 
			
		||||
            trans[0].mask = (1u << 5);
 | 
			
		||||
            trans[0].delay = 10000 - 1;
 | 
			
		||||
 | 
			
		||||
            trans[1].mask = 0;
 | 
			
		||||
            trans[1].delay = (20000 - 10000) - 1;
 | 
			
		||||
            seq.size = 2;
 | 
			
		||||
 | 
			
		||||
            if(use_loading_zone){
 | 
			
		||||
                trans[seq.size - 1].delay -= LOADING_ZONE_SIZE;
 | 
			
		||||
                for(uint i = 0; i < LOADING_ZONE_SIZE; i++) {
 | 
			
		||||
                    trans[seq.size].mask = 0;
 | 
			
		||||
                    trans[seq.size].delay = 0;
 | 
			
		||||
                    seq.size += 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
        case 2:
 | 
			
		||||
        {
 | 
			
		||||
            Sequence& seq = sequences[write_index];
 | 
			
		||||
            Transition* trans = seq.data;
 | 
			
		||||
 | 
			
		||||
            uint count = 0;
 | 
			
		||||
            uint last = 14;
 | 
			
		||||
            for(uint i = 0; i < last; i++) {
 | 
			
		||||
                trans[i].mask = (1u << i);
 | 
			
		||||
                trans[i].delay = 1000 - 1;
 | 
			
		||||
                count += 1000;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            trans[last].mask = 0;
 | 
			
		||||
            trans[last].delay = (20000 - count) - 1;
 | 
			
		||||
            seq.size = last + 1;
 | 
			
		||||
 | 
			
		||||
            if(use_loading_zone){
 | 
			
		||||
                trans[seq.size - 1].delay -= LOADING_ZONE_SIZE;
 | 
			
		||||
                for(uint i = 0; i < LOADING_ZONE_SIZE; i++) {
 | 
			
		||||
                    trans[seq.size].mask = 0;
 | 
			
		||||
                    trans[seq.size].delay = 0;
 | 
			
		||||
                    seq.size += 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
        case 3:
 | 
			
		||||
        default:
 | 
			
		||||
        {
 | 
			
		||||
            Sequence& seq = sequences[write_index];
 | 
			
		||||
            Transition* trans = seq.data;
 | 
			
		||||
            trans[0].mask = 0;
 | 
			
		||||
            trans[0].delay = 20000 - 1;
 | 
			
		||||
            seq.size = 1;
 | 
			
		||||
 | 
			
		||||
            if(use_loading_zone){
 | 
			
		||||
                trans[seq.size - 1].delay -= LOADING_ZONE_SIZE;
 | 
			
		||||
                for(uint i = 0; i < LOADING_ZONE_SIZE; i++) {
 | 
			
		||||
                    trans[seq.size].mask = 0;
 | 
			
		||||
                    trans[seq.size].delay = 0;
 | 
			
		||||
                    seq.size += 1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    last_written_index = write_index;
 | 
			
		||||
    gpio_put(write_gpio, 0);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MultiPWM::set_servo_duty(uint servo, uint32_t duty) {
 | 
			
		||||
    if(servo > 0 && servo <= 18) {
 | 
			
		||||
        pin_duty[servo - 1] = std::min<uint32_t>(duty, 20000);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct myclass {
 | 
			
		||||
  bool operator() (const TransitionData& i, const TransitionData& j) { return i.compare(j); }
 | 
			
		||||
} myobject;
 | 
			
		||||
 | 
			
		||||
void MultiPWM::sorted_insert(TransitionData array[], uint &size, const TransitionData &data) {
 | 
			
		||||
    uint i;
 | 
			
		||||
    for(i = size; (i > 0 && !array[i - 1].compare(data)); i--) {
 | 
			
		||||
        array[i] = array[i - 1];
 | 
			
		||||
    }
 | 
			
		||||
    array[i] = data;
 | 
			
		||||
    //printf("Added %d, %ld, %d\n", data.servo, data.time, data.state);
 | 
			
		||||
    size++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MultiPWM::apply_servo_duty() {
 | 
			
		||||
    gpio_put(write_gpio, 1);
 | 
			
		||||
    const uint window = 20000;
 | 
			
		||||
 | 
			
		||||
    TransitionData transitions[64];
 | 
			
		||||
    uint data_size = 0;
 | 
			
		||||
 | 
			
		||||
    // Go through each pin that we are assigned to
 | 
			
		||||
    for(uint pin = 0; pin < 32; pin++) {
 | 
			
		||||
        if(((1u << pin) & pin_mask) != 0) {
 | 
			
		||||
            // If the duty is greater than zero, add a transition to high
 | 
			
		||||
            if(pin_duty[pin] > 0) {
 | 
			
		||||
                MultiPWM::sorted_insert(transitions, data_size, TransitionData(pin, 0, true));
 | 
			
		||||
            }
 | 
			
		||||
            // If the duty is less than the window size, add a transition to low
 | 
			
		||||
            if(pin_duty[pin] < window) {
 | 
			
		||||
                MultiPWM::sorted_insert(transitions, data_size, TransitionData(pin, pin_duty[pin], false));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //for(uint i = 0; i < data_size; i++) {
 | 
			
		||||
    //    printf("Added %d, %ld, %d\n", transitions[i].servo, transitions[i].time, transitions[i].state);
 | 
			
		||||
    //}
 | 
			
		||||
 | 
			
		||||
    // Read | Last W = Write
 | 
			
		||||
    // 0    | 0      = 1 (or 2)
 | 
			
		||||
    // 0    | 1      = 2
 | 
			
		||||
    // 0    | 2      = 1
 | 
			
		||||
    // 1    | 0      = 2
 | 
			
		||||
    // 1    | 1      = 2 (or 0)
 | 
			
		||||
    // 1    | 2      = 0
 | 
			
		||||
    // 2    | 0      = 1
 | 
			
		||||
    // 2    | 1      = 0
 | 
			
		||||
    // 2    | 2      = 0 (or 1)
 | 
			
		||||
 | 
			
		||||
    // Choose the write index based on the last index
 | 
			
		||||
    // There's probably a single equation for this, but I couldn't work it out
 | 
			
		||||
    uint write_index = (read_index + 1) % NUM_BUFFERS;
 | 
			
		||||
    if(write_index == last_written_index) {
 | 
			
		||||
        write_index = (write_index + 1) % NUM_BUFFERS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Sequence& seq = sequences[write_index];
 | 
			
		||||
    seq.size = 0; // Reset the sequence, otherwise we end up appending, and weird things happen
 | 
			
		||||
    //printf("Write Index = %d\n", write_index);
 | 
			
		||||
 | 
			
		||||
    uint pin_states = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    uint current_time = 0;
 | 
			
		||||
    uint data_start = 0;
 | 
			
		||||
 | 
			
		||||
    while(data_start < data_size) {
 | 
			
		||||
        uint next_time = window; // Set the next time to be the Window, initially
 | 
			
		||||
 | 
			
		||||
        do {
 | 
			
		||||
            // Is the time of this transition the same as the current time?
 | 
			
		||||
            if(transitions[data_start].time <= current_time) {
 | 
			
		||||
                // Yes, so update the state of this pin
 | 
			
		||||
                if(transitions[data_start].state)
 | 
			
		||||
                    pin_states = pin_states | (1u << transitions[data_start].servo);
 | 
			
		||||
                else
 | 
			
		||||
                    pin_states = pin_states & ~(1u << transitions[data_start].servo);
 | 
			
		||||
                data_start++;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // No, so set the next time to be the time of this transition, and break out of the loop
 | 
			
		||||
                next_time = transitions[data_start].time;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } while(data_start < data_size);
 | 
			
		||||
 | 
			
		||||
        //#print("0b{:016b}".format(pin_mask))
 | 
			
		||||
        // Add the transition
 | 
			
		||||
        seq.data[seq.size].mask = pin_states;
 | 
			
		||||
        seq.data[seq.size].delay = (next_time - current_time) - 1;
 | 
			
		||||
 | 
			
		||||
        //printf("%#010x, %ld\n", pin_states, seq.data[seq.size].delay + 1);
 | 
			
		||||
        seq.size++;
 | 
			
		||||
        //#print((next_time - time) - 1)
 | 
			
		||||
 | 
			
		||||
        current_time = next_time;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(use_loading_zone) {
 | 
			
		||||
        seq.data[seq.size - 1].delay -= LOADING_ZONE_SIZE;
 | 
			
		||||
        for(uint i = 0; i < LOADING_ZONE_SIZE; i++) {
 | 
			
		||||
            seq.data[seq.size].mask = 0;
 | 
			
		||||
            seq.data[seq.size].delay = 0;
 | 
			
		||||
            seq.size++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    last_written_index = write_index;
 | 
			
		||||
    gpio_put(write_gpio, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool MultiPWM::stop() {
 | 
			
		||||
    return true;//cancel_repeating_timer(&timer);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,16 +25,34 @@ found here: https://github.com/raspberrypi/pico-examples/tree/master/pio/ws2812
 | 
			
		|||
 | 
			
		||||
namespace servo {
 | 
			
		||||
 | 
			
		||||
    struct TransitionData {
 | 
			
		||||
        uint8_t servo;
 | 
			
		||||
        uint32_t time;
 | 
			
		||||
        bool state;
 | 
			
		||||
 | 
			
		||||
        TransitionData() : servo(0), time(0), state(false) {};
 | 
			
		||||
        TransitionData(uint8_t servo, uint32_t time, bool new_state) : servo(servo), time(time), state(new_state) {};
 | 
			
		||||
 | 
			
		||||
        bool compare(const TransitionData& other) const {
 | 
			
		||||
            return time <= other.time;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class MultiPWM {
 | 
			
		||||
        public:
 | 
			
		||||
            MultiPWM(PIO pio, uint sm, uint pin);
 | 
			
		||||
            ~MultiPWM();
 | 
			
		||||
            bool start(uint fps=60);
 | 
			
		||||
            bool start(uint sequence_num=0);
 | 
			
		||||
            bool stop();
 | 
			
		||||
            void clear();
 | 
			
		||||
            void set_servo_duty(uint servo, uint32_t duty);
 | 
			
		||||
            void apply_servo_duty();
 | 
			
		||||
        private:
 | 
			
		||||
            static void sorted_insert(TransitionData array[], uint &size, const TransitionData &data);
 | 
			
		||||
            PIO pio;
 | 
			
		||||
            uint sm;
 | 
			
		||||
            uint pio_program_offset;
 | 
			
		||||
            uint pin_mask;
 | 
			
		||||
            uint pin_duty[32];
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +40,8 @@ WS2812 led_bar(N_LEDS, pio0, 0, servo2040::LED_DAT);
 | 
			
		|||
 | 
			
		||||
Button user_sw(servo2040::USER_SW, Polarity::ACTIVE_LOW, 0);
 | 
			
		||||
 | 
			
		||||
uint count = 0;
 | 
			
		||||
uint servo_seq = 0;
 | 
			
		||||
int main() {
 | 
			
		||||
  stdio_init_all();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,7 +49,7 @@ int main() {
 | 
			
		|||
 | 
			
		||||
  sleep_ms(5000);
 | 
			
		||||
 | 
			
		||||
  MultiPWM pwms(pio1, 0, 0);
 | 
			
		||||
  MultiPWM pwms(pio1, 0, 0b111111111111111);
 | 
			
		||||
 | 
			
		||||
  int speed = DEFAULT_SPEED;
 | 
			
		||||
  float offset = 0.0f;
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +69,19 @@ int main() {
 | 
			
		|||
      led_bar.set_hsv(i, hue + offset, 1.0f, 0.5f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    count++;
 | 
			
		||||
    if(count >= 1000) {
 | 
			
		||||
      count = 0;
 | 
			
		||||
 | 
			
		||||
      pwms.start(servo_seq);
 | 
			
		||||
      servo_seq++;
 | 
			
		||||
      if(servo_seq >= 4)
 | 
			
		||||
        servo_seq = 0;
 | 
			
		||||
 | 
			
		||||
      pwms.set_servo_duty(1, 1000);
 | 
			
		||||
      pwms.apply_servo_duty();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //pwms.update(true);
 | 
			
		||||
 | 
			
		||||
    // Sleep time controls the rate at which the LED buffer is updated
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue