Skip to content

Commit 5d580e2

Browse files
committed
Add Renesas port.
1 parent 4b4c1bd commit 5d580e2

File tree

3 files changed

+217
-0
lines changed

3 files changed

+217
-0
lines changed

src/Servo.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@
7373
#include "megaavr/ServoTimers.h"
7474
#elif defined(ARDUINO_ARCH_MBED)
7575
#include "mbed/ServoTimers.h"
76+
#elif defined(ARDUINO_ARCH_RENESAS)
77+
#include "renesas/ServoTimers.h"
7678
#else
7779
#error "This library only supports boards with an AVR, SAM, SAMD, NRF52 or STM32F4 processor."
7880
#endif

src/renesas/Servo.cpp

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/* The MIT License (MIT)
2+
*
3+
* Copyright (c) 2022 Arduino SA
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
#if defined(ARDUINO_ARCH_RENESAS)
24+
25+
#include "Arduino.h"
26+
#include "Servo.h"
27+
#include "ServoTimers.h"
28+
#include "math.h"
29+
30+
#define SERVO_MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER)
31+
#define SERVO_INVALID_INDEX (255)
32+
// Lower the timer ticks for finer resolution.
33+
#define SERVO_TIMER_TICK_US (100)
34+
#define SERVO_US_PER_CYCLE (20000)
35+
#define SERVO_IO_PORT_ADDR(pn) &((R_PORT0 + ((uint32_t) (R_PORT1 - R_PORT0) * (pn)))->PCNTR3)
36+
37+
// Internal Servo sturct to keep track of RA configuration.
38+
typedef struct {
39+
// Servo period in microseconds.
40+
uint32_t period_us;
41+
// Store min/max pulse width here, because min/max in
42+
// Servo class are not wide enough for the pulse width.
43+
uint32_t period_min;
44+
uint32_t period_max;
45+
// Period period_count in microseconds.
46+
uint32_t period_count;
47+
// Internal FSP GPIO port/pin control bits.
48+
volatile uint32_t *io_port;
49+
uint32_t io_mask;
50+
} ra_servo_t;
51+
52+
// Keep track of the total number of servos attached.
53+
static size_t n_servos=0;
54+
static ra_servo_t ra_servos[SERVO_MAX_SERVOS];
55+
static bool servo_timer_started = false;
56+
57+
static int servo_timer_config(uint32_t period_us)
58+
{
59+
static bool configured = false;
60+
61+
if (configured == false) {
62+
// Configure and enable the servo timer.
63+
uint32_t clksrc_div = servo_timer_cfg.source_div;
64+
uint32_t freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK_PCLKB) >> clksrc_div;
65+
uint32_t period_counts = freq_hz / (1000000 / period_us);
66+
if (R_AGT_Open(&servo_timer_ctrl, &servo_timer_cfg) != FSP_SUCCESS ||
67+
R_AGT_PeriodSet(&servo_timer_ctrl, period_counts) != FSP_SUCCESS ||
68+
R_AGT_Enable(&servo_timer_ctrl) != FSP_SUCCESS) {
69+
return -1;
70+
}
71+
configured = true;
72+
}
73+
return 0;
74+
}
75+
76+
static int servo_timer_start()
77+
{
78+
// Start the timer if it's not started
79+
if (servo_timer_started == false &&
80+
R_AGT_Start(&servo_timer_ctrl) != FSP_SUCCESS) {
81+
return 0;
82+
}
83+
servo_timer_started = true;
84+
return 0;
85+
}
86+
87+
static int servo_timer_stop()
88+
{
89+
// Start the timer if it's not started
90+
if (servo_timer_started == true &&
91+
R_AGT_Stop(&servo_timer_ctrl) != FSP_SUCCESS) {
92+
return 0;
93+
}
94+
servo_timer_started = false;
95+
return 0;
96+
}
97+
98+
void servo_timer_callback(timer_callback_args_t *args)
99+
{
100+
for (size_t i=0; i<SERVO_MAX_SERVOS; i++) {
101+
ra_servo_t *servo = &ra_servos[i];
102+
if (servo->period_us) {
103+
servo->period_count += SERVO_TIMER_TICK_US;
104+
if (servo->period_count < servo->period_us) {
105+
*servo->io_port = (uint32_t) servo->io_mask;
106+
} else {
107+
*servo->io_port = (uint32_t) (servo->io_mask << 16);
108+
}
109+
if (servo->period_count == SERVO_US_PER_CYCLE) {
110+
servo->period_count = 0;
111+
}
112+
}
113+
}
114+
}
115+
116+
Servo::Servo()
117+
{
118+
servoIndex = SERVO_INVALID_INDEX;
119+
}
120+
121+
uint8_t Servo::attach(int pin)
122+
{
123+
return attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
124+
}
125+
126+
uint8_t Servo::attach(int pin, int min, int max)
127+
{
128+
//assert(pin < NUM_DIGITAL_PINS); ?
129+
if (n_servos == SERVO_MAX_SERVOS) {
130+
return 0;
131+
}
132+
133+
// Try to find a free servo slot.
134+
ra_servo_t *servo = NULL;
135+
bsp_io_port_pin_t io_pin = g_pin_cfg[pin].pin;
136+
for (size_t i=0; i<SERVO_MAX_SERVOS; i++) {
137+
servo = &ra_servos[i];
138+
if (servo->period_us == 0) {
139+
n_servos++;
140+
servoIndex = i;
141+
servo->period_min = min;
142+
servo->period_max = max;
143+
servo->io_mask = (1U << (io_pin & 0xFF));
144+
servo->io_port = SERVO_IO_PORT_ADDR(((io_pin >> 8U) & 0xFF));
145+
writeMicroseconds(DEFAULT_PULSE_WIDTH);
146+
break;
147+
}
148+
}
149+
150+
if (servoIndex == SERVO_INVALID_INDEX) {
151+
return 0;
152+
}
153+
154+
// Configure GPIO pin for the servo.
155+
R_IOPORT_PinCfg(&g_ioport_ctrl, io_pin,
156+
IOPORT_CFG_PORT_DIRECTION_OUTPUT | IOPORT_CFG_PORT_OUTPUT_HIGH);
157+
158+
// Configure and start the timer if it's not started.
159+
if (servo_timer_config(SERVO_TIMER_TICK_US) != 0 ||
160+
servo_timer_start() != 0) {
161+
return 0;
162+
}
163+
return 1;
164+
}
165+
166+
void Servo::detach()
167+
{
168+
if (servoIndex != SERVO_INVALID_INDEX) {
169+
ra_servo_t *servo = &ra_servos[servoIndex];
170+
servo_timer_stop();
171+
servo->period_us = 0;
172+
if (--n_servos) {
173+
servo_timer_start();
174+
}
175+
servoIndex = SERVO_INVALID_INDEX;
176+
}
177+
}
178+
179+
void Servo::write(int angle)
180+
{
181+
if (servoIndex != SERVO_INVALID_INDEX) {
182+
ra_servo_t *servo = &ra_servos[servoIndex];
183+
angle = constrain(angle, 0, 180);
184+
writeMicroseconds(map(angle, 0, 180, servo->period_min, servo->period_max));
185+
}
186+
}
187+
188+
int Servo::read()
189+
{
190+
if (servoIndex != SERVO_INVALID_INDEX) {
191+
ra_servo_t *servo = &ra_servos[servoIndex];
192+
return map(servo->period_us, servo->period_min, servo->period_max, 0, 180);
193+
}
194+
return 0;
195+
}
196+
197+
void Servo::writeMicroseconds(int us)
198+
{
199+
if (servoIndex != SERVO_INVALID_INDEX) {
200+
ra_servo_t *servo = &ra_servos[servoIndex];
201+
servo->period_count = 0;
202+
servo->period_us = constrain(us, servo->period_min, servo->period_max);
203+
}
204+
}
205+
206+
int Servo::readMicroseconds()
207+
{
208+
if (servoIndex != SERVO_INVALID_INDEX) {
209+
ra_servo_t *servo = &ra_servos[servoIndex];
210+
return servo->period_us;
211+
}
212+
return 0;
213+
}
214+
#endif // defined(ARDUINO_ARCH_RENESAS)

src/renesas/ServoTimers.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#define _Nbr_16timers 1

0 commit comments

Comments
 (0)