diff --git a/controller-board/fw/main.c b/controller-board/fw/main.c index d9699fe..dc42a5f 100644 --- a/controller-board/fw/main.c +++ b/controller-board/fw/main.c @@ -4,6 +4,34 @@ #include +enum direction { + DIR_CLOCKWISE, + DIR_COUNTERCLOCKWISE +}; + +volatile struct { + bool active; + bool done; + int step_count; + enum direction dir; + int counter; + int increment; + int threshold; + int phase; +} stepper = { + true, false, 1000000, DIR_CLOCKWISE, 0, 1, 2, 0 +}; + +volatile struct { + bool active; + bool done; + enum direction dir; + int count; + int tocount; +} brushed = { + false, false, DIR_CLOCKWISE, 0, 0 +}; + int main(void) { rcc_periph_clock_enable(RCC_GPIOA); rcc_periph_clock_enable(RCC_GPIOB); @@ -46,21 +74,207 @@ int main(void) { systick_counter_disable(); systick_set_clocksource(STK_CSR_CLKSOURCE_AHB); - systick_set_reload(rcc_ahb_frequency/100000-1); + systick_set_reload(rcc_ahb_frequency/1000-1); systick_clear(); systick_interrupt_enable(); systick_counter_enable(); + int32_t val = 0; + while (1) { + if (stepper.done) { + stepper.done = false; + usart_send_blocking(USART2, 's'); + } + if (brushed.done) { + brushed.done = false; + usart_send_blocking(USART2, 'r'); + } + + if ((USART_ISR(USART2) & USART_ISR_RXNE) != 0) { // TODO process byte uint8_t rx = usart_recv(USART2); - usart_send_blocking(USART2, rx); + + // if it's a hexadecimal echo back and append it to val + if ((rx >= '0') && (rx <= '9')) { + usart_send_blocking(USART2, rx); // echo back + val <<= 4; + val |= (rx - '0'); + } else if ((rx >= 'a') && (rx <= 'f')) { + usart_send_blocking(USART2, rx); // echo back + val <<= 4; + val |= (rx - 'a' + 10); + } else if ((rx >= 'A') && (rx <= 'F')) { + usart_send_blocking(USART2, rx); // echo back + val <<= 4; + val |= (rx - 'A' + 10); + } else { + switch (rx) { + case 's': // get status + if (stepper.active) { + usart_send_blocking(USART2, '!'); + } else { + usart_send_blocking(USART2, '@'); + } + if (brushed.active) { + usart_send_blocking(USART2, '#'); + } else { + usart_send_blocking(USART2, '$'); + } + break; + case 'w': // start stepper + usart_send_blocking(USART2, '!'); + stepper.active = true; + break; + case 'W': // stop stepper + stepper.active = false; + usart_send_blocking(USART2, '@'); + break; + case 'r': // start brushed motor + usart_send_blocking(USART2, '#'); + brushed.count = 0; + brushed.active = true; + break; + case 'R': // stop brushed motor + usart_send_blocking(USART2, '$'); + brushed.count = 0; + brushed.active = false; + break; + case 't': // read stepper counter + // TODO + break; + case 'T': // write stepper counter + // TODO + break; + case 'y': // read stepper increment + // TODO + break; + case 'Y': // write stepper increment + // TODO + break; + case 'u': // read stepper threshold + // TODO + break; + case 'U': // write stepper threshold + // TODO + break; + case 'i': // set stepper direction to clockwise + stepper.dir = DIR_CLOCKWISE; + usart_send_blocking(USART2, 'i'); + break; + case 'I': // set stepper direction to counterclockwise + stepper.dir = DIR_COUNTERCLOCKWISE; + usart_send_blocking(USART2, 'I'); + break; + case 'o': // write brushed counter + // TODO + break; + case 'O': // read brushed counter + // TODO + break; + case 'p': // set brushed direction to clockwise + brushed.dir = DIR_CLOCKWISE; + usart_send_blocking(USART2, 'p'); + break; + case 'P': // set brushed direction to counterclockwise + brushed.dir = DIR_COUNTERCLOCKWISE; + usart_send_blocking(USART2, 'P'); + break; + } + } } } } -void SysTick_Handler(void); -void SysTick_Handler(void) { +const struct { + bool active; + bool positive; +} phase_lut[][2] = { + {{true, true}, {false, true}}, // A+ + //{{true, true}, {true, true}}, // A+, B+ + {{false, true}, {true, true}}, // B+ + //{{true, false}, {true, true}}, // A-, B+ + {{true, false}, {false, true}}, // A- + //{{true, false}, {true, false}}, // A-, B- + {{false, false}, {true, false}}, // B- + //{{true, true}, {true, false}}, // A+, B- +}; + + +void sys_tick_handler(void); +void sys_tick_handler(void) { + if (!stepper.active) { + gpio_clear(GPIOA, GPIO5|GPIO6|GPIO7); + gpio_clear(GPIOB, GPIO1); + } else { + stepper.counter += stepper.increment; + if (stepper.counter >= stepper.threshold) { + --stepper.step_count; + stepper.counter -= stepper.threshold; + if (stepper.dir == DIR_CLOCKWISE) { + ++stepper.phase; + } else { + --stepper.phase; + } + if (stepper.phase < 0) { + stepper.phase = 3; + } + if (stepper.phase >= 4) { + stepper.phase = 0; + } + } + if (stepper.step_count <= 0) { + stepper.counter = 0; + stepper.active = false; + stepper.done = true; + // power down stepper motor; TODO maybe lock its position? + gpio_clear(GPIOA, GPIO5|GPIO6|GPIO7); + gpio_clear(GPIOB, GPIO1); + } else { + // write to GPIO pins + // TODO maybe use a set of OR/AND masks instead? this works but probably + // isn't constant time + if (phase_lut[stepper.phase][0].active) { + if (phase_lut[stepper.phase][0].positive) { + gpio_clear(GPIOA, GPIO6); + gpio_set(GPIOB, GPIO1); + } else { + gpio_set(GPIOA, GPIO6); + gpio_clear(GPIOB, GPIO1); + } + } else { + gpio_clear(GPIOA, GPIO6); + gpio_clear(GPIOB, GPIO1); + } + if (phase_lut[stepper.phase][1].active) { + if (phase_lut[stepper.phase][1].positive) { + gpio_clear(GPIOA, GPIO7); + gpio_set(GPIOA, GPIO5); + } else { + gpio_set(GPIOA, GPIO7); + gpio_clear(GPIOA, GPIO5); + } + } else { + gpio_clear(GPIOA, GPIO7); + gpio_clear(GPIOA, GPIO5); + } + } + } + + if (brushed.active) { + if (brushed.count == 0) { + // TODO toggle pins + } + ++brushed.count; + if (brushed.count >= brushed.tocount) { + // TODO toggle pins + brushed.count = 0; + brushed.active = false; + brushed.done = true; + } + } + + // TODO check limit switches }