Skip to content

Commit

Permalink
[Initial Commit] Port main logic from other repo
Browse files Browse the repository at this point in the history
Topic: inital-commit
Relative:
Reviewers:
  • Loading branch information
sahil-kale committed Oct 9, 2023
1 parent ffd8c83 commit 09caa51
Show file tree
Hide file tree
Showing 64 changed files with 4,528 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 130
13 changes: 13 additions & 0 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Code Format check

on:
pull_request:
branches: [ main ]

jobs:
check-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: sudo apt install clang-format
- run: bash scripts/test_clang_format.sh
13 changes: 13 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Test

on:
pull_request:
branches: [ main ]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: bash scripts/setup.sh
- run: bash scripts/test.sh
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,5 @@
*.exe
*.out
*.app

build/
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "libs/googletest"]
path = libs/googletest
url = https://github.com/google/googletest.git
34 changes: 34 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
cmake_minimum_required(VERSION 3.8)

set(This MAINS)
set(BINARY ${CMAKE_PROJECT_NAME})

project(${This} C CXX)

set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(BUILD_GMOCK ON)

# enable Werror
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Werror")

enable_testing()

# add the googletest subdirectory, located in the lib folder tree that is one level above this one
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/libs/googletest ${CMAKE_CURRENT_BINARY_DIR}/googletest)

# set the HEADERS as everything in the inc folder, as well as test *.hpp files
file(GLOB HEADERS "inc/*.hpp")

# set the SOURCES as everything in the src folder
file(GLOB SOURCES "src/*.cpp")

# add_executable(${BINARY}_run ${SOURCES})
add_library(${This} STATIC ${SOURCES} ${HEADERS})

add_subdirectory(test)

# To find the tests, this is rquired
include_directories(inc)
include_directories(src)
67 changes: 67 additions & 0 deletions inc/bridge_3phase.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef BRIDGE_3PHASE_HPP
#define BRIDGE_3PHASE_HPP

#include "hal_common.hpp"

namespace hwbridge {

// Define a generic 3-phase bridge class

class Bridge3Phase {
public:
Bridge3Phase() = default;
virtual ~Bridge3Phase() = default;

typedef struct phase_command {
float duty_cycle_high_side;
bool invert_low_side;
} phase_command_t;

// Define a struct to return the PHASE (not backemf) voltage
typedef struct bemf_voltage {
float u;
float v;
float w;
} bemf_voltage_t;

// Define a struct to return the current
typedef struct current {
float u;
float v;
float w;
} phase_current_t;

virtual app_hal_status_E init() = 0;

// Define a virtual function to set the individual phases' duty cycles and enable/disable the phase
virtual void set_phase(const phase_command_t& u, const phase_command_t& v, const phase_command_t& w) = 0;

// Define a virtual function to get the back emf voltage
virtual app_hal_status_E read_bemf(bemf_voltage_t& bemf_voltage) = 0;

// Define a virtual function to get the current
virtual app_hal_status_E read_current(phase_current_t& current) = 0;

// Define a virtual function to get the bus voltage
virtual app_hal_status_E read_bus_voltage(float& bus_voltage) = 0;

static constexpr uint8_t NUM_PHASES = 3;
};

// Define a generic class for a sensor that returns the sector of the rotor
class BldcRotorSectorSensor {
public:
BldcRotorSectorSensor() = default;
virtual ~BldcRotorSectorSensor() = default;

// Define a virtual function to initialize the sensor
virtual app_hal_status_E init() = 0;

// Define a virtual function to get the sector
// @RETURNS the sector (0-5)
virtual app_hal_status_E get_sector(uint8_t& sector) = 0;
};

} // namespace hwbridge

#endif // BRIDGE_3PHASE_HPP
164 changes: 164 additions & 0 deletions inc/bridge_3phase_drv8323.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#ifndef BRIDGE_3PHASE_DRV8323_HPP
#define BRIDGE_3PHASE_DRV8323_HPP

#include <math.h>

#include "bridge_3phase.hpp"
#include "control_loop.hpp"
#include "hal_adc.hpp"
#include "hal_common.hpp"
#include "hal_gpio.hpp"
#include "hal_timer.hpp"

namespace hwbridge {

// Define a 3-phase bridge class using DRV8323
class Bridge3PhaseDRV8323 : public Bridge3Phase {
public:
typedef struct drv8323_phase_config_info {
// Timer channel
// TODO: there should be a timer object here as well. Assuming all channels are on the same timer
basilisk_hal::timer_channel_E channel;
basilisk_hal::HAL_GPIO* low_side_gpio; // Not supporting low side gate control for now except for enable/disable
basilisk_hal::HAL_ADC* bemf_sense_adc;
uint8_t bemf_sense_adc_channel;
// TODO: add current sense support. For now, only 6 step is supported.
// basilisk_hal::HAL_ADC* current_sense_adc;
// uint8_t current_sense_adc_channel;
} drv8323_phase_config_info_t;

Bridge3PhaseDRV8323(basilisk_hal::HAL_ComplementaryPWM_Timer& timer, drv8323_phase_config_info_t& u,
drv8323_phase_config_info_t& v, drv8323_phase_config_info_t& w, uint32_t frequency) {
// Register the timer and pin
pwm_timer_ = &timer;
u_ = u;
v_ = v;
w_ = w;
frequency_ = frequency;
};
~Bridge3PhaseDRV8323() = default;

app_hal_status_E init() override {
// Set the direction pin to output
u_.low_side_gpio->set_mode(basilisk_hal::gpio_mode_E::OUTPUT);
v_.low_side_gpio->set_mode(basilisk_hal::gpio_mode_E::OUTPUT);
w_.low_side_gpio->set_mode(basilisk_hal::gpio_mode_E::OUTPUT);

// Set the pwm timer to PWM_CENTRE_ALIGNED
pwm_timer_->set_timer_params(basilisk_hal::timer_mode_E::PWM_CENTRE_ALIGNED, frequency_);

// Set the timer channel
pwm_timer_->set_channel(0, u_.channel);
pwm_timer_->set_channel(0, v_.channel);
pwm_timer_->set_channel(0, w_.channel);

// Start the timer
pwm_timer_->start();

// Start PWM
pwm_timer_->start_pwm(u_.channel);
pwm_timer_->start_pwm(v_.channel);
pwm_timer_->start_pwm(w_.channel);

return app_hal_status_E::APP_HAL_OK;
}

// Define a virtual function to set the individual phases' duty cycles and enable/disable the phase
void set_phase(const phase_command_t& u, const phase_command_t& v, const phase_command_t& w) {
// Determine the appropriate amount of ticks by getting the timer period
uint32_t period = pwm_timer_->get_period();
uint32_t ticks_u =
static_cast<uint32_t>(period * fabs(u.duty_cycle_high_side) / control_loop::ControlLoop::MAX_MOTOR_SPEED);
uint32_t ticks_v =
static_cast<uint32_t>(period * fabs(v.duty_cycle_high_side) / control_loop::ControlLoop::MAX_MOTOR_SPEED);
uint32_t ticks_w =
static_cast<uint32_t>(period * fabs(w.duty_cycle_high_side) / control_loop::ControlLoop::MAX_MOTOR_SPEED);

// Determine the low-side phase active high or active low signal for the complementary timer
// If the inverted boolean is set in the phase command, we should set the command
// to active low, otherwise, we should set the command to active high

basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E u_complementary_phase =
u.invert_low_side ? basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E::ACTIVE_LOW
: basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E::ACTIVE_HIGH;

basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E v_complementary_phase =
v.invert_low_side ? basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E::ACTIVE_LOW
: basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E::ACTIVE_HIGH;

basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E w_complementary_phase =
w.invert_low_side ? basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E::ACTIVE_LOW
: basilisk_hal::HAL_ComplementaryPWM_Timer::complementary_PWM_phase_E::ACTIVE_HIGH;

// Set the PWM timer
pwm_timer_->set_channel_with_complementary_phase(ticks_u, u_.channel, u_complementary_phase);
pwm_timer_->set_channel_with_complementary_phase(ticks_v, v_.channel, v_complementary_phase);
pwm_timer_->set_channel_with_complementary_phase(ticks_w, w_.channel, w_complementary_phase);
}

// Define a function to read the BEMF voltage
app_hal_status_E read_bemf(bemf_voltage_t& bemf_voltage) {
app_hal_status_E status = app_hal_status_E::APP_HAL_OK;
if (u_.bemf_sense_adc == nullptr || v_.bemf_sense_adc == nullptr || w_.bemf_sense_adc == nullptr) {
status = app_hal_status_E::APP_HAL_NOT_INITIALIZED;
} else {
do {
status = u_.bemf_sense_adc->read_adc(bemf_voltage.u, u_.bemf_sense_adc_channel);
if (status != app_hal_status_E::APP_HAL_OK) {
break;
}
status = v_.bemf_sense_adc->read_adc(bemf_voltage.v, v_.bemf_sense_adc_channel);
if (status != app_hal_status_E::APP_HAL_OK) {
break;
}
status = w_.bemf_sense_adc->read_adc(bemf_voltage.w, w_.bemf_sense_adc_channel);
if (status != app_hal_status_E::APP_HAL_OK) {
break;
}
} while (0);
}

return status;
}

// Define a function to read the current
app_hal_status_E read_current(phase_current_t& current) {
IGNORE(current);
return app_hal_status_E::APP_HAL_NOT_IMPLEMENTED;
}

// Define a function that averages out the BEMF voltage readings. Returns a bemf_voltage_t object that contains the
// average of the BEMF voltage readings.
bemf_voltage_t average_bemf_readings(const bemf_voltage_t& new_reading) {
bemf_voltage_t average_bemf_voltage = {0, 0, 0};
for (uint8_t i = 0; i < BEMF_VOLTAGE_AVERAGE_SIZE - 1; i++) {
bemf_voltage_[i] = bemf_voltage_[i + 1];
average_bemf_voltage.u += bemf_voltage_[i].u;
average_bemf_voltage.v += bemf_voltage_[i].v;
average_bemf_voltage.w += bemf_voltage_[i].w;
}
bemf_voltage_[BEMF_VOLTAGE_AVERAGE_SIZE - 1] = new_reading;
average_bemf_voltage.u += new_reading.u;
average_bemf_voltage.v += new_reading.v;
average_bemf_voltage.w += new_reading.w;
average_bemf_voltage.u /= BEMF_VOLTAGE_AVERAGE_SIZE;
average_bemf_voltage.v /= BEMF_VOLTAGE_AVERAGE_SIZE;
average_bemf_voltage.w /= BEMF_VOLTAGE_AVERAGE_SIZE;
return average_bemf_voltage;
}

private:
// Define a timer object
basilisk_hal::HAL_ComplementaryPWM_Timer* pwm_timer_;
drv8323_phase_config_info_t u_;
drv8323_phase_config_info_t v_;
drv8323_phase_config_info_t w_;
uint32_t frequency_;
static constexpr uint8_t BEMF_VOLTAGE_AVERAGE_SIZE = 10;
// Define an array of bemf voltage objects to average out the readings
bemf_voltage_t bemf_voltage_[BEMF_VOLTAGE_AVERAGE_SIZE];
};

} // namespace hwbridge

#endif // BRIDGE_3PHASE_DRV8323_HPP
18 changes: 18 additions & 0 deletions inc/bridge_hbridge.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef BRIDGE_HBRIDGE_HPP
#define BRIDGE_HBRIDGE_HPP

namespace hwbridge {

// Define a generic h-bridge class
class HBridge {
public:
HBridge() = default;
virtual ~HBridge() = default;

// Define a virtual function to run the h-bridge
virtual void run(float speed) = 0;
};

} // namespace hwbridge

#endif
59 changes: 59 additions & 0 deletions inc/bridge_hbridge_drv8801.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef BRIDGE_HBRIDGE_DRV8801_HPP
#define BRIDGE_HBRIDGE_DRV8801_HPP
#include <math.h>

#include "bridge_hbridge.hpp"
#include "control_loop.hpp"
#include "hal_gpio.hpp"
#include "hal_timer.hpp"

namespace hwbridge {

// Define a class that inherits from HBridge
class HBridgeDRV8801 : public HBridge {
public:
HBridgeDRV8801() = default;
~HBridgeDRV8801() = default;

void init(basilisk_hal::HAL_Timer& timer, basilisk_hal::timer_channel_E channel, basilisk_hal::HAL_GPIO& pin,
uint32_t frequency) {
// Register the timer and pin
pwm_timer_ = &timer;
dir_pin_ = &pin;
channel_ = channel;

// Set the direction pin to output
dir_pin_->set_mode(basilisk_hal::gpio_mode_E::OUTPUT);

// Set the pwm timer to PWM_CENTRE_ALIGNED
pwm_timer_->set_timer_params(basilisk_hal::timer_mode_E::PWM_CENTRE_ALIGNED, frequency);

// Set the timer channel
pwm_timer_->set_channel(0, channel_);

// Start the timer
pwm_timer_->start();
}

// Define a run method that overrides the run method in HBridge
void run(float speed) override {
// Set the direction pin
dir_pin_->set_output_state(speed > 0);

// Determine the appropriate amount of ticks by getting the timer period
uint32_t period = pwm_timer_->get_period();
uint32_t ticks = static_cast<uint32_t>(period * fabs(speed) / control_loop::ControlLoop::MAX_MOTOR_SPEED);

// Set the PWM timer
pwm_timer_->set_channel(ticks, channel_);
}

private:
// Define a timer object
basilisk_hal::HAL_Timer* pwm_timer_;
basilisk_hal::timer_channel_E channel_;
basilisk_hal::HAL_GPIO* dir_pin_;
};

} // namespace hwbridge
#endif // BRIDGE_HBRIDGE_DRV8801_HPP
Loading

0 comments on commit 09caa51

Please sign in to comment.