28
28
#include " math.h"
29
29
#include " FspTimer.h"
30
30
31
+ // uncomment to print servo Debug information
32
+ // #define SERVO_PRINT_DEBUG_INFO
33
+
31
34
#define SERVO_MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER)
32
35
#define SERVO_INVALID_INDEX (255 )
33
36
// Lower the timer ticks for finer resolution.
34
37
#define SERVO_TIMER_TICK_US (100 )
35
38
#define SERVO_US_PER_CYCLE (20000 )
36
39
#define SERVO_IO_PORT_ADDR (pn ) &((R_PORT0 + ((uint32_t ) (R_PORT1 - R_PORT0) * (pn)))->PCNTR3)
37
40
41
+ #define MIN_CYCLE_OFF_US 50
42
+
38
43
// Internal Servo sturct to keep track of RA configuration.
39
44
typedef struct {
40
45
// Servo period in microseconds.
@@ -43,8 +48,8 @@ typedef struct {
43
48
// Servo class are not wide enough for the pulse width.
44
49
uint32_t period_min;
45
50
uint32_t period_max;
46
- // Period period_count in microseconds .
47
- uint32_t period_count ;
51
+ // Period period_count in timer ticks .
52
+ uint32_t period_ticks ;
48
53
// Internal FSP GPIO port/pin control bits.
49
54
volatile uint32_t *io_port;
50
55
uint32_t io_mask;
@@ -58,25 +63,66 @@ static FspTimer servo_timer;
58
63
static bool servo_timer_started = false ;
59
64
void servo_timer_callback (timer_callback_args_t *args);
60
65
66
+ // GPT pointer.
67
+ static R_GPT0_Type *s_pgpt0 = nullptr ;
68
+ static uint32_t servo_ticks_per_cycle = 0 ;
69
+ static uint32_t min_servo_cycle_low = 0 ;
70
+ static uint32_t active_servos_mask = 0 ;
71
+ static uint32_t active_servos_mask_refresh = 0 ;
72
+
73
+
74
+ static uint32_t usToticks (uint32_t time_us) {
75
+ return (float (servo_ticks_per_cycle) / float (SERVO_US_PER_CYCLE)) * time_us;
76
+ }
77
+
78
+
79
+
80
+
61
81
static int servo_timer_config (uint32_t period_us)
62
82
{
63
83
static bool configured = false ;
64
84
if (configured == false ) {
65
- // Configure and enable the servo timer.
85
+ // Configure and enable the servo timer, for full 20ms
66
86
uint8_t type = 0 ;
67
87
int8_t channel = FspTimer::get_available_timer (type);
68
88
if (channel != -1 ) {
89
+ // lets initially configure the servo to 50ms
69
90
servo_timer.begin (TIMER_MODE_PERIODIC, type, channel,
70
91
1000000 .0f /period_us, 50 .0f , servo_timer_callback, nullptr );
92
+
93
+ // First pass assume GPT timer
94
+ s_pgpt0 = (R_GPT0_Type *)((uint32_t )R_GPT0 + ((uint32_t )R_GPT1 - (uint32_t )R_GPT0) * channel);
95
+ // turn off GTPR Buffer
96
+ s_pgpt0->GTBER_b .PR = 0 ;
97
+ s_pgpt0->GTBER_b .BD1 = 1 ;
98
+
71
99
servo_timer.setup_overflow_irq ();
72
100
servo_timer.open ();
73
101
servo_timer.stop ();
102
+
103
+ // Now lets see what the period;
104
+ servo_ticks_per_cycle = servo_timer.get_period_raw ();
105
+ min_servo_cycle_low = usToticks (MIN_CYCLE_OFF_US);
106
+ #ifdef SERVO_PRINT_DEBUG_INFO
107
+ Serial.print (" Period:" );
108
+ Serial.println (servo_ticks_per_cycle, DEC);
109
+ uint32_t ticks_544 = usToticks (544 );
110
+ uint32_t ticks_2400 = usToticks (2400 );
111
+ Serial.print (" Min 544(ticks): " );
112
+ Serial.print (ticks_544);
113
+ Serial.print (" Max 2400: " );
114
+ Serial.print (ticks_2400);
115
+ Serial.print (" per degree: " );
116
+ Serial.println ((float )(ticks_2400 - ticks_544) / 180 .0f , 2 );
117
+ #endif
118
+
74
119
configured = true ;
75
120
}
76
121
}
77
122
return configured ? 0 : -1 ;
78
123
}
79
124
125
+
80
126
static int servo_timer_start ()
81
127
{
82
128
// Start the timer if it's not started
@@ -99,22 +145,43 @@ static int servo_timer_stop()
99
145
return 0 ;
100
146
}
101
147
148
+ inline static void updateClockPeriod (uint32_t period) {
149
+ if (s_pgpt0) s_pgpt0->GTPR = period;
150
+ }
151
+
152
+
102
153
void servo_timer_callback (timer_callback_args_t *args)
103
154
{
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
- }
155
+ (void )args; // remove warning
156
+ static uint8_t channel=SERVO_MAX_SERVOS;
157
+ static uint8_t channel_pin_set_high=0xff ;
158
+ static uint32_t ticks_accum=0 ;
159
+
160
+ // See if we need to set a servo back low
161
+ if (channel_pin_set_high != 0xff ) {
162
+ *ra_servos[channel_pin_set_high].io_port = (uint32_t )(ra_servos[channel_pin_set_high].io_mask << 16 );
163
+ }
164
+
165
+ // Find the next servo to set high
166
+ while (active_servos_mask_refresh) {
167
+ channel = __builtin_ctz (active_servos_mask_refresh);
168
+ active_servos_mask_refresh &= ~(1 << channel);
169
+ if (ra_servos[channel].period_us ) {
170
+ *ra_servos[channel].io_port = (uint32_t )ra_servos[channel].io_mask ;
171
+ updateClockPeriod (ra_servos[channel].period_ticks );
172
+ channel_pin_set_high = channel;
173
+ ticks_accum += ra_servos[channel_pin_set_high].period_ticks ;
174
+ return ;
116
175
}
117
176
}
177
+
178
+ // Got to hear we finished processing all servos, now delay to start of next pass.
179
+ ticks_accum += min_servo_cycle_low;
180
+ uint32_t time_to_next_cycle = (servo_ticks_per_cycle > ticks_accum)? servo_ticks_per_cycle - ticks_accum : min_servo_cycle_low;
181
+ ticks_accum = 0 ;
182
+ updateClockPeriod (time_to_next_cycle);
183
+ channel_pin_set_high = 0xff ;
184
+ active_servos_mask_refresh = active_servos_mask;
118
185
}
119
186
120
187
Servo::Servo ()
@@ -139,6 +206,11 @@ uint8_t Servo::attach(int pin, int min, int max)
139
206
return 0 ;
140
207
}
141
208
209
+ // Configure and the timer
210
+ if (servo_timer_config (SERVO_US_PER_CYCLE) != 0 ) {
211
+ return 0 ;
212
+ }
213
+
142
214
// Try to find a free servo slot.
143
215
ra_servo_t *servo = NULL ;
144
216
bsp_io_port_pin_t io_pin = g_pin_cfg[pin].pin ;
@@ -151,6 +223,7 @@ uint8_t Servo::attach(int pin, int min, int max)
151
223
servo->period_max = max;
152
224
servo->io_mask = (1U << (io_pin & 0xFF ));
153
225
servo->io_port = SERVO_IO_PORT_ADDR (((io_pin >> 8U ) & 0xFF ));
226
+ active_servos_mask |= (1 << i); // update mask of servos that are active.
154
227
writeMicroseconds (DEFAULT_PULSE_WIDTH);
155
228
break ;
156
229
}
@@ -164,11 +237,11 @@ uint8_t Servo::attach(int pin, int min, int max)
164
237
R_IOPORT_PinCfg (&g_ioport_ctrl, io_pin,
165
238
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH);
166
239
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 ) {
240
+ // start the timer if it's not started.
241
+ if (servo_timer_start () != 0 ) {
170
242
return 0 ;
171
243
}
244
+
172
245
return 1 ;
173
246
}
174
247
@@ -178,10 +251,12 @@ void Servo::detach()
178
251
ra_servo_t *servo = &ra_servos[servoIndex];
179
252
servo_timer_stop ();
180
253
servo->period_us = 0 ;
254
+ active_servos_mask &= ~(1 << servoIndex); // update mask of servos that are active.
255
+ servoIndex = SERVO_INVALID_INDEX;
181
256
if (--n_servos) {
182
257
servo_timer_start ();
183
258
}
184
- servoIndex = SERVO_INVALID_INDEX;
259
+
185
260
}
186
261
}
187
262
@@ -207,8 +282,9 @@ void Servo::writeMicroseconds(int us)
207
282
{
208
283
if (servoIndex != SERVO_INVALID_INDEX) {
209
284
ra_servo_t *servo = &ra_servos[servoIndex];
210
- servo->period_count = 0 ;
211
- servo->period_us = constrain (us, servo->period_min , servo->period_max );
285
+ // servo->period_count = 0;
286
+ servo->period_us = constrain (us, (int )servo->period_min , (int )servo->period_max );
287
+ servo->period_ticks = usToticks (servo->period_us );
212
288
}
213
289
}
214
290
0 commit comments