Problem reading a PWM signal from RC receiver

Status
Not open for further replies.

Codefella

Member
When reading PWM i got "phantom" signals if using a timer for some calculations in the same project.

I setup few lines of code so that the problem could be reproduced:

Code:
#define RCPIN_IN 20             // input pin for RC receiver signal
#define DEADBAND 10             // tolerance for the RC signal
#define CONTROL_RATE 600        // control rate of timer in Hz

IntervalTimer controlTimer;

volatile long signal = 0;
volatile long signalStart = 0;

void setup() {
    pinMode(RCPIN_IN, INPUT);
    attachInterrupt(RCPIN_IN, signalISR, CHANGE);
    controlTimer.begin(controlISR, (1000000 / CONTROL_RATE));
}

void signalISR() {

    if (digitalRead(RCPIN_IN) == HIGH) {
        signalStart = micros();
    } else {
        signal = micros() - signalStart;

        if (abs(signal - 1500) > DEADBAND) {
            Serial.print(millis());
            Serial.print("ms ");

            Serial.print(signal);
            Serial.print("us");

            Serial.println("");
        }
    }

}

void controlISR() {
    delayMicroseconds(100);  // placeholder for some calculations in the real project
};

void loop() {
    delay(100);
}

The code outputs the signal if the signal is greater than abs(1500-DEADBAND) which is sufficient to avoid glitches from the "normal" change of the
signal which is typically around 2us for my rc contro.

Attached you find the serial ouptut. Please note that the error readings appear every ~3880ms :confused:
If the controlTimer is DEACTIVATED there is NO problem with the readings.

While running this code the RC control was not touched and therefore a signal of ~1500us is send by the RC receiver to teensy 3.1

There is always a bunch of wrong readings (~40), then a break of ~3880ms before outputting wrong readings again.

Code:
18003ms 1517us
18013ms 1513us
21303ms 1402us
21313ms 1407us
21323ms 1411us
21333ms 1415us
21343ms 1419us
21353ms 1424us
21363ms 1428us
21373ms 1433us
21383ms 1436us
21393ms 1442us
21403ms 1445us
21413ms 1449us
21423ms 1454us
21433ms 1457us
21443ms 1462us
21453ms 1467us
21463ms 1471us
21473ms 1476us
21483ms 1479us
21493ms 1485us
21503ms 1488us
21693ms 1598us
21703ms 1593us
21713ms 1589us
21723ms 1585us
21733ms 1580us
21743ms 1576us
21753ms 1572us
21763ms 1567us
21773ms 1563us
21783ms 1559us
21793ms 1555us
21803ms 1550us
21813ms 1546us
21823ms 1542us
21833ms 1537us
21843ms 1533us
21853ms 1529us
21863ms 1524us
21873ms 1520us
21883ms 1516us
21893ms 1512us
25183ms 1403us
25193ms 1407us
25203ms 1413us
25213ms 1417us
25223ms 1420us
25233ms 1425us
25243ms 1429us
25253ms 1433us
25263ms 1437us
25273ms 1441us
25283ms 1446us
25293ms 1450us
25303ms 1455us
25313ms 1459us
25323ms 1463us
25333ms 1467us
25343ms 1473us
25353ms 1476us
25363ms 1480us
25373ms 1486us
25383ms 1489us
25563ms 1603us
25573ms 1599us
25583ms 1594us
25593ms 1590us
25603ms 1586us
25613ms 1581us
25623ms 1577us
25633ms 1573us
25643ms 1568us
25653ms 1564us
25663ms 1560us
25673ms 1556us
25683ms 1549us
25693ms 1545us
25703ms 1541us
25713ms 1536us
25723ms 1532us
25733ms 1528us
25743ms 1523us
25753ms 1519us
25763ms 1515us
25773ms 1511us
29063ms 1404us
29073ms 1408us
29083ms 1413us
29093ms 1417us
29103ms 1421us
29113ms 1425us
29123ms 1430us
29133ms 1434us
29143ms 1439us
29153ms 1442us
29163ms 1447us
29173ms 1450us
29183ms 1456us
29193ms 1461us
29203ms 1464us
29213ms 1468us
29223ms 1473us
29233ms 1476us
29243ms 1481us
29253ms 1486us
29444ms 1600us
29454ms 1596us
29464ms 1591us
29474ms 1587us
29484ms 1583us
29494ms 1578us
29504ms 1574us
29514ms 1570us
29524ms 1565us
29534ms 1561us
29543ms 1557us
29553ms 1553us
29563ms 1548us
29573ms 1544us
29583ms 1540us
29593ms 1535us
29603ms 1531us
29613ms 1527us
29623ms 1522us
29633ms 1518us
29643ms 1514us

after trying some things (disabling interrupts in the controlTimer routine, setting NVIC priorit) i just have no clue what am i doing wrong.

maybe someone can give me a hint!?
 
Hm, make sure that the controlISR has a lower Interrupt priority than signalISR.


But your way of measuring is not optimal, anyway.
It would be better to use a hardwaretimer.
 
Try lowering the priority (a higher number) for the control interrupt.

Like this:

Code:
  controlTimer.priority(192);

Also, if this is a raw PPM signal (encoding several PWM signals), you might consider using the PulsePosition library. It uses a much higher accuracy approach with timer input capture, which is very resilient to interrupt latency from other code and libraries.

http://www.pjrc.com/teensy/td_libs_PulsePosition.html
 
If you're not concerned with a quick update rate, you can consider using the pulseIn() function (see here for working example: http://petrkout.com/electronics/connect-rc-receiver-to-arduino/). Be aware that it takes ~20ms to execute as it waits for the end of each PWM signal which is about a 50Hz signal. So if you are receiving 4 different channels from your receiver this could take close to 80ms to execute.

The other method (that I'm currently using for a project) is to use regular interrupts. Below is sample code that works for me with no issues of erroneous readings, even when sampling at 250Hz:

Code:
// input pin from receiver
#define PIN_RX 21

// interrupt variables
volatile uint16_t RX;
uint16_t RX_START;

void setup() {
    // start serial communication
    Serial.begin(115200);

    // allow input on pin and attach interrupt
    pinMode(PIN_RX, INPUT);
    attachInterrupt(PIN_RX, INT_RX, CHANGE);
}

void loop() {
    // print receiver value
    Serial.println(RX);

    delay(5);
}

void INT_RX() {
    // if pin is high, start timer
    if (digitalRead(PIN_RX) == HIGH) {
        RX_START = micros();
    }
    // otherwise, find the pulse length
    else {
        RX = (uint16_t) (micros() - RX_START);
    }
}
 
@Frank, @Paul: Thanks for the input, lowering the priority of the control timer worked for me. my mistake was to set a low number and not a high like 192...

@joe_prince:

if you look at my code example in the first post you see that your method is exactly what can cause trouble. When not using any timer it's ok because loop
has a lower interrupt priority by default.

Add a timer to your project and you will get erroneous readings...

Quickest solution is to set priority as recommend above.
 
Status
Not open for further replies.
Back
Top