31
31
#define SERVO_MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER)
32
32
#define SERVO_INVALID_INDEX (255 )
33
33
// Lower the timer ticks for finer resolution.
34
- #define SERVO_TIMER_TICK_US (100 )
35
34
#define SERVO_US_PER_CYCLE (20000 )
36
35
#define SERVO_IO_PORT_ADDR (pn ) &((R_PORT0 + ((uint32_t ) (R_PORT1 - R_PORT0) * (pn)))->PCNTR3)
36
+ #define SERVO_MIN_CYCLE_OFF_US 50
37
37
38
38
// Internal Servo struct to keep track of RA configuration.
39
39
typedef struct {
@@ -43,8 +43,8 @@ typedef struct {
43
43
// Servo class are not wide enough for the pulse width.
44
44
uint32_t period_min;
45
45
uint32_t period_max;
46
- // Period period_count in microseconds .
47
- uint32_t period_count ;
46
+ // Period period_count in timer ticks .
47
+ uint32_t period_ticks ;
48
48
// Internal FSP GPIO port/pin control bits.
49
49
volatile uint32_t *io_port;
50
50
uint32_t io_mask;
@@ -58,6 +58,16 @@ static FspTimer servo_timer;
58
58
static bool servo_timer_started = false ;
59
59
void servo_timer_callback (timer_callback_args_t *args);
60
60
61
+ static uint32_t servo_ticks_per_cycle = 0 ;
62
+ static uint32_t min_servo_cycle_low = 0 ;
63
+ static uint32_t active_servos_mask = 0 ;
64
+ static uint32_t active_servos_mask_refresh = 0 ;
65
+
66
+
67
+ static uint32_t us_to_ticks (uint32_t time_us) {
68
+ return ((float ) servo_ticks_per_cycle / (float ) SERVO_US_PER_CYCLE) * time_us;
69
+ }
70
+
61
71
static int servo_timer_config (uint32_t period_us)
62
72
{
63
73
static bool configured = false ;
@@ -68,9 +78,14 @@ static int servo_timer_config(uint32_t period_us)
68
78
if (channel != -1 ) {
69
79
servo_timer.begin (TIMER_MODE_PERIODIC, type, channel,
70
80
1000000 .0f /period_us, 50 .0f , servo_timer_callback, nullptr );
71
- servo_timer.setup_overflow_irq ();
81
+ servo_timer.set_period_buffer (false ); // disable period buffering
82
+ servo_timer.setup_overflow_irq (10 );
72
83
servo_timer.open ();
73
84
servo_timer.stop ();
85
+ // Read the timer's period count.
86
+ servo_ticks_per_cycle = servo_timer.get_period_raw ();
87
+ min_servo_cycle_low = us_to_ticks (SERVO_MIN_CYCLE_OFF_US);
88
+
74
89
configured = true ;
75
90
}
76
91
}
@@ -99,22 +114,47 @@ static int servo_timer_stop()
99
114
return 0 ;
100
115
}
101
116
117
+ inline static void servo_timer_set_period (uint32_t period) {
118
+ servo_timer.set_period (period);
119
+ }
120
+
102
121
void servo_timer_callback (timer_callback_args_t *args)
103
122
{
104
- for (size_t i=0 ; i<SERVO_MAX_SERVOS; i++) {
105
- ra_servo_t *servo = &ra_servos[i];
106
- if (servo->period_us ) {
107
- servo->period_count += SERVO_TIMER_TICK_US;
108
- if (servo->period_count <= servo->period_us ) {
109
- *servo->io_port = (uint32_t ) servo->io_mask ;
110
- } else {
111
- *servo->io_port = (uint32_t ) (servo->io_mask << 16 );
112
- }
113
- if (servo->period_count == SERVO_US_PER_CYCLE) {
114
- servo->period_count = 0 ;
115
- }
123
+ (void )args; // remove warning
124
+ static uint8_t channel = SERVO_MAX_SERVOS;
125
+ static uint8_t channel_pin_set_high = 0xff ;
126
+ static uint32_t ticks_accum = 0 ;
127
+
128
+ // See if we need to set a servo back low
129
+ if (channel_pin_set_high != 0xff ) {
130
+ *ra_servos[channel_pin_set_high].io_port = ra_servos[channel_pin_set_high].io_mask << 16 ;
131
+ }
132
+
133
+ // Find the next servo to set high
134
+ while (active_servos_mask_refresh) {
135
+ channel = __builtin_ctz (active_servos_mask_refresh);
136
+ if (ra_servos[channel].period_us ) {
137
+ *ra_servos[channel].io_port = ra_servos[channel].io_mask ;
138
+ servo_timer_set_period (ra_servos[channel].period_ticks );
139
+ channel_pin_set_high = channel;
140
+ ticks_accum += ra_servos[channel].period_ticks ;
141
+ active_servos_mask_refresh &= ~(1 << channel);
142
+ return ;
116
143
}
144
+ active_servos_mask_refresh &= ~(1 << channel);
145
+ }
146
+ // Finished processing all servos, now delay to start of next pass.
147
+ ticks_accum += min_servo_cycle_low;
148
+ uint32_t time_to_next_cycle;
149
+ if (servo_ticks_per_cycle > ticks_accum) {
150
+ time_to_next_cycle = servo_ticks_per_cycle - ticks_accum;
151
+ } else {
152
+ time_to_next_cycle = min_servo_cycle_low;
117
153
}
154
+ ticks_accum = 0 ;
155
+ servo_timer_set_period (time_to_next_cycle);
156
+ channel_pin_set_high = 0xff ;
157
+ active_servos_mask_refresh = active_servos_mask;
118
158
}
119
159
120
160
Servo::Servo ()
@@ -139,6 +179,11 @@ uint8_t Servo::attach(int pin, int min, int max)
139
179
return 0 ;
140
180
}
141
181
182
+ // Configure the servo timer.
183
+ if (servo_timer_config (SERVO_US_PER_CYCLE) != 0 ) {
184
+ return 0 ;
185
+ }
186
+
142
187
// Try to find a free servo slot.
143
188
ra_servo_t *servo = NULL ;
144
189
bsp_io_port_pin_t io_pin = g_pin_cfg[pin].pin ;
@@ -151,6 +196,7 @@ uint8_t Servo::attach(int pin, int min, int max)
151
196
servo->period_max = max;
152
197
servo->io_mask = (1U << (io_pin & 0xFF ));
153
198
servo->io_port = SERVO_IO_PORT_ADDR (((io_pin >> 8U ) & 0xFF ));
199
+ active_servos_mask |= (1 << i); // update mask of servos that are active.
154
200
writeMicroseconds (DEFAULT_PULSE_WIDTH);
155
201
break ;
156
202
}
@@ -164,9 +210,8 @@ uint8_t Servo::attach(int pin, int min, int max)
164
210
R_IOPORT_PinCfg (&g_ioport_ctrl, io_pin,
165
211
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH);
166
212
167
- // Configure and start the timer if it's not started.
168
- if (servo_timer_config (SERVO_TIMER_TICK_US) != 0 ||
169
- servo_timer_start () != 0 ) {
213
+ // Start the timer if it's not started.
214
+ if (servo_timer_start () != 0 ) {
170
215
return 0 ;
171
216
}
172
217
return 1 ;
@@ -178,10 +223,12 @@ void Servo::detach()
178
223
ra_servo_t *servo = &ra_servos[servoIndex];
179
224
servo_timer_stop ();
180
225
servo->period_us = 0 ;
226
+ active_servos_mask &= ~(1 << servoIndex); // update mask of servos that are active.
227
+ servoIndex = SERVO_INVALID_INDEX;
181
228
if (--n_servos) {
182
229
servo_timer_start ();
183
230
}
184
- servoIndex = SERVO_INVALID_INDEX;
231
+
185
232
}
186
233
}
187
234
@@ -207,8 +254,8 @@ void Servo::writeMicroseconds(int us)
207
254
{
208
255
if (servoIndex != SERVO_INVALID_INDEX) {
209
256
ra_servo_t *servo = &ra_servos[servoIndex];
210
- servo->period_count = 0 ;
211
257
servo->period_us = constrain (us, servo->period_min , servo->period_max );
258
+ servo->period_ticks = us_to_ticks (servo->period_us );
212
259
}
213
260
}
214
261
0 commit comments