made zephyr implementation for digital out and in, encoder, motordriver and main.

This commit is contained in:
nokkvinetti
2026-10-14 18:46:01 +00:00
parent 8e738568ec
commit e9614cff9e
8 changed files with 239 additions and 86 deletions
@@ -1,14 +1,14 @@
#ifndef DIGITAL_IN_H #ifndef DIGITAL_IN_H
#define DIGITAL_IN_H #define DIGITAL_IN_H
#include <stdint.h> #include <zephyr/drivers/gpio.h>
class Digital_in class Digital_in
{ {
public: public:
// pin is the PORTB bit number: // pin is the PORTB bit number:
// PB0 = D8, PB1 = D9, ..., PB5 = D13 // PB0 = D8, PB1 = D9, ..., PB5 = D13
Digital_in(uint8_t pin); Digital_in();
void init(); void init();
@@ -16,7 +16,7 @@ public:
bool is_lo() const; bool is_lo() const;
private: private:
uint8_t pinMask; struct gpio_dt_spec pin;
}; };
#endif #endif
@@ -1,14 +1,14 @@
#ifndef DIGITAL_OUT_H #ifndef DIGITAL_OUT_H
#define DIGITAL_OUT_H #define DIGITAL_OUT_H
#include <stdint.h> #include <zephyr/drivers/gpio.h>
class Digital_out class Digital_out
{ {
public: public:
// pin is the PORTB bit number: // pin is the PORTB bit number:
// PB0 = D8, ..., PB5 = D13 // PB0 = D8, ..., PB5 = D13
Digital_out(uint8_t pin); Digital_out();
void init(); void init();
@@ -17,7 +17,7 @@ public:
void toggle(); void toggle();
private: private:
uint8_t pinMask; struct gpio_dt_spec pin;
}; };
#endif #endif
@@ -3,11 +3,12 @@
#include <stdint.h> #include <stdint.h>
#include <digital_in.h> #include <digital_in.h>
#include <zephyr/drivers/gpio.h>
class Encoder class Encoder
{ {
public: public:
Encoder(uint8_t c1Pin, uint8_t c2Pin); Encoder();
void init(); void init();
void update(); void update();
@@ -15,13 +16,14 @@ public:
int32_t position() const; int32_t position() const;
private: private:
static void callback(const struct device *port,struct gpio_callback *cb,uint32_t pins);
Digital_in c1; Digital_in c1;
Digital_in c2; Digital_in c2;
uint8_t c1Pin; struct gpio_callback gpioCallback;
bool previousC1; bool previousC1;
volatile int32_t count; volatile int32_t count;
}; };
@@ -1,26 +1,19 @@
#include <digital_in.h> #include <digital_in.h>
#include <avr/io.h> #define INPUT_NODE DT_ALIAS(sw1)
Digital_in::Digital_in(uint8_t pin) Digital_in::Digital_in(): pin(GPIO_DT_SPEC_GET(INPUT_NODE, gpios)){}
{
pinMask = static_cast<uint8_t>(1U << pin);
}
void Digital_in::init() void Digital_in::init()
{ {
// Input gpio_pin_configure_dt(&pin, GPIO_INPUT);
DDRB &= static_cast<uint8_t>(~pinMask);
// Internal pull-up
PORTB |= pinMask;
} }
bool Digital_in::is_hi() const bool Digital_in::is_hi() const
{ {
return (PINB & pinMask) != 0; return gpio_pin_get_dt(&pin) > 0;
} }
bool Digital_in::is_lo() const bool Digital_in::is_lo() const
{ {
return (PINB & pinMask) == 0; return gpio_pin_get_dt(&pin) == 0;
} }
@@ -1,27 +1,24 @@
#include <digital_out.h> #include <digital_out.h>
#include <avr/io.h> #define LED_NODE DT_ALIAS(led0)
Digital_out::Digital_out(uint8_t pin) Digital_out::Digital_out():pin(GPIO_DT_SPEC_GET(LED_NODE, gpios)){}
{
pinMask = static_cast<uint8_t>(1U << pin);
}
void Digital_out::init() void Digital_out::init()
{ {
DDRB |= pinMask; gpio_pin_configure_dt(&pin, GPIO_OUTPUT_INACTIVE);
} }
void Digital_out::set_hi() void Digital_out::set_hi()
{ {
PORTB |= pinMask; gpio_pin_set_dt(&pin, 1);
} }
void Digital_out::set_lo() void Digital_out::set_lo()
{ {
PORTB &= static_cast<uint8_t>(~pinMask); gpio_pin_set_dt(&pin, 0);
} }
void Digital_out::toggle() void Digital_out::toggle()
{ {
PORTB ^= pinMask; gpio_pin_toggle_dt(&pin);
} }
@@ -0,0 +1,190 @@
#include <zephyr/devicetree.h>
#include <zephyr/drivers/uart.h>
#include <digital_in.h>
#include <digital_out.h>
#include <encoder.h>
#include <control_timer.h>
#include <speed_estimator.h>
#include <motor_driver.h>
#include <p_controller.h>
#include <speed_controller.h>
#include <context.h>
#include <initialization.h>
#include <operational.h>
#include <stopped.h>
// --------------------------------------------------
// 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;
}
@@ -1,50 +1,27 @@
#include <motor_driver.h> #include <motor_driver.h>
#include <zephyr/drivers/pwm.h>
#include <zephyr/devicetree.h>
#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 <avr/io.h>
void Motor_driver::init() void Motor_driver::init()
{ {
currentCommand = 0.0; currentCommand = 0.0;
// D11 / PB3 / OC2A -> AIN1 enable_pwm_outputs();
DDRB |= (1 << PB3);
// D3 / PD3 / OC2B -> AIN2 coast();
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);
} }
void Motor_driver::enable_pwm_outputs() void Motor_driver::enable_pwm_outputs()
{ {
// Non-inverting PWM on OC2A and OC2B // The PWM peripheral is configured through devicetree.
TCCR2A |=
(1 << COM2A1) |
(1 << COM2B1);
TCCR2A &=
~((1 << COM2A0) |
(1 << COM2B0));
} }
unsigned char Motor_driver::magnitude( unsigned char Motor_driver::magnitude(
@@ -83,23 +60,26 @@ void Motor_driver::set_command(double command)
unsigned char pwm = unsigned char pwm =
magnitude(command); magnitude(command);
if (command > 0.0) if (command > 0.0)
{ {
// Same direction that previously gave positive RPM: // Same direction that previously gave positive RPM:
// AIN1 = LOW // AIN1 = LOW
// AIN2 = PWM // AIN2 = PWM
OCR2A = 0; pwm_set_dt(&ain1, ain1.period, 0);
OCR2B = pwm; pwm_set_dt(&ain2, ain2.period,
static_cast<uint32_t>(ain2.period * pwm / 255.0));
} }
else if (command < 0.0) else if (command < 0.0)
{ {
OCR2A = pwm;
OCR2B = 0; pwm_set_dt(&ain1, ain1.period,
static_cast<uint32_t>(ain1.period * pwm / 255.0));
pwm_set_dt(&ain2, ain2.period, 0);
} }
else else
{ {
OCR2A = 0; coast();
OCR2B = 0;
} }
} }
@@ -107,26 +87,17 @@ void Motor_driver::coast()
{ {
currentCommand = 0.0; currentCommand = 0.0;
enable_pwm_outputs(); pwm_set_dt(&ain1, ain1.period, 0);
pwm_set_dt(&ain2, ain2.period, 0);
OCR2A = 0;
OCR2B = 0;
} }
void Motor_driver::brake() void Motor_driver::brake()
{ {
currentCommand = 0.0; currentCommand = 0.0;
// Disconnect Timer2 PWM from the pins.
TCCR2A &=
~((1 << COM2A1) |
(1 << COM2A0) |
(1 << COM2B1) |
(1 << COM2B0));
// DRV8833: both inputs HIGH gives braking. // DRV8833: both inputs HIGH gives braking.
PORTB |= (1 << PB3); pwm_set_dt(&ain1, ain1.period, ain1.period);
PORTD |= (1 << PD3); pwm_set_dt(&ain2, ain2.period, ain2.period);
} }
double Motor_driver::command() const double Motor_driver::command() const
@@ -39,12 +39,12 @@
motor { motor {
motor_ain1: ain1 { motor_ain1: ain1 {
pwms = <&pwm1 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; pwms = <&pwm1 1 PWM_HZ(8000) PWM_POLARITY_NORMAL>;
label = "Motor AIN1"; label = "Motor AIN1";
}; };
motor_ain2: ain2 { motor_ain2: ain2 {
pwms = <&pwm2 1 PWM_MSEC(20) PWM_POLARITY_NORMAL>; pwms = <&pwm2 1 PWM_HZ(8000) PWM_POLARITY_NORMAL>;
label = "Motor AIN2"; label = "Motor AIN2";
}; };