Skip to content

Commit 402a461

Browse files
Rework stm32l4_servo.c to use the EVENT_PERIOD to sequence throu the timeout
1 parent f4df323 commit 402a461

File tree

9 files changed

+93
-112
lines changed

9 files changed

+93
-112
lines changed

libraries/Servo/src/Servo.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ uint8_t Servo::attach(int pin, int min, int max)
7979
pinMode(pin, OUTPUT);
8080

8181
ServoTable.slot[this->servoIndex].pin = g_APinDescription[pin].pin;
82-
82+
8383
this->min = min;
8484
this->max = max;
8585

@@ -138,12 +138,12 @@ void Servo::writeMicroseconds(int width)
138138
return;
139139
}
140140

141-
if (width < SERVO_PULSE_MIN) {
142-
width = SERVO_PULSE_MIN;
141+
if (width < this->min) {
142+
width = this->min;
143143
}
144144

145-
if (width > SERVO_PULSE_MAX) {
146-
width = SERVO_PULSE_MAX;
145+
if (width > this->max) {
146+
width = this->max;
147147
}
148148

149149
ServoTable.slot[this->servoIndex].width = width;

libraries/Servo/src/Servo.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@
6161

6262
#define Servo_VERSION 2 // software version of this library
6363

64-
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
65-
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
64+
#define MIN_PULSE_WIDTH 1000 // the shortest pulse sent to a servo
65+
#define MAX_PULSE_WIDTH 2000 // the longest pulse sent to a servo
6666
#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
6767
#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
6868

69-
// NOTE: to maintain a strict refresh interval the user needs to not exceed 2000us pulse width
70-
#define MAX_SERVOS 9
69+
// NOTE: to maintain a strict refresh interval the user needs to not exceed 2250us pulse width
70+
#define MAX_SERVOS 8
7171

7272
class Servo
7373
{

system/STM32L4xx/Include/stm32l4_servo.h

+8-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016 Thomas Roell. All rights reserved.
2+
* Copyright (c) 2016-2017 Thomas Roell. All rights reserved.
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a copy
55
* of this software and associated documentation files (the "Software"), to
@@ -40,7 +40,6 @@
4040
extern "C" {
4141
#endif
4242

43-
#define SERVO_EVENT_UPDATE 0x40000000
4443
#define SERVO_EVENT_SYNC 0x80000000
4544

4645
typedef void (*stm32l4_servo_callback_t)(void *context, uint32_t events);
@@ -51,14 +50,11 @@ typedef void (*stm32l4_servo_callback_t)(void *context, uint32_t events);
5150
#define SERVO_STATE_READY 3
5251
#define SERVO_STATE_ACTIVE 4
5352

54-
#define SERVO_SLOT_COUNT 9
53+
#define SERVO_SLOT_COUNT 10
5554

56-
#define SERVO_SYNC_MARGIN 50 /* sync needs to be at least 50us after the last pulse */
57-
#define SERVO_SYNC_WIDTH 1950 /* last slot is 2ms, hence the default sync width is 1950us */
58-
#define SERVO_FRAME_WIDTH 20000 /* the default RC servo frame is 10 slots or 20000us */
59-
#define SERVO_PULSE_THRESHOLD 500 /* below a pulse is deemed illegal */
60-
#define SERVO_PULSE_MIN 1000
61-
#define SERVO_PULSE_MAX 2000
55+
#define SERVO_SYNC_WIDTH 100 /* sync needs to be at least 100us after the last pulse */
56+
#define SERVO_FRAME_WIDTH 20000 /* the default RC servo frame is 20000us */
57+
#define SERVO_PULSE_WIDTH 100 /* below a pulse is deemed illegal */
6258

6359
typedef struct _stm32l4_servo_table_t {
6460
uint32_t entries;
@@ -69,21 +65,19 @@ typedef struct _stm32l4_servo_table_t {
6965
} stm32l4_servo_table_t;
7066

7167
typedef struct _stm32l4_servo_schedule_t {
72-
uint16_t period;
73-
uint16_t offset;
74-
uint32_t entries;
68+
uint16_t sync;
69+
uint16_t entries;
7570
struct {
7671
GPIO_TypeDef *GPIO;
7772
uint16_t mask;
78-
uint16_t offset;
73+
uint16_t width;
7974
} slot[SERVO_SLOT_COUNT];
8075
} stm32l4_servo_schedule_t;
8176

8277
typedef struct _stm32l4_servo_t {
8378
volatile uint8_t state;
8479
uint8_t index;
8580
uint16_t prescaler;
86-
uint16_t period;
8781
stm32l4_timer_t timer;
8882
stm32l4_servo_callback_t callback;
8983
void *context;

system/STM32L4xx/Include/stm32l4_timer.h

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ extern bool stm32l4_timer_notify(stm32l4_timer_t *timer, stm32l4_timer_callb
145145
extern bool stm32l4_timer_start(stm32l4_timer_t *timer, bool oneshot);
146146
extern bool stm32l4_timer_stop(stm32l4_timer_t *timer);
147147
extern uint32_t stm32l4_timer_count(stm32l4_timer_t *timer);
148+
extern bool stm32l4_timer_period(stm32l4_timer_t *timer, uint32_t period, bool offset);
148149
extern bool stm32l4_timer_channel(stm32l4_timer_t *timer, unsigned int channel, uint32_t compare, uint32_t control);
149150
extern bool stm32l4_timer_compare(stm32l4_timer_t *timer, unsigned int channel, uint32_t compare);
150151
extern uint32_t stm32l4_timer_capture(stm32l4_timer_t *timer, unsigned int channel);

system/STM32L4xx/Lib/libstm32l432.a

734 Bytes
Binary file not shown.

system/STM32L4xx/Lib/libstm32l433.a

734 Bytes
Binary file not shown.

system/STM32L4xx/Lib/libstm32l476.a

728 Bytes
Binary file not shown.

system/STM32L4xx/Source/stm32l4_servo.c

+47-89
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016 Thomas Roell. All rights reserved.
2+
* Copyright (c) 2016-2017 Thomas Roell. All rights reserved.
33
*
44
* Permission is hereby granted, free of charge, to any person obtaining a copy
55
* of this software and associated documentation files (the "Software"), to
@@ -42,96 +42,62 @@ static void stm32l4_servo_event_callback(void *context, uint32_t events)
4242
stm32l4_servo_schedule_t *active, *pending;
4343
unsigned int index;
4444

45-
if (events & TIMER_EVENT_PERIOD)
46-
{
47-
pending = servo->pending;
48-
servo->pending = NULL;
49-
50-
if (pending)
51-
{
52-
servo->active = pending;
53-
}
54-
55-
active = servo->active;
45+
index = servo->index;
46+
active = servo->active;
5647

57-
if (active->entries != 0)
58-
{
59-
if (servo->period == active->period)
60-
{
61-
active->slot[0].GPIO->BSRR = active->slot[0].mask;
48+
if (index != active->entries)
49+
{
50+
active->slot[index].GPIO->BRR = active->slot[index].mask;
6251

63-
stm32l4_timer_compare(&servo->timer, TIMER_CHANNEL_1, active->slot[0].offset);
64-
}
65-
else
66-
{
67-
servo->period = active->period;
52+
index++;
6853

69-
stm32l4_timer_stop(&servo->timer);
70-
stm32l4_timer_configure(&servo->timer, servo->prescaler -1, servo->period -1, 0);
71-
stm32l4_timer_channel(&servo->timer, TIMER_CHANNEL_1, active->slot[0].offset, TIMER_CONTROL_COMPARE_TIMING);
72-
stm32l4_timer_start(&servo->timer, false);
73-
74-
active->slot[0].GPIO->BSRR = active->slot[0].mask;
54+
if (index != active->entries)
55+
{
56+
active->slot[index].GPIO->BSRR = active->slot[index].mask;
7557

76-
servo->state = SERVO_STATE_ACTIVE;
77-
}
58+
stm32l4_timer_period(&servo->timer, active->slot[index].width -1, true);
7859
}
7960
else
8061
{
81-
stm32l4_timer_stop(&servo->timer);
82-
83-
servo->active = NULL;
84-
85-
servo->state = SERVO_STATE_READY;
62+
stm32l4_timer_period(&servo->timer, active->sync -1, true);
8663
}
8764

88-
servo->index = 0;
89-
90-
if (pending && (servo->events & SERVO_EVENT_UPDATE))
91-
{
92-
(*servo->callback)(servo->context, SERVO_EVENT_UPDATE);
93-
}
65+
servo->index = index;
9466
}
9567
else
9668
{
97-
index = servo->index;
98-
active = servo->active;
69+
servo->index = 0;
9970

100-
if (index != active->entries)
71+
pending = servo->pending;
72+
73+
if (pending == NULL)
10174
{
102-
active->slot[index].GPIO->BRR = active->slot[index].mask;
103-
104-
index++;
75+
active->slot[0].GPIO->BSRR = active->slot[0].mask;
10576

106-
if (index != active->entries)
77+
stm32l4_timer_period(&servo->timer, active->slot[0].width -1, true);
78+
}
79+
else
80+
{
81+
if (pending->entries)
10782
{
108-
active->slot[index].GPIO->BSRR = active->slot[index].mask;
83+
pending->slot[0].GPIO->BSRR = pending->slot[0].mask;
10984

110-
stm32l4_timer_compare(&servo->timer, TIMER_CHANNEL_1, active->slot[index].offset);
85+
stm32l4_timer_period(&servo->timer, pending->slot[0].width -1, true);
11186
}
11287
else
11388
{
114-
if (active->offset)
115-
{
116-
stm32l4_timer_compare(&servo->timer, TIMER_CHANNEL_1, active->offset);
117-
}
118-
else
119-
{
120-
if (servo->events & SERVO_EVENT_SYNC)
121-
{
122-
(*servo->callback)(servo->context, SERVO_EVENT_SYNC);
123-
}
124-
}
89+
stm32l4_timer_stop(&servo->timer);
90+
91+
servo->state = SERVO_STATE_READY;
12592
}
12693

127-
servo->index = index;
94+
servo->pending = NULL;
95+
servo->active = pending;
12896
}
129-
else
97+
98+
if (servo->events & SERVO_EVENT_SYNC)
13099
{
131-
if (servo->events & SERVO_EVENT_SYNC)
132-
{
133-
(*servo->callback)(servo->context, SERVO_EVENT_SYNC);
134-
}
100+
(*servo->callback)(servo->context, SERVO_EVENT_SYNC);
135101
}
136102
}
137103
}
@@ -150,7 +116,6 @@ bool stm32l4_servo_create(stm32l4_servo_t *servo, unsigned int instance, unsigne
150116

151117
servo->index = 0;
152118
servo->prescaler = 0;
153-
servo->period = 0;
154119
servo->active = NULL;
155120
servo->pending = NULL;
156121

@@ -178,7 +143,7 @@ bool stm32l4_servo_enable(stm32l4_servo_t *servo, const stm32l4_servo_table_t *t
178143

179144
servo->state = SERVO_STATE_BUSY;
180145

181-
if (!stm32l4_timer_enable(&servo->timer, 0, 0, 0, stm32l4_servo_event_callback, servo, (TIMER_EVENT_PERIOD | TIMER_EVENT_CHANNEL_1)))
146+
if (!stm32l4_timer_enable(&servo->timer, 0, 0, 0, stm32l4_servo_event_callback, servo, TIMER_EVENT_PERIOD))
182147
{
183148
servo->state = SERVO_STATE_INIT;
184149

@@ -233,22 +198,20 @@ bool stm32l4_servo_configure(stm32l4_servo_t *servo, const stm32l4_servo_table_t
233198

234199
for (offset = 0, entry = 0, index = 0; entry < table->entries; entry++)
235200
{
236-
if ((table->slot[entry].pin != GPIO_PIN_NONE) && (table->slot[index].width >= SERVO_PULSE_THRESHOLD))
201+
if ((table->slot[entry].pin != GPIO_PIN_NONE) && (table->slot[index].width >= SERVO_PULSE_WIDTH))
237202
{
238-
offset += table->slot[entry].width;
239-
240203
pending->slot[index].GPIO = (GPIO_TypeDef *)(GPIOA_BASE + (GPIOB_BASE - GPIOA_BASE) * ((table->slot[entry].pin & GPIO_PIN_GROUP_MASK) >> GPIO_PIN_GROUP_SHIFT));
241204
pending->slot[index].mask = (1ul << ((table->slot[entry].pin & GPIO_PIN_INDEX_MASK) >> GPIO_PIN_INDEX_SHIFT));
242-
pending->slot[index].offset = offset;
205+
pending->slot[index].width = table->slot[entry].width;
243206

207+
offset += table->slot[entry].width;
244208
index++;
245209
}
246210
}
247211

248212
if (offset == 0)
249213
{
250-
pending->period = 0;
251-
pending->offset = 0;
214+
pending->sync = 0;
252215
pending->entries = 0;
253216
}
254217
else
@@ -257,15 +220,13 @@ bool stm32l4_servo_configure(stm32l4_servo_t *servo, const stm32l4_servo_table_t
257220

258221
servo->prescaler = stm32l4_timer_clock(&servo->timer) / 1000000;
259222

260-
if ((offset + SERVO_SYNC_MARGIN + SERVO_SYNC_WIDTH) >= SERVO_FRAME_WIDTH)
223+
if ((offset + SERVO_SYNC_WIDTH) >= SERVO_FRAME_WIDTH)
261224
{
262-
pending->period = (offset + SERVO_SYNC_MARGIN + SERVO_SYNC_WIDTH);
263-
pending->offset = SERVO_SYNC_MARGIN;
225+
pending->sync = SERVO_SYNC_WIDTH;
264226
}
265227
else
266228
{
267-
pending->period = SERVO_FRAME_WIDTH;
268-
pending->offset = SERVO_FRAME_WIDTH - SERVO_SYNC_WIDTH;
229+
pending->sync = SERVO_FRAME_WIDTH - offset;
269230
}
270231
}
271232

@@ -275,20 +236,17 @@ bool stm32l4_servo_configure(stm32l4_servo_t *servo, const stm32l4_servo_table_t
275236
}
276237
else
277238
{
278-
if (pending->period)
239+
if (pending->entries)
279240
{
280-
servo->active = pending;
281-
282-
servo->period = pending->period;
241+
servo->state = SERVO_STATE_ACTIVE;
283242

284-
stm32l4_timer_stop(&servo->timer);
285-
stm32l4_timer_configure(&servo->timer, servo->prescaler -1, servo->period -1, 0);
286-
stm32l4_timer_channel(&servo->timer, TIMER_CHANNEL_1, pending->slot[0].offset, TIMER_CONTROL_COMPARE_TIMING);
243+
servo->active = pending;
244+
servo->index = 0;
245+
246+
stm32l4_timer_configure(&servo->timer, servo->prescaler -1, pending->slot[0].width -1, 0);
287247
stm32l4_timer_start(&servo->timer, false);
288248

289249
pending->slot[0].GPIO->BSRR = pending->slot[0].mask;
290-
291-
servo->state = SERVO_STATE_ACTIVE;
292250
}
293251
}
294252

system/STM32L4xx/Source/stm32l4_timer.c

+28
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,34 @@ uint32_t stm32l4_timer_count(stm32l4_timer_t *timer)
543543
return TIM->CNT;
544544
}
545545

546+
bool stm32l4_timer_period(stm32l4_timer_t *timer, uint32_t period, bool offset)
547+
{
548+
TIM_TypeDef *TIM = timer->TIM;
549+
uint32_t primask;
550+
551+
if ((timer->state != TIMER_STATE_READY) && (timer->state != TIMER_STATE_ACTIVE))
552+
{
553+
return false;
554+
}
555+
556+
if (offset)
557+
{
558+
primask = __get_PRIMASK();
559+
560+
__disable_irq();
561+
562+
TIM->ARR = period - TIM->CNT;
563+
564+
__set_PRIMASK(primask);
565+
}
566+
else
567+
{
568+
TIM->ARR = period;
569+
}
570+
571+
return true;
572+
}
573+
546574
bool stm32l4_timer_channel(stm32l4_timer_t *timer, unsigned int channel, uint32_t compare, uint32_t control)
547575
{
548576
TIM_TypeDef *TIM = timer->TIM;

0 commit comments

Comments
 (0)