1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-02-17 06:29:15 +01:00

Update DCCTimerSTM32.cpp

Enable hardware pulse generation on STM32 for pins 12 and 13 (standard motor shield pins), using timers TIM2 and TIM3.  Any other pins will currently be controlled directly by the interrupt routine (in effect, by digitalWrite calls).
This commit is contained in:
Neil McKechnie 2023-02-21 11:03:14 +00:00
parent 43b1e8db21
commit 034bb6b675

View File

@ -51,10 +51,13 @@ HardwareSerial Serial1(PG9, PG14); // Rx=PG9, Tx=PG14 -- D0, D1 - F412ZG/F446ZE
#endif #endif
INTERRUPT_CALLBACK interruptHandler=0; INTERRUPT_CALLBACK interruptHandler=0;
// Let's use STM32's timer #2 which supports hardware pulse generation on pins D3 and D6 // Let's use STM32's timer #2 which supports hardware pulse generation on pin D13.
// (accurate timing, independent of the latency of interrupt handling). // Also, timer #3 will do hardware pulses on pin D12. This gives
// Pin D3 is driven by TIM2 channel 2 and D6 is TIM2 channel 3. // accurate timing, independent of the latency of interrupt handling.
// We only need to interrupt on one of these (TIM2), the other will just generate
// pulses.
HardwareTimer timer(TIM2); HardwareTimer timer(TIM2);
HardwareTimer timerAux(TIM3);
// Timer IRQ handler // Timer IRQ handler
void Timer_Handler() { void Timer_Handler() {
@ -67,24 +70,30 @@ void DCCTimer::begin(INTERRUPT_CALLBACK callback) {
// adc_set_sample_rate(ADC_SAMPLETIME_480CYCLES); // adc_set_sample_rate(ADC_SAMPLETIME_480CYCLES);
timer.pause(); timer.pause();
timerAux.pause();
timer.setPrescaleFactor(1); timer.setPrescaleFactor(1);
timer.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT); timer.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT);
timer.attachInterrupt(Timer_Handler); timer.attachInterrupt(Timer_Handler);
timer.refresh(); timer.refresh();
timerAux.setPrescaleFactor(1);
timerAux.setOverflow(DCC_SIGNAL_TIME, MICROSEC_FORMAT);
timerAux.refresh();
timer.resume(); timer.resume();
timerAux.resume();
interrupts(); interrupts();
} }
bool DCCTimer::isPWMPin(byte pin) { bool DCCTimer::isPWMPin(byte pin) {
// Timer 2 Channel 2 controls pin D3, and Timer2 Channel 3 controls D6. // Timer 2 Channel 1 controls pin D13, and Timer3 Channel 1 controls D12.
// Enable the appropriate timer channel. // Enable the appropriate timer channel.
switch (pin) { switch (pin) {
case 3: case 12:
timer.setMode(2, TIMER_OUTPUT_COMPARE_INACTIVE, D3); timerAux.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, D12);
return true; return true;
case 6: case 13:
timer.setMode(3, TIMER_OUTPUT_COMPARE_INACTIVE, D6); timer.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, D13);
return true; return true;
default: default:
return false; return false;
@ -94,25 +103,26 @@ bool DCCTimer::isPWMPin(byte pin) {
void DCCTimer::setPWM(byte pin, bool high) { void DCCTimer::setPWM(byte pin, bool high) {
// Set the timer so that, at the next counter overflow, the requested // Set the timer so that, at the next counter overflow, the requested
// pin state is activated automatically before the interrupt code runs. // pin state is activated automatically before the interrupt code runs.
// TIM2 is timer, TIM3 is timerAux.
switch (pin) { switch (pin) {
case 3: case 12:
if (high) if (high)
TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC2M_Msk) | TIM_CCMR1_OC2M_0; TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0;
else else
TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC2M_Msk) | TIM_CCMR1_OC2M_1; TIM3->CCMR1 = (TIM3->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1;
break; break;
case 6: case 13:
if (high) if (high)
TIM2->CCMR2 = (TIM2->CCMR2 & ~TIM_CCMR2_OC3M_Msk) | TIM_CCMR2_OC3M_0; TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_0;
else else
TIM2->CCMR2 = (TIM2->CCMR2 & ~TIM_CCMR2_OC3M_Msk) | TIM_CCMR2_OC3M_1; TIM2->CCMR1 = (TIM2->CCMR1 & ~TIM_CCMR1_OC1M_Msk) | TIM_CCMR1_OC1M_1;
break; break;
} }
} }
void DCCTimer::clearPWM() { void DCCTimer::clearPWM() {
timer.setMode(2, TIMER_OUTPUT_COMPARE_INACTIVE, NC); timer.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, NC);
timer.setMode(3, TIMER_OUTPUT_COMPARE_INACTIVE, NC); timerAux.setMode(1, TIMER_OUTPUT_COMPARE_INACTIVE, NC);
} }
void DCCTimer::getSimulatedMacAddress(byte mac[6]) { void DCCTimer::getSimulatedMacAddress(byte mac[6]) {