rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Sharing a DREQ between multiple DMA engines

Thu Jan 22, 2015 5:13 pm

Hi,

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.

Thanks,

Roger

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)

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Fri Jan 23, 2015 4:40 pm

I initialised a third channel and the timings remained the same (double what they should be). This casts some doubt on my contention theory. Any ideas anyone? Can anyone else confirm the same behaviour? I am running the test on a B+ with the latest 3.12.35+ kernel. I cannot believe that the RPIO.PWM code could be so broken and nobody has noticed.

Roger

Latest test code

Code: Select all

#!/usr/bin/env python
#
# DMA engines(dma channels) to avoid.
# ===============================
# 1,3,6,7 (from /sys/modules/dma/parameters/dmachans
# 0 framebuffer
# 2 sd card
# 8 also appears to cause problems with the sd card although it is not listed in dmachans

import RPIO
from RPIO import PWM
import time

PWM.setup()
RPIO.setup(25, RPIO.OUT, initial=RPIO.LOW)
PWM.init_channel(4)
PWM.init_channel(5)
PWM.init_channel(9)
PWM.add_channel_pulse(9, 25, 0, 100)
time.sleep(5000)

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Sat Jan 24, 2015 6:46 pm

I have found out this that problem only occurs when using the PWM fifo as the DMA_REQ source. The timings are fine when using the PCM fifo as the DMA_REQ source (PWM.setup(delay_hw=PWM.DELAY_VIA_PCM)).

I have attached three little scripts that can be used to show this problem without an oscilloscope.

All scripts need to be run sudo to access the gpio and you need to jumper together pins 21 and 22 of the gpio header (GPIOs 25 and 9). Run either goodpulse.py or badpulse.py in background or in a separate terminal. Then run pulsetimer.py and make a note of the result.

Roger

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Sat Jan 24, 2015 6:47 pm

Sorry forgot to credit #metachris with finding out about PCM.

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Sat Jan 24, 2015 11:53 pm

Oops even got that wrong it was #camusdv

davidbeal
Posts: 1
Joined: Mon Mar 16, 2015 4:10 am

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 4:16 am

I'd be interested to see what your experience with https://github.com/richardghirst/PiBits ... rvoBlaster would be, as ServoBlaster is the code that RPIO.PWM was derived from.

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 10:16 am

I have given up on RPIO now and moved to pigpio. I have had much more success with this. As well as the problem with the clock source the pwm waveforms generated by RPIO would not drive some of the servos I had. These all work fine with pigpio. There are some features of RPIO and pigpio that I need which are not in servoblaster. However I have found it works fine when I used it in the past for driving servos. Although I don't think I ever tried one of the servos that would not work with RPIO on it. There is a lot of high frequency noise on the waveforms generated by RPIO. I suspect this is what some servos are objecting to.

For information I am currently struggling with latency issues on pigpio when trying to drive a one wire sonar range finder.

Roger

User avatar
joan
Posts: 14179
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 11:41 am

rogerjames99 wrote: ...
For information I am currently struggling with latency issues on pigpio when trying to drive a one wire sonar range finder.

Roger
May I ask what sort of latency problem? It may be the sort of problem which just can't be handled by pigpio.

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 3:53 pm

files.zip
Test script and debug output
(10.09 KiB) Downloaded 82 times
Hi Joan,

I think you are the author of pigpio. Is my guess correct? I was just about to send an email to [email protected] asking for some guidance. But I will ask here instead!

I am currently struggling with latency problems when using pigpio to drive a ultrasonic range finder. The module uses a single gpio channel. I need to send a 10us pulse on the gpio then set the gpio into input mode and wait for a rising edge and then wait again for a falling edge and measure the time difference between the two edges. The only way I have got anywhere near getting this to work has been to use a pigpiod script. However I am still missing pulses.

I have attached a test program that illustrates this, and some debug output.
files.zip
Test script and debug output
(10.09 KiB) Downloaded 82 times
I understand that the daemon runs in user space and can be pre-empted by other processes. But I was just wondering any you or anyone else had any suggestions. I am about to try nice(ing) the daemon to see if I can make things work better.

Just a quick suggestion on pigpiod itself. It would be nice to have a option for it not to fork and exec itself. Doing that when it is run from an init.d script makes it hard to terminate bcause the init system stores the wrong (parent) pid.

Thanks

Roger

User avatar
joan
Posts: 14179
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 4:24 pm

Interesting, and bonus points for using a script.

I can see why you are using the script to handle the gpio mode change and pulse.

I'd use a callback in the Python to actually measure the level changes.

Add something like the following to your Python and see if the numbers make sense and are stable.

Code: Select all

RANGER=4

...

def cbf(g, l, t):
   print("gpio={} level={} tick={}".format(g, l, t))

...

cb = pi.callback(RANGER, pigpio.EITHER_EDGE, cbf)

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 5:05 pm

Aha,

I was was looking for a callback function in the script language. Now I understand. Use a script to trigger the pulse on the pigiod host, and get callbacks via the socket on the client. That should reduce the cpu load in pigpiod which I suspect is the cause of the problems.

Thanks,

Roger

User avatar
joan
Posts: 14179
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 5:13 pm

The callback tick is that recorded by DMA at the time the level change was detected and will be immune from scheduling jitter. Any calls to gpioTick (t) or gettimeofday etc. will be subject to scheduling problems, i.e, there may be a process reschedule between a level change being detected and the call to the time stamp function.

The timings between gpio events using callbacks will be the most stable.

rogerjames99
Posts: 29
Joined: Fri Sep 28, 2012 2:58 pm

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 7:00 pm

Thanks,
I thought that might be the case. It's working a lot better now. Just getting a bit confused about the length of the ticks. Are they still 1 millisecond? Oh and for posterity in the original test script I posted there was a bogus extra call to run_script that probably did not help things much.
Roger

User avatar
joan
Posts: 14179
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: Sharing a DREQ between multiple DMA engines

Mon Mar 16, 2015 8:38 pm

Ticks are in microseconds.

I didn't notice the bogus call!

merci
Posts: 1
Joined: Wed Aug 24, 2016 2:54 pm

Re: Sharing a DREQ between multiple DMA engines

Wed Aug 24, 2016 3:01 pm

Hi,
Is there a fix for this issue? I am trying to control four dc motors and a brushless motor using RPIO PWM. I am experiencing the same problem. When I initialize a new channel, it messes up the old ones. I am new to RPI and Python and I don't know to use pigpio. I would appreciate your help.

Thanks.

Return to “Interfacing (DSI, CSI, I2C, etc.)”