I am trying to use RPIO.PWM to generate multiple pwm streams. However as soon as I ask RPIO.PWM to use more than one DMA engine the timing becomes inaccurate. I have posted this problem on the RPIO thread and emailed the author but with no response. I thought I would recast the problem as a general hardware query and see if anyone could offer any advice.
The RPIO module uses the Broadcom PWM hardware as a timing source. It does this by setting up the PWM hardware to read data from its fifo at a controlled rate. The content of this data is irrelevant as the hardware PWM output is not connected to any GPIO pins, all RPIO is interested is the DREQ signals generating on Broadcom peripheral number 5 (PWM fifo). RPIO programs one or more Broadcom DMA dma engines are set up with a loop of two control blocks. The first control block manipulates the GPIO pins which have been associated with this dma engine. The transfer information for this control block is DMA_NO_WIDE_BURSTS|DMA|WAIT_RESP. The control block writes a dummy word to the PWM fifo. The transfer information for this control block is DMA_NO_WIDE_BURSTS|DMA_WAIT_RESP|DMA_D_DREQ|DMA_PER_MAP(5). The second block is the one of interest. It is intended to synchronise the execution of the control block loop to the DREQ signal from the the fifo.
This all works fine provided if only one DMA engine is used by the RPIO.PWM code. As soon as another engine is added the pulse timings double. I cannot see how this code ever worked unless there has been some change in the Broadcom firmware. The code is assuming that the DREQ is gating all the engines in parallel. However it looks to me like the dma engines are actually effectively contending for the DREQ with each one consuming alternate DREQ signals.
Has anyone got any ideas on this? I have searched and cannot find anything documented the behaviour when multiple engines are connected to the same DREQ signal.
P.S. Here is some python code if you want to try this out. You will need an oscilloscope to see the signals.
Code: Select all
#!/usr/bin/env python import RPIO from RPIO import PWM import time PWM.setup() RPIO.setup(25, RPIO.OUT, initial=RPIO.LOW) # Comment the next line out to make things work properly PWM.init_channel(4) PWM.init_channel(0) PWM.add_channel_pulse(0, 25, 0, 100) time.sleep(5000)