ARM: implement the stepper interrupt.
Works nicely, much less code than on AVR, because we have 32-bit hardware timers. Test: steppers should move. Only slowly, because dda_clock() isn't called, yet, so no acceleration. Pulse time on the Debug LED is 5.21 us or 250 clock ticks.
This commit is contained in:
parent
5a8d51cb19
commit
a171a0c57f
|
|
@ -81,6 +81,7 @@ void queue_step() {
|
||||||
if (current_movebuffer->live) {
|
if (current_movebuffer->live) {
|
||||||
if (current_movebuffer->waitfor_temp) {
|
if (current_movebuffer->waitfor_temp) {
|
||||||
timer_set(HEATER_WAIT_TIMEOUT, 0);
|
timer_set(HEATER_WAIT_TIMEOUT, 0);
|
||||||
|
#ifndef __ARMEL_NOTYET__
|
||||||
if (temp_achieved()) {
|
if (temp_achieved()) {
|
||||||
current_movebuffer->live = current_movebuffer->done = 0;
|
current_movebuffer->live = current_movebuffer->done = 0;
|
||||||
serial_writestr_P(PSTR("Temp achieved\n"));
|
serial_writestr_P(PSTR("Temp achieved\n"));
|
||||||
|
|
@ -88,6 +89,7 @@ void queue_step() {
|
||||||
else {
|
else {
|
||||||
temp_print(TEMP_SENSOR_none);
|
temp_print(TEMP_SENSOR_none);
|
||||||
}
|
}
|
||||||
|
#endif /* __ARMEL_NOTYET__ */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
dda_step(current_movebuffer);
|
dda_step(current_movebuffer);
|
||||||
|
|
|
||||||
102
timer-arm.c
102
timer-arm.c
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
#include "cmsis-core_cm0.h"
|
#include "cmsis-core_cm0.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
|
#include "pinio.h"
|
||||||
|
#include "dda_queue.h"
|
||||||
|
|
||||||
|
|
||||||
/** Timer initialisation.
|
/** Timer initialisation.
|
||||||
|
|
@ -45,6 +47,28 @@ void timer_init() {
|
||||||
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk // Enable the ticker.
|
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk // Enable the ticker.
|
||||||
| SysTick_CTRL_TICKINT_Msk // Enable interrupt.
|
| SysTick_CTRL_TICKINT_Msk // Enable interrupt.
|
||||||
| SysTick_CTRL_CLKSOURCE_Msk; // Run at full CPU clock.
|
| SysTick_CTRL_CLKSOURCE_Msk; // Run at full CPU clock.
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initialise the stepper timer. On ARM we have the comfort of hardware
|
||||||
|
32-bit timers, so we don't have to artifically extend the timer to this
|
||||||
|
size. We use match register 0 of the first 32-bit timer, CT32B0.
|
||||||
|
|
||||||
|
We run the timer all the time, just turn the interrupt on and off, to
|
||||||
|
allow interrupts equally spaced, independent from processing time. See
|
||||||
|
also description of timer_set().
|
||||||
|
*/
|
||||||
|
LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 9); // Turn on CT32B0 power.
|
||||||
|
|
||||||
|
LPC_TMR32B0->TCR = (1 << 0); // Enable counter.
|
||||||
|
//LPC_TMR32B0->PR = 0; ( = reset value) // Prescaler off.
|
||||||
|
//LPC_TMR32B0->MCR is handled by timer_set() and IRQ handler.
|
||||||
|
//LPC_TMR32B0->CCR = 0; ( = reset value) // No pin capture.
|
||||||
|
//LPC_TMR32B0->EMR = 0; ( = reset value) // No external matches.
|
||||||
|
//LPC_TMR32B0->CTCR = 0; ( = reset value) // Timer mode.
|
||||||
|
//LPC_TMR32B0->PWMC = 0; ( = reset value) // All PWM off.
|
||||||
|
|
||||||
|
NVIC_SetPriority(TIMER_32_0_IRQn, 0); // Also highest priority.
|
||||||
|
NVIC_EnableIRQ(TIMER_32_0_IRQn); // Enable interrupt generally.
|
||||||
}
|
}
|
||||||
|
|
||||||
/** System clock interrupt.
|
/** System clock interrupt.
|
||||||
|
|
@ -60,6 +84,36 @@ void SysTick_Handler(void) {
|
||||||
#endif /* __ARMEL_NOTYET__ */
|
#endif /* __ARMEL_NOTYET__ */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Step interrupt.
|
||||||
|
|
||||||
|
Happens for every stepper motor step. Must have the same name as in
|
||||||
|
cmsis-startup_lpc11xx.s
|
||||||
|
*/
|
||||||
|
void TIMER32_0_IRQHandler(void) {
|
||||||
|
|
||||||
|
#ifdef DEBUG_LED_PIN
|
||||||
|
WRITE(DEBUG_LED_PIN, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
Turn off interrupt generation, timer counter continues. As this interrupt
|
||||||
|
is the only use of this timer, there's no need for a read-modify-write.
|
||||||
|
*/
|
||||||
|
LPC_TMR32B0->MCR = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
We have to "reset" this interrupt, else it'll be triggered over and over
|
||||||
|
again.
|
||||||
|
*/
|
||||||
|
LPC_TMR32B0->IR = (1 << 0); // Clear match on channel 0.
|
||||||
|
|
||||||
|
queue_step();
|
||||||
|
|
||||||
|
#ifdef DEBUG_LED_PIN
|
||||||
|
WRITE(DEBUG_LED_PIN, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/** Specify how long until the step timer should fire.
|
/** Specify how long until the step timer should fire.
|
||||||
|
|
||||||
\param delay Delay for the next step interrupt, in CPU ticks.
|
\param delay Delay for the next step interrupt, in CPU ticks.
|
||||||
|
|
@ -70,9 +124,9 @@ void SysTick_Handler(void) {
|
||||||
usually wants to handle this case.
|
usually wants to handle this case.
|
||||||
|
|
||||||
Calls from elsewhere should set it to 0. In this case a timer
|
Calls from elsewhere should set it to 0. In this case a timer
|
||||||
interrupt is always scheduled. At the risk that this scheduling
|
interrupt is always scheduled. At the risk that if this scheduling
|
||||||
doesn't delay the requested time, but up to a full timer counter
|
is too short, the timer doesn't delay the requested time, but up to
|
||||||
overflow ( = 65536 / F_CPU = 3 to 4 milliseconds).
|
a full timer counter overflow ( = 2^32 / F_CPU = ~96 seconds).
|
||||||
|
|
||||||
\return A flag whether the requested time was too short to allow scheduling
|
\return A flag whether the requested time was too short to allow scheduling
|
||||||
an interrupt. This is meaningful for ACCELERATION_TEMPORAL, where
|
an interrupt. This is meaningful for ACCELERATION_TEMPORAL, where
|
||||||
|
|
@ -92,8 +146,50 @@ void SysTick_Handler(void) {
|
||||||
So, if you use it from inside the step interrupt, make sure to do so
|
So, if you use it from inside the step interrupt, make sure to do so
|
||||||
as late as possible. If you use it from outside the step interrupt,
|
as late as possible. If you use it from outside the step interrupt,
|
||||||
do a sei() after it to make the interrupt actually fire.
|
do a sei() after it to make the interrupt actually fire.
|
||||||
|
|
||||||
|
On ARM we have the comfort of hardware 32-bit timers, so we don't have to
|
||||||
|
artifically extend the timer to this size. We use match register 0 of the
|
||||||
|
first 32-bit timer, CT32B0.
|
||||||
*/
|
*/
|
||||||
uint8_t timer_set(int32_t delay, uint8_t check_short) {
|
uint8_t timer_set(int32_t delay, uint8_t check_short) {
|
||||||
|
|
||||||
|
#ifdef ACCELERATION_TEMPORAL
|
||||||
|
if (check_short) {
|
||||||
|
/**
|
||||||
|
100 = safe number of cpu cycles after current_time to allow a new
|
||||||
|
interrupt happening. This is mostly the time needed to complete the
|
||||||
|
current interrupt.
|
||||||
|
|
||||||
|
LPC_TMR32B0->TC = timer counter = current time.
|
||||||
|
LPC_TMR32B0->MR0 = last timer match = time of the last step.
|
||||||
|
*/
|
||||||
|
if ((LPC_TMR32B0->TC - LPC_TMR32B0->MR0) + 100 > delay)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* ACCELERATION_TEMPORAL */
|
||||||
|
|
||||||
|
/**
|
||||||
|
Still here? Then we can schedule the next step. Usually off of the previous
|
||||||
|
step. If we passed this time already, usually because this is the first
|
||||||
|
move after a pause, we delay off of the current time. Other than on AVR we
|
||||||
|
can't affort a full round through the timer here, because this round would
|
||||||
|
be up to 60 seconds.
|
||||||
|
|
||||||
|
TODO: this check costs time and is a plausibility check only. It'd be
|
||||||
|
better to reset the timer from elsewhere when starting a movement
|
||||||
|
after a pause.
|
||||||
|
*/
|
||||||
|
if (LPC_TMR32B0->TC - LPC_TMR32B0->MR0 > delay - 100)
|
||||||
|
LPC_TMR32B0->MR0 = LPC_TMR32B0->TC + delay;
|
||||||
|
else
|
||||||
|
LPC_TMR32B0->MR0 += delay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Turn on the stepper interrupt. As this interrupt is the only use of this
|
||||||
|
timer, there's no need for a read-modify-write.
|
||||||
|
*/
|
||||||
|
LPC_TMR32B0->MCR = (1 << 0); // Interrupt on MR0 match.
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue