Teacup_Firmware
Teacup_Firmware copied to clipboard
Any pointers on how to attach a servo?
I wonder if there are any pointers on how to attach a servo? I know that M280 is not supported (because it's a > 255 code) but would not mind misusing anything here. Basically I need to send just two servo positions (aka two PWM codes but with the servo PWM freq. of 50 Hz).
In Teacup a servo is configured like a heater. It's not well-documented as it's rarely used. M106 is used to control the PWM for heaters and other devices. Servo math is funny, though. It's based on a 20ms duty cycle, regardless of the actual pulse repeat period. I guess you know this, already. 20ms = 50Hz.
I did some math here to attach a servo-like probe in the BLTouch z-probe. The resultant pulse-widths are dependent on the CPU frequency, among other things.
The math is pulse-width * 1024 * 256 / F_CPU
(F_CPU is 16MHz or 20MHz on AVRs).
The required pulse width seems to be 600 + DEGREES * 10
.
So, (600 + DEGREES * 10) * 1024 * 256 / F_CPU
gets your desired angle in heater steps for M106. For 90 degrees on a 16MHZ chip, (600 + 900) * 1024 * 256 / 16000000 = 24.6
==> M106 P3 S25
. (YMMV. I found S24 worked better on the Z-probe.)
I considered writing this into some servo-specific M-command a few months ago, but had trouble getting it to work reliably. I thought my math was overflowing somewhere, but I'm not sure I remember that right anymore. Since I don't have a known-quantity servo to test with here, I decided it was better to leave it for another day.
Make sure to choose a PWM pin that uses Timer0. The other pins are probably not configured correctly, and Timer1 is used internally.
Great, thanks for that! I'll see whether I can get it to work somehow. If so, I'll post feedback then.
Hmm. I implemented timer0 on a test sketch and it worked nicely. Once put into Teacup I realized that timer0 is already scaled for use with the heater PWM. I tried using timer2 but that instantly drove my extruder to send smoke signal. Seems to be more tricky than I thought :-/
@phord I'm a bit lost now. I tried a simple sketch (on a Mega2560) which produces nice servo ticks. But once I implant that (adapted) code into Teacup it loop-resets permanently once I start timer3. Any idea?
void setup() {
// put your setup code here, to run once:
for (int i = 3; i <= 13; i++) {
pinMode(i, OUTPUT);
digitalWrite(i, 1);
}
digitalWrite(3, 0);
digitalWrite(9, 0);
TCCR3A = 0;
TCCR3B = 0;
TCNT3 = 0;
OCR3A = 199;
TCCR3A |= (1 << WGM31);
TCCR3B |= (1 << CS31);
}
int servoTicks;
int servoWidth;
int servoDuty;
void timer0_start(int i) {
cli();
servoTicks = 0;
servoWidth = i;
servoDuty = 10; // 10 ticks ~ 0.2 sec
digitalWrite(3, 1);
TIMSK3 |= (1 << OCIE3A);
sei();
}
ISR(TIMER3_COMPA_vect){
servoTicks++;
if (servoTicks >= 80) {
servoTicks = 0;
digitalWrite(3, 1);
servoDuty--;
} else if (servoTicks == servoWidth) {
t[ptr++] = micros();
digitalWrite(3, 0);
if (servoDuty <= 0)
TIMSK3 &= ~ (1 << OCIE3A);
}
}
int w = 10;
void loop() {
delay(2000);
cli();
timer0_start(w);
w = 15-w;
sei();
}
Never mind.It seems as if I need to enclose TIMSK3 |= (1 << OCIE3A);
in cli/sei
.
Not working still, but the reset loop is gone.
I'd really appreciate some help now. I rather figured out how the heating PWM works. I'm using DIO7, 9 and 10 for bed, extruder and fan. On my Mega this will involve timers 2 and 4 for the PWM. So I used timer3 for my own purpose. I did set it like in the code snippet I posted above (without the ISR just resetting TIMSK3 once called). But after 5 seconds or so the Arduino gets a reset. Where is it that timer3 interferes somewhere the Arduino is reset???
First I would do very simple thing with the ISR for testing. Probably you could send one single char (ISR should always do its stuff very fast) through the serial line.
I don't know what would help me in that. I'm after a way to create a 50Hz signal with varying duty lengths (of about 1ms).
So your timer looks like doing the right thing? And after 5 seconds the Arduino is reseting? Where do you exactly implement your code?
Yes. The timer is definitely triggered, but after some 5 seconds the whole thing resets. I implemented it in heater-avr.c in the #ifdef TCCR3A
part and below the timer start routine/ISR
Please share your complete project/code somewhere.
I removed stuff I did not need. heater-avr.c and gcode_process.c contain the most important modifications. It's just hardcoded for the Atmega use (port 3 shall receive the servo PWM).
How did you test your changes? I see that you've implement a test gcode for yourself.
Yup. I just send a "G2", "G2 P0" or "G2 P1". They all trigger the timer once. For my purpose that will do since I anyway write the SW for the servo movement myself (rather than using the unreachable position servo code somewhere above 255).
I have just altered the PWM to SW and the reset is gone. I could live with that but still curious why the HW PWM interferes that way.
So (finally) I can confirm this works. You need to modify the timer setting in heater_avr.c and add an ISR like in the above example code. To trigger the servo movements for one of its (for me 2) positions you need to implement a M- or G-code. I just used G2 Px to call the timer_start routine. You could as well implement M24 as a substitute for M280 (servo position) as long as you don't have a SD-card. M24 because 280%256 = 24; Teacup just recognizes one byte for the code.
And as additional remark: The PWM now does not longer send the short pulses but are steadily off when not in use. So the noise from the fan during idle is now completely gone.