Browse Source

New CPPM code. Should now be basically working.

Thomas Buck 8 years ago
parent
commit
f91c7225b7
6 changed files with 113 additions and 87 deletions
  1. 9
    5
      Saitek-X52-PPM.ino
  2. 44
    72
      cppm.cpp
  3. 1
    1
      cppm.h
  4. 9
    8
      events_cppm.cpp
  5. 44
    1
      x52.cpp
  6. 6
    0
      x52.h

+ 9
- 5
Saitek-X52-PPM.ino View File

19
 #include "x52.h"
19
 #include "x52.h"
20
 #include "cppm.h"
20
 #include "cppm.h"
21
 
21
 
22
-#define ENABLE_SERIAL_PORT
23
-#define DEBUG_OUTPUT
22
+//#define ENABLE_SERIAL_PORT
23
+//#define DEBUG_OUTPUT
24
+//#define DEBUG_INPUT
24
 
25
 
25
 USB usb;
26
 USB usb;
26
 USBHub hub(&usb);
27
 USBHub hub(&usb);
53
 }
54
 }
54
 
55
 
55
 void init_joystick() {
56
 void init_joystick() {
57
+    x52.initialize();
56
     x52.setLEDBrightness(2);
58
     x52.setLEDBrightness(2);
57
     x52.setMFDBrightness(2);
59
     x52.setMFDBrightness(2);
58
     x52.setShift(0);
60
     x52.setShift(0);
59
     x52.setBlink(0);
61
     x52.setBlink(0);
60
     x52.setMFDText(0, "Arduino X52 Host");
62
     x52.setMFDText(0, "Arduino X52 Host");
61
-    x52.setMFDText(1, "    has been    ");
62
-    x52.setMFDText(2, "  initialized!  ");
63
+    x52.setMFDText(1, "  initialized!");
63
 }
64
 }
64
 
65
 
65
 void loop() {
66
 void loop() {
73
             init_joystick();
74
             init_joystick();
74
             initialized = 1;
75
             initialized = 1;
75
         }
76
         }
77
+
78
+        String text = "Uptime: " + String(millis() / 1000) + "s";
79
+        x52.setMFDText(2, text.c_str());
76
     }
80
     }
77
 
81
 
78
-#ifdef DEBUG_OUTPUT
82
+#ifdef DEBUG_INPUT
79
     if (Serial.available()) {
83
     if (Serial.available()) {
80
         char c = Serial.read();
84
         char c = Serial.read();
81
         if (c == 't') {
85
         if (c == 't') {

+ 44
- 72
cppm.cpp View File

1
 /*
1
 /*
2
  * Combined-PPM signal generator
2
  * Combined-PPM signal generator
3
  *
3
  *
4
- * The whole CPPM pulse should be 20ms long.
5
- * It contains 8 channels with 2ms each, followed
6
- * by 4ms of silence. One channel pulse varies between
7
- * 1 and 2 ms. They are seperated with a very short low
8
- * pulse of about 0.1ms.
9
- *
10
- * 20.000us
11
- *   - 8 * 2.000us = 16.000us
12
- *   - 9 * 100us = 900us
13
- *   = 3.100us
14
- *
15
- *     1     2     3     4     5     6     7     8
16
- *    ___   ___   ___   ___   ___   ___   ___   ___   __________
17
- * | |   | |   | |   | |   | |   | |   | |   | |   | |          |
18
- * | |   | |   | |   | |   | |   | |   | |   | |   | |          |
19
- * | |   | |   | |   | |   | |   | |   | |   | |   | |          |
20
- * |_|   |_|   |_|   |_|   |_|   |_|   |_|   |_|   |_|          |
21
- *
22
- * States:
23
- *  0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16    17
4
+ * Based on the code from:
5
+ * https://quadmeup.com/generate-ppm-signal-with-arduino/
6
+ * https://github.com/DzikuVx/ppm_encoder/blob/master/ppm_encoder_source.ino
24
  *
7
  *
25
  * Copyright 2016 by Thomas Buck <xythobuz@xythobuz.de>
8
  * Copyright 2016 by Thomas Buck <xythobuz@xythobuz.de>
26
  *
9
  *
28
  * modify it under the terms of the GNU General Public License as
11
  * modify it under the terms of the GNU General Public License as
29
  * published by the Free Software Foundation, version 2.
12
  * published by the Free Software Foundation, version 2.
30
  */
13
  */
31
-#include <TimerOne.h>
14
+#include <Arduino.h>
32
 #include "cppm.h"
15
 #include "cppm.h"
33
 
16
 
34
 //#define DEBUG_OUTPUT
17
 //#define DEBUG_OUTPUT
35
-//#define DEBUG_OUTPUT_ALL
36
-
37
-#define CHANNELS 8
38
-#define MAX_STATES ((2 * CHANNELS) + 1)
39
-#define WHOLE_PULSE_WIDTH 20000
40
-#define PULSE_WIDTH 2000
41
-#define MAX_PULSE_WIDTH (CHANNELS * PULSE_WIDTH) // 16.000
42
-#define PULSE_LOW 100
43
-#define PULSE_LOW_SUM ((CHANNELS + 1) * PULSE_LOW) // 900
44
-#define MIN_WAIT (WHOLE_PULSE_WIDTH - MAX_PULSE_WIDTH - PULSE_LOW_SUM) // 3100
45
-#define TIME_AFTER_OVERFLOW 128
46
-#define TIME_MULTIPLIER 2
47
 
18
 
48
-volatile uint16_t cppmData[CHANNELS] = { 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500 };
49
-volatile uint16_t delaySum = 0;
50
-volatile uint8_t state = 0;
19
+#define CHANNELS 8 // set the number of chanels
20
+#define CHANNEL_DEFAULT_VALUE 1500 // set the default servo value
21
+#define FRAME_LENGTH 20000 // set the PPM frame length in microseconds (1ms = 1000µs)
22
+#define PULSE_LENGTH 100 // set the pulse length
23
+#define ON_STATE 1 // set polarity of the pulses: 1 is positive, 0 is negative
51
 
24
 
52
-static void triggerIn(uint16_t us);
53
-static void nextState(void);
25
+static volatile uint16_t cppmData[CHANNELS];
26
+static volatile uint8_t state = 1;
27
+static volatile uint8_t currentChannel = CHANNELS;
28
+static volatile uint16_t calcRest = 0;
54
 
29
 
55
 void cppmInit(void) {
30
 void cppmInit(void) {
56
 #ifdef DEBUG_OUTPUT
31
 #ifdef DEBUG_OUTPUT
57
     Serial.println("Initializing Timer...");
32
     Serial.println("Initializing Timer...");
58
 #endif
33
 #endif
59
 
34
 
35
+    for (uint8_t i = 0; i < CHANNELS; i++) {
36
+        cppmData[i] = CHANNEL_DEFAULT_VALUE;
37
+    }
38
+
60
     pinMode(CPPM_OUTPUT_PIN, OUTPUT);
39
     pinMode(CPPM_OUTPUT_PIN, OUTPUT);
61
-    digitalWrite(CPPM_OUTPUT_PIN, LOW);
62
-    Timer1.initialize(PULSE_LOW);
63
-    Timer1.attachInterrupt(&nextState);
64
-    state = 0;
65
-    delaySum = MIN_WAIT;
40
+    digitalWrite(CPPM_OUTPUT_PIN, ON_STATE ? LOW : HIGH);
41
+
42
+    cli();
43
+    TCCR1A = 0; // set entire TCCR1 register to 0
44
+    TCCR1B = 0;
45
+    OCR1A = 100; // compare match register
46
+    TCCR1B |= (1 << WGM12); // turn on CTC mode
47
+    TCCR1B |= (1 << CS11); // 8 prescaler: 0,5 microseconds at 16mhz
48
+    TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
49
+    sei();
66
 }
50
 }
67
 
51
 
68
 void cppmCopy(uint16_t *data) {
52
 void cppmCopy(uint16_t *data) {
77
     sei();
61
     sei();
78
 }
62
 }
79
 
63
 
80
-static void triggerIn(uint16_t us) {
81
-    Timer1.setPeriod(us);
82
-    //Timer1.start();
83
-}
84
-
85
-static void nextState(void) {
86
-    //Timer1.stop();
87
-
88
-#ifdef DEBUG_OUTPUT_ALL
89
-    Serial.print("CPPM state ");
90
-    Serial.println(state, DEC);
91
-#endif
92
-    
93
-    state++;
94
-    if (state > MAX_STATES) {
64
+ISR(TIMER1_COMPA_vect){
65
+    TCNT1 = 0;
66
+    if (state) {
67
+        // start pulse
68
+        digitalWrite(CPPM_OUTPUT_PIN, ON_STATE ? HIGH : LOW);
69
+        OCR1A = PULSE_LENGTH << 1;
95
         state = 0;
70
         state = 0;
96
-        delaySum = MIN_WAIT;
97
-    }
98
-    if (!(state & 0x01)) {
99
-        // pulse pause
100
-        digitalWrite(CPPM_OUTPUT_PIN, LOW);
101
-        triggerIn(PULSE_LOW);
102
     } else {
71
     } else {
103
-        digitalWrite(CPPM_OUTPUT_PIN, HIGH);
104
-        if (state <= 15) {
105
-            // normal ppm pulse
106
-            uint8_t index = state >> 1;
107
-            triggerIn(cppmData[index]);
108
-            delaySum += PULSE_WIDTH - cppmData[index];
72
+        // end pulse and calculate when to start the next pulse
73
+        digitalWrite(CPPM_OUTPUT_PIN, ON_STATE ? LOW : HIGH);
74
+        state = 1;
75
+        if (currentChannel >= CHANNELS) {
76
+            currentChannel = 0;
77
+            calcRest += PULSE_LENGTH;
78
+            OCR1A = (FRAME_LENGTH - calcRest) << 1;
79
+            calcRest = 0;
109
         } else {
80
         } else {
110
-            // sync pulse
111
-            triggerIn(delaySum);
81
+            OCR1A = (cppmData[currentChannel] - PULSE_LENGTH) << 1;
82
+            calcRest += cppmData[currentChannel];
83
+            currentChannel++;
112
         }
84
         }
113
     }
85
     }
114
 }
86
 }

+ 1
- 1
cppm.h View File

12
 
12
 
13
 #include <stdint.h>
13
 #include <stdint.h>
14
 
14
 
15
-#define CPPM_OUTPUT_PIN 13
15
+#define CPPM_OUTPUT_PIN 4
16
 
16
 
17
 void cppmInit(void);
17
 void cppmInit(void);
18
 void cppmCopy(uint16_t *data);
18
 void cppmCopy(uint16_t *data);

+ 9
- 8
events_cppm.cpp View File

10
  * published by the Free Software Foundation, version 2.
10
  * published by the Free Software Foundation, version 2.
11
  */
11
  */
12
 
12
 
13
+#include <Arduino.h>
13
 #include "data.h"
14
 #include "data.h"
14
 #include "cppm.h"
15
 #include "cppm.h"
15
 #include "events.h"
16
 #include "events.h"
26
         values[i] = 1500;
27
         values[i] = 1500;
27
     }
28
     }
28
 
29
 
29
-    values[CHANNEL_AUX1] = 200;
30
-    values[CHANNEL_AUX2] = 200;
30
+    values[CHANNEL_AUX1] = 1000;
31
+    values[CHANNEL_AUX2] = 1000;
31
 
32
 
32
     cppmCopy(values);
33
     cppmCopy(values);
33
 }
34
 }
34
 
35
 
35
 void JoystickEventsCPPM::OnGamePadChanged(const GamePadEventData& evt) {
36
 void JoystickEventsCPPM::OnGamePadChanged(const GamePadEventData& evt) {
36
-    values[CHANNEL_THROTTLE] = evt.Z;
37
-    values[CHANNEL_PITCH] = evt.Y;
38
-    values[CHANNEL_ROLL] = evt.X;
39
-    values[CHANNEL_YAW] = evt.Rz;
40
-    values[CHANNEL_AUX1] = evt.Ry;
41
-    values[CHANNEL_AUX2] = evt.Slider;
37
+    values[CHANNEL_THROTTLE] = map(evt.Z, 0, 0xFF, 1000, 2000);
38
+    values[CHANNEL_PITCH] = map(evt.Y, 0, 0x7FF, 1000, 2000);
39
+    values[CHANNEL_ROLL] = map(evt.X, 0, 0x7FF, 1000, 2000);
40
+    values[CHANNEL_YAW] = map(evt.Rz, 0, 0x3FF, 1000, 2000);
41
+    values[CHANNEL_AUX1] = map(evt.Ry, 0, 0xFF, 1000, 2000);
42
+    values[CHANNEL_AUX2] = map(evt.Slider, 0, 0xFF, 1000, 2000);
42
 
43
 
43
     cppmCopy(values);
44
     cppmCopy(values);
44
 }
45
 }

+ 44
- 1
x52.cpp View File

16
 
16
 
17
 #define TIME_24H_FORMAT
17
 #define TIME_24H_FORMAT
18
 
18
 
19
-X52::X52(USB* u, HID* h) : usb(u), hid(h) { }
19
+X52::X52(USB* u, HID* h) : usb(u), hid(h), ready(0) { }
20
+
21
+void X52::initialize() {
22
+    ready = 0;
23
+    
24
+    if ((!usb) || (!hid)) {
25
+        return;
26
+    }
27
+
28
+    uint8_t buf[sizeof (USB_DEVICE_DESCRIPTOR)];
29
+    USB_DEVICE_DESCRIPTOR* udd = reinterpret_cast<USB_DEVICE_DESCRIPTOR*>(buf);
30
+    uint8_t ret = usb->getDevDescr(hid->GetAddress(), 0, sizeof(USB_DEVICE_DESCRIPTOR), (uint8_t*)buf);
31
+    if (ret) {
32
+#ifdef DEBUG_OUTPUT
33
+        Serial.print("Error getting descriptor: ");
34
+        Serial.println(ret, DEC);
35
+#endif
36
+    }
37
+
38
+    uint16_t vid = udd->idVendor;
39
+    uint16_t pid = udd->idProduct;
40
+
41
+#ifdef DEBUG_OUTPUT
42
+        Serial.print("VID: ");
43
+        Serial.print(vid, DEC);
44
+        Serial.print(" PID: ");
45
+        Serial.println(pid, DEC);
46
+#endif
47
+
48
+    if ((vid == 1699) && (pid == 597)) {
49
+        ready = 1;
50
+    } else {
51
+#ifdef DEBUG_OUTPUT
52
+        Serial.println("No valid VID/PID found!");
53
+#endif
54
+    }
55
+}
20
 
56
 
21
 void X52::setTime(uint8_t h, uint8_t m) {
57
 void X52::setTime(uint8_t h, uint8_t m) {
22
     uint8_t ret = sendCommand(X52_TIME_CLOCK1, m | ((h & 0x7F) << 8)
58
     uint8_t ret = sendCommand(X52_TIME_CLOCK1, m | ((h & 0x7F) << 8)
141
 }
177
 }
142
 
178
 
143
 uint8_t X52::sendCommand(uint16_t command, uint16_t val) {
179
 uint8_t X52::sendCommand(uint16_t command, uint16_t val) {
180
+    if (!ready) {
181
+#ifdef DEBUG_OUTPUT
182
+        Serial.println("Invalid state!");
183
+#endif
184
+        return 23;
185
+    }
186
+    
144
     if ((!usb) || (!hid)) {
187
     if ((!usb) || (!hid)) {
145
 #ifdef DEBUG_OUTPUT
188
 #ifdef DEBUG_OUTPUT
146
         Serial.println("Invalid objects!");
189
         Serial.println("Invalid objects!");

+ 6
- 0
x52.h View File

40
     X52(USB* u, HID* h);
40
     X52(USB* u, HID* h);
41
 
41
 
42
     /*
42
     /*
43
+     * Check if a valid PID/VID device has been found.
44
+     */
45
+    void initialize();
46
+
47
+    /*
43
      * Set brightness of LEDs and MFD backlight.
48
      * Set brightness of LEDs and MFD backlight.
44
      * Three states, 0=off, 1=dim, 2=on.
49
      * Three states, 0=off, 1=dim, 2=on.
45
      */
50
      */
80
     
85
     
81
     USB* usb;
86
     USB* usb;
82
     HID* hid;
87
     HID* hid;
88
+    uint8_t ready;
83
 };
89
 };
84
 
90
 
85
 #endif // __X52_H__
91
 #endif // __X52_H__

Loading…
Cancel
Save