Microstepping is good solution for remove "jagged lines" - it add smoothness to steppers movement.
My suggestion of "almost ideal" stepper controller:
- Use something from MSP430F53XX or MSP430F55XX series (this serie give you advantage of USB communication)
- Use 3 timers A to independent and precise frequence generating for 3 axes
- Use timer B with 7 registers for synchronously generating PWM signals for microstepping controll 3 axes (two signals for axis...)
- Use 3 DMA channels directed by timers A to move modified sinus tables into timer B registers to precise timed, software - independent stepper movement
- Then You have full potential of processor power for interpolation computing (hardware multiplier help you a lot)
Here is some code that can tx at 115.2 kbps while running at only 1 MHz clock. This can be useful for "printf debugging" with minimal impact on code speed.
The bit time of 115.2 kbps is aprox 8.68 us. The timing granularity at 1 MHz is only 1 us, so dithering is used to maintain correct average bit time. Most UART look at the middle of the bit, so this generally works well. The jitter is under 500 ns as shown in the following table.
bN rrc R14 Move the next bit to send in to the carry flag, shift all others
jc bNh --+ Test the carry flag and jump if one
bic.b R15, &P1OUT | The carry flag was zero, so put a zero on the serial output
jmp nxb --|--+ Jump to the next bit
bNh bis.b R15, &P1OUT <-+ | The carry flag was one, so put a one on the serial output
jmp nxb -----+ Jump to the next bit - this jump is required to keep the
| code path for the bit isochronous
nxb next bit <----+
9 cycles are required for each bit using that code, so something must be done for the 3 bits that must be sent in 8 cycles.
The last jmp can be replace with a nop to reduce the cycle count when a one is sent. To reduce the cycle count when a zero is sent, the second jump is also replaced with a nop and part of the code for the next bit is copied to directly after the nop.
Uses software delay loop instead of timer [interrupt] for small code size.
Minimum bit duration is 18 clock cycles. One cycle granularity.
I think this code is optimal (can not be done with fewer instruction words or cycles).
tx_char ; Char to tx in R14
; R10, R11, R12, R15 trashed
mov #65553 - 104, R10 ; Bit duration (18 minimum)
mov #0x02, R15 ; Serial output bitmask
mov #10, R12 ; 10 bit times (may be reduced to 9 at high bit rates)
bic.b R15, &P1OUT ; Start bit
or #0xFF00, R14 ; Stop bit(s)
nop ;
bit_loop mov R10, R11 ; Get bit duration
bit_time nop ; 4 cycle loop
add #4, R11 ;
jnc bit_time ;
rla R11 ; 0 to 3 cycle delay
add R11, PC ;
nop ;
nop ;
nop ;
rrc R14 ; Get bit to tx
jc bit_high ; If high...
bic.b R15, &P1OUT ; Send zero bit
dec R12 ; Dec bit count
jmp bit_loop ; Next bit...
bit_high bis.b R15, &P1OUT ; Send one bit
dec R12 ; Dec bit count
jnz bit_loop ; Next bit...
ret ; Return when all bits sent