Browse Source

Added CPPM timer implementation.

Thomas Buck 8 years ago
parent
commit
251695a17f
5 changed files with 148 additions and 1 deletions
  1. 19
    0
      include/cppm.h
  2. 1
    0
      makefile
  3. 123
    0
      src/cppm.c
  4. 4
    1
      src/main.c
  5. 1
    0
      src/timer.c

+ 19
- 0
include/cppm.h View File

@@ -0,0 +1,19 @@
1
+/*
2
+ * Combined-PPM signal generator
3
+ */
4
+
5
+#ifndef _CPPM_H
6
+#define _CPPM_H
7
+
8
+#include <stdint.h>
9
+
10
+#define CPPM_PORT PORTB
11
+#define CPPM_DDR DDRB
12
+#define CPPM_PIN PB5
13
+
14
+extern volatile uint16_t cppmData[8];
15
+
16
+void cppmInit(void);
17
+
18
+#endif
19
+

+ 1
- 0
makefile View File

@@ -17,6 +17,7 @@ SRC += src/timer.c
17 17
 SRC += src/spi.c
18 18
 SRC += src/cc2500.c
19 19
 SRC += src/rx.c
20
+SRC += src/cppm.c
20 21
 
21 22
 OBJ = $(addprefix $(BUILDDIR)/, $(SRC:.c=.o))
22 23
 

+ 123
- 0
src/cppm.c View File

@@ -0,0 +1,123 @@
1
+/*
2
+ * Combined-PPM signal generator
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
24
+ */
25
+
26
+#include <avr/io.h>
27
+#include <avr/interrupt.h>
28
+
29
+#include "cppm.h"
30
+
31
+#define MAX_STATES 17
32
+#define CHANNELS 8
33
+#define WHOLE_PULSE_WIDTH 20000
34
+#define PULSE_WIDTH 2000
35
+#define MAX_PULSE_WIDTH (CHANNELS * PULSE_WIDTH) // 16.000
36
+#define PULSE_LOW 100
37
+#define PULSE_LOW_SUM ((CHANNELS + 1) * PULSE_LOW) // 900
38
+#define MIN_WAIT (WHOLE_PULSE_WIDTH - MAX_PULSE_WIDTH - PULSE_LOW_SUM) // 3100
39
+#define TIME_AFTER_OVERFLOW 128
40
+#define TIME_MULTIPLIER 2
41
+
42
+volatile uint16_t cppmData[CHANNELS] = { 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500 };
43
+volatile uint16_t delaySum = 0;
44
+volatile uint8_t state = 0;
45
+volatile uint16_t triggerTimeRemaining = 0;
46
+
47
+#define NONE 0
48
+#define COMPARE_MATCH 1
49
+#define OVERFLOW 2
50
+volatile uint8_t triggerState = NONE;
51
+
52
+static void triggerIn(uint16_t us);
53
+static void nextState(void);
54
+
55
+void cppmInit(void) {
56
+    // Set pin to output mode
57
+    CPPM_DDR |= (1 << CPPM_PIN);
58
+
59
+    // Start with a low pulse
60
+    CPPM_PORT &= ~(1 << CPPM_PIN);
61
+
62
+    TCCR0B |= (1 << CS01); // Prescaler: 8
63
+    TIMSK |= (1 << TOIE0) | (1 << OCIE0A); // Enable Overflow and Compare Match Interrupt
64
+    OCR0A = 0;
65
+
66
+    state = 0;
67
+    delaySum = MIN_WAIT;
68
+    triggerIn(PULSE_LOW);
69
+}
70
+
71
+static void triggerIn(uint16_t us) {
72
+    TCNT0 = 0; // Reset Timer
73
+    if (us <= (TIME_AFTER_OVERFLOW - 1)) {
74
+        triggerState = COMPARE_MATCH;
75
+        OCR0A = us * TIME_MULTIPLIER;
76
+    } else {
77
+        triggerState = OVERFLOW;
78
+        triggerTimeRemaining = us - TIME_AFTER_OVERFLOW;
79
+    }
80
+}
81
+
82
+static void nextState(void) {
83
+    state++;
84
+    if (state > MAX_STATES) {
85
+        state = 0;
86
+        delaySum = MIN_WAIT;
87
+    }
88
+    if ((state % 2) == 0) {
89
+        // pulse pause
90
+        CPPM_PORT &= ~(1 << CPPM_PIN);
91
+        triggerIn(PULSE_LOW);
92
+    } else {
93
+        CPPM_PORT |= (1 << CPPM_PIN);
94
+        if (state <= 15) {
95
+            // normal ppm pulse
96
+            uint8_t index = state / 2;
97
+            triggerIn(cppmData[index]);
98
+            delaySum += PULSE_WIDTH - cppmData[index];
99
+        } else {
100
+            // sync pulse
101
+            triggerIn(delaySum);
102
+        }
103
+    }
104
+}
105
+
106
+ISR(TIM0_OVF_vect) {
107
+    if (triggerState == OVERFLOW) {
108
+        if (triggerTimeRemaining == 0) {
109
+            triggerState = NONE;
110
+            nextState();
111
+        } else {
112
+            triggerIn(triggerTimeRemaining);
113
+        }
114
+    }
115
+}
116
+
117
+ISR(TIM0_COMPA_vect) {
118
+    if (triggerState == COMPARE_MATCH) {
119
+        triggerState = NONE;
120
+        nextState();
121
+    }
122
+}
123
+

+ 4
- 1
src/main.c View File

@@ -7,6 +7,7 @@
7 7
 
8 8
 #include "spi.h"
9 9
 #include "timer.h"
10
+#include "cppm.h"
10 11
 #include "rx.h"
11 12
 
12 13
 void watchdogBoot(void) __attribute__((naked)) __attribute__((section(".init3")));
@@ -16,11 +17,13 @@ void watchdogBoot(void) {
16 17
 }
17 18
 
18 19
 void main(void) {
20
+    cppmInit();
19 21
     timerInit();
22
+
20 23
     sei(); // Enable interrupts (required for timer)
21
-    spiInit();
22 24
     wdt_enable(WDTO_120MS); // Trigger Watchdog after 120ms
23 25
 
26
+    spiInit();
24 27
     rxInit();
25 28
 
26 29
     for(;;) { }

+ 1
- 0
src/timer.c View File

@@ -10,6 +10,7 @@
10 10
 volatile time_t systemTime = 0;
11 11
 
12 12
 void timerInit(void) {
13
+    // Using 8bit Timer1
13 14
     TCCR1 |= (1 << CTC1); // CTC Mode
14 15
     TCCR1 |= (1 << CS12) | (1 << CS11) | (1 << CS10); // Prescaler: 64
15 16
     OCR1A = 250; // Count to 250

Loading…
Cancel
Save