Joined a robotics hackathon with a coworker. 36 hours of embedded development. The end result was a BLDC motor controller.
Magnetic encoder to motor driver
This is some kind of half-step pattern to drive the motor efficiently.
Param 1 | Param 2 | In-W | In-V | In-U | PWM1 | PWM2 | PWM3 |
---|---|---|---|---|---|---|---|
1 | 1 | 0 | High | ||||
2 | 0 | 1 | Low | ||||
3 | 0 | 1 | Low | ||||
1 | 1 | 0 | High | ||||
2 | 1 | 0 | High | ||||
3 | 0 | 1 | Low | ||||
1 | 0 | 1 | Low | ||||
2 | 1 | 0 | High | ||||
3 | 0 | 1 | Low | ||||
1 | 0 | 1 | Low | ||||
2 | 1 | 0 | High | ||||
3 | 1 | 0 | High | ||||
1 | 0 | 1 | Low | ||||
2 | 0 | 1 | Low | ||||
3 | 1 | 0 | High | ||||
1 | 1 | 0 | High | ||||
2 | 0 | 1 | Low | ||||
3 | 1 | 0 | High |
In our sleep-deprived state, we managed to turn it into this lookup-table based code.
static uint8_t EncoderHallState(void)
{
// Read C6, C7, C8 as digital
uint8_t c6 = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_6);
uint8_t c7 = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7);
uint8_t c8 = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_8);
return (c6 << 2) | (c7 << 1) | c8;
}
bool motor_u_lookup[] = { false, false, true, true, true, false };
bool motor_v_lookup[] = { true, false, false, false, true, true };
bool motor_w_lookup[] = { true, true, true, false, false, false };
uint8_t motor_next_lookup[] = { 4, 5, 1, 3, 2, 6 };
static uint8_t ApplyControl(uint8_t enc, uint16_t pwm)
{
uint8_t u_val = enc >> 2;
uint8_t v_val = (enc >> 1) & 1;
uint8_t w_val = enc & 1;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, u_val ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, v_val ? GPIO_PIN_SET : GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, w_val ? GPIO_PIN_SET : GPIO_PIN_RESET);
size_t j = pwm;
TIM1->CCR1 = u_val ? 0 : j;
TIM1->CCR2 = v_val ? 0 : j;
TIM1->CCR3 = w_val ? 0 : j;
}
static void MoveNext(uint16_t pwm, bool backwards)
{
uint8_t current = EncoderHallState();
uint8_t i = 0;
if (backwards)
{
for (size_t c = 0; c < 6; c++)
{
if (motor_next_lookup[c] == current)
{
i = (c + 5) % 6;
break;
}
}
}
else
{
for (size_t c = 0; c < 6; c++)
{
if (motor_next_lookup[c] == current)
{
i = (c + 1) % 6;
break;
}
}
}
uint8_t next = motor_next_lookup[i];
ApplyControl(next, pwm);
}