0

Please excuse me for the lengthiness of the problem but its beyond my knowhow, I dont know where else to go.

I am trying to send a PPM signal to a FlySkyi10 radio over the trainer cable. When using the PPM code below I am able to send the correct PPM signals to my radio.

//this programm will put out a PPM signal

//////////////////////CONFIGURATION///////////////////////////////
#define chanel_number 8  //set the number of chanels
#define default_servo_value 1500  //set the default servo value
#define PPM_FrLen 22500  //set the PPM frame length in microseconds (1ms = 1000µs)
#define PPM_PulseLen 300  //set the pulse length
#define onState 1  //set polarity of the pulses: 1 is positive, 0 is negative
#define sigPin 10  //set PPM signal output pin on the arduino
//////////////////////////////////////////////////////////////////


/*this array holds the servo values for the ppm signal
 change theese values in your code (usually servo values move between 1000 and 2000)*/
int ppm[chanel_number];

void setup(){  
  //initiallize default ppm values
  for(int i=0; i<chanel_number; i++){
    ppm[i]= default_servo_value;
  }

  pinMode(sigPin, OUTPUT);
  digitalWrite(sigPin, !onState);  //set the PPM signal pin to the default state (off)

  cli();
  TCCR1A = 0; // set entire TCCR1 register to 0
  TCCR1B = 0;

  OCR1A = 100;  // compare match register, change this
  TCCR1B |= (1 << WGM12);  // turn on CTC mode
  TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  sei();
}

void loop(){
  //put main code here
  static int val = 1;

  ppm[0] = ppm[0] + val;
  if(ppm[0] >= 2000){ val = -1; }
  if(ppm[0] <= 1000){ val = 1; }
  delay(10);
}

ISR(TIMER1_COMPA_vect){  //leave this alone
  static boolean state = true;

  TCNT1 = 0;

  if(state) {  //start pulse
    digitalWrite(sigPin, onState);
    OCR1A = PPM_PulseLen * 2;
    state = false;
  }
  else{  //end pulse and calculate when to start the next pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;

    digitalWrite(sigPin, !onState);
    state = true;

    if(cur_chan_numb >= chanel_number){
      cur_chan_numb = 0;
      calc_rest = calc_rest + PPM_PulseLen;// 
      OCR1A = (PPM_FrLen - calc_rest) * 2;
      calc_rest = 0;
    }
    else{
      OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * 2;
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }     
  }
}

But, the problem comes in when I read data from a sensor over i2c and some other functions. As soon as I use the i2c code, the PPM signal becomes noisy, and what should be a 1500ms signal, has noise of +/-20ms.

I dont want to make this post too bulky, I have used the i2c library for the LSM9DS0 to read sensor data. I have not used interrupts anywhere and I will have to have a closer look at the library. unfortunately i dont understand much of it. The simplified code for reading from the seensors is below. the website for the libraries is here: https://learn.adafruit.com/adafruit-lsm9ds0-accelerometer-gyro-magnetometer-9-dof-breakouts/arduino-code

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_LSM9DS0.h>
#include <Adafruit_Sensor.h>  // not used in this demo but required!

// i2c
Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0();

// You can also use software SPI
//Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0(13, 12, 11, 10, 9);
// Or hardware SPI! In this case, only CS pins are passed in
//Adafruit_LSM9DS0 lsm = Adafruit_LSM9DS0(10, 9);

void setupSensor()
{
  // 1.) Set the accelerometer range
  lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_2G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_4G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_6G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_8G);
  //lsm.setupAccel(lsm.LSM9DS0_ACCELRANGE_16G);

  // 2.) Set the magnetometer sensitivity
  lsm.setupMag(lsm.LSM9DS0_MAGGAIN_2GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_4GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_8GAUSS);
  //lsm.setupMag(lsm.LSM9DS0_MAGGAIN_12GAUSS);

  // 3.) Setup the gyroscope
  lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_245DPS);
  //lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_500DPS);
  //lsm.setupGyro(lsm.LSM9DS0_GYROSCALE_2000DPS);
}

void setup() 
{
#ifndef ESP8266
  while (!Serial);     // will pause Zero, Leonardo, etc until serial console opens
#endif
  Serial.begin(9600);
  Serial.println("LSM raw read demo");

  // Try to initialise and warn if we couldn't detect the chip
  if (!lsm.begin())
  {
    Serial.println("Oops ... unable to initialize the LSM9DS0. Check your wiring!");
    while (1);
  }
  Serial.println("Found LSM9DS0 9DOF");
  Serial.println("");
  Serial.println("");
}

void loop(void) 
{  
  /* Get a new sensor event */ 
  sensors_event_t accel, mag, gyro, temp;
  lsm.getEvent(&accel, &mag, &gyro, &temp); 

  // print out accelleration data
  Serial.print("Accel X: "); Serial.print(accel.acceleration.x); Serial.print(" ");
  Serial.print("  \tY: "); Serial.print(accel.acceleration.y);       Serial.print(" ");
  Serial.print("  \tZ: "); Serial.print(accel.acceleration.z);     Serial.println("  \tm/s^2");

  // print out magnetometer data
  Serial.print("Magn. X: "); Serial.print(mag.magnetic.x); Serial.print(" ");
  Serial.print("  \tY: "); Serial.print(mag.magnetic.y);       Serial.print(" ");
  Serial.print("  \tZ: "); Serial.print(mag.magnetic.z);     Serial.println("  \tgauss");

  // print out gyroscopic data
  Serial.print("Gyro  X: "); Serial.print(gyro.gyro.x); Serial.print(" ");
  Serial.print("  \tY: "); Serial.print(gyro.gyro.y);       Serial.print(" ");
  Serial.print("  \tZ: "); Serial.print(gyro.gyro.z);     Serial.println("  \tdps");

  // print out temperature data
  Serial.print("Temp: "); Serial.print(temp.temperature); Serial.println(" *C");

  Serial.println("**********************\n");

  delay(250);
}

Does anyone have an suggestions?

  • Noisy PPM could be because of interrupts are blocked and therefore delayed for that amount of time. So, probably, the issue is in the code you have not posted. Look carefully at where interrupts can be blocked for long period of times. – AterLux Sep 06 '18 at 12:59
  • Hi AterLux. Thanks for your response!! Ill have a look at any and all of the interrupts. Again, I am completely out of my depth here, but is there a way to move the PPM code onto a different timer? is the perhaps a way of eliminating this problem? Or do interrupts interfere with all timers? – Andreas Gerald Sep 07 '18 at 06:42
  • Also, I haven't added any interrupts from my side. I will have a look at the libraries I used. – Andreas Gerald Sep 07 '18 at 06:56
  • I also found, that one of my functions that filter signals, has a very large lists and calculations. this also caused noise. when i reduced the size of lists it helped reduce noise. But the i2c is still problematic. I thought the PPM code was supposed to run smooth regardless of lengthy functions? ie only interrupts affect it? – Andreas Gerald Sep 07 '18 at 07:01
  • Where and when `get_sensor_values()` is called? – AterLux Sep 07 '18 at 07:48
  • the get_sensor_values() is called in "void loop()". – Andreas Gerald Sep 07 '18 at 07:50
  • It is not shown in the code above. Can you put the whole code here? – AterLux Sep 07 '18 at 07:52
  • I have narrowed the problem down to the following. (sorry for all the edits) im trying to figure out exactly where the problem lies. Now, i have narrowed it down to the following line: lsm.getEvent(&accel, &mag, &gyro, &temp); Regarding my previous problem, the "get_sensor_values()" function that was causing noise, was because it was still feeding in values into the filter. The filter for some reason is causing noise. I have taken the filter out completely and will check that at a later stage. – Andreas Gerald Sep 07 '18 at 07:54
  • Answering the question: AVR has no interrupt priority management, so, yes, any interrupt executing, also any block of code which masks out interrupts, will block all the interrupts. So, from this point, there is no difference, which timer to use. So, if you have any interrupts, their handlers should return as soon as possible. – AterLux Sep 07 '18 at 07:56
  • I can put the entire code here, but its massive and i think would make things more confusing. the above code, even when simplified, is the code in question – Andreas Gerald Sep 07 '18 at 07:57
  • ok, i will have a look at the library i am calling in the "lsm.getEvenr(..." line. im convinced the problem lies there. – Andreas Gerald Sep 07 '18 at 07:58
  • sorry, what is AVR? – Andreas Gerald Sep 07 '18 at 07:59
  • AVR is an architecture of ATmega MCUs – AterLux Sep 07 '18 at 08:00
  • ohh, ok, so thats something one cant change. damn. geesh, not sure how i am going to figure this one out. In your opinion, can this be solved on an arduino? Can one read data over i2c and output a stable PPM signal from the same arduino? If so, what would you suggest is the best course to follow? – Andreas Gerald Sep 07 '18 at 08:02
  • Ive looked at the two libraries that are imported as shown in the second batch of code, and I understand nothing. :) any suggestions would be welcome – Andreas Gerald Sep 07 '18 at 08:14
  • is there any way you can see that the PPM code could be edited to fix this problem? – Andreas Gerald Sep 07 '18 at 08:28
  • Can you provide real code you have? Where PWM interrupt comes together with the sensor inquiry. You have posted two different files, each has it's own `setup` and `loop`. Or better you put zip with the project somewhere – AterLux Sep 07 '18 at 11:12

1 Answers1

0

I changed the method of reading data from the sensors to SPI, which solved the problem. All noise in the ppm signal has been eliminated.