Main Site Documentation

PWM Signal Train


#1

I am looking for a way to generate a PWM signal train. What I mean by that is I need to send something like this out a PWM pin or other digital pin with pretty precise timing.

--------------------

So instead of a steady square wave I need to vary the timing on that train. This is for R/C use and so it would need to be a train of 22.5ms in total with all high except for 8 varying 3ms low pulses. This is to simulate the signal one would be receiving on a buddy box setup of R/C transmitters. The different low pulses would simulate the servo positions for up to 8 servos.

My goal is to use the USBizi chip to control a R/C transmitter via potentiometers in a flight chair designed to control helicopters. Right now I have to mutilate the transmitters to get it to work but if I could simply design this circuit to plug in to the buddy box port of a transmitter it would be much easier to distribute.


#2

OutputCompare is made to do exactly that http://wiki.tinyclr.com/index.php?title=Output_Compare


#3

I have been pouring over the documentation for OutputCompare. I do see how this would generate the signal perfectly. Just a couple of questions. I was wondering if you could point me in the right direction of maybe some sample code where this is being done for something similar and with other things being done along side of this. Do you simply setup the sequence over and over with the different values and it queues them up one at a time or when you setup the values will it repeat over and over until you change the values?

Thinking about it what would seem logical is to setup a timer that would fire ever 22.5ms sending the proper values. Does that seem correct or am I missing how this all works.


#4

Take a look at our free “internet of things book” You will find it with FEZ Panda II downloads.


#5

SetBocking is adding a 1000us to the first timing transition.

For example…



static uint[] timings = new uint[18];
static OutputCompare _oc;
_oc = new OutputCompare((Cpu.Pin)FEZ_Pin.Digital.Di0, false, timings.Length);

timings[0] = 300;
timings[1] = 1500 - timings[0]; // Channel 1
timings[2] = 300;
timings[3] = 1500 - timings[2]; // Channel 2
timings[4] = 300;
timings[5] = 1000 - timings[4]; // Channel 3
timings[6] = 300;
timings[7] = 1000 - timings[6]; // Channel 4
timings[8] = 300;
timings[9] = 2000 - timings[8]; // Channel 5
timings[10] = 300;
timings[11] = 1500 - timings[10]; // Channel 6
timings[12] = 300;
timings[13] = 1250 - timings[12]; // Channel 7
timings[14] = 300;
timings[15] = 1750 - timings[14]; // Channel 8
timings[16] = 300;
timings[17] = 22500 - (timings[0] + timings[1] + timings[2] + timings[3] + timings[4] + timings[5] + timings[6] + timings[7] + timings[8] + timings[9] + timings[10] + timings[11] + timings[12] + timings[13] + timings[14] + timings[15] + timings[16]);

_oc.SetBlocking(false, timings, 0, timings.Length, 0, true);

It will create a 1300us for timings[0] instead of the 300us it is supposed to be. If I put it in a loop it does the same thing on each iteration.


#6

Can you show the output signal with the problem and the code that generated it?
From what you provided the pin was false even before you called SetBlocking(…) so it will be false for longer than 300 micro seconds…


#7

Here is an example code and the output from the oscilloscope. If you put a while(true) around the timings[0] = 300; and the _oc.SetBlocking(false, timings, 0, timings.Length, 0, true); you will see it happens on each iteration. You do not get the floating. I will upload a second picture on the next post.


using System;
using System.Threading;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;


namespace FEZ_Domino_Test_1
{
    public class Program
    {
        static uint[] timings = new uint[18];
        static OutputCompare _oc;

        static AnalogIn chan1;
        static AnalogIn chan2;

        public static void Main()
        {

            chan1 = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An2);
            chan2 = new AnalogIn((AnalogIn.Pin)FEZ_Pin.AnalogIn.An3);
            chan1.SetLinearScale(1000, 2000);
            chan2.SetLinearScale(1000, 2000);
            _oc = new OutputCompare((Cpu.Pin)FEZ_Pin.Digital.Di0, false, timings.Length);

            timings[0] = 300;
            timings[1] = 1500 - timings[0]; // Channel 1
            timings[2] = 300;
            timings[3] = 1500 - timings[2]; // Channel 2
            timings[4] = 300;
            timings[5] = 1000 - timings[4]; // Channel 3
            timings[6] = 300;
            timings[7] = 1000 - timings[6]; // Channel 4
            timings[8] = 300;
            timings[9] = 2000 - timings[8]; // Channel 5
            timings[10] = 300;
            timings[11] = 1500 - timings[10]; // Channel 6
            timings[12] = 300;
            timings[13] = 1250 - timings[12]; // Channel 7
            timings[14] = 300;
            timings[15] = 1750 - timings[14]; // Channel 8
            timings[16] = 300;
            timings[17] = 22500 - (timings[0] + timings[1] + timings[2] + timings[3] + timings[4] + timings[5] + timings[6] + timings[7] + timings[8] + timings[9] +
                            timings[10] + timings[11] + timings[12] + timings[13] + timings[14] + timings[15] + timings[16]);
            _oc.SetBlocking(false, timings, 0, timings.Length, 0, true);
        }
    }
}


#8

Here is the output with the while(true) loop.


#9

Here is a 2 loop shot with the values shown on the scope.


#10

The the ‘extra’ delay is happening before you call SetBlocking(). The pin was already low and then it will be low for an additional 300 us.
In the while(true) loop, the pin will toggle after the last delay timings[17] and it will be low until you call SetBlocking again…
You can try this in the while(true):
_oc.SetBlocking(false, timings, 0, timings.Length - 1, timings[17], true);
This holds the pin high instead of toggling at the end.


#11

Okay that does seem to work although it still seems to have a 1000us delay that way too. I had to shorten timings[17] by 1000 to make it come out right. Is this done for a reason or do I have some sort of other timing issue going on that I need to be concerned with.

Also when setting up the OutputCompare there is a boolean for defaulting the pin to true and also when doing the SetBlocking there is a boolean to default the output to true there as well. On the SetBlocking I have to set this to false to get the PPM signal to default as a high when I would have thought it would be the other way around.


#12

No I am not buying it. There is a 1000us delay in there somewhere that is not documented. Yes it can be hidden in this case by doing the work around you suggested but its still a delay that should not be there. When I changed the OutputCompare boolean to true it caused the pin to go high after it initialized but that same 1ms delay is still there. By doing what you suggested it works after the first PPM signal because I took that 1ms delay from the end of the train. The problem is if I needed less than a 1ms delay at the end of the train it would not work. Luckily for me this wont be an issue and this work around will solve my issue but there may be a need down the road where this hack wont work. So there is a 1ms delay in there some where that should be tracked down and squashed unless you can tell me it is a necessary evil to make the OutputCompare work.


#13

I tried it on my board. I don’t think there is a problem.
Let’s start over. There is:
_oc = new OutputCompare((Cpu.Pin)FEZ_Pin.Digital.Di0, false, timings.Length);
_oc.SetBlocking(false, timings, 0, timings.Length, 0, true);

Constructor starts out as false and then you ask it to be false for an additional 300 us.
Setting the constructor to true, makes the low signal 300 us exactly.
If you can provide some code that shows the problem, please provide it.


#14

Look at the second train. You see the same exact 1300us low there as well. I could understand if you were saying that the initial train might have that 1300us low because it is initially set low but the second train would not be that way. The below code is from your suggested fix.


using System;
using System.Threading;
 
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
 
using GHIElectronics.NETMF.FEZ;
using GHIElectronics.NETMF.Hardware;
 
 
namespace FEZ_Domino_Test_1
{
    public class Program
    {
        static uint[] timings = new uint[18];
        static OutputCompare _oc;
 
        public static void Main()
        {
            _oc = new OutputCompare((Cpu.Pin)FEZ_Pin.Digital.Di0, false, timings.Length);
 
            timings[0] = 300;
            timings[1] = 1500 - timings[0]; // Channel 1
            timings[2] = 300;
            timings[3] = 1500 - timings[2]; // Channel 2
            timings[4] = 300;
            timings[5] = 1000 - timings[4]; // Channel 3
            timings[6] = 300;
            timings[7] = 1000 - timings[6]; // Channel 4
            timings[8] = 300;
            timings[9] = 2000 - timings[8]; // Channel 5
            timings[10] = 300;
            timings[11] = 1500 - timings[10]; // Channel 6
            timings[12] = 300;
            timings[13] = 1250 - timings[12]; // Channel 7
            timings[14] = 300;
            timings[15] = 1750 - timings[14]; // Channel 8
            timings[16] = 300;
            timings[17] = 22500 - (timings[0] + timings[1] + timings[2] + timings[3] + timings[4] + timings[5] + timings[6] + timings[7] + timings[8] + timings[9] +
                            timings[10] + timings[11] + timings[12] + timings[13] + timings[14] + timings[15] + timings[16]);
							
            //_oc.SetBlocking(false, timings, 0, timings.Length, 0, true);
            _oc.SetBlocking(false, timings, 0, timings.Length - 1, timings[17], true);
        }
    }
}

In this there should be a 22.5ms train repeating itself over and over. The issue is it becomes a 23.5ms train because of the 1ms delay that should not be there. I could see the code being an issue on the first train possibly but not really but you will consistently see the train take 23.5ms when it should only be 22.5ms. To correct this to work okay for me now I have to change the timings[17] = 22500 - etc to 21500 which then allows the train to come out to 22.5ms.


#15

The picture that corresponds with this code is the 8th reply.