diff --git a/source/RPIO/PWM/__init__.py b/source/RPIO/PWM/__init__.py index f500164..226fc6e 100644 --- a/source/RPIO/PWM/__init__.py +++ b/source/RPIO/PWM/__init__.py @@ -114,6 +114,21 @@ def add_channel_pulse(dma_channel, gpio, start, width): """ return _PWM.add_channel_pulse(dma_channel, gpio, start, width) +def buffer_set_on(dma_channel, position): + """Write an on instruction to the buffer at the specified position""" + return _PWM.buffer_set_on(dma_channel, position) + +def buffer_set_off(dma_channel, position): + """Write an off instruction to the buffer at the specified position""" + return _PWM.buffer_set_off(dma_channel, position) + +def buffer_assign(dma_channel, gpio, position): + """Assign a gpio channel to a specific point in the buffer""" + return _PWM.buffer_assign(dma_channel, gpio, position) + +def buffer_unassign(dma_channel, gpio, position): + """Unassign a gpio channel to a specific point in the buffer""" + return _PWM.buffer_unassign(dma_channel, gpio, position) def print_channel(channel): """ Print info about a specific channel to stdout """ diff --git a/source/c_pwm/pwm.c b/source/c_pwm/pwm.c index 86729f3..5af180d 100644 --- a/source/c_pwm/pwm.c +++ b/source/c_pwm/pwm.c @@ -51,13 +51,13 @@ * PULSE WIDTH INCREMENT GRANULARITY * --------------------------------- * Another very important setting is the pulse width increment granularity, which - * defaults to 10µs and is used for _all_ DMA channels (since its passed to the PWM + * defaults to 10µs and is used for _all_ DMA channels (since its passed to the PWM * timing hardware). Under the hood you need to set the pulse widths as multiples - * of the increment-granularity. Eg. in order to set 500µs pulses with a granularity - * setting of 10µs, you'll need to set the pulse-width as 50 (50 * 10µs = 500µs). + * of the increment-granularity. Eg. in order to set 500µs pulses with a granularity + * setting of 10µs, you'll need to set the pulse-width as 50 (50 * 10µs = 500µs). * Less granularity needs more DMA memory. * - * To achieve shorter pulses than 10µs, you simply need set a lower granularity. + * To achieve shorter pulses than 10µs, you simply need set a lower granularity. * * * WARNING @@ -84,6 +84,7 @@ #include #include #include + #include "pwm.h" // 15 DMA channels are usable on the RPi (0..14) @@ -468,19 +469,104 @@ add_channel_pulse(int channel, int gpio, int width_start, int width) *(dp + width_start) |= 1 << gpio; cbp->dst = phys_gpset0; - // Do nothing for the specified width - for (i = 1; i < width - 1; i++) { - *(dp + width_start + i) &= ~(1 << gpio); // set just this gpio's bit to 0 - cbp += 2; - } + //PaulP - re-order to write the off code before clearing the mid region. + cbp += 2 * (width - 2); // Clear GPIO at end *(dp + width_start + width) |= 1 << gpio; cbp->dst = phys_gpclr0; + + //PaulP - force a cache flush so this is in the DMA chain now. + __clear_cache((char*) (dp + width_start + width), (char*) (dp + width_start + width + 1)); + __clear_cache((char*) (cbp), (char*) (cbp + 2)); + + // Do nothing for the specified width + for (i = 1; i < width - 1; i++) { + *(dp + width_start + i) &= ~(1 << gpio); // set just this gpio's bit to 0 + } + return EXIT_SUCCESS; } +//Write an 'on' instruction to the buffer at the specified position. +int +buffer_set_on(int channel, int position) +{ + static uint32_t phys_gpset0 = 0x7e200000 + 0x1c; + //log_debug("buffer_set_on: channel=%d, position=%d\n", channel, position); + if (!channels[channel].virtbase) + return fatal("Error: channel %d has not been initialized with 'init_channel(..)'\n", channel); + if (position > channels[channel].width_max || position < 0) + return fatal("Error: position exceeds max_width of %d\n", channels[channel].width_max); + + dma_cb_t *cbp = (dma_cb_t *) get_cb(channel) + (position * 2); + cbp->dst = phys_gpset0; + __clear_cache((char*) cbp, (char*) (cbp + 2)); + + return EXIT_SUCCESS; +} + +//Write an 'off' instruction to the buffer at the specified position. +int +buffer_set_off(int channel, int position) +{ + static uint32_t phys_gpclr0 = 0x7e200000 + 0x28; + + //log_debug("buffer_set_on: channel=%d, position=%d\n", channel, position); + if (!channels[channel].virtbase) + return fatal("Error: channel %d has not been initialized with 'init_channel(..)'\n", channel); + if (position > channels[channel].width_max || position < 0) + return fatal("Error: position exceeds max_width of %d\n", channels[channel].width_max); + + dma_cb_t *cbp = (dma_cb_t *) get_cb(channel) + (position * 2); + cbp->dst = phys_gpclr0; + __clear_cache((char*) cbp, (char*) (cbp + 2)); + + return EXIT_SUCCESS; +} + +//Assign a gpio channel to a specific point in the buffer +int +buffer_assign(int channel, int gpio, int position) +{ + uint32_t *dp = (uint32_t *) channels[channel].virtbase; + + //log_debug("buffer_assign: channel=%d, gpio=%d, position=%d\n", channel, gpio, position); + if (!channels[channel].virtbase) + return fatal("Error: channel %d has not been initialized with 'init_channel(..)'\n", channel); + if (position > channels[channel].width_max || position < 0) + return fatal("Error: position exceeds max_width of %d\n", channels[channel].width_max); + + if ((gpio_setup & 1< channels[channel].width_max || position < 0) + return fatal("Error: position exceeds max_width of %d\n", channels[channel].width_max); + + if ((gpio_setup & 1<