Hello!
I'm trying to use the hardware timers on my SAMD21 (Arduino Zero) to measure the phase shift of my motor, but I don't understand how to set it up properly.
I tried coding it, but nothing seems to work. Could someone help me convert my code to use hardware timers (e.g., TC or TCC modules) instead of micros() in interrupts?
My goal is to measure the time between a phase signal and a Hall signal with better accuracy and less noise.
Any example or explanation would be really appreciated!
// Déclaration des broches pour les signaux (fronts montants)
const int Phase1 = 8; // Signal de phase
const int Hall_PulsePin1 = 0; // Signal Hall
const int Phase2 = 11; // Signal de phase
const int Hall_PulsePin2 = 2; // Signal Hall
const int Phase3 = 13; // Signal de phase
const int Hall_PulsePin3 = 6; // Signal Hall
// Déclaration des broches pour les signaux (fronts descendants)
const int phasePinsFall[] = {9, 12, 15};
const int hallPinsFall[] = {1, 3, 7};
//création d'un tableau flag pour synchroniser l'arriver des signaux
volatile bool flag_PhaseReady[3] = {false};
volatile bool flag_PhaseFallReady[3] = {false};
// Variables pour la période et le déphasage (fronts montants)
volatile unsigned long startTime_Phase[3] = {0};
volatile unsigned long period_Phase[3] = {0};
volatile unsigned long startTime_Hall[3] = {0};
volatile unsigned long phase_shift[3] = {0};
// Variables pour la période et le déphasage (fronts descendants)
volatile unsigned long startTime_Phase_fall[3] = {0};
volatile unsigned long period_Phase_fall[3] = {0};
volatile unsigned long startTime_Hall_fall[3] = {0};
volatile unsigned long phase_shift_fall[3] = {0};
// Anti-rebond
const unsigned long debounceDelay = 20;//µs
volatile unsigned long lastInterruptTime[6] = {0}; // 0-2: rising, 3-5: falling
void setup() {
// Configuration des broches en entrée (fronts montants)
pinMode(Phase1, INPUT);
pinMode(Hall_PulsePin1, INPUT);
pinMode(Phase2, INPUT);
pinMode(Hall_PulsePin2, INPUT);
pinMode(Phase3, INPUT);
pinMode(Hall_PulsePin3, INPUT);
// Configuration des broches en entrée (fronts descendants)
for (int i = 0; i < 3; i++) {
pinMode(phasePinsFall[i], INPUT);
pinMode(hallPinsFall[i], INPUT);
}
// Démarrage de la communication série
Serial.begin(115200);
// Attachement des interruptions (fronts montants)
attachInterrupt(digitalPinToInterrupt(Phase1), []{countPulse_Phase(0, false);}, RISING);
attachInterrupt(digitalPinToInterrupt(Hall_PulsePin1), []{countPulse_Hall(0, false);}, RISING);
attachInterrupt(digitalPinToInterrupt(Phase2), []{countPulse_Phase(1, false);}, RISING);
attachInterrupt(digitalPinToInterrupt(Hall_PulsePin2), []{countPulse_Hall(1, false);}, RISING);
attachInterrupt(digitalPinToInterrupt(Phase3), []{countPulse_Phase(2, false);}, RISING);
attachInterrupt(digitalPinToInterrupt(Hall_PulsePin3), []{countPulse_Hall(2, false);}, RISING);
// Attachement des interruptions (fronts descendants)
attachInterrupt(digitalPinToInterrupt(phasePinsFall[0]), []{countPulse_Phase(0, true);}, FALLING);
attachInterrupt(digitalPinToInterrupt(hallPinsFall[0]), []{countPulse_Hall(0, true);}, FALLING);
attachInterrupt(digitalPinToInterrupt(phasePinsFall[1]), []{countPulse_Phase(1, true);}, FALLING);
attachInterrupt(digitalPinToInterrupt(hallPinsFall[1]), []{countPulse_Hall(1, true);}, FALLING);
attachInterrupt(digitalPinToInterrupt(phasePinsFall[2]), []{countPulse_Phase(2, true);}, FALLING);
attachInterrupt(digitalPinToInterrupt(hallPinsFall[2]), []{countPulse_Hall(2, true);}, FALLING);
}
void loop() {
// Lecture sécurisée des valeurs
noInterrupts();
// Fronts montants
unsigned long p[3] = {period_Phase[0], period_Phase[1], period_Phase[2]};
unsigned long shift_us[3] = {phase_shift[0], phase_shift[1], phase_shift[2]};
// Fronts descendants
unsigned long p_fall[3] = {period_Phase_fall[0], period_Phase_fall[1], period_Phase_fall[2]};
unsigned long shift_us_fall[3] = {phase_shift_fall[0], phase_shift_fall[1], phase_shift_fall[2]};
interrupts();
// Affichage des résultats
displayResults("Montant", p, shift_us);
displayResults("Descendant", p_fall, shift_us_fall);
delay(100); // Délai pour éviter de saturer la sortie série
}
void displayResults(const char* type, unsigned long periods[3], unsigned long shifts[3]) {
Serial.print("=== Front ");
Serial.println(type);
for (int i = 0; i < 3; i++) {
if (periods[i] > 0) {
float shift_deg = (float)shifts[i] / periods[i] * 360.0;
shift_deg = shift_deg >= 180 ? shift_deg - 360 : shift_deg;
Serial.print("Phase");
Serial.print(i+1);
Serial.print(": Période=");
Serial.print(periods[i]);
Serial.print("us, Déphasage=");
Serial.print(shifts[i]);
Serial.print("us, Angle=");
Serial.print(shift_deg, 2);
Serial.println("°");
}
}
}
// Fonction unique pour gérer les interruptions de phase
void countPulse_Phase(int phase, bool isFalling) {
unsigned long now = micros();
int index = phase + (isFalling ? 3 : 0);
// Anti-rebond
if (now - lastInterruptTime[index] < debounceDelay) return;
lastInterruptTime[index] = now;
if (isFalling) {
if (startTime_Phase_fall[phase] == 0) {
startTime_Phase_fall[phase] = now;
flag_PhaseFallReady[phase] = true;
startTime_Hall_fall[phase] = 0;
} else {
period_Phase_fall[phase] = now - startTime_Phase_fall[phase];
startTime_Phase_fall[phase] = now;
flag_PhaseReady[phase] = true;
}
} else {
if (startTime_Phase[phase] == 0) {
startTime_Phase[phase] = now;
startTime_Hall[phase] = 0;
} else {
period_Phase[phase] = now - startTime_Phase[phase];
startTime_Phase[phase] = now;
}
}
}
// Fonction unique pour gérer les interruptions Hall
void countPulse_Hall(int phase, bool isFalling) {
unsigned long now = micros();
int index = phase + (isFalling ? 3 : 0);
// Anti-rebond
if (now - lastInterruptTime[index] < debounceDelay) return;
lastInterruptTime[index] = now;
if (isFalling) {
if (startTime_Phase_fall[phase] != 0) {
startTime_Hall_fall[phase] = now;
phase_shift_fall[phase] = now - startTime_Phase_fall[phase];
flag_PhaseFallReady[phase] = false;
}
} else {
if (startTime_Phase[phase] != 0) {
startTime_Hall[phase] = now;
phase_shift[phase] = now - startTime_Phase[phase];
flag_PhaseReady[phase] = false;
}
}
}