diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_in.h b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_in.h index 2218aad..5a63ad4 100644 --- a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_in.h +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_in.h @@ -1,14 +1,14 @@ #ifndef DIGITAL_IN_H #define DIGITAL_IN_H -#include +#include class Digital_in { public: // pin is the PORTB bit number: // PB0 = D8, PB1 = D9, ..., PB5 = D13 - Digital_in(uint8_t pin); + Digital_in(); void init(); @@ -16,7 +16,7 @@ public: bool is_lo() const; private: - uint8_t pinMask; + struct gpio_dt_spec pin; }; #endif \ No newline at end of file diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_out.h b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_out.h index 485541b..111e54c 100644 --- a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_out.h +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/digital_out.h @@ -1,14 +1,14 @@ #ifndef DIGITAL_OUT_H #define DIGITAL_OUT_H -#include +#include class Digital_out { public: // pin is the PORTB bit number: // PB0 = D8, ..., PB5 = D13 - Digital_out(uint8_t pin); + Digital_out(); void init(); @@ -17,7 +17,7 @@ public: void toggle(); private: - uint8_t pinMask; + struct gpio_dt_spec pin; }; #endif \ No newline at end of file diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/encoder.h b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/encoder.h index 84689a4..92f2278 100644 --- a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/encoder.h +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/include/encoder.h @@ -3,11 +3,12 @@ #include #include +#include class Encoder { public: - Encoder(uint8_t c1Pin, uint8_t c2Pin); + Encoder(); void init(); void update(); @@ -15,13 +16,14 @@ public: int32_t position() const; private: + static void callback(const struct device *port,struct gpio_callback *cb,uint32_t pins); + Digital_in c1; Digital_in c2; - uint8_t c1Pin; + struct gpio_callback gpioCallback; bool previousC1; - volatile int32_t count; }; diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_in.cpp b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_in.cpp index 4ac93ce..5bfc2df 100644 --- a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_in.cpp +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_in.cpp @@ -1,26 +1,19 @@ #include -#include +#define INPUT_NODE DT_ALIAS(sw1) -Digital_in::Digital_in(uint8_t pin) -{ - pinMask = static_cast(1U << pin); -} +Digital_in::Digital_in(): pin(GPIO_DT_SPEC_GET(INPUT_NODE, gpios)){} void Digital_in::init() { - // Input - DDRB &= static_cast(~pinMask); - - // Internal pull-up - PORTB |= pinMask; + gpio_pin_configure_dt(&pin, GPIO_INPUT); } bool Digital_in::is_hi() const { - return (PINB & pinMask) != 0; + return gpio_pin_get_dt(&pin) > 0; } bool Digital_in::is_lo() const { - return (PINB & pinMask) == 0; + return gpio_pin_get_dt(&pin) == 0; } \ No newline at end of file diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_out.cpp b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_out.cpp index 598ee0b..783163e 100644 --- a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_out.cpp +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/digital_out.cpp @@ -1,27 +1,24 @@ #include -#include +#define LED_NODE DT_ALIAS(led0) -Digital_out::Digital_out(uint8_t pin) -{ - pinMask = static_cast(1U << pin); -} +Digital_out::Digital_out():pin(GPIO_DT_SPEC_GET(LED_NODE, gpios)){} void Digital_out::init() { - DDRB |= pinMask; + gpio_pin_configure_dt(&pin, GPIO_OUTPUT_INACTIVE); } void Digital_out::set_hi() { - PORTB |= pinMask; + gpio_pin_set_dt(&pin, 1); } void Digital_out::set_lo() { - PORTB &= static_cast(~pinMask); + gpio_pin_set_dt(&pin, 0); } void Digital_out::toggle() { - PORTB ^= pinMask; + gpio_pin_toggle_dt(&pin); } \ No newline at end of file diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/main.cpp b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/main.cpp new file mode 100644 index 0000000..20ebc37 --- /dev/null +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/main.cpp @@ -0,0 +1,190 @@ +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +// -------------------------------------------------- +// Hardware / drivers +// -------------------------------------------------- + +// Encoder: +// PB0 = D8 +// PB1 = D9 +Encoder encoder; + +// Emergency-stop: +// PB2 = D10 +// Internal pull-up enabled. +// LOW = emergency stop pressed. +Digital_in emergencyStop; + +// Status LED: +// PB5 = D13 +Digital_out statusLED; + +Control_timer controlTimer; + +Motor_driver motorDriver; + +// 2100 counts/revolution, +// 4 ms fixed controller period +Speed_estimator speedEstimator( + 2100.0, + 0.004 +); + +P_controller pController(40.0); + +Speed_controller speedController( + encoder, + speedEstimator, + motorDriver, + pController +); + +// -------------------------------------------------- +// State machine +// -------------------------------------------------- + +Initialization initialization( + speedController, + statusLED +); + +Operational operational( + speedController, + statusLED +); + +Stopped stopped( + speedController, + statusLED +); + +Context* stateMachine = nullptr; + +static const struct device* uartDevice = + DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + +int main() +{ + + if (!device_is_ready(uartDevice)) + { + printk("Console UART is not ready\n"); + return 0; + + } + + statusLED.init(); + + emergencyStop.init(); + + encoder.init(); + + motorDriver.init(); + + speedController.set_reference( + 50.0 + ); + + // -------------------------------------------------- + // State transitions + // -------------------------------------------------- + + initialization.set_operational_state( + operational + ); + + operational.set_initialization_state( + initialization + ); + + operational.set_stopped_state( + stopped + ); + + stopped.set_initialization_state( + initialization + ); + + static Context context( + initialization + ); + + stateMachine = &context; + + controlTimer.init(); + + printk("\n"); + printk("Project 3 - Part 2\n"); + printk("Commands:\n"); + printk("o = set operational\n"); + printk("r = reset\n"); + printk("Emergency stop or motor fault = fault\n"); + + + while (true) + { + // -------------------------------------------------- + // Emergency-stop fault + // -------------------------------------------------- + + if (emergencyStop.is_hi()) // was is_lo + { + stateMachine->fault(); + } + + if (motorDriver.has_fault()) + { + stateMachine->fault(); + } + + // -------------------------------------------------- + // Serial commands + // -------------------------------------------------- + + unsigned char command; + + if (uart_poll_in(uartDevice, &command) == 0) + { + if (command == 'o') + { + stateMachine-> + set_operational(); + } + else if (command == 'r') + { + stateMachine-> + reset(); + } + } + + + // -------------------------------------------------- + // Stable 250 Hz state activity + // -------------------------------------------------- + + if (controlTimer.take_tick()) + { + stateMachine->do_work(); + } + k_sleep(K_MSEC(1)); + } + return 0; +} \ No newline at end of file diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/motor_driver.cpp b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/motor_driver.cpp index 6f247e6..8732941 100644 --- a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/motor_driver.cpp +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/src/motor_driver.cpp @@ -1,50 +1,27 @@ #include +#include +#include + +#define AIN1_NODE DT_ALIAS(motor_ain1) +#define AIN2_NODE DT_ALIAS(motor_ain2) + +static const struct pwm_dt_spec ain1 = PWM_DT_SPEC_GET(AIN1_NODE); + +static const struct pwm_dt_spec ain2 = PWM_DT_SPEC_GET(AIN2_NODE); -#include void Motor_driver::init() { currentCommand = 0.0; - // D11 / PB3 / OC2A -> AIN1 - DDRB |= (1 << PB3); + enable_pwm_outputs(); - // D3 / PD3 / OC2B -> AIN2 - DDRD |= (1 << PD3); - - PORTB &= ~(1 << PB3); - PORTD &= ~(1 << PD3); - - // Timer2 Fast PWM - TCCR2A = 0; - TCCR2B = 0; - TCNT2 = 0; - - OCR2A = 0; - OCR2B = 0; - - TCCR2A = - (1 << COM2A1) | - (1 << COM2B1) | - (1 << WGM21) | - (1 << WGM20); - - // Prescaler = 8 - // PWM frequency ~= 7.8 kHz - TCCR2B = - (1 << CS21); + coast(); } void Motor_driver::enable_pwm_outputs() { - // Non-inverting PWM on OC2A and OC2B - TCCR2A |= - (1 << COM2A1) | - (1 << COM2B1); - - TCCR2A &= - ~((1 << COM2A0) | - (1 << COM2B0)); + // The PWM peripheral is configured through devicetree. } unsigned char Motor_driver::magnitude( @@ -83,23 +60,26 @@ void Motor_driver::set_command(double command) unsigned char pwm = magnitude(command); + if (command > 0.0) { // Same direction that previously gave positive RPM: // AIN1 = LOW // AIN2 = PWM - OCR2A = 0; - OCR2B = pwm; + pwm_set_dt(&ain1, ain1.period, 0); + pwm_set_dt(&ain2, ain2.period, + static_cast(ain2.period * pwm / 255.0)); } else if (command < 0.0) { - OCR2A = pwm; - OCR2B = 0; + + pwm_set_dt(&ain1, ain1.period, + static_cast(ain1.period * pwm / 255.0)); + pwm_set_dt(&ain2, ain2.period, 0); } else { - OCR2A = 0; - OCR2B = 0; + coast(); } } @@ -107,26 +87,17 @@ void Motor_driver::coast() { currentCommand = 0.0; - enable_pwm_outputs(); - - OCR2A = 0; - OCR2B = 0; + pwm_set_dt(&ain1, ain1.period, 0); + pwm_set_dt(&ain2, ain2.period, 0); } void Motor_driver::brake() { currentCommand = 0.0; - // Disconnect Timer2 PWM from the pins. - TCCR2A &= - ~((1 << COM2A1) | - (1 << COM2A0) | - (1 << COM2B1) | - (1 << COM2B0)); - // DRV8833: both inputs HIGH gives braking. - PORTB |= (1 << PB3); - PORTD |= (1 << PD3); + pwm_set_dt(&ain1, ain1.period, ain1.period); + pwm_set_dt(&ain2, ain2.period, ain2.period); } double Motor_driver::command() const diff --git a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/zephyr/boards/nucleo_l432kc.overlay b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/zephyr/boards/nucleo_l432kc.overlay index 3c85ab2..dc79edf 100644 --- a/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/zephyr/boards/nucleo_l432kc.overlay +++ b/Project_4_Distributed_Control/Part_1_Porting_controller_to_Zephyr/zephyr/boards/nucleo_l432kc.overlay @@ -39,12 +39,12 @@ motor { motor_ain1: ain1 { - pwms = <&pwm1 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + pwms = <&pwm1 1 PWM_HZ(8000) PWM_POLARITY_NORMAL>; label = "Motor AIN1"; }; motor_ain2: ain2 { - pwms = <&pwm2 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; + pwms = <&pwm2 1 PWM_HZ(8000) PWM_POLARITY_NORMAL>; label = "Motor AIN2"; };