Browse Source

New CPPM code. Should now be basically working.

Thomas Buck 7 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,8 +19,9 @@
19 19
 #include "x52.h"
20 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 26
 USB usb;
26 27
 USBHub hub(&usb);
@@ -53,13 +54,13 @@ void setup() {
53 54
 }
54 55
 
55 56
 void init_joystick() {
57
+    x52.initialize();
56 58
     x52.setLEDBrightness(2);
57 59
     x52.setMFDBrightness(2);
58 60
     x52.setShift(0);
59 61
     x52.setBlink(0);
60 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 66
 void loop() {
@@ -73,9 +74,12 @@ void loop() {
73 74
             init_joystick();
74 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 83
     if (Serial.available()) {
80 84
         char c = Serial.read();
81 85
         if (c == 't') {

+ 44
- 72
cppm.cpp View File

@@ -1,26 +1,9 @@
1 1
 /*
2 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 8
  * Copyright 2016 by Thomas Buck <xythobuz@xythobuz.de>
26 9
  *
@@ -28,41 +11,42 @@
28 11
  * modify it under the terms of the GNU General Public License as
29 12
  * published by the Free Software Foundation, version 2.
30 13
  */
31
-#include <TimerOne.h>
14
+#include <Arduino.h>
32 15
 #include "cppm.h"
33 16
 
34 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 30
 void cppmInit(void) {
56 31
 #ifdef DEBUG_OUTPUT
57 32
     Serial.println("Initializing Timer...");
58 33
 #endif
59 34
 
35
+    for (uint8_t i = 0; i < CHANNELS; i++) {
36
+        cppmData[i] = CHANNEL_DEFAULT_VALUE;
37
+    }
38
+
60 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 52
 void cppmCopy(uint16_t *data) {
@@ -77,38 +61,26 @@ void cppmCopy(uint16_t *data) {
77 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 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 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 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,7 +12,7 @@
12 12
 
13 13
 #include <stdint.h>
14 14
 
15
-#define CPPM_OUTPUT_PIN 13
15
+#define CPPM_OUTPUT_PIN 4
16 16
 
17 17
 void cppmInit(void);
18 18
 void cppmCopy(uint16_t *data);

+ 9
- 8
events_cppm.cpp View File

@@ -10,6 +10,7 @@
10 10
  * published by the Free Software Foundation, version 2.
11 11
  */
12 12
 
13
+#include <Arduino.h>
13 14
 #include "data.h"
14 15
 #include "cppm.h"
15 16
 #include "events.h"
@@ -26,19 +27,19 @@ JoystickEventsCPPM::JoystickEventsCPPM(JoystickEvents* client) : JoystickEvents(
26 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 33
     cppmCopy(values);
33 34
 }
34 35
 
35 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 44
     cppmCopy(values);
44 45
 }

+ 44
- 1
x52.cpp View File

@@ -16,7 +16,43 @@
16 16
 
17 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 57
 void X52::setTime(uint8_t h, uint8_t m) {
22 58
     uint8_t ret = sendCommand(X52_TIME_CLOCK1, m | ((h & 0x7F) << 8)
@@ -141,6 +177,13 @@ void X52::setMFDText(uint8_t line, const char* text) {
141 177
 }
142 178
 
143 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 187
     if ((!usb) || (!hid)) {
145 188
 #ifdef DEBUG_OUTPUT
146 189
         Serial.println("Invalid objects!");

+ 6
- 0
x52.h View File

@@ -40,6 +40,11 @@ class X52 {
40 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 48
      * Set brightness of LEDs and MFD backlight.
44 49
      * Three states, 0=off, 1=dim, 2=on.
45 50
      */
@@ -80,6 +85,7 @@ class X52 {
80 85
     
81 86
     USB* usb;
82 87
     HID* hid;
88
+    uint8_t ready;
83 89
 };
84 90
 
85 91
 #endif // __X52_H__

Loading…
Cancel
Save