Open Silvanosky opened 5 years ago
@facchinm heya would y'all take a PR to fix this?
Hi @ladyada , we are going to merge the PR, no problem :wink:
I’m on it. It’s a little more involved than just the sync registers, but I should have something this afternoon.
A pull request has been made to arduino-libraries:master. If you need it sooner than the next merge, can be downloaded here: https://github.com/PaintYourDragon/Servo
Thank you for the fix, this has been driving me crazy for weeks! Was about to attempt to write my own PWM class. It is compiling for me now.
Please note, in your existing sketch, copy the servo.h from this updated library which you will download and place in your Arduino libraries folder under servo-master, into whatever sketch you are using.
I tried this, but I still get a number of compiler errors when compiling for the Adafruit ItsyBitsy M4 (SAMD51).
In file included from /home/rlpepe/Arduino/libraries/Servo-master/src/Servo.h:67:0,
from /home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:22:
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp: In function 'void TC4_Handler()':
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/ServoTimers.h:41:35: error: 'TC4' was not declared in this scope
#define TC_FOR_TIMER1 TC4
^
I get the same for a number of other macro definitions. The list is much shorter than before updating the library, but I still can't compile successfully. Any thoughts?
Tc4 needs to be a declared variable?
At top add :
const int TC4;
TC4 = 4;
Hi, since I'm working on Marlin and I integrated Grand Central M4 into it, this servo library will be very helpful if integrated into libraries (Marlin uses platformIO but I think this is not a problem). There are some news about the status of this?
There seem to be a number of issues yet to resolve to support the SAMD51 (compiles fine for the SAMD21 though). Here's the complete list of compiler messages when compiling for the Adafruit ItsyBitsy M4:
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp: In function 'void TC4_Handler()':
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:63:86: error: invalid conversion from 'int' to 'Tc*' [-fpermissive]
Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, INTFLAG_BIT_FOR_TIMER_1);
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:60:6: error: initializing argument 2 of 'void Servo_Handler(timer16_Sequence_t, Tc*, uint8_t, uint8_t)' [-fpermissive]
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel, uint8_t intFlag);
^
In file included from /home/rlpepe/Arduino/libraries/Servo-master/src/Servo.h:67:0,
from /home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:22:
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp: In function 'void initISR(timer16_Sequence_t)':
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/ServoTimers.h:48:35: error: 'ID_TC4' was not declared in this scope
#define ID_TC_FOR_TIMER1 ID_TC4
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:251:53: note: in expansion of macro 'ID_TC_FOR_TIMER1'
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/ServoTimers.h:49:35: error: 'TC4_IRQn' was not declared in this scope
#define IRQn_FOR_TIMER1 TC4_IRQn
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:251:71: note: in expansion of macro 'IRQn_FOR_TIMER1'
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp: In function 'void finISR(timer16_Sequence_t)':
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:263:18: error: base operand of '->' is not a pointer
TC_FOR_TIMER1->COUNT16.INTENCLR.reg = INTENCLR_BIT_FOR_TIMER_1;
^
@richard-pepe that sound weird, I temporary added #28 in Marlin and it compile fine for samd51 (don't know if it works because I don't have proper H/W to test)
I gave it a shot, but still doesn't compile.
In file included from /home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/Servo.h:67:0,
from /home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp:19:
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp: In function 'void TC4_Handler()':
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/ServoTimers.h:41:35: error: 'TC4' was not declared in this scope
#define TC_FOR_TIMER1 TC4
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp:60:28: note: in expansion of macro 'TC_FOR_TIMER1'
Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, INTFLAG_BIT_FOR_TIMER_1);
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp: In function 'void initISR(timer16_Sequence_t)':
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/ServoTimers.h:41:35: error: 'TC4' was not declared in this scope
#define TC_FOR_TIMER1 TC4
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp:248:18: note: in expansion of macro 'TC_FOR_TIMER1'
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/ServoTimers.h:46:35: error: 'ID_TC4' was not declared in this scope
#define ID_TC_FOR_TIMER1 ID_TC4
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp:248:53: note: in expansion of macro 'ID_TC_FOR_TIMER1'
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/ServoTimers.h:47:35: error: 'TC4_IRQn' was not declared in this scope
#define IRQn_FOR_TIMER1 TC4_IRQn
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp:248:71: note: in expansion of macro 'IRQn_FOR_TIMER1'
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp: In function 'void finISR(timer16_Sequence_t)':
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/ServoTimers.h:41:35: error: 'TC4' was not declared in this scope
#define TC_FOR_TIMER1 TC4
^
/home/rlpepe/Downloads/arduino-1.8.5-linux64/arduino-1.8.5/libraries/Servo/src/samd/Servo.cpp:260:5: note: in expansion of macro 'TC_FOR_TIMER1'
TC_FOR_TIMER1->COUNT16.INTENCLR.reg = INTENCLR_BIT_FOR_TIMER_1;
^
Looks like the timer function is not properly populating. In servo.cpp
comment out function void tc4_handler()
In marlin I have done some job on it and now it should works. Maybe some hints may be got from there
Not working for me. A number of things aren't defined (TC4, ID_TC4, TC4_IRQn) along with other issues:
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp: In function 'void TC4_Handler()':
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:60:86: error: invalid conversion from 'int' to 'Tc*' [-fpermissive]
Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, INTFLAG_BIT_FOR_TIMER_1);
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:57:6: error: initializing argument 2 of 'void Servo_Handler(timer16_Sequence_t, Tc*, uint8_t, uint8_t)' [-fpermissive]
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel, uint8_t intFlag);
^
In file included from /home/rlpepe/Arduino/libraries/Servo-master/src/Servo.h:67:0,
from /home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:19:
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp: In function 'void initISR(timer16_Sequence_t)':
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/ServoTimers.h:48:35: error: 'ID_TC4' was not declared in this scope
#define ID_TC_FOR_TIMER1 ID_TC4
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:248:53: note: in expansion of macro 'ID_TC_FOR_TIMER1'
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/ServoTimers.h:49:35: error: 'TC4_IRQn' was not declared in this scope
#define IRQn_FOR_TIMER1 TC4_IRQn
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:248:71: note: in expansion of macro 'IRQn_FOR_TIMER1'
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
^
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp: In function 'void finISR(timer16_Sequence_t)':
/home/rlpepe/Arduino/libraries/Servo-master/src/samd/Servo.cpp:260:18: error: base operand of '->' is not a pointer
TC_FOR_TIMER1->COUNT16.INTENCLR.reg = INTENCLR_BIT_FOR_TIMER_1;
I am starting to think that the issues are chipset compatibility issues with the newer samd. Those functions may require cosimg updates in the libraries.
I grabbed the fork that @PaintYourDragon posted, and that compiled fine for me. However, it only seems to work with the first servo object defined. If, for example, I have code like this:
Servo s1;
s1.attach(3);
s1.write(100);
Servo s2;
s2.attach(4);
s2.write(100);
the servo attached to pin 3 responds appropriately and my scope shows what looks like a reasonable PWM signal, but the servo on pin 4 doesn't move and the signal on the scope is not at all the same. If I change the order, so s2 is defined before s1, then s2 works and s1 doesn't. The issue seems to be related only to the order in which the objects are instantiated, and doesn't have anything to do with what pins are in use. It also doesn't seem to matter whether I call the attach method on the first servo or not; the second servo still doesn't get the right signal.
At a suggestion from adafruit_support_bill, I've copied this comment from a post I made over on the Adafruit forum, where there's a screenshot from my scope showing the signals being generated. Happy to help troubleshoot from here if I can.
hiya please try https://github.com/arduino-libraries/Servo/pull/34 which should compie & work with samd51g19 and j19
multiple-servos also fixed
Not sure if it works (I don't have a valid shield to test) and/or may be usefull. This is what I did in Marlin to support both timers:
HAL_SERVO_TIMER_ISR() {
Tc * const tc = TimerConfig[SERVO_TC].pTimer;
const timer16_Sequence_t timer =
#ifndef _useTimer1
_timer2
#elif !defined(_useTimer2)
_timer1
#else
(tc->COUNT16.INTFLAG.reg & tc->COUNT16.INTENSET.reg & TC_INTFLAG_MC0) ? _timer1 : _timer2
#endif
;
const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
if (currentServoIndex[timer] < 0) {
#if defined(_useTimer1) && defined(_useTimer2)
if (currentServoIndex[timer ^ 1] >= 0) {
// Wait for both channels
// Clear the interrupt
tc->COUNT16.INTFLAG.reg = (tcChannel == 0) ? TC_INTFLAG_MC0 : TC_INTFLAG_MC1;
return;
}
#endif
tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL;
SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
}
else if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive)
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated
// Select the next servo controlled by this timer
currentServoIndex[timer]++;
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && currentServoIndex[timer] < SERVOS_PER_TIMER) {
if (SERVO(timer, currentServoIndex[timer]).Pin.isActive) // check if activated
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, currentServoIndex[timer]).ticks;
}
else {
// finished all channels so wait for the refresh period to expire before starting over
currentServoIndex[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
const uint16_t tcCounterValue = getTimerCount();
if ((TC_COUNTER_START_VAL - tcCounterValue) + 4UL < usToTicks(REFRESH_INTERVAL)) // allow a few ticks to ensure the next OCR1A not missed
tc->COUNT16.CC[tcChannel].reg = TC_COUNTER_START_VAL - (uint16_t)usToTicks(REFRESH_INTERVAL);
else
tc->COUNT16.CC[tcChannel].reg = (uint16_t)(tcCounterValue - 4UL); // at least REFRESH_INTERVAL has elapsed
}
if (tcChannel == 0) {
SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
// Clear the interrupt
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
}
else {
SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
// Clear the interrupt
tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1;
}
SYNC(a)
is a define that just do while(a)
#define TIMER_TCCHANNEL(t) ((t) & 1)
because I tied timerN with channel
we're doing something similar here, we wanted to be as close to the samd21 implementation as possible
yes but SAMD51 CC0 and CC1 share the same timer count, so something different must be done
hiya please explain in more detail. we're using all of TC0, for now just CC0 but it doesnt matter because CC1 wont be usable by anything else anyways. please reference the PR - we want to make this as similar as possible to the SAMD21 code so that means not refactoring the ISR
I'll try to explain, but it's not easy due to the fact English is not my natural language. Code should support 2 timers (timer1 and timer2), both share TC0 and use both TC0 channels (0 and 1) these compare COUNT to CC0 and CC1. Once CC0 terminates its job COUNT is reset but since also CC1 is using the same COUNT value you will change its timing. AFAIK samd21 has separate counts for channels
OK i know what you're saying - it seems SAMD21 has only one COUNT per timer as well?
Table 30-5. Register Summary – 16-bit Mode
oh yes it seems..but how can it works on samd21?
oh how stupid I am...I read it but I was thinking only at samd51...but 21 is also samd...
Hi,
The implementation for the samd servo library doesn't work on samd51.
The syncbusy bit and clock management are different on this new chip so the code here need to be adapted for samd51.
For example when I try to compile the sweep example for the Feather M4 I get this :