1+ /*
2+ Copyright (c) 2016 Arduino. All right reserved.
3+
4+ This library is free software; you can redistribute it and/or
5+ modify it under the terms of the GNU Lesser General Public
6+ License as published by the Free Software Foundation; either
7+ version 2.1 of the License, or (at your option) any later version.
8+
9+ This library is distributed in the hope that it will be useful,
10+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12+ Lesser General Public License for more details.
13+
14+ You should have received a copy of the GNU Lesser General Public
15+ License along with this library; if not, write to the Free Software
16+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17+ */
18+
19+ #if defined(ARDUINO_ARCH_NRF52)
20+
21+ #include < Arduino.h>
22+ #include < Servo.h>
23+
24+
25+ static servo_t servos[MAX_SERVOS]; // static array of servo structures
26+
27+ uint8_t ServoCount = 0 ; // the total number of attached servos
28+
29+
30+
31+ uint32_t group_pins[3 ][NRF_PWM_CHANNEL_COUNT]={{NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}, {NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}, {NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}};
32+ static uint16_t seq_values[3 ][NRF_PWM_CHANNEL_COUNT]={{0 , 0 , 0 , 0 }, {0 , 0 , 0 , 0 }, {0 , 0 , 0 , 0 }};
33+
34+ Servo::Servo ()
35+ {
36+ if (ServoCount < MAX_SERVOS) {
37+ this ->servoIndex = ServoCount++; // assign a servo index to this instance
38+ } else {
39+ this ->servoIndex = INVALID_SERVO; // too many servos
40+ }
41+
42+ }
43+
44+ uint8_t Servo::attach (int pin)
45+ {
46+
47+ return this ->attach (pin, 0 , 2500 );
48+ }
49+
50+
51+ uint8_t Servo::attach (int pin, int min, int max)
52+ {
53+ int servo_min, servo_max;
54+ if (this ->servoIndex < MAX_SERVOS) {
55+ pinMode (pin, OUTPUT); // set servo pin to output
56+ servos[this ->servoIndex ].Pin .nbr = pin;
57+
58+ if (min < servo_min) min = servo_min;
59+ if (max > servo_max) max = servo_max;
60+ this ->min = min;
61+ this ->max = max;
62+
63+ servos[this ->servoIndex ].Pin .isActive = true ;
64+
65+ }
66+ return this ->servoIndex ;
67+ }
68+
69+ void Servo::detach ()
70+ {
71+ servos[this ->servoIndex ].Pin .isActive = false ;
72+ }
73+
74+
75+ void Servo::write (int value)
76+ {
77+ if (value < 0 )
78+ value = 0 ;
79+ else if (value > 180 )
80+ value = 180 ;
81+ value = map (value, 0 , 180 , MIN_PULSE, MAX_PULSE);
82+
83+ writeMicroseconds (value);
84+ }
85+
86+
87+ void Servo::writeMicroseconds (int value)
88+ {
89+ uint8_t channel, instance;
90+ uint8_t pin = servos[this ->servoIndex ].Pin .nbr ;
91+ // instance of pwm module is MSB - look at VWariant.h
92+ instance=(g_APinDescription[pin].ulPWMChannel & 0xF0 )/16 ;
93+ // index of pwm channel is LSB - look at VWariant.h
94+ channel=g_APinDescription[pin].ulPWMChannel & 0x0F ;
95+ group_pins[instance][channel]=g_APinDescription[pin].ulPin ;
96+ NRF_PWM_Type * PWMInstance = instance == 0 ? NRF_PWM0 : (instance == 1 ? NRF_PWM1 : NRF_PWM2);
97+ // configure pwm instance and enable it
98+ seq_values[instance][channel]= value | 0x8000 ;
99+ nrf_pwm_sequence_t const seq={
100+ seq_values[instance],
101+ NRF_PWM_VALUES_LENGTH (seq_values),
102+ 0 ,
103+ 0
104+ };
105+ nrf_pwm_pins_set (PWMInstance, group_pins[instance]);
106+ nrf_pwm_enable (PWMInstance);
107+ nrf_pwm_configure (PWMInstance, NRF_PWM_CLK_125kHz, NRF_PWM_MODE_UP, 2500 ); // 20ms - 50Hz
108+ nrf_pwm_decoder_set (PWMInstance, NRF_PWM_LOAD_INDIVIDUAL, NRF_PWM_STEP_AUTO);
109+ nrf_pwm_sequence_set (PWMInstance, 0 , &seq);
110+ nrf_pwm_loop_set (PWMInstance, 0UL );
111+ nrf_pwm_task_trigger (PWMInstance, NRF_PWM_TASK_SEQSTART0);
112+ }
113+
114+ int Servo::read () // return the value as degrees
115+ {
116+ return map (readMicroseconds (), MIN_PULSE, MAX_PULSE, 0 , 180 );
117+ }
118+
119+ int Servo::readMicroseconds ()
120+ {
121+ uint8_t channel, instance;
122+ uint8_t pin=servos[this ->servoIndex ].Pin .nbr ;
123+ instance=(g_APinDescription[pin].ulPWMChannel & 0xF0 )/16 ;
124+ channel=g_APinDescription[pin].ulPWMChannel & 0x0F ;
125+ // remove the 16th bit we added before
126+ return seq_values[instance][channel] & 0x7FFF ;
127+ }
128+
129+ bool Servo::attached ()
130+ {
131+ return servos[this ->servoIndex ].Pin .isActive ;
132+ }
133+
134+ #endif // ARDUINO_ARCH_NRF52
0 commit comments