45 #ifndef _SERVO_EASING_HPP
46 #define _SERVO_EASING_HPP
52 #if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY) && (defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328PB__) || defined(__AVR_ATmega2560__))
62 #define LOCAL_DEBUG // Propagate debug level
74 #if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
75 #include "digitalWriteFast.h"
76 #define TIMING_OUTPUT_PIN 12
79 #if defined(ESP8266) || defined(ESP32)
87 #elif defined(STM32F1xx) // for "Generic STM32F1 series / STMicroelectronics:stm32" from STM32 Boards from STM32 cores of Arduino Board manager
89 #include <HardwareTimer.h>
94 HardwareTimer Timer20ms(TIM1);
96 #elif defined(__STM32F1__) // or ARDUINO_ARCH_STM32F1 for "Generic STM32F103C series / stm32duino:STM32F1" from STM32F1 Boards (STM32duino.com) of Arduino Board manager
98 #include <HardwareTimer.h>
99 # if defined(STM32_HIGH_DENSITY)
100 HardwareTimer Timer20ms(7);
106 HardwareTimer Timer20ms(3);
109 #elif defined(__SAM3X8E__) // Arduino DUE
119 #define TC_FOR_20_MS_TIMER TC2
120 #define CHANNEL_FOR_20_MS_TIMER 2
121 #define ID_TC_FOR_20_MS_TIMER ID_TC8 // Timer 8 is TC2 channel 2
122 #define IRQn_FOR_20_MS_TIMER TC8_IRQn
123 #define HANDLER_FOR_20_MS_TIMER TC8_Handler
125 #elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE + Sparkfun Apollo3
126 mbed::Ticker Timer20ms;
134 #elif defined(ARDUINO_ARCH_RP2040) // Raspberry Pi Pico, Adafruit Feather RP2040, etc.
135 #include "pico/time.h"
136 repeating_timer_t Timer20ms;
139 bool handleServoTimerInterruptHelper(repeating_timer_t*) {
144 #elif defined(TEENSYDUINO)
146 IntervalTimer Timer20ms;
164 const char easeTypeLinear[]
PROGMEM =
"linear";
165 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
166 const char easeTypeQuadratic[]
PROGMEM =
"quadratic";
167 const char easeTypeCubic[]
PROGMEM =
"cubic";
168 const char easeTypeQuartic[]
PROGMEM =
"quartic";
169 const char easeTypePrecision[]
PROGMEM =
"precision";
170 const char easeTypeUser[]
PROGMEM =
"user";
171 const char easeTypeNotDefined[]
PROGMEM =
"";
172 const char easeTypeDummy[]
PROGMEM =
"dummy";
173 # if !defined(DISABLE_COMPLEX_FUNCTIONS)
174 const char easeTypeSine[]
PROGMEM =
"sine";
175 const char easeTypeCircular[]
PROGMEM =
"circular";
176 const char easeTypeBack[]
PROGMEM =
"back";
177 const char easeTypeElastic[]
PROGMEM =
"elastic";
178 const char easeTypeBounce[]
PROGMEM =
"bounce";
180 #endif // !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
182 const char *
const easeTypeStrings[]
PROGMEM = { easeTypeLinear
183 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
184 , easeTypeQuadratic, easeTypeCubic, easeTypeQuartic, easeTypeNotDefined, easeTypeNotDefined, easeTypeUser, easeTypeDummy,
185 # if !defined(DISABLE_COMPLEX_FUNCTIONS)
186 easeTypeSine, easeTypeCircular, easeTypeBack, easeTypeElastic, easeTypeBounce, easeTypePrecision
191 #if defined(USE_PCA9685_SERVO_EXPANDER)
193 # if defined(USE_SOFT_I2C_MASTER)
194 #include "SoftI2CMasterConfig.h"
195 #include "SoftI2CMaster.h"
196 # endif // defined(USE_SOFT_I2C_MASTER)
199 # define _BV(bit) (1 << (bit))
202 #if defined(USE_SOFT_I2C_MASTER)
208 mPCA9685I2CAddress = aPCA9685I2CAddress;
209 #if !defined(USE_SOFT_I2C_MASTER)
210 mI2CClass = aI2CClass;
219 #if defined(USE_SERVO_LIB)
220 mServoIsConnectedToExpander =
true;
222 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
224 # if defined(ENABLE_EASE_USER)
230 #if defined(ENABLE_MIN_AND_MAX_CONSTRAINTS)
236 #if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
237 pinMode(TIMING_OUTPUT_PIN, OUTPUT);
241 void ServoEasing::I2CInit() {
243 #if defined(USE_SOFT_I2C_MASTER)
247 mI2CClass->setClock(I2C_CLOCK_FREQUENCY);
248 # if defined (ARDUINO_ARCH_AVR) // Other platforms do not have this new function
249 mI2CClass->setWireTimeout();
256 void ServoEasing::PCA9685Reset() {
258 #if defined(USE_SOFT_I2C_MASTER)
265 mI2CClass->endTransmission();
273 void ServoEasing::PCA9685Init() {
285 void ServoEasing::PCA9685InitWithExternalClock(uint32_t aExternalClockFrequencyHertz) {
303 void ServoEasing::PCA9685Init(uint32_t aActualPCA9685ClockFrequencyHertz) {
311 void ServoEasing::I2CWriteByte(uint8_t aAddress, uint8_t aData) {
312 #if defined(USE_SOFT_I2C_MASTER)
313 i2c_start(mPCA9685I2CAddress << 1);
318 mI2CClass->beginTransmission(mPCA9685I2CAddress);
319 mI2CClass->write(aAddress);
320 mI2CClass->write(aData);
321 # if defined(LOCAL_DEBUG)
322 uint8_t tWireReturnCode = mI2CClass->endTransmission();
323 if (tWireReturnCode != 0) {
325 Serial.print((
char) (tWireReturnCode +
'0'));
328 mI2CClass->endTransmission();
339 void ServoEasing::setPWM(uint16_t aPWMOffValueAsUnits) {
340 #if defined(USE_SOFT_I2C_MASTER)
341 i2c_start(mPCA9685I2CAddress << 1);
343 i2c_write(aPWMOffValueAsUnits);
344 i2c_write(aPWMOffValueAsUnits >> 8);
347 mI2CClass->beginTransmission(mPCA9685I2CAddress);
350 mI2CClass->write(aPWMOffValueAsUnits);
351 mI2CClass->write(aPWMOffValueAsUnits >> 8);
352 # if defined(LOCAL_DEBUG) && not defined(ESP32)
355 uint8_t tWireReturnCode = mI2CClass->endTransmission();
356 if (tWireReturnCode != 0) {
358 Serial.print((
char) (tWireReturnCode +
'0'));
361 mI2CClass->endTransmission();
373 void ServoEasing::setPWM(uint16_t aPWMOnStartValueAsUnits, uint16_t aPWMPulseDurationAsUnits) {
374 #if defined(USE_SOFT_I2C_MASTER)
375 i2c_start(mPCA9685I2CAddress << 1);
377 i2c_write(aPWMOnStartValueAsUnits);
378 i2c_write(aPWMOnStartValueAsUnits >> 8);
379 i2c_write(aPWMOnStartValueAsUnits + aPWMPulseDurationAsUnits);
380 i2c_write((aPWMOnStartValueAsUnits + aPWMPulseDurationAsUnits) >> 8);
383 mI2CClass->beginTransmission(mPCA9685I2CAddress);
385 mI2CClass->write(aPWMOnStartValueAsUnits);
386 mI2CClass->write(aPWMOnStartValueAsUnits >> 8);
387 mI2CClass->write(aPWMOnStartValueAsUnits + aPWMPulseDurationAsUnits);
388 mI2CClass->write((aPWMOnStartValueAsUnits + aPWMPulseDurationAsUnits) >> 8);
389 # if defined(LOCAL_DEBUG) && not defined(ESP32)
392 uint8_t tWireReturnCode = mI2CClass->endTransmission();
393 if (tWireReturnCode != 0) {
395 Serial.print((
char) (tWireReturnCode +
'0'));
398 mI2CClass->endTransmission();
403 int ServoEasing::MicrosecondsToPCA9685Units(
int aMicroseconds) {
407 #if defined(USE_SERVO_LIB)
408 if (!mServoIsConnectedToExpander) {
409 return aMicroseconds;
415 int ServoEasing::PCA9685UnitsToMicroseconds(
int aPCA9685Units) {
423 #endif // defined(USE_PCA9685_SERVO_EXPANDER)
427 #if (!defined(USE_PCA9685_SERVO_EXPANDER) || defined(USE_SERVO_LIB)) && !defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
435 #if !defined(DISABLE_PAUSE_RESUME)
439 #if defined(USE_PCA9685_SERVO_EXPANDER) && defined(USE_SERVO_LIB)
440 mServoIsConnectedToExpander =
false;
442 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
444 # if defined(ENABLE_EASE_USER)
450 #if defined(ENABLE_MIN_AND_MAX_CONSTRAINTS)
456 #if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
457 pinMode(TIMING_OUTPUT_PIN, OUTPUT);
478 uint8_t
ServoEasing::attach(
int aPin,
int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree) {
479 return attach(aPin, aMicrosecondsForServo0Degree, aMicrosecondsForServo180Degree, 0, 180);
505 int aMicrosecondsForServo180Degree) {
506 return attach(aPin, aInitialDegreeOrMicrosecond, aMicrosecondsForServo0Degree, aMicrosecondsForServo180Degree, 0, 180);
510 int aMicrosecondsForServo0Degree,
int aMicrosecondsForServo180Degree) {
511 return attachWithTrim(aPin, aTrimDegreeOrMicrosecond, aInitialDegreeOrMicrosecond, aMicrosecondsForServo0Degree,
512 aMicrosecondsForServo180Degree, 0, 180);
521 uint8_t
ServoEasing::attach(
int aPin,
int aInitialDegreeOrMicrosecond,
int aMicrosecondsForServoLowDegree,
522 int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
int aServoHighDegree) {
523 uint8_t tReturnValue =
attach(aPin, aMicrosecondsForServoLowDegree, aMicrosecondsForServoHighDegree, aServoLowDegree,
525 write(aInitialDegreeOrMicrosecond);
530 int aMicrosecondsForServoLowDegree,
int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
int aServoHighDegree) {
531 uint8_t tReturnValue =
attach(aPin, aMicrosecondsForServoLowDegree, aMicrosecondsForServoHighDegree, aServoLowDegree,
537 setTrim(aTrimDegreeOrMicrosecond,
false);
538 write(aInitialDegreeOrMicrosecond);
552 for (uint_fast8_t tServoIndex = 0; tServoIndex <
MAX_EASING_SERVOS; ++tServoIndex) {
563 #if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
564 checkAndInitLightweightServoPin(
mServoPin);
566 #else // We have no Servo::attach for USE_LIGHTWEIGHT_SERVO_LIBRARY
568 # if !defined(USE_PCA9685_SERVO_EXPANDER) || defined(USE_SERVO_LIB)
572 # if defined(ARDUINO_ARCH_APOLLO3)
580 # endif // defined(ARDUINO_ARCH_APOLLO3)
583 # endif // defined(USE_SERVO_LIB)
584 #endif // defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
598 uint8_t
ServoEasing::attach(
int aPin,
int aMicrosecondsForServoLowDegree,
int aMicrosecondsForServoHighDegree,
int aServoLowDegree,
599 int aServoHighDegree) {
610 int tMicrosecondsForServo0Degree = map(0, aServoLowDegree, aServoHighDegree, aMicrosecondsForServoLowDegree,
611 aMicrosecondsForServoHighDegree);
612 int tMicrosecondsForServo180Degree = map(180, aServoLowDegree, aServoHighDegree, aMicrosecondsForServoLowDegree,
613 aMicrosecondsForServoHighDegree);
616 #if defined(USE_PCA9685_SERVO_EXPANDER)
617 # if defined(USE_SERVO_LIB)
618 if (mServoIsConnectedToExpander) {
642 for (uint_fast8_t tServoIndex = 0; tServoIndex <
MAX_EASING_SERVOS; ++tServoIndex) {
653 #if defined(LOCAL_TRACE)
654 Serial.print(
"Index=");
656 Serial.print(
" pin=");
658 Serial.print(
" low=");
659 Serial.print(aServoLowDegree);
661 Serial.print(aMicrosecondsForServoLowDegree);
662 Serial.print(
" high=");
663 Serial.print(aServoHighDegree);
665 Serial.print(aMicrosecondsForServoHighDegree);
674 #if defined(USE_PCA9685_SERVO_EXPANDER)
676 # if defined(USE_SERVO_LIB)
677 if (mServoIsConnectedToExpander) {
693 #endif // defined(USE_PCA9685_SERVO_EXPANDER)
695 #if !defined(USE_PCA9685_SERVO_EXPANDER) || defined(USE_SERVO_LIB)
701 # if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
702 if (aPin != LIGHTWEIGHT_SERVO_CHANNEL_A_PIN && aPin != LIGHTWEIGHT_SERVO_CHANNEL_B_PIN
703 #
if defined(LIGHTWEIGHT_SERVO_CHANNEL_C_PIN)
704 && aPin != LIGHTWEIGHT_SERVO_CHANNEL_C_PIN
715 # if defined(ARDUINO_ARCH_APOLLO3)
720 # endif // defined(ARDUINO_ARCH_APOLLO3)
721 # endif // defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
722 #endif // defined(USE_SERVO_LIB)
738 #if defined(USE_PCA9685_SERVO_EXPANDER)
739 # if defined(USE_SERVO_LIB)
740 if (mServoIsConnectedToExpander) {
743 # if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
751 # endif // defined(USE_SERVO_LIB)
754 # if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
759 #endif // defined(USE_PCA9685_SERVO_EXPANDER)
780 mSpeed = aDegreesPerSecond;
790 if (aTrimDegreeOrMicrosecond >= 0) {
809 #if defined(LOCAL_DEBUG)
810 Serial.print(F(
"Set trim to "));
811 Serial.println(aTrimMicrosecondsOrUnits);
813 #if defined(ENABLE_MIN_AND_MAX_CONSTRAINTS)
814 mMaxMicrosecondsOrUnits -= aTrimMicrosecondsOrUnits;
815 mMinMicrosecondsOrUnits -= aTrimMicrosecondsOrUnits;
822 #if defined(ENABLE_MIN_AND_MAX_CONSTRAINTS)
823 void ServoEasing::setMaxConstraint(
int aMaxDegreeOrMicrosecond) {
826 void ServoEasing::setMinConstraint(
int aMinDegreeOrMicrosecond) {
829 void ServoEasing::setMinMaxConstraint(
int aMinDegreeOrMicrosecond,
int aMaxDegreeOrMicrosecond) {
835 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
844 # if defined(ENABLE_EASE_USER)
846 void *aUserDataPointer) {
854 #endif // !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
861 #if defined(LOCAL_TRACE)
862 Serial.print(F(
"write "));
863 Serial.print(aTargetDegreeOrMicrosecond);
864 Serial.print(F(
" | "));
870 #if defined(LOCAL_TRACE)
871 Serial.print(F(
"Error: detached servo"));
880 #if defined(LOCAL_TRACE)
881 Serial.print(F(
"write "));
882 Serial.print(aTargetDegreeOrMicrosecond);
883 Serial.print(F(
" | "));
889 #if defined(LOCAL_TRACE)
890 Serial.print(F(
"Error: detached servo"));
907 #if defined(LOCAL_TRACE)
908 Serial.print(F(
"Error: detached servo"));
912 #if defined(ENABLE_MIN_AND_MAX_CONSTRAINTS)
913 if (aTargetMicrosecondsOrUnits > mMaxMicrosecondsOrUnits) {
914 #if defined(LOCAL_TRACE)
915 Serial.print(aTargetMicrosecondsOrUnits);
916 Serial.print(F(
" > "));
917 Serial.print(mMaxMicrosecondsOrUnits);
918 Serial.print(F(
" | "));
920 aTargetMicrosecondsOrUnits = mMaxMicrosecondsOrUnits;
921 }
else if (aTargetMicrosecondsOrUnits < mMinMicrosecondsOrUnits) {
922 #if defined(LOCAL_TRACE)
923 Serial.print(aTargetMicrosecondsOrUnits);
924 Serial.print(F(
" < "));
925 Serial.print(mMinMicrosecondsOrUnits);
926 Serial.print(F(
" | "));
928 aTargetMicrosecondsOrUnits = mMinMicrosecondsOrUnits;
933 #if defined(LOCAL_TRACE)
937 Serial.print(F(
" us/u="));
938 Serial.print(aTargetMicrosecondsOrUnits);
940 Serial.print(
" +trim=");
956 #if defined(LOCAL_TRACE)
957 Serial.print(F(
" +reverse="));
958 Serial.print(aTargetMicrosecondsOrUnits);
962 #if defined(PRINT_FOR_SERIAL_PLOTTER) && !defined(LOCAL_TRACE)
964 Serial.print(aTargetMicrosecondsOrUnits);
967 #if defined(USE_PCA9685_SERVO_EXPANDER)
968 # if defined(LOCAL_TRACE)
970 Serial.print(F(
" s="));
973 # if defined(USE_SERVO_LIB)
974 if (mServoIsConnectedToExpander) {
977 # if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
978 writeMicrosecondsLightweightServo(aTargetMicrosecondsOrUnits, (
mServoPin == LIGHTWEIGHT_SERVO_CHANNEL_A_PIN));
992 # if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
993 writeMicrosecondsLightweightServoPin(aTargetMicrosecondsOrUnits,
mServoPin);
999 #if defined(LOCAL_TRACE) && !defined(PRINT_FOR_SERIAL_PLOTTER)
1010 #if defined(USE_PCA9685_SERVO_EXPANDER)
1011 # if defined(USE_SERVO_LIB)
1012 if (!mServoIsConnectedToExpander) {
1017 tResult = (tResult * 180) + 928;
1044 #if defined(USE_PCA9685_SERVO_EXPANDER)
1045 # if defined(USE_SERVO_LIB)
1046 if (mServoIsConnectedToExpander) {
1048 tResult = (tResult * 180) + 190;
1051 tResult = (tResult * 180) + 928;
1055 tResult = (tResult * 180) + 190;
1059 tResult = (tResult * 180) + 928;
1067 #if defined(USE_PCA9685_SERVO_EXPANDER)
1068 return PCA9685UnitsToMicroseconds(aMicrosecondsOrUnits);
1070 return aMicrosecondsOrUnits;
1081 #if defined(DISABLE_MICROS_AS_DEGREE_PARAMETER)
1085 #else // defined(DISABLE_MICROS_AS_DEGREE_PARAMETER)
1098 # if defined(USE_PCA9685_SERVO_EXPANDER)
1099 return MicrosecondsToPCA9685Units(aDegreeOrMicrosecond);
1101 return aDegreeOrMicrosecond;
1104 #endif // defined(DISABLE_MICROS_AS_DEGREE_PARAMETER)
1109 #if defined(DISABLE_MICROS_AS_DEGREE_PARAMETER)
1124 # if defined(USE_PCA9685_SERVO_EXPANDER)
1125 return MicrosecondsToPCA9685Units(aDegreeOrMicrosecond);
1127 return aDegreeOrMicrosecond;
1130 #endif // defined(DISABLE_MICROS_AS_DEGREE_PARAMETER)
1143 return tResultValue;
1164 #if defined(PRINT_FOR_SERIAL_PLOTTER)
1176 #if defined(PRINT_FOR_SERIAL_PLOTTER)
1187 #if defined(PRINT_FOR_SERIAL_PLOTTER)
1198 #if defined(PRINT_FOR_SERIAL_PLOTTER)
1244 bool aStartUpdateByInterrupt) {
1245 return startEaseTo((
int) aTargetDegreeOrMicrosecond, aDegreesPerSecond, aStartUpdateByInterrupt);
1258 if (aDegreesPerSecond == 0) {
1259 #if defined(LOCAL_DEBUG)
1260 Serial.println(F(
"Speed is 0 -> set to 1"));
1262 aDegreesPerSecond = 1;
1268 int tTargetDegree = aTargetDegreeOrMicrosecond;
1269 #if defined(DISABLE_MICROS_AS_DEGREE_PARAMETER)
1270 tTargetDegree = aTargetDegreeOrMicrosecond;
1283 uint_fast16_t tMillisForCompleteMove = abs(tTargetDegree - tCurrentDegree) *
MILLIS_IN_ONE_SECOND / aDegreesPerSecond;
1286 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1288 tMillisForCompleteMove *= 2;
1292 return startEaseToD(aTargetDegreeOrMicrosecond, tMillisForCompleteMove, aStartUpdateByInterrupt);
1299 if (aDegreesPerSecond == 0) {
1300 #if defined(LOCAL_DEBUG)
1301 Serial.println(F(
"Speed is 0 -> set to 1"));
1303 aDegreesPerSecond = 1;
1310 int tTargetDegree = aTargetDegreeOrMicrosecond;
1311 #if defined(DISABLE_MICROS_AS_DEGREE_PARAMETER)
1312 tTargetDegree = aTargetDegreeOrMicrosecond;
1325 uint_fast16_t tMillisForCompleteMove = abs(tTargetDegree - tCurrentDegree) *
MILLIS_IN_ONE_SECOND / aDegreesPerSecond;
1328 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1330 tMillisForCompleteMove *= 2;
1334 return startEaseToD(aTargetDegreeOrMicrosecond, tMillisForCompleteMove, aStartUpdateByInterrupt);
1362 return startEaseToD((
int) aDegreeOrMicrosecond, aMillisForMove, aStartUpdateByInterrupt);
1375 #if defined(LOCAL_TRACE)
1376 Serial.print(F(
"Error: detached servo"));
1381 #if defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1397 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1406 #if defined(LOCAL_TRACE)
1408 #elif defined(LOCAL_DEBUG)
1415 #if !defined(DISABLE_PAUSE_RESUME)
1422 return tReturnValue;
1430 #if defined(LOCAL_TRACE)
1431 Serial.println(F(
"Error: detached servo"));
1436 #if defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1452 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1461 #if defined(LOCAL_TRACE)
1463 #elif defined(LOCAL_DEBUG)
1471 #if !defined(DISABLE_PAUSE_RESUME)
1478 return tReturnValue;
1486 #if !defined(ENABLE_EXTERNAL_SERVO_TIMER_HANDLER)
1495 #if !defined(DISABLE_PAUSE_RESUME)
1502 #if !defined(DISABLE_PAUSE_RESUME)
1510 #if !defined(DISABLE_PAUSE_RESUME)
1523 #if defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1557 #else // PROVIDE_ONLY_LINEAR_MOVEMENT
1560 #if defined(LOCAL_TRACE)
1565 # if defined(PRINT_FOR_SERIAL_PLOTTER)
1572 #if !defined(DISABLE_PAUSE_RESUME)
1578 #if defined(LOCAL_TRACE)
1594 int tNewMicrosecondsOrUnits;
1612 float tFactorOfMovementCompletion = 0.0;
1622 tFactorOfMovementCompletion = 1.0 - (
callEasingFunction(1.0 - tFactorOfTimeCompletion));
1625 if (tFactorOfTimeCompletion <= 0.5) {
1628 tFactorOfMovementCompletion = 0.5 * (
callEasingFunction(2.0 * tFactorOfTimeCompletion));
1632 tFactorOfMovementCompletion = 1.0 - (
callEasingFunction(1.0 - (2.0 * tFactorOfTimeCompletion)));
1637 tFactorOfMovementCompletion = 1.0 - (0.5 * (
callEasingFunction(2.0 - (2.0 * tFactorOfTimeCompletion))));
1641 tFactorOfMovementCompletion = 1.0 -
callEasingFunction((2.0 * tFactorOfTimeCompletion) - 1.0);
1646 #if defined(LOCAL_TRACE)
1647 Serial.print(F(
"FactorOfTimeCompletion="));
1648 Serial.print(tFactorOfTimeCompletion);
1649 Serial.print(F(
" FactorOfMovementCompletion="));
1650 Serial.println(tFactorOfMovementCompletion);
1653 #if defined(ENABLE_EASE_USER) || defined(ENABLE_EASE_PRECISION) // Only these two types returns microseconds yet
1657 #if defined(USE_PCA9685_SERVO_EXPANDER)
1658 # if defined(USE_SERVO_LIB)
1659 if (mServoIsConnectedToExpander) {
1660 tNewMicrosecondsOrUnits = MicrosecondsToPCA9685Units(tFactorOfMovementCompletion);
1662 tNewMicrosecondsOrUnits = tFactorOfMovementCompletion;
1665 tNewMicrosecondsOrUnits = MicrosecondsToPCA9685Units(tFactorOfMovementCompletion);
1668 tNewMicrosecondsOrUnits = tFactorOfMovementCompletion;
1672 #if defined(ENABLE_EASE_USER)
1686 # if defined(PRINT_FOR_SERIAL_PLOTTER)
1703 switch (tEasingType) {
1705 # if defined(ENABLE_EASE_USER)
1714 # if defined(ENABLE_EASE_QUADRATIC)
1718 # if defined(ENABLE_EASE_CUBIC)
1722 # if defined(ENABLE_EASE_QUARTIC)
1727 # if defined(ENABLE_EASE_SINE)
1731 # if defined(ENABLE_EASE_CIRCULAR)
1735 # if defined(ENABLE_EASE_BACK)
1739 # if defined(ENABLE_EASE_ELASTIC)
1743 # if defined(ENABLE_EASE_BOUNCE)
1747 # if defined(ENABLE_EASE_PRECISION)
1756 #endif //PROVIDE_ONLY_LINEAR_MOVEMENT
1762 #if defined(ESP8266)
1764 #elif defined(ESP32)
1775 #if defined(ESP8266)
1777 #elif defined(ESP32)
1845 # if defined(__AVR__)
1846 const char *tEaseTypeStringPtr = (
char*) pgm_read_word(&easeTypeStrings[aEasingType &
EASE_TYPE_MASK]);
1847 aSerial->print((__FlashStringHelper*) (tEaseTypeStringPtr));
1853 aSerial->print(F(
"_in"));
1855 aSerial->print(F(
"_out"));
1857 aSerial->print(F(
"_in_out"));
1859 aSerial->print(F(
"_bouncing_in_out"));
1869 return aTargetMicrosecondsOrUnits;
1880 aSerial->print(
'/');
1882 aSerial->print(F(
": "));
1885 if (doExtendedOutput) {
1886 aSerial->print(
'|');
1890 aSerial->print(F(
" -> "));
1892 if (doExtendedOutput) {
1893 aSerial->print(
'|');
1897 aSerial->print(F(
" = "));
1904 aSerial->print(tDelta);
1905 if (doExtendedOutput) {
1906 aSerial->print(
'|');
1910 aSerial->print(F(
" in "));
1912 aSerial->print(F(
" ms"));
1914 aSerial->print(F(
" with speed="));
1917 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
1918 aSerial->print(F(
" and easingType=0x"));
1920 aSerial->print(
'|');
1924 if (doExtendedOutput) {
1925 aSerial->print(F(
" MillisAtStartMove="));
1938 aSerial->print(F(
"0="));
1940 aSerial->print(F(
" 180="));
1943 aSerial->print(F(
" trim="));
1949 aSerial->print(
'|');
1952 aSerial->print(F(
" reverse="));
1955 #if defined(USE_PCA9685_SERVO_EXPANDER)
1956 aSerial->print(F(
" PCA9685I2CAddress=0x"));
1957 aSerial->print(mPCA9685I2CAddress, HEX);
1958 #if !defined(USE_SOFT_I2C_MASTER)
1959 aSerial->print(F(
" &Wire=0x"));
1961 aSerial->print((uint_fast16_t) mI2CClass, HEX);
1964 # if defined(USE_SERVO_LIB)
1965 aSerial->print(F(
" at expander="));
1966 aSerial->print(mServoIsConnectedToExpander);
1970 aSerial->print(F(
" callback=0x"));
1973 aSerial->print(F(
" MAX_EASING_SERVOS="));
1976 aSerial->print(F(
" this=0x"));
1977 aSerial->println((uint_fast16_t)
this, HEX);
1981 aSerial->print(F(
"ServoArrayMaxIndex="));
1983 aSerial->print(F(
" InterruptsAreActive="));
1992 if (aDegreeToClip) {
1993 return aDegreeToClip;
1995 if (aDegreeToClip < 218) {
2008 #if !defined(ENABLE_EXTERNAL_SERVO_TIMER_HANDLER)
2009 # if defined(STM32F1xx) && STM32_CORE_VERSION_MAJOR == 1 && STM32_CORE_VERSION_MINOR <= 8 // for "Generic STM32F1 series" from STM32 Boards from STM32 cores of Arduino Board manager
2015 # if defined(USE_PCA9685_SERVO_EXPANDER)
2017 # if !defined(ARDUINO_ARCH_MBED)
2026 #endif // !defined(ENABLE_EXTERNAL_SERVO_TIMER_HANDLER)
2033 void setTimer1InterruptMarginMicros(uint16_t aInterruptMarginMicros){
2049 #if defined(LOCAL_TRACE)
2050 Serial.println(F(
"enableServoEasingInterrupt"));
2052 #if defined(__AVR__)
2053 # if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2054 # if defined(USE_PCA9685_SERVO_EXPANDER) && !defined(USE_SERVO_LIB)
2056 TCCR5A = _BV(WGM11);
2057 TCCR5B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
2066 TIFR5 |= _BV(OCF5C);
2067 TIMSK5 |= _BV(OCIE5C);
2068 # if defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
2070 DDRL &= ~(_BV(DDL5));
2071 TCCR5A &= ~(_BV(COM5C1));
2075 # elif defined(__AVR_ATmega4808__) || defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3217__) // Thinary Nano Every with MegaCoreX, Uno WiFi Rev 2, Nano Every, Tiny Core 32 Dev Board
2081 TCA0.SINGLE.CTRLD = 0;
2082 TCA0.SINGLE.CTRLB = TCA_SINGLE_WGMODE_NORMAL_gc;
2084 TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV8_gc | TCA_SINGLE_ENABLE_bm;
2085 TCA0.SINGLE.INTCTRL = TCA_SINGLE_OVF_bm;
2087 # if defined(MEGACOREX) && defined(USE_TIMERB2)
2088 #error It seems, that not the Megacore Servo library, but an Arduino Servo library is taken for compile, which will lead to errors. You must update MEGACOREX to >= 1.1.1 or remove the Arduino Servo library to fix this.
2090 # elif defined(TCCR1B) && defined(TIFR1) // Uno, Nano etc.
2097 # if defined(USE_PCA9685_SERVO_EXPANDER) && !defined(USE_SERVO_LIB)
2099 TCCR1A = _BV(WGM11);
2100 TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
2104 TIFR1 |= _BV(OCF1B);
2105 TIMSK1 |= _BV(OCIE1B);
2111 TCCR1B |= _BV(ICNC1);
2112 # if !defined(USE_LIGHTWEIGHT_SERVO_LIBRARY)
2117 #error "This AVR CPU is not supported by ServoEasing"
2120 #elif defined(ESP8266) || defined(ESP32)
2128 #elif defined(STM32F1xx) // for "STMicroelectronics:stm32" from STM32 Boards from STM32 cores of Arduino Board manager
2129 Timer20ms.setMode(LL_TIM_CHANNEL_CH1, TIMER_OUTPUT_COMPARE, NC);
2134 #elif defined(__STM32F1__) // for "stm32duino:STM32F1 Generic STM32F103C series" from STM32F1 Boards (Roger Clark STM32duino.com)
2135 Timer20ms.setMode(TIMER_CH1, TIMER_OUTPUT_COMPARE);
2138 Timer20ms.refresh();
2140 #elif defined(__SAM3X8E__) // Arduino DUE
2141 pmc_set_writeprotect(
false);
2142 pmc_enable_periph_clk(ID_TC_FOR_20_MS_TIMER);
2143 NVIC_ClearPendingIRQ(IRQn_FOR_20_MS_TIMER);
2144 NVIC_EnableIRQ(IRQn_FOR_20_MS_TIMER);
2147 TC_Configure(TC_FOR_20_MS_TIMER, CHANNEL_FOR_20_MS_TIMER, TC_CMR_TCCLKS_TIMER_CLOCK3 | TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC);
2150 TC_Start(TC_FOR_20_MS_TIMER, CHANNEL_FOR_20_MS_TIMER);
2153 TC_FOR_20_MS_TIMER->TC_CHANNEL[CHANNEL_FOR_20_MS_TIMER].TC_IER = TC_IER_CPCS;
2155 TC_FOR_20_MS_TIMER->TC_CHANNEL[CHANNEL_FOR_20_MS_TIMER].TC_IDR = ~TC_IER_CPCS;
2157 #elif defined(ARDUINO_ARCH_SAMD)
2160 TcCount16 *TC = (TcCount16*) TC5;
2161 # if defined(__SAMD51__)
2172 GCLK->PCHCTRL[TC5_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
2173 while (GCLK->SYNCBUSY.reg > 0);
2176 TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
2177 while (TC->SYNCBUSY.bit.ENABLE);
2179 TC->CTRLA.reg = TC_CTRLA_SWRST;
2181 while (TC->SYNCBUSY.bit.SWRST);
2188 TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16 | TC_WAVE_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV256 | TC_CTRLA_ENABLE;
2193 GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5));
2198 TC->CTRLA.reg &= ~TC_CTRLA_ENABLE;
2202 while (TC->STATUS.bit.SYNCBUSY == 1);
2204 TC->CTRLA.reg = TC_CTRLA_SWRST;
2206 while (TC->CTRLA.bit.SWRST);
2212 TC->CTRLA.reg |= TC_CTRLA_MODE_COUNT16| TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_PRESCALER_DIV64 | TC_CTRLA_ENABLE;
2215 # endif // defined(__SAMD51__)
2218 NVIC_DisableIRQ(TC5_IRQn);
2219 NVIC_ClearPendingIRQ(TC5_IRQn);
2220 NVIC_SetPriority(TC5_IRQn, 0);
2221 NVIC_EnableIRQ(TC5_IRQn);
2224 TC->INTENSET.bit.MC0 = 1;
2241 #elif defined(ARDUINO_ARCH_MBED)
2244 #elif defined(ARDUINO_ARCH_RP2040)
2247 #elif defined(TEENSYDUINO)
2252 #warning Board / CPU is not covered by definitions using pre-processor symbols -> no timer available. Please extend ServoEasing.cpp.
2258 #if defined(LOCAL_TRACE)
2259 Serial.println(F(
"disableServoEasingInterrupt"));
2261 #if defined(__AVR__)
2262 # if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2263 TIMSK5 &= ~(_BV(OCIE5C));
2265 # elif defined(__AVR_ATmega4808__) || defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3217__) // Thinary Nano Every with MegaCoreX, Uno WiFi Rev 2, Nano Every, Tiny Core 32 Dev Board
2266 TCA0.SINGLE.INTCTRL &= ~(TCA_SINGLE_OVF_bm);
2268 # elif defined(TIMSK1)// defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2269 TIMSK1 &= ~(_BV(OCIE1B));
2272 #error "This AVR CPU is not supported by ServoEasing"
2275 #elif defined(ESP8266) || defined(ESP32)
2278 #elif defined(STM32F1xx) // for "Generic STM32F1 series" from STM32 Boards from STM32 cores of Arduino Board manager
2280 Timer20ms.setMode(LL_TIM_CHANNEL_CH1, TIMER_DISABLED);
2281 Timer20ms.detachInterrupt();
2283 #elif defined(__STM32F1__) // for "Generic STM32F103C series" from STM32F1 Boards (STM32duino.com) of Arduino Board manager
2285 Timer20ms.setMode(TIMER_CH1, TIMER_DISABLED);
2286 Timer20ms.detachInterrupt(TIMER_CH1);
2288 #elif defined(__SAM3X8E__) // Arduino DUE
2289 NVIC_DisableIRQ(IRQn_FOR_20_MS_TIMER);
2291 #elif defined(ARDUINO_ARCH_SAMD)
2292 TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
2293 # if defined(__SAMD51__)
2294 while (TC5->COUNT16.STATUS.reg & TC_SYNCBUSY_STATUS);
2296 while (TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY);
2299 #elif defined(ARDUINO_ARCH_MBED) // Arduino Nano 33 BLE + Sparkfun Apollo3
2302 #elif defined(ARDUINO_ARCH_RP2040)
2303 cancel_repeating_timer(&Timer20ms);
2308 #elif defined(TEENSYDUINO)
2320 #if defined(__AVR__)
2321 # if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
2322 ISR(TIMER5_COMPC_vect) {
2326 # elif defined(__AVR_ATmega4808__) || defined(__AVR_ATmega4809__) || defined(__AVR_ATtiny3217__) // Thinary Nano Every with MegaCoreX, Uno WiFi Rev 2, Nano Every, Tiny Core 32 Dev Board
2327 ISR(TCA0_OVF_vect) {
2328 TCA0.SINGLE.INTFLAGS = TCA_SINGLE_OVF_bm;
2332 # else // defined(__AVR__)
2333 ISR(TIMER1_COMPB_vect) {
2334 # if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
2335 digitalWriteFast(TIMING_OUTPUT_PIN, HIGH);
2338 # if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
2339 digitalWriteFast(TIMING_OUTPUT_PIN, LOW);
2344 #elif defined(__SAM3X8E__) // Arduino DUE
2345 void HANDLER_FOR_20_MS_TIMER(
void) {
2346 # if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
2347 digitalWrite(TIMING_OUTPUT_PIN, HIGH);
2350 TC_GetStatus(TC_FOR_20_MS_TIMER, CHANNEL_FOR_20_MS_TIMER);
2352 # if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
2353 digitalWrite(TIMING_OUTPUT_PIN, LOW);
2357 #elif defined(ARDUINO_ARCH_SAMD)
2358 void TC5_Handler(
void) {
2359 # if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
2360 digitalWrite(TIMING_OUTPUT_PIN, HIGH);
2363 TC5->COUNT16.INTFLAG.bit.MC0 = 1;
2365 # if defined(MEASURE_SERVO_EASING_INTERRUPT_TIMING)
2366 digitalWrite(TIMING_OUTPUT_PIN, LOW);
2379 #endif // defined(__AVR__)
2385 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
2394 for (uint_fast8_t tServoIndex = 0; tServoIndex <= aNumberOfServos; ++tServoIndex) {
2442 aSerial->print(F(
"ServoNextPositionArray="));
2462 aSerial->print(F(
" | "));
2487 void setIntegerDegreeForAllServos(uint_fast8_t aNumberOfServos, va_list *aDegreeValues) {
2488 for (uint_fast8_t tServoIndex = 0; tServoIndex < aNumberOfServos; ++tServoIndex) {
2495 void setFloatDegreeForAllServos(uint_fast8_t aNumberOfServos, va_list *aDegreeValues) {
2496 for (uint_fast8_t tServoIndex = 0; tServoIndex < aNumberOfServos; ++tServoIndex) {
2502 #if defined(va_start)
2506 void setDegreeForAllServos(uint_fast8_t aNumberOfServos, ...) {
2507 va_list aDegreeValues;
2508 va_start(aDegreeValues, aNumberOfServos);
2509 setIntegerDegreeForAllServos(aNumberOfServos, &aDegreeValues);
2510 va_end(aDegreeValues);
2513 void setIntegerDegreeForAllServos(uint_fast8_t aNumberOfServos, ...) {
2514 va_list aDegreeValues;
2515 va_start(aDegreeValues, aNumberOfServos);
2516 setIntegerDegreeForAllServos(aNumberOfServos, &aDegreeValues);
2517 va_end(aDegreeValues);
2522 void setFloatDegreeForAllServos(uint_fast8_t aNumberOfServos, ...) {
2523 va_list aDegreeValues;
2524 va_start(aDegreeValues, aNumberOfServos);
2525 setFloatDegreeForAllServos(aNumberOfServos, &aDegreeValues);
2526 va_end(aDegreeValues);
2536 bool tOneServoIsMoving =
false;
2541 || tOneServoIsMoving;
2544 return tOneServoIsMoving;
2553 bool tOneServoIsMoving =
false;
2560 return tOneServoIsMoving;
2569 bool tOneServoIsMoving =
false;
2576 return tOneServoIsMoving;
2594 #if !defined(ENABLE_EXTERNAL_SERVO_TIMER_HANDLER)
2600 #if !defined(DISABLE_PAUSE_RESUME)
2601 unsigned long tMillis = millis();
2631 #if defined(LOCAL_TRACE)
2635 bool tAllServosStopped =
true;
2641 #if defined(PRINT_FOR_SERIAL_PLOTTER)
2644 return tAllServosStopped;
2673 delay(aMillisDelay);
2695 uint_fast16_t tMillisForCompleteMove = 0;
2696 if (aSynchronizeToMinimumDuration) {
2697 tMillisForCompleteMove = __UINT16_MAX__;
2699 uint32_t tMillisAtStartMove = 0;
2704 if (aSynchronizeToMinimumDuration) {
2718 #if defined(LOCAL_TRACE)
2720 Serial.print(F(
" servos, MillisAtStartMove="));
2721 Serial.print(tMillisAtStartMove);
2722 Serial.print(F(
", MillisForCompleteMove="));
2723 Serial.println(tMillisForCompleteMove);
2738 if (aStartUpdateByInterrupt) {
2743 #if !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
2756 return (aFactorOfTimeCompletion * aFactorOfTimeCompletion);
2760 return (aFactorOfTimeCompletion *
QuadraticEaseIn(aFactorOfTimeCompletion));
2772 return sin((aFactorOfTimeCompletion - 1) * M_PI_2) + 1;
2781 return 1 - sqrt(1 - (aFactorOfTimeCompletion * aFactorOfTimeCompletion));
2789 return (aFactorOfTimeCompletion * aFactorOfTimeCompletion * aFactorOfTimeCompletion)
2790 - (aFactorOfTimeCompletion * sin(aFactorOfTimeCompletion * M_PI));
2798 return sin(13 * M_PI_2 * aFactorOfTimeCompletion) * pow(2, 10 * (aFactorOfTimeCompletion - 1));
2801 #define PART_OF_LINEAR_MOVEMENT 0.8
2802 #define PART_OF_BOUNCE_MOVEMENT (1.0 - PART_OF_LINEAR_MOVEMENT)
2803 #define PART_OF_BOUNCE_MOVEMENT_HALF ((1.0 - PART_OF_LINEAR_MOVEMENT) / 2) // 0.1
2805 #define OVERSHOOT_AMOUNT_MILLIS 50 // around 5 degree
2806 #define OVERSHOOT_AMOUNT_UNITS 10 // around 5 degree
2819 return aFactorOfTimeCompletion;
2822 aFactorOfTimeCompletion = 1 - aFactorOfTimeCompletion;
2833 return 1 - aFactorOfTimeCompletion;
2835 return aFactorOfTimeCompletion;
2841 float tRemainingFactor;
2846 tRemainingFactor = 1.0 - tRemainingFactor;
2854 #if defined(USE_PCA9685_SERVO_EXPANDER)
2855 # if defined(USE_SERVO_LIB)
2856 if (mServoIsConnectedToExpander) {
2874 - (tBumpMicrosecondsOrUnits * tRemainingFactor * tRemainingFactor));
2880 - tBumpMicrosecondsOrUnits;
2892 float tFactorOfMovementCompletion;
2893 if (aFactorOfTimeCompletion < 4 / 11.0) {
2894 tFactorOfMovementCompletion = (121 * aFactorOfTimeCompletion * aFactorOfTimeCompletion) / 16.0;
2895 }
else if (aFactorOfTimeCompletion < 8 / 11.0) {
2896 tFactorOfMovementCompletion = (363 / 40.0 * aFactorOfTimeCompletion * aFactorOfTimeCompletion)
2897 - (99 / 10.0 * aFactorOfTimeCompletion) + 17 / 5.0;
2898 }
else if (aFactorOfTimeCompletion < 9 / 10.0) {
2899 tFactorOfMovementCompletion = (4356 / 361.0 * aFactorOfTimeCompletion * aFactorOfTimeCompletion)
2900 - (35442 / 1805.0 * aFactorOfTimeCompletion) + 16061 / 1805.0;
2902 tFactorOfMovementCompletion = (54 / 5.0 * aFactorOfTimeCompletion * aFactorOfTimeCompletion)
2903 - (513 / 25.0 * aFactorOfTimeCompletion) + 268 / 25.0;
2905 return tFactorOfMovementCompletion;
2907 #endif // !defined(PROVIDE_ONLY_LINEAR_MOVEMENT)
2913 #if defined(USE_PCA9685_SERVO_EXPANDER)
2920 #if defined(__AVR__)
2921 bool ServoEasing::InitializeAndCheckI2CConnection(Print *aSerial)
2923 bool ServoEasing::InitializeAndCheckI2CConnection(Stream *aSerial)
2926 return initializeAndCheckI2CConnection(aSerial);
2928 #if defined(__AVR__)
2929 bool ServoEasing::initializeAndCheckI2CConnection(Print *aSerial)
2931 bool ServoEasing::initializeAndCheckI2CConnection(Stream *aSerial)
2934 #if !defined(USE_SOFT_I2C_MASTER)
2941 #if defined(__AVR__)
2948 bool tRetValue =
false;
2949 aSerial->print(F(
"Try to communicate with " STR(I2C_CLOCK_FREQUENCY)
" Hz with I2C device at address=0x"));
2950 aSerial->println(aI2CAddress, HEX);
2954 #if defined(USE_SOFT_I2C_MASTER)
2956 if(!i2c_start(aI2CAddress << 1)){
2957 aSerial->println(F(
"No acknowledge received from the slave"));
2958 aSerial->print(F(
"Communication with I2C was successful, but found no"));
2961 aSerial->print(F(
"Found"));
2964 aSerial->print(F(
" I2C device attached at address: 0x"));
2965 aSerial->println(aI2CAddress, HEX);
2967 aSerial->println(F(
"I2C init failed"));
2969 #else // defined(USE_SOFT_I2C_MASTER)
2971 # if defined (ARDUINO_ARCH_AVR) // Other platforms do not have this new function
2973 Wire.beginTransmission(aI2CAddress);
2974 if (Wire.getWireTimeoutFlag()) {
2975 aSerial->println(F(
"Timeout accessing I2C bus. Wait for bus becoming available"));
2976 Wire.clearWireTimeoutFlag();
2983 Wire.beginTransmission(aI2CAddress);
2986 uint8_t tWireReturnCode = Wire.endTransmission(
true);
2987 if (tWireReturnCode == 0) {
2988 aSerial->print(F(
"Found"));
2990 aSerial->print(F(
"Error code="));
2991 aSerial->print(tWireReturnCode);
2992 aSerial->print(F(
". Communication with I2C was successful, but found no"));
2995 aSerial->print(F(
" I2C device attached at address: 0x"));
2996 aSerial->println(aI2CAddress, HEX);
2997 #endif // defined(USE_SOFT_I2C_MASTER)
3000 aSerial->println(F(
"PCA9685 expander not connected. Check power supply, try to reduce I2C clock of " STR(I2C_CLOCK_FREQUENCY)
" Hz (I2C_CLOCK_FREQUENCY in ServoEasing.h) or pull-up resistor values."));
3004 # endif // defined(USE_PCA9685_SERVO_EXPANDER)
3006 #if defined(LOCAL_DEBUG)
3009 #if defined(LOCAL_TRACE)
3012 #endif // _SERVO_EASING_HPP