Skip to content

Commit

Permalink
PDU Auto Switch control driver (#93)
Browse files Browse the repository at this point in the history
Contains the following functions:

External periodic function that retrieves power state of switches and stores in a struct:
void autoSwitchPeriodic();

Two functions that can be called externally to enable/disable switches and check their status:
void setSwitch(switches_t auto_switch_enum, bool state);
bool getSwitchStatus(switches_t auto_switch_enum);
  • Loading branch information
zyonse authored Feb 22, 2024
1 parent 6b9293f commit ce25a55
Show file tree
Hide file tree
Showing 4 changed files with 323 additions and 22 deletions.
171 changes: 171 additions & 0 deletions source/pdu/auto_switch/auto_switch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/**
* @file auto_switch.c
* @author Gavin Zyonse ([email protected])
* @brief
* @version 1.0
* @date 2023-11-09
*
* @copyright Copyright (c) 2023
*
*/
#include "auto_switch.h"
#include "common/phal_F4_F7/gpio/gpio.h"

// Initialize struct
auto_switches_t auto_switches;

// Static function declarations
static void updateCurrent();
static void updateVoltage();
static uint16_t calcCurrent_HP(uint16_t);
static uint16_t calcCurrent_LP(uint16_t);
static void calcCurrent_Total();
static uint16_t calcVoltage(uint16_t, int, int);

// Called periodically, Calculates current through each switch in mA
void updateCurrent() {
// High power switches
auto_switches.current[SW_PUMP_1] = calcCurrent_HP(adc_readings.pump_1_imon);
auto_switches.current[SW_PUMP_2] = calcCurrent_HP(adc_readings.pump_2_imon);
auto_switches.current[SW_SDC] = calcCurrent_HP(adc_readings.sdc_imon);
auto_switches.current[SW_AUX] = calcCurrent_HP(adc_readings.aux_hp_imon);

// Low power switches
auto_switches.current[SW_FAN_1] = calcCurrent_LP(adc_readings.fan_1_cs);
auto_switches.current[SW_FAN_2] = calcCurrent_LP(adc_readings.fan_2_cs);
auto_switches.current[SW_DASH] = calcCurrent_LP(adc_readings.dash_cs);
auto_switches.current[SW_ABOX] = calcCurrent_LP(adc_readings.abox_cs);
auto_switches.current[SW_MAIN] = calcCurrent_LP(adc_readings.main_cs);

// Upstream CS
calcCurrent_Total();
}

// Called periodically, Updates voltage for each rail in mV
void updateVoltage() {
auto_switches.voltage.in_24v = calcVoltage(adc_readings.lv_24_v_sense, LV_24V_R1, LV_24V_R2);
auto_switches.voltage.out_5v = calcVoltage(adc_readings.lv_5_v_sense, LV_5V_R1, LV_5V_R2);
auto_switches.voltage.out_3v3 = calcVoltage(adc_readings.lv_3v3_v_sense, LV_3V3_R1, LV_3V3_R2);
}

// Current helper functions
uint16_t calcCurrent_HP(uint16_t current) {
current = current * ADC_REF_mV / ADC_MAX; // Convert to mV
current = current * (HP_CS_R1 + HP_CS_R2) / HP_CS_R2;
current = current * HP_CS_R3 / (HP_CS_R1 + HP_CS_R2);
return current;
}

uint16_t calcCurrent_LP(uint16_t current) {
current = current * ADC_REF_mV / ADC_MAX; // Convert to mA
return current;
}

// CS signals for upstream 24V and 5V (total current through each)
void calcCurrent_Total() {
// 24V current
uint16_t current = adc_readings.lv_24_i_sense;
current = current * ADC_REF_mV / ADC_MAX; // Convert to mV
current = current / HP_CS_R_SENSE / CS_GAIN;
auto_switches.current[CS_24V] = current;

// 5V current
current = adc_readings.lv_5_i_sense;
current = current * ADC_REF_mV / ADC_MAX; // Convert to mA
auto_switches.current[CS_5V] = current;
}

// Converts ADC voltage reading to mV
uint16_t calcVoltage(uint16_t voltage, int r1, int r2) {
// Compensate for voltage divider
voltage = voltage * (r1 + r2) / r2;
// Scale for 12-bit adc at 3.3v
voltage = voltage * ADC_REF_mV / ADC_MAX;
return voltage;
}

// Enable or disable switches by name
void setSwitch(switches_t auto_switch_enum, bool state) {
switch (auto_switch_enum) {
case SW_PUMP_1:
PHAL_writeGPIO(PUMP_1_CTRL_GPIO_Port, PUMP_1_CTRL_Pin, state);
break;
case SW_PUMP_2:
PHAL_writeGPIO(PUMP_2_CTRL_GPIO_Port, PUMP_2_CTRL_Pin, state);
break;
case SW_SDC:
PHAL_writeGPIO(SDC_CTRL_GPIO_Port, SDC_CTRL_Pin, state);
break;
case SW_AUX:
PHAL_writeGPIO(AUX_HP_CTRL_GPIO_Port, AUX_HP_CTRL_Pin, state);
break;
case SW_FAN_1:
PHAL_writeGPIO(FAN_1_CTRL_GPIO_Port, FAN_1_CTRL_Pin, state);
break;
case SW_FAN_2:
PHAL_writeGPIO(FAN_2_CTRL_GPIO_Port, FAN_2_CTRL_Pin, state);
break;
case SW_BLT:
PHAL_writeGPIO(BLT_CTRL_GPIO_Port, BLT_CTRL_Pin, state);
break;
case SW_CRIT_5V:
PHAL_writeGPIO(CRIT_5V_CTRL_GPIO_Port, CRIT_5V_CTRL_Pin, state);
break;
case SW_NCRIT_5V:
PHAL_writeGPIO(NCRIT_5V_CTRL_GPIO_Port, NCRIT_5V_CTRL_Pin, state);
break;
case SW_DAQ:
PHAL_writeGPIO(DAQ_CTRL_GPIO_Port, DAQ_CTRL_Pin, state);
break;
case SW_FAN_5V:
PHAL_writeGPIO(FAN_5V_CTRL_GPIO_Port, FAN_5V_CTRL_Pin, state);
break;
}
}

// Get switch state and return it
bool getSwitchStatus(switches_t auto_switch_enum) {
bool status;
switch (auto_switch_enum) {
case SW_PUMP_1:
status = PHAL_readGPIO(PUMP_1_CTRL_GPIO_Port, PUMP_1_CTRL_Pin);
break;
case SW_PUMP_2:
status = PHAL_readGPIO(PUMP_2_CTRL_GPIO_Port, PUMP_2_CTRL_Pin);
break;
case SW_SDC:
status = PHAL_readGPIO(SDC_CTRL_GPIO_Port, SDC_CTRL_Pin);
break;
case SW_AUX:
status = PHAL_readGPIO(AUX_HP_CTRL_GPIO_Port, AUX_HP_CTRL_Pin);
break;
case SW_FAN_1:
status = PHAL_readGPIO(FAN_1_CTRL_GPIO_Port, FAN_1_CTRL_Pin);
break;
case SW_FAN_2:
status = PHAL_readGPIO(FAN_2_CTRL_GPIO_Port, FAN_2_CTRL_Pin);
break;
case SW_BLT:
status = PHAL_readGPIO(BLT_CTRL_GPIO_Port, BLT_CTRL_Pin);
break;
case SW_CRIT_5V:
status = PHAL_readGPIO(CRIT_5V_CTRL_GPIO_Port, CRIT_5V_CTRL_Pin);
break;
case SW_NCRIT_5V:
status = PHAL_readGPIO(NCRIT_5V_CTRL_GPIO_Port, NCRIT_5V_CTRL_Pin);
break;
case SW_DAQ:
status = PHAL_readGPIO(DAQ_CTRL_GPIO_Port, DAQ_CTRL_Pin);
break;
case SW_FAN_5V:
status = PHAL_readGPIO(FAN_5V_CTRL_GPIO_Port, FAN_5V_CTRL_Pin);
break;
}

return status;
}

void autoSwitchPeriodic() {
updateCurrent();
updateVoltage();
}
117 changes: 117 additions & 0 deletions source/pdu/auto_switch/auto_switch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* @file auto_switch.h
* @author Gavin Zyonse ([email protected])
* @brief
* @version 1.0
* @date 2023-11-09
*
* @copyright Copyright (c) 2023
*
*/
#ifndef _AUTO_SWITCH_H_
#define _AUTO_SWITCH_H_

#include <stdint.h>
#include <stdbool.h>
#include <source/pdu/main.h>

// Static variables
#define SHUNT_R 10000000
#define ADC_MAX 4095

// Voltage sense resistors
#define LV_24V_R1 47000 // Ohms
#define LV_24V_R2 3400 // Ohms
#define LV_5V_R1 4300 // Ohms
#define LV_5V_R2 3400 // Ohms
#define LV_3V3_R1 4300 // Ohms
#define LV_3V3_R2 10000 // Ohms

// HP Current sense resistors
#define HP_CS_R1 180 // Ohms
#define HP_CS_R2 330 // Ohms
#define HP_CS_R3 500 // Ohms

// Upstream Current sense
#define HP_CS_R_SENSE 0.002 // Ohms
#define CS_GAIN 100


// Enumeration
typedef enum {
// High power switches
SW_PUMP_1,
SW_PUMP_2,
SW_SDC,
SW_AUX,

// Low power switches
SW_FAN_1,
SW_FAN_2,
SW_DASH,
SW_ABOX,
SW_MAIN,

// Not actually switches
CS_24V,
CS_5V,

// Number of switches with CS signals (used for array bounds)
// If switch has a current senese circuit, PLACE IT ABOVE THIS COMMENT
CS_SWITCH_COUNT,

// Low power switches (no CS)
SW_BLT,
// 5V switches (no CS)
SW_CRIT_5V,
SW_NCRIT_5V,
SW_DAQ,
SW_FAN_5V
} switches_t;

// Structures
typedef struct {
uint16_t in_24v;
uint16_t out_5v;
uint16_t out_3v3;
} voltage_t; // Voltage in mV

typedef struct {
uint16_t current[CS_SWITCH_COUNT]; // Current in mA
voltage_t voltage;
} auto_switches_t;

extern auto_switches_t auto_switches;

// Function declarations
/**
* @brief Enable or disable a switch
*
* @param auto_switch_enum Switch to enable or disable
* @param state 1 to enable, 0 to disable
*/
void setSwitch(switches_t auto_switch_enum, bool state);

/**
* @brief Check if a switch is enabled
*
* @param auto_switch_enum Switch to check
* @return 1 if enabled, 0 if disabled
*/
bool getSwitchStatus(switches_t auto_switch_enum);

/**
* @brief Combined function that calls updateVoltage()
* and updateCurrent()
*
* Voltage on each rail is stored at:
* auto_switches.voltage.in_24v
* auto_switches.voltage.out_5v
* auto_switches.voltage.out_3v3
*
* Current through each switch is stored at:
* auto_switches.current[auto_switch_enum]
*/
void autoSwitchPeriodic();

#endif
15 changes: 14 additions & 1 deletion source/pdu/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

/* Module Includes */
#include "main.h"
#include "auto_switch.h"
#include "can_parse.h"
#include "daq.h"

Expand Down Expand Up @@ -130,7 +131,7 @@ ADCChannelConfig_t adc_channel_config[] = {
{.channel=INTERNAL_THERM_ADC_CHNL, .rank=16, .sampling_time=ADC_CHN_SMP_CYCLES_480},
};
dma_init_t adc_dma_config = ADC1_DMA_CONT_CONFIG((uint32_t) &adc_readings,
sizeof(adc_readings) / sizeof(adc_readings.lv_3v3_v_sense), 0b01);
sizeof(adc_readings) / sizeof(adc_readings.lv_24_v_sense), 0b01);

#define TargetCoreClockrateHz 16000000
ClockRateConfig_t clock_config = {
Expand Down Expand Up @@ -177,6 +178,17 @@ int main()

PHAL_writeGPIO(LED_CTRL_BLANK_GPIO_Port, LED_CTRL_BLANK_Pin, 1);

if(!PHAL_initADC(ADC1, &adc_config, adc_channel_config,
sizeof(adc_channel_config)/sizeof(ADCChannelConfig_t)))
{
HardFault_Handler();
}
if(!PHAL_initDMA(&adc_dma_config))
{
HardFault_Handler();
}
PHAL_startTxfer(&adc_dma_config);
PHAL_startADC(ADC1);

/* Task Creation */
schedInit(APB1ClockRateHz);
Expand All @@ -188,6 +200,7 @@ int main()
taskCreate(daqPeriodic, DAQ_UPDATE_PERIOD);
taskCreateBackground(canTxUpdate);
taskCreateBackground(canRxUpdate);
taskCreate(autoSwitchPeriodic, 15);
schedStart();
return 0;
}
Expand Down
Loading

0 comments on commit ce25a55

Please sign in to comment.