-
Notifications
You must be signed in to change notification settings - Fork 0
/
servo.c
168 lines (121 loc) · 2.95 KB
/
servo.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <stdint.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
#include "setup.h"
#include "servo.h"
extern config_t config;
static uint16_t buffer_OCR1A, buffer_OCR1B;
ISR( TIMER1_OVF_vect ) {
OCR1A = buffer_OCR1A;
OCR1B = buffer_OCR1B;
}
void servo_init( void ) {
servo_enable();
buffer_OCR1A = config.data.yMin + (config.data.yMax - config.data.yMin) / 2; // 1.5 ms is default
buffer_OCR1B = config.data.pMin + (config.data.pMax - config.data.pMin) / 2; // 1.5 ms is default
}
void servo_calibrateLowerLimit( void ) {
// make sure upper and lower limit are not inverted
if( OCR1A > config.data.yMax ) {
config.data.yMin = config.data.pMax;
}
else {
config.data.yMin = OCR1A;
}
if( OCR1B > config.data.pMax ) {
config.data.pMin = config.data.pMax;
}
else {
config.data.pMin = OCR1B;
}
}
void servo_calibrateUpperLimit( void ) {
// make sure upper and lower limit are not inverted
if( buffer_OCR1A < config.data.yMin ) {
config.data.yMax = config.data.yMin;
}
else {
config.data.yMax = OCR1A;
}
if( buffer_OCR1B < config.data.pMin ) {
config.data.pMax = config.data.pMin;
}
else {
config.data.pMax = OCR1B;
}
}
void servo_setValue( uint8_t servoId, uint8_t value ) {
uint16_t range;
switch( servoId ) {
case ePitch: {
range = config.data.pMax - config.data.pMin;
buffer_OCR1B = config.data.pMin + (((uint32_t)range * (uint32_t)value) / 0xff);
break;
}
case eYaw: {
range = config.data.yMax - config.data.yMin;
buffer_OCR1A = config.data.yMin + (((uint32_t)range * (uint32_t)value) / 0xff);
break;
}
default: {
break;
}
}
}
void servo_setRawValue( uint8_t servoId, uint16_t value ) {
switch( servoId ) {
case ePitch: {
buffer_OCR1B = value;
break;
}
case eYaw: {
buffer_OCR1A = value;
break;
}
default: {
break;
}
}
}
uint16_t servo_getRawValue( uint8_t servoId ) {
uint16_t tmp = 0xFFFF;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
switch( servoId ) {
case ePitch: {
tmp = OCR1B;
break;
}
case eYaw: {
tmp = OCR1A;
break;
}
default: {
break;
}
}
}
return tmp;
}
void servo_enable( void ) {
DDRD |= (1<<PD2); // OCR1A
DDRC |= (1<<PC1); // OCR1B
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
TCCR1C = (1<<FOC1A) | (1<<FOC1B); // force output
TIMSK1 = (1<<TOIE1);
// pwm output for servos (16 bit fast PWM)
TCCR1A = (1<<COM1A1); // pin goes high on reset and low on compare match
TCCR1A |= (1<<COM1B0)|(1<<COM1B1); // pin goes low on reset and high on compare match
TCCR1A |= (1<<WGM11); // 16 bit fast PWM
TCCR1B = (1<<WGM12)|(1<<WGM13); // 16 bit fast PWM (continued) (ICR1=TOP)
TCCR1B |= (1<<CS11); // clockdivider F_CPU / 8
ICR1 = 40000; // 20 ms duty cycle
}
}
void servo_disable( void ) {
TCCR1B &= ~( (1<<CS12) | (1<<CS11) | (1<<CS10) ); // deactivate PWM clock
// float both PWM pins
DDRD &= ~(1<<PD2);
PORTD &= ~(1<<PD2);
DDRC &= ~(1<<PC1);
PORTC &= ~(1<<PC1);
}