SAMD51 Servo class (#14781)
This commit is contained in:
parent
8efa3455c2
commit
21993b75f4
|
@ -54,7 +54,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
|
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
|
||||||
#define PRESCALER 8 // timer prescaler
|
#define SERVO_TIMER_PRESCALER 8 // timer prescaler
|
||||||
|
|
||||||
// Say which 16 bit timers can be used and in what order
|
// Say which 16 bit timers can be used and in what order
|
||||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#define _useTimer5
|
#define _useTimer5
|
||||||
|
|
||||||
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
|
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
|
||||||
#define PRESCALER 32 // timer prescaler
|
#define SERVO_TIMER_PRESCALER 32 // timer prescaler
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TC0, chan 0 => TC0_Handler
|
TC0, chan 0 => TC0_Handler
|
||||||
|
|
|
@ -193,8 +193,8 @@ uint16_t HAL_adc_result;
|
||||||
uint16_t HAL_adc_results[COUNT(adc_pins)];
|
uint16_t HAL_adc_results[COUNT(adc_pins)];
|
||||||
|
|
||||||
#if ADC0_IS_REQUIRED
|
#if ADC0_IS_REQUIRED
|
||||||
Adafruit_ZeroDMA adc0ProgramDMA,
|
Adafruit_ZeroDMA adc0DMAProgram,
|
||||||
adc0ReadDMA;
|
adc0DMARead;
|
||||||
|
|
||||||
const HAL_DMA_DAC_Registers adc0_dma_regs_list[] = {
|
const HAL_DMA_DAC_Registers adc0_dma_regs_list[] = {
|
||||||
#if GET_TEMP_0_ADC() == 0
|
#if GET_TEMP_0_ADC() == 0
|
||||||
|
@ -233,8 +233,8 @@ uint16_t HAL_adc_result;
|
||||||
#endif // ADC0_IS_REQUIRED
|
#endif // ADC0_IS_REQUIRED
|
||||||
|
|
||||||
#if ADC1_IS_REQUIRED
|
#if ADC1_IS_REQUIRED
|
||||||
Adafruit_ZeroDMA adc1ProgramDMA,
|
Adafruit_ZeroDMA adc1DMAProgram,
|
||||||
adc1ReadDMA;
|
adc1DMARead;
|
||||||
|
|
||||||
const HAL_DMA_DAC_Registers adc1_dma_regs_list[] = {
|
const HAL_DMA_DAC_Registers adc1_dma_regs_list[] = {
|
||||||
#if GET_TEMP_0_ADC() == 1
|
#if GET_TEMP_0_ADC() == 1
|
||||||
|
@ -284,11 +284,11 @@ uint16_t HAL_adc_result;
|
||||||
DmacDescriptor *descriptor;
|
DmacDescriptor *descriptor;
|
||||||
|
|
||||||
#if ADC0_IS_REQUIRED
|
#if ADC0_IS_REQUIRED
|
||||||
adc0ProgramDMA.setTrigger(ADC0_DMAC_ID_SEQ);
|
adc0DMAProgram.setTrigger(ADC0_DMAC_ID_SEQ);
|
||||||
adc0ProgramDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
|
adc0DMAProgram.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||||
adc0ProgramDMA.loop(true);
|
adc0DMAProgram.loop(true);
|
||||||
if (adc0ProgramDMA.allocate() == DMA_STATUS_OK) {
|
if (adc0DMAProgram.allocate() == DMA_STATUS_OK) {
|
||||||
descriptor = adc0ProgramDMA.addDescriptor(
|
descriptor = adc0DMAProgram.addDescriptor(
|
||||||
(void *)adc0_dma_regs_list, // SRC
|
(void *)adc0_dma_regs_list, // SRC
|
||||||
(void *)&ADC0->DSEQDATA.reg, // DEST
|
(void *)&ADC0->DSEQDATA.reg, // DEST
|
||||||
sizeof(adc0_dma_regs_list) / 4, // CNT
|
sizeof(adc0_dma_regs_list) / 4, // CNT
|
||||||
|
@ -300,14 +300,14 @@ uint16_t HAL_adc_result;
|
||||||
);
|
);
|
||||||
if (descriptor != nullptr)
|
if (descriptor != nullptr)
|
||||||
descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT;
|
descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT;
|
||||||
adc0ProgramDMA.startJob();
|
adc0DMAProgram.startJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
adc0ReadDMA.setTrigger(ADC0_DMAC_ID_RESRDY);
|
adc0DMARead.setTrigger(ADC0_DMAC_ID_RESRDY);
|
||||||
adc0ReadDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
|
adc0DMARead.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||||
adc0ReadDMA.loop(true);
|
adc0DMARead.loop(true);
|
||||||
if (adc0ReadDMA.allocate() == DMA_STATUS_OK) {
|
if (adc0DMARead.allocate() == DMA_STATUS_OK) {
|
||||||
adc0ReadDMA.addDescriptor(
|
adc0DMARead.addDescriptor(
|
||||||
(void *)&ADC0->RESULT.reg, // SRC
|
(void *)&ADC0->RESULT.reg, // SRC
|
||||||
&HAL_adc_results, // DEST
|
&HAL_adc_results, // DEST
|
||||||
ADC0_AINCOUNT, // CNT
|
ADC0_AINCOUNT, // CNT
|
||||||
|
@ -317,15 +317,15 @@ uint16_t HAL_adc_result;
|
||||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
|
DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
|
||||||
DMA_STEPSEL_DST // STEPSEL
|
DMA_STEPSEL_DST // STEPSEL
|
||||||
);
|
);
|
||||||
adc0ReadDMA.startJob();
|
adc0DMARead.startJob();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if ADC1_IS_REQUIRED
|
#if ADC1_IS_REQUIRED
|
||||||
adc1ProgramDMA.setTrigger(ADC1_DMAC_ID_SEQ);
|
adc1DMAProgram.setTrigger(ADC1_DMAC_ID_SEQ);
|
||||||
adc1ProgramDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
|
adc1DMAProgram.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||||
adc1ProgramDMA.loop(true);
|
adc1DMAProgram.loop(true);
|
||||||
if (adc1ProgramDMA.allocate() == DMA_STATUS_OK) {
|
if (adc1DMAProgram.allocate() == DMA_STATUS_OK) {
|
||||||
descriptor = adc1ProgramDMA.addDescriptor(
|
descriptor = adc1DMAProgram.addDescriptor(
|
||||||
(void *)adc1_dma_regs_list, // SRC
|
(void *)adc1_dma_regs_list, // SRC
|
||||||
(void *)&ADC1->DSEQDATA.reg, // DEST
|
(void *)&ADC1->DSEQDATA.reg, // DEST
|
||||||
sizeof(adc1_dma_regs_list) / 4, // CNT
|
sizeof(adc1_dma_regs_list) / 4, // CNT
|
||||||
|
@ -337,14 +337,14 @@ uint16_t HAL_adc_result;
|
||||||
);
|
);
|
||||||
if (descriptor != nullptr)
|
if (descriptor != nullptr)
|
||||||
descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT;
|
descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT;
|
||||||
adc1ProgramDMA.startJob();
|
adc1DMAProgram.startJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
adc1ReadDMA.setTrigger(ADC1_DMAC_ID_RESRDY);
|
adc1DMARead.setTrigger(ADC1_DMAC_ID_RESRDY);
|
||||||
adc1ReadDMA.setAction(DMA_TRIGGER_ACTON_BEAT);
|
adc1DMARead.setAction(DMA_TRIGGER_ACTON_BEAT);
|
||||||
adc1ReadDMA.loop(true);
|
adc1DMARead.loop(true);
|
||||||
if (adc1ReadDMA.allocate() == DMA_STATUS_OK) {
|
if (adc1DMARead.allocate() == DMA_STATUS_OK) {
|
||||||
adc1ReadDMA.addDescriptor(
|
adc1DMARead.addDescriptor(
|
||||||
(void *)&ADC1->RESULT.reg, // SRC
|
(void *)&ADC1->RESULT.reg, // SRC
|
||||||
&HAL_adc_results[ADC0_AINCOUNT], // DEST
|
&HAL_adc_results[ADC0_AINCOUNT], // DEST
|
||||||
ADC1_AINCOUNT, // CNT
|
ADC1_AINCOUNT, // CNT
|
||||||
|
@ -354,11 +354,11 @@ uint16_t HAL_adc_result;
|
||||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
|
DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
|
||||||
DMA_STEPSEL_DST // STEPSEL
|
DMA_STEPSEL_DST // STEPSEL
|
||||||
);
|
);
|
||||||
adc1ReadDMA.startJob();
|
adc1DMARead.startJob();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DMAC->PRICTRL0.bit.RRLVLEN0 = true; // Activate round robin for DMA channels used by ADCs
|
DMAC->PRICTRL0.bit.RRLVLEN0 = true; // Activate round robin for DMA channels required by ADCs
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // DMA_IS_REQUIRED
|
#endif // DMA_IS_REQUIRED
|
||||||
|
|
|
@ -76,7 +76,8 @@
|
||||||
|
|
||||||
typedef int8_t pin_t;
|
typedef int8_t pin_t;
|
||||||
|
|
||||||
//#define HAL_SERVO_LIB Servo
|
#define SHARED_SERVOS HAS_SERVOS
|
||||||
|
#define HAL_SERVO_LIB Servo
|
||||||
|
|
||||||
//
|
//
|
||||||
// Interrupts
|
// Interrupts
|
||||||
|
|
|
@ -40,8 +40,8 @@
|
||||||
const tTimerConfig TimerConfig[NUM_HARDWARE_TIMERS] = {
|
const tTimerConfig TimerConfig[NUM_HARDWARE_TIMERS] = {
|
||||||
{ TC0, TC0_IRQn, TC_PRIORITY(0) },
|
{ TC0, TC0_IRQn, TC_PRIORITY(0) },
|
||||||
{ TC1, TC1_IRQn, TC_PRIORITY(1) },
|
{ TC1, TC1_IRQn, TC_PRIORITY(1) },
|
||||||
{ TC2, TC2_IRQn, TC_PRIORITY(2) },
|
{ TC2, TC2_IRQn, TC_PRIORITY(2) }, // Reserved by framework tone function
|
||||||
{ TC3, TC3_IRQn, TC_PRIORITY(3) },
|
{ TC3, TC3_IRQn, TC_PRIORITY(3) }, // Reserved by servo library
|
||||||
{ TC4, TC4_IRQn, TC_PRIORITY(4) },
|
{ TC4, TC4_IRQn, TC_PRIORITY(4) },
|
||||||
{ TC5, TC5_IRQn, TC_PRIORITY(5) },
|
{ TC5, TC5_IRQn, TC_PRIORITY(5) },
|
||||||
{ TC6, TC6_IRQn, TC_PRIORITY(6) },
|
{ TC6, TC6_IRQn, TC_PRIORITY(6) },
|
||||||
|
|
|
@ -33,7 +33,6 @@ typedef uint32_t hal_timer_t;
|
||||||
|
|
||||||
#define STEP_TIMER_NUM 0 // index of timer to use for stepper (also +1 for 32bits counter)
|
#define STEP_TIMER_NUM 0 // index of timer to use for stepper (also +1 for 32bits counter)
|
||||||
#define PULSE_TIMER_NUM STEP_TIMER_NUM
|
#define PULSE_TIMER_NUM STEP_TIMER_NUM
|
||||||
#define TONE_TIMER_NUM 2 // index of timer to use for beeper tones (also +1 for 32bits counter)
|
|
||||||
#define TEMP_TIMER_NUM 4 // index of timer to use for temperature (also +1 for 32bits counter)
|
#define TEMP_TIMER_NUM 4 // index of timer to use for temperature (also +1 for 32bits counter)
|
||||||
|
|
||||||
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
|
#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
|
||||||
|
@ -55,7 +54,8 @@ typedef uint32_t hal_timer_t;
|
||||||
|
|
||||||
#define TC_PRIORITY(t) (t == STEP_TIMER_NUM || t == PULSE_TIMER_NUM) ? 2 \
|
#define TC_PRIORITY(t) (t == STEP_TIMER_NUM || t == PULSE_TIMER_NUM) ? 2 \
|
||||||
: (t == TEMP_TIMER_NUM) ? 6 \
|
: (t == TEMP_TIMER_NUM) ? 6 \
|
||||||
: (t == TONE_TIMER_NUM) ? 5 : 7
|
: 7
|
||||||
|
|
||||||
#define _TC_HANDLER(t) void TC##t##_Handler()
|
#define _TC_HANDLER(t) void TC##t##_Handler()
|
||||||
#define TC_HANDLER(t) _TC_HANDLER(t)
|
#define TC_HANDLER(t) _TC_HANDLER(t)
|
||||||
#define HAL_STEP_TIMER_ISR() TC_HANDLER(STEP_TIMER_NUM)
|
#define HAL_STEP_TIMER_ISR() TC_HANDLER(STEP_TIMER_NUM)
|
||||||
|
@ -63,7 +63,6 @@ typedef uint32_t hal_timer_t;
|
||||||
#define HAL_PULSE_TIMER_ISR() TC_HANDLER(PULSE_TIMER_NUM)
|
#define HAL_PULSE_TIMER_ISR() TC_HANDLER(PULSE_TIMER_NUM)
|
||||||
#endif
|
#endif
|
||||||
#define HAL_TEMP_TIMER_ISR() TC_HANDLER(TEMP_TIMER_NUM)
|
#define HAL_TEMP_TIMER_ISR() TC_HANDLER(TEMP_TIMER_NUM)
|
||||||
#define HAL_TONE_TIMER_ISR() TC_HANDLER(TONE_TIMER_NUM)
|
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
// Types
|
// Types
|
||||||
|
|
39
Marlin/src/HAL/HAL_SAMD51/ServoTimers.h
Normal file
39
Marlin/src/HAL/HAL_SAMD51/ServoTimers.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* Marlin 3D Printer Firmware
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||||
|
* SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _useTimer1
|
||||||
|
#define _useTimer2
|
||||||
|
|
||||||
|
#define TRIM_DURATION 5 // compensation ticks to trim adjust for digitalWrite delays
|
||||||
|
#define SERVO_TIMER_PRESCALER 64 // timer prescaler factor to 64 (avoid overflowing 16-bit clock counter, at 120MHz this is 1831 ticks per millisecond
|
||||||
|
|
||||||
|
#define SERVO_TC 3
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
#ifdef _useTimer1
|
||||||
|
_timer1,
|
||||||
|
#endif
|
||||||
|
#ifdef _useTimer2
|
||||||
|
_timer2,
|
||||||
|
#endif
|
||||||
|
_Nbr_16timers
|
||||||
|
} timer16_Sequence_t;
|
226
Marlin/src/HAL/HAL_SAMD51/Servo_SAMD51.cpp
Normal file
226
Marlin/src/HAL/HAL_SAMD51/Servo_SAMD51.cpp
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
/**
|
||||||
|
* Marlin 3D Printer Firmware
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||||
|
* SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This comes from Arduino library which at the moment is buggy and uncompilable
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __SAMD51__
|
||||||
|
|
||||||
|
#include "../../inc/MarlinConfig.h"
|
||||||
|
|
||||||
|
#if HAS_SERVOS
|
||||||
|
|
||||||
|
#include "../shared/Marduino.h"
|
||||||
|
#include "../shared/servo.h"
|
||||||
|
#include "../shared/servo_private.h"
|
||||||
|
#include "SAMD51.h"
|
||||||
|
#include "HAL_timers_SAMD51.h"
|
||||||
|
|
||||||
|
#define __TC_GCLK_ID(t) TC##t##_GCLK_ID
|
||||||
|
#define _TC_GCLK_ID(t) __TC_GCLK_ID(t)
|
||||||
|
#define TC_GCLK_ID _TC_GCLK_ID(SERVO_TC)
|
||||||
|
|
||||||
|
#define _TC_PRESCALER(d) TC_CTRLA_PRESCALER_DIV##d##_Val
|
||||||
|
#define TC_PRESCALER(d) _TC_PRESCALER(d)
|
||||||
|
|
||||||
|
#define __SERVO_IRQn(t) TC##t##_IRQn
|
||||||
|
#define _SERVO_IRQn(t) __SERVO_IRQn(t)
|
||||||
|
#define SERVO_IRQn _SERVO_IRQn(SERVO_TC)
|
||||||
|
|
||||||
|
#define HAL_SERVO_TIMER_ISR() TC_HANDLER(SERVO_TC)
|
||||||
|
|
||||||
|
#define TIMER_TCCHANNEL(t) ((t) & 1)
|
||||||
|
#define TC_COUNTER_START_VAL 0xFFFF
|
||||||
|
|
||||||
|
|
||||||
|
static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval)
|
||||||
|
|
||||||
|
FORCE_INLINE static uint16_t getTimerCount() {
|
||||||
|
Tc * const tc = TimerConfig[SERVO_TC].pTimer;
|
||||||
|
|
||||||
|
tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_CMD_READSYNC;
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB || tc->COUNT16.SYNCBUSY.bit.COUNT);
|
||||||
|
|
||||||
|
return tc->COUNT16.COUNT.reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------
|
||||||
|
// Interrupt handler for the TC
|
||||||
|
// ----------------------------
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initISR(timer16_Sequence_t timer) {
|
||||||
|
Tc * const tc = TimerConfig[SERVO_TC].pTimer;
|
||||||
|
const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
|
||||||
|
|
||||||
|
static bool initialized = false; // Servo TC has been initialized
|
||||||
|
if (!initialized) {
|
||||||
|
NVIC_DisableIRQ(SERVO_IRQn);
|
||||||
|
|
||||||
|
// Disable the timer
|
||||||
|
tc->COUNT16.CTRLA.bit.ENABLE = false;
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
|
||||||
|
|
||||||
|
// Select GCLK0 as timer/counter input clock source
|
||||||
|
GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN = false;
|
||||||
|
SYNC(GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
|
||||||
|
GCLK->PCHCTRL[TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 120MHz startup code programmed
|
||||||
|
SYNC(!GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
|
||||||
|
|
||||||
|
// Reset the timer
|
||||||
|
tc->COUNT16.CTRLA.bit.SWRST = true;
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.SWRST);
|
||||||
|
SYNC(tc->COUNT16.CTRLA.bit.SWRST);
|
||||||
|
|
||||||
|
// Set timer counter mode to 16 bits
|
||||||
|
tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16;
|
||||||
|
|
||||||
|
// Set timer counter mode as normal PWM
|
||||||
|
tc->COUNT16.WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
|
||||||
|
|
||||||
|
// Set the prescaler factor
|
||||||
|
tc->COUNT16.CTRLA.bit.PRESCALER = TC_PRESCALER(SERVO_TIMER_PRESCALER);
|
||||||
|
|
||||||
|
// Count down
|
||||||
|
tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_DIR;
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB);
|
||||||
|
|
||||||
|
// Reset all servo indexes
|
||||||
|
memset(currentServoIndex, 0xFF, sizeof(currentServoIndex));
|
||||||
|
|
||||||
|
// Configure interrupt request
|
||||||
|
NVIC_ClearPendingIRQ(SERVO_IRQn);
|
||||||
|
NVIC_SetPriority(SERVO_IRQn, 5);
|
||||||
|
NVIC_EnableIRQ(SERVO_IRQn);
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tc->COUNT16.CTRLA.bit.ENABLE) {
|
||||||
|
// Reset the timer counter
|
||||||
|
tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL;
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
|
||||||
|
|
||||||
|
// Enable the timer and start it
|
||||||
|
tc->COUNT16.CTRLA.bit.ENABLE = true;
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
|
||||||
|
}
|
||||||
|
// First interrupt request after 1 ms
|
||||||
|
tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)usToTicks(1000UL);
|
||||||
|
|
||||||
|
if (tcChannel == 0 ) {
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
|
||||||
|
|
||||||
|
// Clear pending match interrupt
|
||||||
|
tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC0;
|
||||||
|
// Enable the match channel interrupt request
|
||||||
|
tc->COUNT16.INTENSET.reg = TC_INTENSET_MC0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
|
||||||
|
|
||||||
|
// Clear pending match interrupt
|
||||||
|
tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC1;
|
||||||
|
// Enable the match channel interrupt request
|
||||||
|
tc->COUNT16.INTENSET.reg = TC_INTENSET_MC1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void finISR(timer16_Sequence_t timer) {
|
||||||
|
Tc * const tc = TimerConfig[SERVO_TC].pTimer;
|
||||||
|
const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
|
||||||
|
|
||||||
|
// Disable the match channel interrupt request
|
||||||
|
tc->COUNT16.INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1;
|
||||||
|
|
||||||
|
if (true
|
||||||
|
#if defined(_useTimer1) && defined(_useTimer2)
|
||||||
|
&& (tc->COUNT16.INTENCLR.reg & (TC_INTENCLR_MC0|TC_INTENCLR_MC1)) == 0
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
// Disable the timer if not used
|
||||||
|
tc->COUNT16.CTRLA.bit.ENABLE = false;
|
||||||
|
SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // HAS_SERVOS
|
||||||
|
|
||||||
|
#endif // __SAMD51__
|
|
@ -1,59 +0,0 @@
|
||||||
/**
|
|
||||||
* Marlin 3D Printer Firmware
|
|
||||||
*
|
|
||||||
* Copyright (C) 2019 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
|
||||||
* SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description: Tone function for Arduino Due and compatible (SAM3X8E)
|
|
||||||
* Derived from http://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef __SAMD51__
|
|
||||||
|
|
||||||
#include "../../inc/MarlinConfig.h"
|
|
||||||
#include "HAL_timers_SAMD51.h"
|
|
||||||
|
|
||||||
static pin_t tone_pin;
|
|
||||||
volatile static int32_t toggles;
|
|
||||||
|
|
||||||
void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration) {
|
|
||||||
tone_pin = _pin;
|
|
||||||
toggles = 2 * frequency * duration / 1000;
|
|
||||||
HAL_timer_start(TONE_TIMER_NUM, 2 * frequency);
|
|
||||||
}
|
|
||||||
|
|
||||||
void noTone(const pin_t _pin) {
|
|
||||||
HAL_timer_disable_interrupt(TONE_TIMER_NUM);
|
|
||||||
extDigitalWrite(_pin, LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
HAL_TONE_TIMER_ISR() {
|
|
||||||
static bool pin_state = false;
|
|
||||||
HAL_timer_isr_prologue(TONE_TIMER_NUM);
|
|
||||||
|
|
||||||
if (toggles) {
|
|
||||||
toggles--;
|
|
||||||
extDigitalWrite(tone_pin, (pin_state = !pin_state));
|
|
||||||
}
|
|
||||||
else noTone(tone_pin); // turn off interrupt
|
|
||||||
|
|
||||||
HAL_timer_isr_epilogue(TONE_TIMER_NUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __SAMD51__
|
|
|
@ -32,8 +32,6 @@
|
||||||
|
|
||||||
#define NUM_HARDWARE_TIMERS 2
|
#define NUM_HARDWARE_TIMERS 2
|
||||||
|
|
||||||
//#define PRESCALER 1
|
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// Private Variables
|
// Private Variables
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
|
@ -33,8 +33,6 @@
|
||||||
#define STEP_TIMER_IRQ_ID TIM5_IRQn
|
#define STEP_TIMER_IRQ_ID TIM5_IRQn
|
||||||
#define TEMP_TIMER_IRQ_ID TIM7_IRQn
|
#define TEMP_TIMER_IRQ_ID TIM7_IRQn
|
||||||
|
|
||||||
//#define PRESCALER 1
|
|
||||||
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// Private Variables
|
// Private Variables
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
|
|
@ -116,9 +116,8 @@ void Servo::detach() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Servo::write(int value) {
|
void Servo::write(int value) {
|
||||||
if (value < MIN_PULSE_WIDTH) { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
|
if (value < MIN_PULSE_WIDTH) // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
|
||||||
value = map(constrain(value, 0, 180), 0, 180, SERVO_MIN(), SERVO_MAX());
|
value = map(constrain(value, 0, 180), 0, 180, SERVO_MIN(), SERVO_MAX());
|
||||||
}
|
|
||||||
this->writeMicroseconds(value);
|
this->writeMicroseconds(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +139,7 @@ void Servo::writeMicroseconds(int value) {
|
||||||
int Servo::read() { return map(this->readMicroseconds() + 1, SERVO_MIN(), SERVO_MAX(), 0, 180); }
|
int Servo::read() { return map(this->readMicroseconds() + 1, SERVO_MIN(), SERVO_MAX(), 0, 180); }
|
||||||
|
|
||||||
int Servo::readMicroseconds() {
|
int Servo::readMicroseconds() {
|
||||||
return (this->servoIndex == INVALID_SERVO) ? 0 : ticksToUs(servo_info[this->servoIndex].ticks) + TRIM_DURATION;
|
return (this->servoIndex == INVALID_SERVO) ? 0 : ticksToUs(servo_info[this->servoIndex].ticks) + (TRIM_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Servo::attached() { return servo_info[this->servoIndex].Pin.isActive; }
|
bool Servo::attached() { return servo_info[this->servoIndex].Pin.isActive; }
|
||||||
|
|
|
@ -84,10 +84,10 @@
|
||||||
#else
|
#else
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if defined(__AVR__) || defined(ARDUINO_ARCH_SAM)
|
#if defined(__AVR__) || defined(ARDUINO_ARCH_SAM) || defined (__SAMD51__)
|
||||||
// we're good to go
|
// we're good to go
|
||||||
#else
|
#else
|
||||||
#error "This library only supports boards with an AVR or SAM3X processor."
|
#error "This library only supports boards with an AVR, SAM3X or SAMD51 processor."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define Servo_VERSION 2 // software version of this library
|
#define Servo_VERSION 2 // software version of this library
|
||||||
|
|
|
@ -47,8 +47,10 @@
|
||||||
#include "../HAL_AVR/ServoTimers.h"
|
#include "../HAL_AVR/ServoTimers.h"
|
||||||
#elif defined(ARDUINO_ARCH_SAM)
|
#elif defined(ARDUINO_ARCH_SAM)
|
||||||
#include "../HAL_DUE/ServoTimers.h"
|
#include "../HAL_DUE/ServoTimers.h"
|
||||||
|
#elif defined(__SAMD51__)
|
||||||
|
#include "../HAL_SAMD51/ServoTimers.h"
|
||||||
#else
|
#else
|
||||||
#error "This library only supports boards with an AVR or SAM3X processor."
|
#error "This library only supports boards with an AVR, SAM3X or SAMD51 processor."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Macros
|
// Macros
|
||||||
|
@ -64,10 +66,8 @@
|
||||||
#define INVALID_SERVO 255 // flag indicating an invalid servo index
|
#define INVALID_SERVO 255 // flag indicating an invalid servo index
|
||||||
|
|
||||||
// Convert microseconds to ticks and back (PRESCALER depends on architecture)
|
// Convert microseconds to ticks and back (PRESCALER depends on architecture)
|
||||||
#define usToTicks(_us) (clockCyclesPerMicrosecond() * (_us) / (PRESCALER))
|
#define usToTicks(_us) (clockCyclesPerMicrosecond() * (_us) / (SERVO_TIMER_PRESCALER))
|
||||||
#define ticksToUs(_ticks) (unsigned(_ticks) * (PRESCALER) / clockCyclesPerMicrosecond())
|
#define ticksToUs(_ticks) (unsigned(_ticks) * (SERVO_TIMER_PRESCALER) / clockCyclesPerMicrosecond())
|
||||||
|
|
||||||
//#define NBR_TIMERS ((MAX_SERVOS) / (SERVOS_PER_TIMER))
|
|
||||||
|
|
||||||
// convenience macros
|
// convenience macros
|
||||||
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / (SERVOS_PER_TIMER))) // returns the timer controlling this servo
|
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / (SERVOS_PER_TIMER))) // returns the timer controlling this servo
|
||||||
|
@ -78,7 +78,7 @@
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t nbr : 6 ; // a pin number from 0 to 63
|
uint8_t nbr : 7 ; // a pin number from 0 to 127
|
||||||
uint8_t isActive : 1 ; // true if this channel is enabled, pin not pulsed if false
|
uint8_t isActive : 1 ; // true if this channel is enabled, pin not pulsed if false
|
||||||
} ServoPin_t;
|
} ServoPin_t;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue