Go Down

Topic: Arduino due / ppm (Read 4706 times) previous topic - next topic

Sijjim

Ok, you really wants the same code back? Please test it, i dont have an Due now. But hope this problem isnt one, when i have my own.
Get the Lib from ivanseidel/DueTimer
and test this:

Code: [Select]
#include <DueTimer.h>

#define chanel_number 8
#define default_servo_value 1500
#define PPM_FrLen 22500
#define PPM_PulseLen 300
#define sigPin 10
#define onState 1

int ppm[chanel_number];

void doit(){
  static boolean state = true;
  if(state){
    digitalWrite(sigPin, onState);
    Timer3.attachInterrupt(doit).setPeriod(PPM_PulseLen);
    state = false;
  } else {
    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;
      Timer3.attachInterrupt(doit).setPeriod(PPM_FrLen - calc_rest);
      calc_rest = 0;
    } else {
      Timer3.attachInterrupt(doit).setPeriod(ppm[cur_chan_numb] - PPM_PulseLen);
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }
  }     
}

void setup(){
  for (int i = 0; i < chanel_number; i++){
    ppm[i] = default_servo_value;
  }
  pinMode(sigPin, OUTPUT);
  digitalWrite(sigPin, !onState);
  Timer3.attachInterrupt(doit).start(1000);
}

void loop(){
  while(1){ }
}

Francois

#16
Dec 12, 2013, 02:57 am Last Edit: Dec 12, 2013, 03:03 am by Francois Reason: 1
Thank you very much for your help, I will be able to check the code on Friday (I do not have an osciloscope at home  =( ).

Here is what i would like to learn to do on the arduino due ( in green is the equivalent code for the arduino uno):

1. Setup a timer on the due & Start a timer  
  cli();
 TCCR1A = 0;                        // set entire TCCR1 register to 0
 TCCR1B = 0;
 OCR1A = 100;                     // compare match register
 TCCR1B |= (1 << WGM12);   // turn on CTC mode
 TIMSK1 |= (1 << OCIE1A);    // enable timer compare interrupt
 sei();


2. Set a presacaler
  TCCR1B |= (1 << CS11);    // 8 prescaler: 0,5 microseconds at 16mhz

3. Change the match register (trigger)
  OCR1A = XXX // what every value i decide

4. Run into a loop every time the match register is reached
  ISR(TIMER1_COMPA_vect){ code }

Is it possible to do ?

Sijjim

#17
Dec 12, 2013, 10:01 am Last Edit: Dec 12, 2013, 10:03 am by Sijjim Reason: 1
First, if u have an other Arduino, i use this sketch on a Uno for fast bugfixing:

Code: [Select]
#define channumber 7 //How many channels have your radio?
int value[channumber];

void setup()
{
Serial.begin(57600); //Serial Begin
pinMode(3, INPUT); //Pin 3 as input
}
void loop()
{
while(pulseIn(3, LOW) < 5000){} //Wait for the beginning of the frame
// while(pulseIn(3, HIGH) < 5000){} //alt for invert signal
for(int x=0; x<=channumber-1; x++)//Loop to store all the channel position
{
value[x]=pulseIn(3, LOW);
// value[x]=pulseIn(3, HIGH); //alt for invert signal
}
for(int x=0; x<=channumber-1; x++)//Loop to print and clear all the channel readings
{
Serial.print(value[x]); //Print the value
Serial.print(" ");
value[x]=0; //Clear the value afeter is printed
}
Serial.println(""); //Start a new line
}

Just hang pin 3 from this one to ppm-out on Due an connect ground together.

and the other points, look to stimmers code too:

Quote
1. Setup a timer on the due & Start a timer  

Code: [Select]
REG_PIOB_PDR = 1<<25; // disable PIO, enable peripheral
 REG_PIOB_ABSR= 1<<25; // select peripheral B
 REG_TC0_WPMR=0x54494D00; // enable write to registers
//REG_TC0_CMR0=0b00000000000010011100010000000000; // set channel mode register (see datasheet)
 REG_TC0_CMR0=0b00000000000001101100010000000000; // alternative CMR for inverted output
 REG_TC0_RC0=100000000; // counter period
 REG_TC0_CCR0=0b101;    // start counter
 REG_TC0_IER0=0b00010000; // enable interrupt on counter=rc
 REG_TC0_IDR0=0b11101111; // disable other interrupts


Quote
2. Set a presacaler

not sure, think its inside this part, the TCCLKS, look in datasheet at page 869, Table 37-1 and page 904
Code: [Select]
REG_TC0_CMR0=0b00000000000001101100010000000000;

Quote
3. Change the match register (trigger)

Code: [Select]
REG_TC0_RC0= XXX

Quote
4. Run into a loop every time the match register is reached

Code: [Select]
void TC0_Handler() { code }

greetings

VerlatyAlex

#18
Feb 25, 2015, 10:28 am Last Edit: Feb 25, 2015, 06:25 pm by VerlatyAlex
Good day.
I'm not an experienced programmer Arduino, had a lot to deal with timers Atmel SAM3X8E ARM Cortex-M3 NC.
Helped Frankois code in this post.
Thank very much for Frankois working code.
I redid it and simplified.
Code 100% working on Arduino Due.
My code changes PPM signal to the respective signals at the inputs A0-A2.

Code: [Select]

#define PPM_PIN 2             // выход PPM
#define MAX_PPM_CHANNELS 8
#define PPM_FrLen 22500
#define PPM_PulseLen 250
int ppm[MAX_PPM_CHANNELS];
int PPMmin = 900;
byte PPM_cur_ch = 0;
unsigned int PPM_sum = 0;

void setup() {
  pinMode(PPM_PIN, OUTPUT);          // port B pin 25
  analogWrite(PPM_PIN, 255);         // sets up some other registers I haven't worked out yet

  // timer is clocked at 42MHz, so 42 ticks per us
  REG_PIOB_PDR  = 1 << 25;     // disable PIO, enable peripheral
  REG_PIOB_ABSR = 1 << 25;     // select peripheral B
  REG_TC0_WPMR  = 0x54494D00;  // enable write to registers
  // REG_TC0_CMR0  = 0b00000000000010011100010000000000; // set channel mode register (see datasheet)
  REG_TC0_CMR0  = 0b00000000000001101100010000000000; // alternative CMR for inverted output
  REG_TC0_RC0   = 100000000;   // counter period
  REG_TC0_CCR0  = 0b101;       // start counter
  REG_TC0_IER0  = 0b00010000;  // enable interrupt on counter = rc
  REG_TC0_IDR0  = 0b11101111;  // disable other interrupts

  REG_TC0_RA0   = PPM_PulseLen * 42; // Pulse lenght
  NVIC_EnableIRQ(TC0_IRQn);    // enable TC0 interrupts

  for (int i = 0; i < MAX_PPM_CHANNELS; i++) ppm[i] = PPMmin;
}

void TC0_Handler()
{
  long dummy = REG_TC0_SR0;  // vital - reading this clears some flag, otherwise you get infinite interrupts
  if (PPM_cur_ch < MAX_PPM_CHANNELS)
  {
    REG_TC0_RC0 = ppm[PPM_cur_ch] * 42;
    PPM_sum += ppm[PPM_cur_ch];
    PPM_cur_ch++;
  }
  else
  {
    REG_TC0_RC0 = (PPM_FrLen - PPM_sum) * 42;
    PPM_cur_ch = 0;
    PPM_sum = 0;
  }
}

void loop()
{
  ppm[0] = PPMmin + analogRead(0);
  ppm[1] = PPMmin + analogRead(1);
  ppm[2] = PPMmin + analogRead(2);
  
  
}


Sijjim's code in this post must be changed.
Each row in the:
Timer3.attachInterrupt (doit) .setPeriod (PPM_PulseLen);
Timer3.attachInterrupt (doit) .setPeriod (PPM_FrLen - calc_rest);
Timer3.attachInterrupt (doit) .setPeriod (ppm [cur_chan_numb] - PPM_PulseLen);
it is necessary to add the start ()

Corrected row looks like this:
Timer3.attachInterrupt (doit) .setPeriod (PPM_PulseLen). start ();
Timer3.attachInterrupt (doit) .setPeriod (PPM_FrLen - calc_rest). start ();
Timer3.attachInterrupt (doit) .setPeriod (ppm [cur_chan_numb] - PPM_PulseLen). start ();

VerlatyAlex

#19
Feb 25, 2015, 10:56 am Last Edit: Feb 25, 2015, 10:59 am by VerlatyAlex
To read the PPM signal in my project using this code:
Code: [Select]
#define MAX_PPM_CHANNELS 8          // we are working with an 8-ch-Transmitter
#define PPM_PIN 3           // Input Pin Number

const int FrameSpace = 2500;
unsigned long Last_Time;
unsigned long Current_Time;
unsigned long Delta_Time;
volatile byte Current_Channel = 0;
volatile int Channel[MAX_PPM_CHANNELS];

void setup()
{
    attachInterrupt(1, CalcPPM, RISING);
    Last_Time = micros(); 
    Serial.begin(9600);
}

void CalcPPM()
{
  Current_Time = micros();
  Delta_Time = Current_Time - Last_Time;
  Last_Time = Current_Time;
  if (Delta_Time > FrameSpace) Current_Channel = 0;
  else
  {
    Channel[Current_Channel]=Delta_Time;
    Current_Channel++;
  }   


void loop()
{
  for ( byte x = 0; x < MAX_PPM_CHANNELS; x++)
  {
    Serial.print("Ch. ");
    Serial.print(x);
    Serial.print(": ");
    Serial.print(Channel[x]); 
    Serial.print("      ");
  }
  Serial.println();
 }
 
 


Checked this code to Arduino Due, Mega and Pro Mini.
This code works 100%.

To use the Due need to change the line:

attachInterrupt(1, CalcPPM, RISING);

to:

attachInterrupt(PPM_PIN, CalcPPM, RISING);

Paul Stoffregen

I recently wrote a PPM signal library called PulsePosition.


http://www.pjrc.com/teensy/td_libs_PulsePosition.html


It's designed around Teensy's timers, but if someone wanted to get a good start on a Due-based library, maybe this could at least help?

Go Up