made zephyr implementation for digital out and in, encoder, motordriver and main.
This commit is contained in:
+3
-3
@@ -1,14 +1,14 @@
|
||||
#ifndef DIGITAL_IN_H
|
||||
#define DIGITAL_IN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
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
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
#ifndef DIGITAL_OUT_H
|
||||
#define DIGITAL_OUT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
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
|
||||
@@ -3,11 +3,12 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <digital_in.h>
|
||||
#include <zephyr/drivers/gpio.h>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
+5
-12
@@ -1,26 +1,19 @@
|
||||
#include <digital_in.h>
|
||||
#include <avr/io.h>
|
||||
#define INPUT_NODE DT_ALIAS(sw1)
|
||||
|
||||
Digital_in::Digital_in(uint8_t pin)
|
||||
{
|
||||
pinMask = static_cast<uint8_t>(1U << pin);
|
||||
}
|
||||
Digital_in::Digital_in(): pin(GPIO_DT_SPEC_GET(INPUT_NODE, gpios)){}
|
||||
|
||||
void Digital_in::init()
|
||||
{
|
||||
// Input
|
||||
DDRB &= static_cast<uint8_t>(~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;
|
||||
}
|
||||
+6
-9
@@ -1,27 +1,24 @@
|
||||
#include <digital_out.h>
|
||||
#include <avr/io.h>
|
||||
#define LED_NODE DT_ALIAS(led0)
|
||||
|
||||
Digital_out::Digital_out(uint8_t pin)
|
||||
{
|
||||
pinMask = static_cast<uint8_t>(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<uint8_t>(~pinMask);
|
||||
gpio_pin_set_dt(&pin, 0);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
+25
-54
@@ -1,50 +1,27 @@
|
||||
#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()
|
||||
{
|
||||
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<uint32_t>(ain2.period * pwm / 255.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
|
||||
{
|
||||
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
|
||||
|
||||
+2
-2
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user