5 Commits

Author SHA1 Message Date
f8c09f1a49 Saved work 2024-12-03 09:17:59 +02:00
25e6f593d3 Added mode translators 2024-09-17 23:24:01 +03:00
e199a2c2be Saved work 2024-08-20 16:44:35 +03:00
657915fa01 Created more helpers 2024-08-02 10:18:09 +03:00
4a84afcf7a feat-hal-2 (#4)
Finished working initial version

Co-authored-by: Andis Zīle <andis.jarganns@gmail.com>
Reviewed-on: #4
Co-authored-by: Andis Zīle <andis.jargans@gmail.com>
Co-committed-by: Andis Zīle <andis.jargans@gmail.com>
2024-07-31 16:15:35 +00:00
166 changed files with 5261 additions and 13936 deletions

Binary file not shown.

53
firmware/src/bsp/ain.cpp Normal file
View File

@@ -0,0 +1,53 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "ain.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::AnalogIn::AnalogIn(void)
{
this->is_init_done = 0;
return;
}
bsp::AnalogIn::~AnalogIn(void)
{
return;
}
void bsp::AnalogIn::init(uint8_t adc_ch)
{
this->adc_ch = adc_ch;
this->mul = DEF_AIN_MUL;
this->div = DEF_AIN_DIV;
this->offset = DEF_AIN_OFFSET;
this->last_read = 0;
this->is_init_done = 1;
}
uint8_t bsp::AnalogIn::is_init(void)
{
return this->is_init_done;
}
uint16_t bsp::AnalogIn::read(void)
{
if(this->is_init_done==0) return 0;
//Read ADC
uint16_t raw = mcu::adc_read(this->adc_ch);
//Convert to mV
this->last_read = util::convert_muldivoff(raw, this->mul, this->div, this->offset);
return this->last_read;
}
/**** Private function definitions ****/

44
firmware/src/bsp/ain.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef ANALOG_IN_H_
#define ANALOG_IN_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
static const uint8_t DEF_AIN_MUL = 215;
static const uint8_t DEF_AIN_DIV = 44;
static const int16_t DEF_AIN_OFFSET = 0;
class AnalogIn
{
public:
AnalogIn(void);
~AnalogIn(void);
void init(uint8_t adc_ch);
uint8_t is_init(void);
uint8_t mul;
uint8_t div;
int16_t offset;
uint16_t last_read;
uint16_t read(void);
#ifndef TESTING
protected:
#endif
uint8_t adc_ch;
uint8_t is_init_done;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* ANALOG_IN_H_ */

View File

@@ -0,0 +1,56 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "ain_lpf.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::AnalogInLfp::AnalogInLfp(void)
{
this->is_init_done = 0;
return;
}
bsp::AnalogInLfp::~AnalogInLfp(void)
{
return;
}
void bsp::AnalogInLfp::init(uint8_t adc_ch)
{
this->adc_ch = adc_ch;
this->mul = DEF_AIN_MUL;
this->div = DEF_AIN_DIV;
this->offset = DEF_AIN_OFFSET;
this->strength = 0;
this->last_read = 0;
this->last_read_direct = 0;
this->is_init_done = 1;
}
uint16_t bsp::AnalogInLfp::read(void)
{
if(this->is_init_done==0) return 0;
//Read ADC
uint16_t raw = mcu::adc_read(this->adc_ch);
//Convert to mV
this->last_read_direct = util::convert_muldivoff(raw, this->mul, this->div, this->offset);
// Do filtering
uint32_t td0 = ((uint32_t)(255 - this->strength) * this->last_read_direct);
uint32_t td1 = ((uint32_t)(this->strength) * this->last_read);
uint32_t out = (td0 + td1)/255;
this->last_read = util::sat_cast(out);
return this->last_read;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,36 @@
#ifndef ANALOG_IN_LPF_H_
#define ANALOG_IN_LPF_H_
/**** Includes ****/
#include <stdint.h>
#include "ain.h"
namespace bsp {
/**** Public definitions ****/
class AnalogInLfp : public AnalogIn
{
public:
// New stuff
AnalogInLfp(void);
~AnalogInLfp(void);
void init(uint8_t adc_ch);
uint16_t read(void);
uint8_t strength;
uint16_t last_read_direct;
#ifndef TESTING
protected:
#endif
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* ANALOG_IN_LPF_H_ */

118
firmware/src/bsp/board.cpp Normal file
View File

@@ -0,0 +1,118 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "board.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::Board::Board(void)
{
this->is_init_done = 0;
return;
}
bsp::Board::~Board(void)
{
return;
}
void bsp::Board::init(boardCfg_t* cfg)
{
// Calculate settings
// Controller setup
mcu::startupCfg_t mcu_cfg;
mcu_cfg.adc_clk = mcu::ADC_DIV64; // 8MHz/64=125kHz
mcu_cfg.pwm_clk = mcu::TIM_DIV1; // 8MHz/1 = 8MHz
mcu_cfg.pwm_top = 4000/(uint16_t)cfg->pwm_f_khz;
mcu_cfg.od_common_is_pwm = cfg->od_common_is_pwm;
mcu::startup(&mcu_cfg);
// Analog inputs
this->out_voltage.init(mcu::ADC_VOUT);
this->out_voltage.mul = 20;
this->out_voltage.div = 1;
this->out_voltage.offset = 0;
this->out_current.init(mcu::ADC_IOUT);
this->out_current.mul = 215;
this->out_current.div = 22;
this->out_current.offset = 0;
this->battery_voltage.init(mcu::ADC_VBAT);
this->battery_voltage.mul = 20;
this->battery_voltage.div = 1;
this->battery_voltage.offset = 0;
this->battery_current.init(mcu::ADC_IBAT);
this->battery_current.mul = 235;
this->battery_current.div = 6;
this->battery_current.offset = 0;
this->ain1.init(mcu::ADC_AIN1);
this->ain2.init(mcu::ADC_AIN2);
// Digital inputs
this->din1.init(mcu::GPIO_DIN1, 0);
this->din2.init(mcu::GPIO_DIN2, 0);
this->din3.init(mcu::GPIO_DIN3, 0);
this->din4.init(mcu::GPIO_DIN4, 0);
this->hvdin1.init(mcu::GPIO_HVDIN1, 1);
this->hvdin2.init(mcu::GPIO_HVDIN2, 1);
this->hvdin3.init(mcu::GPIO_HVDIN3, 1);
this->hvdin3_pull.init(mcu::GPIO_HVDIN3_PULL, 0);
this->freq_pull.init(mcu::GPIO_FREQ_PULL, 0);
// Open-drain outputs
this->od1.init(mcu::GPIO_OD1, 1);
this->od2.init(mcu::GPIO_OD2, 1);
this->od3.init(mcu::GPIO_OD3, 1);
this->od4.init(mcu::GPIO_OD4, 1);
this->od5.init(mcu::GPIO_OD5, 1);
this->od6.init(mcu::GPIO_OD6, 1);
this->od_pwm.init(mcu::PWM_OD, 100);
// PWM driver output
this->out_pwm.init(mcu::PWM_OUT, 95);
this->out_low.init(mcu::GPIO_OUT_LOW, 0);
this->is_init_done = 1;
}
uint8_t bsp::Board::is_init(void)
{
return this->is_init_done;
}
void bsp::Board::read(void)
{
if(this->is_init_done==0) return;
// Update all analog inputs
this->out_voltage.read();
this->out_current.read();
this->battery_voltage.read();
this->battery_current.read();
this->ain1.read();
this->ain2.read();
// Update all digital inputs
this->din1.read();
this->din2.read();
this->din3.read();
this->din4.read();
this->hvdin1.read();
this->hvdin2.read();
this->hvdin3.read();
}
/**** Private function definitions ****/

77
firmware/src/bsp/board.h Normal file
View File

@@ -0,0 +1,77 @@
#ifndef UDCCD_BOARD_H_
#define UDCCD_BOARD_H_
/**** Includes ****/
#include <stdint.h>
#include "ain.h"
#include "ain_lpf.h"
#include "din.h"
#include "dout.h"
#include "pwm_out.h"
#include "memory.h"
namespace bsp {
/**** Public definitions ****/
class Board
{
public:
typedef struct {
uint8_t pwm_f_khz;
uint8_t od_common_is_pwm;
} boardCfg_t;
Board(void);
~Board(void);
void init(boardCfg_t* cfg);
uint8_t is_init(void);
AnalogIn out_voltage;
AnalogIn out_current;
AnalogIn battery_voltage;
AnalogIn battery_current;
AnalogIn ain1;
AnalogIn ain2;
DigitalIn din1;
DigitalIn din2;
DigitalIn din3;
DigitalIn din4;
DigitalIn hvdin1;
DigitalIn hvdin2;
DigitalIn hvdin3;
DigitalOut hvdin3_pull;
DigitalOut freq_pull;
DigitalOut od1;
DigitalOut od2;
DigitalOut od3;
DigitalOut od4;
DigitalOut od5;
DigitalOut od6;
PwmOut od_pwm;
PwmOut out_pwm;
DigitalOut out_low;
Memory nvmem;
void read(void);
#ifndef TESTING
protected:
#endif
uint8_t is_init_done;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* UDCCD_BOARD_H_ */

56
firmware/src/bsp/din.cpp Normal file
View File

@@ -0,0 +1,56 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "din.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::DigitalIn::DigitalIn(void)
{
this->is_init_done = 0;
return;
}
bsp::DigitalIn::~DigitalIn(void)
{
return;
}
void bsp::DigitalIn::init(uint8_t gpio_ch, uint8_t inverted)
{
this->gpio_ch = gpio_ch;
if(inverted == 0) this->is_inverted = 0;
else this->is_inverted = 1;
this->last_read = 0;
this->is_init_done = 1;
}
uint8_t bsp::DigitalIn::is_init(void)
{
return this->is_init_done;
}
uint8_t bsp::DigitalIn::read(void)
{
if(this->is_init_done==0) return 0;
// Read GPIO
this->last_read = mcu::gpio_read(this->gpio_ch);
// Invert if necessary
if(this->is_inverted)
{
if(this->last_read==0) this->last_read = 1;
else this->last_read = 0;
};
return this->last_read;
}
/**** Private function definitions ****/

38
firmware/src/bsp/din.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef DIGITAL_IN_H_
#define DIGITAL_IN_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
class DigitalIn
{
public:
DigitalIn(void);
~DigitalIn(void);
void init(uint8_t gpio_ch, uint8_t inverted);
uint8_t is_init(void);
uint8_t last_read;
uint8_t read(void);
#ifndef TESTING
protected:
#endif
uint8_t gpio_ch;
uint8_t is_inverted;
uint8_t is_init_done;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DIGITAL_IN_H_ */

40
firmware/src/bsp/dout.cpp Normal file
View File

@@ -0,0 +1,40 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "dout.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::DigitalOut::DigitalOut(void)
{
this->is_init_done = 0;
return;
}
bsp::DigitalOut::~DigitalOut(void)
{
return;
}
void bsp::DigitalOut::write(int8_t level)
{
if(this->is_init_done==0) return;
if(this->is_inverted)
{
if(level==0) level = 1;
else if (level > 0) level = 0;
};
mcu::gpio_write(this->gpio_ch, level);
this->last_writen = level;
}
/**** Private function definitions ****/

34
firmware/src/bsp/dout.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef DIGITAL_OUT_H_
#define DIGITAL_OUT_H_
/**** Includes ****/
#include <stdint.h>
#include "din.h"
namespace bsp {
/**** Public definitions ****/
class DigitalOut : public DigitalIn
{
public:
// New or redefined stuff
DigitalOut(void);
~DigitalOut(void);
int8_t last_writen;
void write(int8_t level);
#ifndef TESTING
protected:
#endif
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DIGITAL_OUT_H_ */

View File

@@ -0,0 +1,115 @@
#ifndef MCU_HAL_H_
#define MCU_HAL_H_
/**** Includes ****/
#include <stdint.h>
namespace mcu {
/**** Public definitions ****/
/*
*/
const uint8_t LEVEL_LOW = 0;
const uint8_t LEVEL_HIGH = 1;
const int8_t LEVEL_HIZ = -1;
const uint8_t GPIO_DIN1 = 0;
const uint8_t GPIO_DIN2 = 1;
const uint8_t GPIO_DIN3 = 2;
const uint8_t GPIO_DIN4 = 3;
const uint8_t GPIO_HVDIN1 = 4;
const uint8_t GPIO_HVDIN2 = 5;
const uint8_t GPIO_HVDIN3 = 6;
const uint8_t GPIO_HVDIN3_PULL = 7;
const uint8_t GPIO_OD1 = 8;
const uint8_t GPIO_OD2 = 9;
const uint8_t GPIO_OD3 = 10;
const uint8_t GPIO_OD4 = 11;
const uint8_t GPIO_OD5 = 12;
const uint8_t GPIO_OD6 = 13;
const uint8_t GPIO_OUT_LOW = 14;
const uint8_t GPIO_OUT_HIGH = 15;
const uint8_t GPIO_OD_PWM = 16;
const uint8_t GPIO_FREQ1 = 17;
const uint8_t GPIO_FREQ2 = 18;
const uint8_t GPIO_FREQ_PULL = 19;
const uint8_t GPIO_TX = 20;
const uint8_t GPIO_RX = 21;
const uint8_t ADC_IOUT = 0; //Output current
const uint8_t ADC_VOUT = 1; //Output voltage
const uint8_t ADC_VBAT = 2; //Battery voltage
const uint8_t ADC_IBAT = 3; //Battery current
const uint8_t ADC_AIN2 = 4; //Potentiometer
const uint8_t ADC_AIN1 = 5; //Mode
const uint8_t ADC_TEMP = 8; //MCU temperature
const uint8_t ADC_IVREF = 14; //MCU internal reference
const uint8_t ADC_GND = 15; //MCU ground
const uint8_t PWM_OUT = 0; //DCCD
const uint8_t PWM_OD = 1; //LED
//ADC definitions
typedef enum {
ADC_DIV2 = 0x01,
ADC_DIV4 = 0x02,
ADC_DIV8 = 0x03,
ADC_DIV16 = 0x04,
ADC_DIV32 = 0x05,
ADC_DIV64 = 0x06,
ADC_DIV128 = 0x07
} adcClkDiv_t;
//Timer definitions
typedef enum {
TIM_DIV1 = 0x01,
TIM_DIV8 = 0x02,
TIM_DIV64 = 0x03,
TIM_DIV256 = 0x04,
TIM_DIV1024 = 0x05
} timerClkDiv_t;
typedef struct {
adcClkDiv_t adc_clk;
timerClkDiv_t pwm_clk;
uint16_t pwm_top;
uint8_t od_common_is_pwm;
} startupCfg_t;
/**** Public function declarations ****/
void startup(startupCfg_t* hwCfg);
uint8_t is_init(void);
void rtc_set_calibration(uint16_t coef);
uint8_t gpio_read(uint8_t ch);
void gpio_write(uint8_t ch, int8_t lvl);
void gpio_write_pull(uint8_t ch, int8_t lvl);
void adc_start(uint8_t ch);
uint8_t adc_is_running(void);
uint8_t adc_is_new(void);
uint16_t adc_read(void);
uint16_t adc_read(uint8_t ch);
void pwm_write(uint8_t ch, uint16_t dc);
uint16_t pwm_read(uint8_t ch);
void timer_reset(uint8_t ch);
uint16_t timer_read(uint8_t ch);
uint16_t timer_read_top(uint8_t ch);
uint32_t timer_convert_us(uint8_t ch, uint16_t raw);
uint32_t timer_convert_ms(uint8_t ch, uint16_t raw);
uint8_t eeprom_read8b(uint16_t address);
uint16_t eeprom_read16b(uint16_t address);
uint32_t eeprom_read32b(uint16_t address);
void eeprom_write8b(uint16_t address, uint8_t value);
void eeprom_write16b(uint16_t address, uint16_t value);
void eeprom_write32b(uint16_t address, uint32_t value);
} //namespace
#endif /* MCU_HAL_H_ */

View File

@@ -3,17 +3,26 @@
#include <avr/eeprom.h>
#include "mcu_hal.h"
using namespace mcu;
/**** Private definitions ****/
/**** Private constants ****/
static const uint8_t def_gpio_read = 0;
/**** Private variables ****/
static volatile uint16_t rtc_ms = 1000;
static volatile uint8_t is_init_done = 0;
/**** Private function declarations ****/
static uint8_t gpio_read(uint8_t pin_reg, uint8_t mask);
static uint8_t gpio_read_level(uint8_t pin_reg, uint8_t mask);
static void pwm_write_ocx(uint8_t ch, uint16_t value);
static uint16_t pwm_read_ocx(uint8_t ch);
/**** Public function definitions ****/
void mcu_startup(startupCfg_t* hwCfg)
void mcu::startup(startupCfg_t* hwCfg)
{
is_init_done = 0;
// Fail-safe GPIO init
PORTB = 0xF8; // Set PORTB pull-ups
DDRB = 0x00; // Set all as inputs
@@ -32,9 +41,9 @@ void mcu_startup(startupCfg_t* hwCfg)
DDRB |= 0x03; //Set as output
// Common OD PWM pin
if(hwCfg->pwm_chb_en) PORTB &= ~0x04; //Set low
else PORTB |= 0x04; //Set high
DDRB |= 0x04; //Set as output
if(hwCfg->od_common_is_pwm) PORTB &= ~0x04; //Set low
else PORTB |= 0x04; //Set high
DDRB |= 0x04; //Set as output
// OD control pins
PORTD &= ~0x3F; //Set low (off)
@@ -64,6 +73,10 @@ void mcu_startup(startupCfg_t* hwCfg)
PORTC &= ~0x30; //Pull-up off
DDRC &= ~0x30; //Set as inputs
// Freq-pull control pins
PORTD &= ~0x40; //Set low
DDRD |= 0x40; //Set as output
//ADC configuration
PRR0 &= ~0x01; //Enable ADC power
DIDR0 |= 0x0F; //Disable digital inputs, ADC0-ADC3
@@ -78,7 +91,7 @@ void mcu_startup(startupCfg_t* hwCfg)
//DCCD and LED PWM configuration
PRR0 &= ~0x80; //Enable Timer1 power
TCCR1A = 0xC2; //Connect OC1A, inverted mode
if(hwCfg->pwm_chb_en) TCCR1A |= 0x30; //Connect OC1B, inverted mode
if(hwCfg->od_common_is_pwm) TCCR1A |= 0x30; //Connect OC1B, inverted mode
TCCR1B = 0x18; //PWM, Phase & Frequency Correct ICR1 top, no clock, WGM:0xE
TCCR1C = 0x00;
TCNT1 = 0x0000;
@@ -90,130 +103,105 @@ void mcu_startup(startupCfg_t* hwCfg)
uint8_t tim1_prescaler = (uint8_t)hwCfg->pwm_clk;
TCCR1B |= tim1_prescaler; //Enable timer
is_init_done = 1;
}
// ADC Interface functions
uint16_t mcu_adc_read(uint8_t ch)
uint8_t mcu::is_init(void)
{
//check if ADC is enabled
if(!(ADCSRA&0x80)) return 0xFFFF;
//Safe guard mux
if(ch > 15) return 0xFFFF;
// Not available channels
if((ch > 8) && (ch<14)) return 0xFFFF;
ADMUX &= ~0x0F;
ADMUX |= ch;
ADCSRA |= 0x40;
while(ADCSRA&0x40); //wait to finish
return ADC;
return is_init_done;
}
// PWM Timer Interface functions
void mcu_pwm_write(uint8_t ch, uint16_t dc)
void mcu::rtc_set_calibration(uint16_t coef)
{
dc = 0xFFFF - dc;
// Calculate value as % of TOP
uint32_t top = (uint32_t)ICR1;
uint32_t temp = (uint32_t)dc * top;
temp = temp/0x0000FFFF;
//Limit temp
if(temp>0x0000FFFF) temp = 0x0000FFFF;
uint16_t ocrx = (uint16_t)temp;
// Write register
pwm_write_ocx(ch, ocrx);
rtc_ms = coef;
}
uint16_t mcu_pwm_read(uint8_t ch)
// GPIO interface functions
uint8_t mcu::gpio_read(uint8_t ch)
{
uint16_t ocrx = pwm_read_ocx(ch);
if(is_init_done==0) return def_gpio_read;
// Check easy answers
if(ocrx == 0) return 0;
if(ocrx >= ICR1) return 0xFFFF;
// Calculate
uint32_t top = (uint32_t)ICR1;
uint32_t temp = (uint32_t)ocrx * 0xFFFF;
temp = temp/top;
//Limit temp
if(temp>0x0000FFFF) return 0xFFFF;
return (uint16_t)temp;
}
uint8_t mcu_gpio_read(uint8_t ch)
{
switch(ch)
{
case MCU_GPIO0: // Mode DIN1
return gpio_read(PINC,0x20);
case GPIO_DIN1: // Mode DIN1
return gpio_read_level(PINC,0x20);
case MCU_GPIO1: // Pot DIN2
return gpio_read(PINC,0x10);
case GPIO_DIN2: // Pot DIN2
return gpio_read_level(PINC,0x10);
case MCU_GPIO2: // Down DIN3
return gpio_read(PINE,0x02);
case GPIO_DIN3: // Down DIN3
return gpio_read_level(PINE,0x02);
case MCU_GPIO3: // Up DIN4
return gpio_read(PINE,0x08);
case GPIO_DIN4: // Up DIN4
return gpio_read_level(PINE,0x08);
case MCU_GPIO4: // Dimm DIN5
return gpio_read(PIND,0x80);
case GPIO_HVDIN1: // Dimm DIN5
return gpio_read_level(PIND,0x80);
case MCU_GPIO5: // Brakes DIN6
return gpio_read(PINB,0x80);
case GPIO_HVDIN2: // Brakes DIN6
return gpio_read_level(PINB,0x80);
case MCU_GPIO6: // Handbrake DIN7
return gpio_read(PINB,0x40);
case GPIO_HVDIN3: // Handbrake DIN7
return gpio_read_level(PINB,0x40);
case MCU_GPIO7: // Handbrake pull DIN8
return gpio_read(PINB,0x20);
case GPIO_HVDIN3_PULL: // Handbrake pull DIN8
return gpio_read_level(PINB,0x20);
case MCU_GPIO8: // Speed-pull
return gpio_read(PIND,0x40);
case GPIO_OD1: // LED 0
return gpio_read_level(PIND,0x01);
case MCU_GPIO9: // LED 0
return gpio_read(PIND,0x01);
case GPIO_OD2: // LED 1
return gpio_read_level(PIND,0x02);
case MCU_GPIO10: // LED 1
return gpio_read(PIND,0x02);
case GPIO_OD3: // LED 2
return gpio_read_level(PIND,0x04);
case MCU_GPIO11: // LED 2
return gpio_read(PIND,0x04);
case GPIO_OD4: // LED 3
return gpio_read_level(PIND,0x08);
case MCU_GPIO12: // LED 3
return gpio_read(PIND,0x08);
case GPIO_OD5: // LED 4
return gpio_read_level(PIND,0x10);
case MCU_GPIO13: // LED 4
return gpio_read(PIND,0x10);
case GPIO_OD6: // LED 5
return gpio_read_level(PIND,0x20);
case MCU_GPIO14: // LED 5
return gpio_read(PIND,0x20);
case GPIO_OUT_LOW: // DCCD Enable
return gpio_read_level(PINB,0x01);
case MCU_GPIO15: // DCCD Enable
return gpio_read(PINB,0x01);
case GPIO_OUT_HIGH: // DCCD PWM
return gpio_read_level(PINB,0x02);
case MCU_GPIO16: // DCCD PWM
return gpio_read(PINB,0x02);
case GPIO_OD_PWM: // LED PWM
return gpio_read_level(PINB,0x04);
case MCU_GPIO17: // LED PWM
return gpio_read(PINB,0x04);
case GPIO_FREQ1: // Speed 1
return gpio_read_level(PINE,0x04);
case GPIO_FREQ2: // Speed 2
return gpio_read_level(PINE,0x01);
case GPIO_FREQ_PULL: // Speed-pull
return gpio_read_level(PIND,0x40);
case GPIO_TX: //
return gpio_read_level(PINB,0x08);
case GPIO_RX: //
return gpio_read_level(PINB,0x10);
default:
return 0;
return def_gpio_read;
}
}
void mcu_gpio_write(uint8_t ch, int8_t lvl)
void mcu::gpio_write(uint8_t ch, int8_t lvl)
{
if(is_init_done==0) return;
switch(ch)
{
case MCU_GPIO0: // Mode DIN1
case GPIO_DIN1: // Mode DIN1
if(lvl>0)
{
PORTC |= 0x20;
@@ -231,7 +219,7 @@ void mcu_gpio_write(uint8_t ch, int8_t lvl)
}
return;
case MCU_GPIO1: // Pot DIN2
case GPIO_DIN2: // Pot DIN2
if(lvl>0)
{
PORTC |= 0x10;
@@ -249,7 +237,7 @@ void mcu_gpio_write(uint8_t ch, int8_t lvl)
}
return;
case MCU_GPIO2: // Down DIN3
case GPIO_DIN3: // Down DIN3
if(lvl>0)
{
PORTE |= 0x02;
@@ -267,7 +255,7 @@ void mcu_gpio_write(uint8_t ch, int8_t lvl)
}
return;
case MCU_GPIO3: // Up DIN4
case GPIO_DIN4: // Up DIN4
if(lvl>0)
{
PORTE |= 0x08;
@@ -285,7 +273,7 @@ void mcu_gpio_write(uint8_t ch, int8_t lvl)
}
return;
case MCU_GPIO7: // Handbrake pull DIN
case GPIO_HVDIN3_PULL: // Handbrake pull DIN
if(lvl>0)
{
PORTB |= 0x20;
@@ -303,97 +291,246 @@ void mcu_gpio_write(uint8_t ch, int8_t lvl)
}
return;
case MCU_GPIO8: // Speed-pull
if(lvl>0) PORTD |= 0x40;
else PORTD &= ~0x40;
return;
case MCU_GPIO9: // LED 0
case GPIO_OD1: // LED 0
if(lvl>0) PORTD |= 0x01;
else PORTD &= ~0x01;
return;
case MCU_GPIO10: // LED 1
case GPIO_OD2: // LED 1
if(lvl>0) PORTD |= 0x02;
else PORTD &= ~0x02;
return;
case MCU_GPIO11: // LED 2
case GPIO_OD3: // LED 2
if(lvl>0) PORTD |= 0x04;
else PORTD &= ~0x04;
return;
case MCU_GPIO12: // LED 3
case GPIO_OD4: // LED 3
if(lvl>0) PORTD |= 0x08;
else PORTD &= ~0x08;
return;
case MCU_GPIO13: // LED 4
case GPIO_OD5: // LED 4
if(lvl>0) PORTD |= 0x10;
else PORTD &= ~0x10;
return;
case MCU_GPIO14: // LED 5
case GPIO_OD6: // LED 5
if(lvl>0) PORTD |= 0x20;
else PORTD &= ~0x20;
return;
case MCU_GPIO15: // DCCD Enable
case GPIO_OUT_LOW: // DCCD Enable
if(lvl>0) PORTB |= 0x01;
else PORTB &= ~0x01;
return;
case GPIO_FREQ_PULL: // Speed-pull
if(lvl>0) PORTD |= 0x40;
else PORTD &= ~0x40;
return;
default:
return;
}
}
uint8_t mcu_ee_read8b(uint16_t address)
void mcu::gpio_write_pull(uint8_t ch, int8_t lvl)
{
if(is_init_done==0) return;
switch(ch)
{
case GPIO_DIN1: // Mode DIN1
if(lvl>0) PORTC |= 0x20;
else PORTC &= ~0x20;
return;
case GPIO_DIN2: // Pot DIN2
if(lvl>0) PORTC |= 0x10;
else PORTC &= ~0x10;
return;
case GPIO_DIN3: // Down DIN3
if(lvl>0) PORTE |= 0x02;
else PORTE &= ~0x02;
return;
case GPIO_DIN4: // Up DIN4
if(lvl>0) PORTE |= 0x08;
else PORTE &= ~0x08;
return;
case GPIO_HVDIN1: // Dimm
if(lvl>0) PORTD |= 0x80;
else PORTD &= ~0x80;
return;
case GPIO_HVDIN2: // Brakes
if(lvl>0) PORTB |= 0x80;
else PORTB &= ~0x80;
return;
case GPIO_HVDIN3: // Handbrake
if(lvl>0) PORTB |= 0x40;
else PORTB &= ~0x40;
return;
default:
return;
}
}
// ADC interface functions
void mcu::adc_start(uint8_t ch)
{
if(is_init_done==0) return;
// check if already running
if(ADCSRA&0x40) return;
//check if ADC is enabled
if(!(ADCSRA&0x80)) return;
//Safe guard mux
if(ch > 15) return;
// Not available channels
if((ch > 8) && (ch<14)) return;
ADMUX &= ~0x0F;
ADMUX |= ch;
ADCSRA |= 0x10; // Reset int. flag
ADCSRA |= 0x40;
}
uint8_t mcu::adc_is_running(void)
{
if(ADCSRA&0x40) return 1;
else return 0;
}
uint8_t mcu::adc_is_new(void)
{
if(ADCSRA&0x10) return 1;
else return 0;
}
uint16_t mcu::adc_read(void)
{
if(is_init_done==0) return 0;
ADCSRA |= 0x10; // Reset int. flag
return ADC;
}
uint16_t mcu::adc_read(uint8_t ch)
{
if(is_init_done==0) return 0;
//check if ADC is enabled
if(!(ADCSRA&0x80)) return 0xFFFF;
//Safe guard mux
if(ch > 15) return 0xFFFF;
// Not available channels
if((ch > 8) && (ch<14)) return 0xFFFF;
ADMUX &= ~0x0F;
ADMUX |= ch;
ADCSRA |= 0x40;
while(ADCSRA&0x40); //wait to finish
return ADC;
}
// PWM interface functions
void mcu::pwm_write(uint8_t ch, uint16_t dc)
{
if(is_init_done==0) return;
dc = 0xFFFF - dc;
// Calculate value as % of TOP
uint32_t top = (uint32_t)ICR1;
uint32_t temp = (uint32_t)dc * top;
temp = temp/0x0000FFFF;
//Limit temp
if(temp>0x0000FFFF) temp = 0x0000FFFF;
uint16_t ocrx = (uint16_t)temp;
// Write register
pwm_write_ocx(ch, ocrx);
}
uint16_t mcu::pwm_read(uint8_t ch)
{
if(is_init_done==0) return 0;
uint16_t ocrx = pwm_read_ocx(ch);
// Check easy answers
if(ocrx == 0) return 0;
if(ocrx >= ICR1) return 0xFFFF;
// Calculate
uint32_t top = (uint32_t)ICR1;
uint32_t temp = (uint32_t)ocrx * 0xFFFF;
temp = temp/top;
//Limit temp
if(temp>0x0000FFFF) return 0xFFFF;
return (uint16_t)temp;
}
// EEPROM interface functions
uint8_t mcu::eeprom_read8b(uint16_t address)
{
return eeprom_read_byte((uint8_t*)address);
}
uint16_t mcu_ee_read16b(uint16_t address)
uint16_t mcu::eeprom_read16b(uint16_t address)
{
return eeprom_read_word((uint16_t*)address);
}
uint32_t mcu_ee_read32b(uint16_t address)
uint32_t mcu::eeprom_read32b(uint16_t address)
{
return eeprom_read_dword((uint32_t*)address);
}
void mcu_ee_write8b(uint16_t address, uint8_t value)
void mcu::eeprom_write8b(uint16_t address, uint8_t value)
{
eeprom_write_byte((uint8_t*)address, value);
}
void mcu_ee_write16b(uint16_t address, uint16_t value)
void mcu::eeprom_write16b(uint16_t address, uint16_t value)
{
eeprom_write_word((uint16_t*)address, value);
}
void mcu_ee_write32b(uint16_t address, uint32_t value)
void mcu::eeprom_write32b(uint16_t address, uint32_t value)
{
eeprom_write_dword((uint32_t*)address, value);
}
/**** Private function definitions ****/
static uint8_t gpio_read(uint8_t pin_reg, uint8_t mask)
static uint8_t gpio_read_level(uint8_t pin_reg, uint8_t mask)
{
if(pin_reg&mask) return MCU_GPIO_HIGH;
else return MCU_GPIO_LOW;
if(pin_reg&mask) return LEVEL_HIGH;
else return LEVEL_LOW;
}
static void pwm_write_ocx(uint8_t ch, uint16_t value)
{
switch(ch)
{
case MCU_PWM0:
case PWM_OUT:
OCR1A = value;
return;
case MCU_PWM1:
case PWM_OD:
OCR1B = value;
return;
@@ -406,13 +543,13 @@ static uint16_t pwm_read_ocx(uint8_t ch)
{
switch(ch)
{
case MCU_PWM0:
case PWM_OUT:
return OCR1A;
case MCU_PWM1:
case PWM_OD:
return OCR1B ;
default:
return 0x0000;
}
}
}

View File

@@ -0,0 +1,55 @@
/**** Includes ****/
#include "mcu/mcu_hal.h"
#include "memory.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::Memory::Memory(void)
{
return;
}
bsp::Memory::~Memory(void)
{
return;
}
uint8_t bsp::Memory::read_8b(uint16_t address)
{
return mcu::eeprom_read8b(address);
}
uint16_t bsp::Memory::read_16b(uint16_t address)
{
return mcu::eeprom_read16b(address);
}
uint32_t bsp::Memory::read_32b(uint16_t address)
{
return mcu::eeprom_read32b(address);
}
void bsp::Memory::write_8b(uint16_t address, uint8_t value)
{
mcu::eeprom_write8b(address, value);
}
void bsp::Memory::write_16b(uint16_t address, uint16_t value)
{
mcu::eeprom_write16b(address, value);
}
void bsp::Memory::write_32b(uint16_t address, uint32_t value)
{
mcu::eeprom_write32b(address, value);
}
/**** Private function definitions ****/

36
firmware/src/bsp/memory.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef MEMORY_IN_H_
#define MEMORY_IN_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
class Memory
{
public:
Memory(void);
~Memory(void);
uint8_t read_8b(uint16_t address);
uint16_t read_16b(uint16_t address);
uint32_t read_32b(uint16_t address);
void write_8b(uint16_t address, uint8_t value);
void write_16b(uint16_t address, uint16_t value);
void write_32b(uint16_t address, uint32_t value);
#ifndef TESTING
protected:
#endif
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* MEMORY_IN_H_ */

View File

@@ -0,0 +1,68 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "pwm_out.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::PwmOut::PwmOut(void)
{
this->is_init_done = 0;
return;
}
bsp::PwmOut::~PwmOut(void)
{
this->last_duty = 0;
}
void bsp::PwmOut::init(uint8_t pwm_ch, uint8_t max_dc)
{
this->pwm_ch = pwm_ch;
this->last_duty = 0;
if(max_dc>100) max_dc = 100;
this->max_dc = util::percent_to_16b(max_dc);
this->is_init_done = 1;
}
uint8_t bsp::PwmOut::is_init(void)
{
return this->is_init_done;
}
void bsp::PwmOut::write(uint16_t numerator)
{
if(this->is_init_done==0) return;
// Update target
if(numerator > this->max_dc) numerator = this->max_dc;
this->last_duty = numerator;
// Set PWM
mcu::pwm_write(this->pwm_ch, numerator);
}
void bsp::PwmOut::write(uint8_t percent)
{
if(this->is_init_done==0) return;
// Convert to numerator/0xFFFF
this->write(util::percent_to_16b(percent));
}
uint16_t bsp::PwmOut::get_set_duty(void)
{
return this->last_duty;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,39 @@
#ifndef PWM_OUT_H_
#define PWM_OUT_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
class PwmOut
{
public:
PwmOut(void);
~PwmOut(void);
void init(uint8_t pwm_ch, uint8_t max_dc);
uint8_t is_init(void);
void write(uint16_t numerator);
void write(uint8_t percent);
uint16_t get_set_duty(void);
#ifndef TESTING
protected:
#endif
uint8_t pwm_ch;
uint16_t last_duty;
uint16_t max_dc;
uint8_t is_init_done;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* PWM_OUT_H_ */

View File

@@ -0,0 +1,117 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "brakes.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::Brakes::Brakes(void)
{
return;
}
dccd::Brakes::~Brakes(void)
{
return;
}
void dccd::Brakes::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->mode = OPEN;
this->is_new_mode = 0;
this->is_active = 0;
}
void dccd::Brakes::cfg_debounce(uint16_t dbnc_time)
{
this->hardware->brakes.dbnc_lim = dbnc_time;
}
uint8_t dccd::Brakes::process(void)
{
if(this->hardware->brakes.state > 0)
{
this->is_active = 1;
}
else
{
this->is_active = 0;
}
return this->is_active;
}
Brakes::bmode_t dccd::Brakes::cycle_mode(void)
{
switch(this->mode)
{
case OPEN:
this->mode = KEEP;
break;
case KEEP:
this->mode = LOCK;
break;
case LOCK:
this->mode = OPEN;
break;
default:
this->mode = OPEN;
break;
}
this->is_new_mode = 1;
return this->mode;
}
uint8_t dccd::Brakes::get_mode_int(void)
{
switch(this->mode)
{
case OPEN:
return 0;
case KEEP:
return 1;
case LOCK:
return 2;
default:
return 0;
}
}
void dccd::Brakes::set_mode_int(uint8_t mode_int)
{
switch(mode_int)
{
case 0:
this->mode = OPEN;
break;
case 1:
this->mode = KEEP;
break;
case 2:
this->mode = LOCK;
break;
default:
this->mode = OPEN;
break;
}
}
/**** Private function definitions ***/

View File

@@ -0,0 +1,49 @@
#ifndef DCCD_BRAKES_H_
#define DCCD_BRAKES_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class Brakes
{
public:
typedef enum
{
OPEN = 0,
KEEP = 1,
LOCK = 2
}bmode_t;
Brakes(void);
~Brakes(void);
void init(dccd::DccdHw* dccd_hw);
bmode_t mode;
uint8_t is_active;
uint8_t is_new_mode;
void cfg_debounce(uint16_t dbnc_time);
bmode_t cycle_mode(void);
uint8_t process(void);
uint8_t get_mode_int(void);
void set_mode_int(uint8_t mode_int);
#ifdef TESTING
protected:
#endif
dccd::DccdHw* hardware;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_BRAKES_H_ */

View File

@@ -0,0 +1,115 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "coil_reg.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::CoilReg::CoilReg(void)
{
return;
}
dccd::CoilReg::~CoilReg(void)
{
return;
}
void dccd::CoilReg::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->lock_current = 4500;
this->ref_resistance = 1500;
this->cc_max_resistance = 2000;
this->cc_min_resistance = 1000;
this->target_force = 0;
this->set_force = 0;
this->disable_protection = 0;
// Config output protection
this->hardware->out_voltage.under_treshold = 0;
this->hardware->out_voltage.over_treshold = 0xFFFF;
this->hardware->out_voltage.hold_time = 200;
this->hardware->out_voltage.cooldown_time = 1000;
this->hardware->out_voltage.auto_reset = 1;
}
void dccd::CoilReg::process(void)
{
// Fix target force
if(this->target_force > 100) this->target_force = 100;
// Check protection
if((this->disable_protection==0)&&(this->hardware->out_voltage.fault!=0))
{
// HiZ
this->hardware->outreg.write_voltage(0);
this->hardware->outreg.write_current(0);
this->hardware->outreg.write_on(0);
this->hardware->out_voltage.under_treshold = 0;
this->set_force = -1;
return;
};
// Check for target changes
if(this->target_force == this->set_force) return;
// Update set force
this->set_force = this->target_force;
if(this->set_force < 0)
{
// HiZ
this->hardware->outreg.write_voltage(0);
this->hardware->outreg.write_current(0);
this->hardware->outreg.write_on(0);
this->hardware->out_voltage.under_treshold = 0;
}
else if(this->set_force == 0)
{
// Open
this->hardware->outreg.write_voltage(0);
this->hardware->outreg.write_current(0);
this->hardware->outreg.write_on(1);
this->hardware->out_voltage.under_treshold = 0;
}
else
{
// Calculate current and voltage settings
this->hardware->outreg.write_current(util::percent_of((uint8_t)this->set_force, this->lock_current));
uint16_t resistance = this->ref_resistance;
if(this->hardware->outreg.cc_mode_en) resistance = this->cc_max_resistance;
this->hardware->outreg.write_voltage(util::sat_mul_kilo(this->hardware->outreg.read_current(), resistance));
this->hardware->outreg.write_on(1);
// Calculate min. voltage
if(this->disable_protection==0) this->hardware->out_voltage.under_treshold = util::sat_mul_kilo(this->hardware->outreg.read_current(), cc_min_resistance);
}
}
uint8_t dccd::CoilReg::is_fault(void)
{
if(this->disable_protection!=0) return 0;
return this->hardware->out_voltage.fault;
}
uint8_t dccd::CoilReg::read_act_force(void)
{
if(this->set_force < 0) return 0;
else return (uint8_t)this->set_force;
}
void dccd::CoilReg::cfg_set_cv_mode(void)
{
this->hardware->outreg.cc_mode_en = 0;
}
void dccd::CoilReg::cfg_set_cc_mode(void)
{
this->hardware->outreg.cc_mode_en = 1;
}
/**** Private function definitions ***/

View File

@@ -0,0 +1,47 @@
#ifndef DCCD_COIL_REG_H_
#define DCCD_COIL_REG_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class CoilReg
{
public:
CoilReg(void);
~CoilReg(void);
void init(dccd::DccdHw* dccd_hw);
uint16_t lock_current;
uint16_t ref_resistance;
uint16_t cc_max_resistance;
uint16_t cc_min_resistance;
uint8_t disable_protection;
int8_t target_force;
void process(void);
uint8_t read_act_force(void);
void cfg_set_cv_mode(void);
void cfg_set_cc_mode(void);
uint8_t is_fault(void);
#ifdef TESTING
protected:
#endif
dccd::DccdHw* hardware;
int8_t set_force;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_COIL_REG_H_ */

438
firmware/src/dccd/dccd.cpp Normal file
View File

@@ -0,0 +1,438 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "dccd.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::DccdApp::DccdApp(void)
{
return;
}
dccd::DccdApp::~DccdApp(void)
{
return;
}
void dccd::DccdApp::init(DccdHw* dccd_hw, cfg_app_t* def_cfg)
{
this->hardware = dccd_hw;
this->config = def_cfg;
// Memory
this->nvmem.init(dccd_hw);
this->read_nvmem_cfg();
// Set config
this->user_force.init(dccd_hw);
this->user_force.btn_repeat_time = this->config->user_btn_repeat_time;
this->user_force.pot_mode = this->config->pot_mode;
this->user_force.btn_step = this->config->btn_step;
this->user_force.cfg_debounce(this->config->user_btn_dbnc);
this->mode_btn.init(dccd_hw);
this->mode_btn.btn_repeat_time = this->config->mode_btn_repeat_time;
this->mode_btn.cfg_debounce(this->config->user_btn_dbnc);
this->tps.init(dccd_hw);
this->tps.treshold_on = this->config->tps_treshold_on;
this->tps.treshold_off = this->config->tps_treshold_off;
this->tps.timeout_time = this->config->tps_timeout;
this->tps.mode = Thtrottle::MODE0;
this->hbrake.init(dccd_hw);
this->hbrake.latch_time_1 = this->config->hbrake_latch_time_1;
this->hbrake.latch_time_2 = this->config->hbrake_latch_time_2;
this->hbrake.latch_time_3 = this->config->hbrake_latch_time_3;
this->hbrake.mode = Handbrake::LATCH0;
this->hbrake.cfg_debounce(this->config->hbrake_dbnc);
this->brakes.init(dccd_hw);
this->brakes.mode = Brakes::OPEN;
this->brakes.cfg_debounce(this->config->brakes_dbnc);
this->coil_reg.init(dccd_hw);
this->coil_reg.lock_current = this->config->coil_lock_current;
this->coil_reg.ref_resistance = this->config->coil_ref_resistance;
this->coil_reg.cc_max_resistance = this->config->coil_out_max_resistance;
this->coil_reg.cc_min_resistance = this->config->coil_out_min_resistance;
this->coil_reg.target_force = 0;
this->coil_reg.disable_protection = this->config->coil_disable_protection;
if(this->config->coil_cc_mode) this->coil_reg.cfg_set_cc_mode();
else this->coil_reg.cfg_set_cv_mode();
this->dsp.init(dccd_hw);
this->dsp.brigth_pwm = this->config->dsp_brigth_pwm;
this->dsp.dimm_pwm = this->config->dsp_dimm_pwm;
this->dsp.next_image = 0x01;
this->dsp.next_lock_lvl = 0;
this->dsp.next_lock_time = 0;
// Variable config
if(this->user_force.pot_mode!=0) this->config->tps_enabled = 0;
// Restore saved user config
this->user_force.btn_force = this->nvmem.dynamic_cfg.btn_force;
if(this->user_force.btn_force > 100)
{
this->user_force.btn_force = 100;
this->nvmem.dynamic_cfg.btn_force = 100;
};
this->tps.set_mode_int(this->nvmem.dynamic_cfg.tps_mode);
this->hbrake.set_mode_int(this->nvmem.dynamic_cfg.hbrake_mode);
this->brakes.set_mode_int(this->nvmem.dynamic_cfg.brakes_mode);
// Initialize state
this->hardware->read();
this->coil_reg.process();
this->dsp.force_backlight(this->dsp.brigth_pwm);
this->dsp.process();
this->hardware->write();
}
void dccd::DccdApp::process(void)
{
// Update all inputs
this->hardware->read();
// Process pedals
this->tps.process();
this->hbrake.process();
this->brakes.process();
// Process mode
this->mode_btn.process();
if(this->mode_btn.is_new)
{
this->mode_btn.is_new = 0;
if(this->hbrake.is_active)
{
this->hbrake.cycle_mode();
this->nvmem.dynamic_cfg.hbrake_mode = this->hbrake.get_mode_int();
}
else if (this->brakes.is_active)
{
this->brakes.cycle_mode();
this->nvmem.dynamic_cfg.brakes_mode = this->brakes.get_mode_int();
}
else if(this->user_force.pot_mode==0)
{
this->tps.cycle_mode();
this->nvmem.dynamic_cfg.tps_mode = this->tps.get_mode_int();
}
else
{
this->brakes.cycle_mode();
this->nvmem.dynamic_cfg.brakes_mode = this->brakes.get_mode_int();
}
};
// Process user force
this->user_force.process();
if(this->user_force.is_new_btn_force)
{
this->nvmem.dynamic_cfg.btn_force = this->user_force.btn_force;
};
// Calculate new output force
this->coil_reg.target_force = this->calc_next_force();
// Process coil driver
this->coil_reg.process();
// Process display logic
this->dsp_logic();
// Execute outputs
this->hardware->write();
// Save new user config
this->nvmem.update();
}
/**** Private function definitions ***/
int8_t dccd::DccdApp::calc_next_force(void)
{
if(this->hbrake.is_active)
{
return this->config->hbrake_force;
}
else if(this->brakes.is_active)
{
switch(this->brakes.mode)
{
case Brakes::OPEN:
return this->config->brakes_open_force;
case Brakes::KEEP:
return (int8_t)(this->user_force.force);
case Brakes::LOCK:
return this->config->brakes_lock_force;
default:
return 0;
}
}
else
{
// Determine TPS force override
int8_t tps_force = 0;
if((this->config->tps_enabled)&&(this->tps.is_active()))
{
switch(this->tps.mode)
{
case Thtrottle::MODE0:
tps_force = 0;
break;
case Thtrottle::MODE1:
tps_force = this->config->tps_force_1;
break;
case Thtrottle::MODE2:
tps_force = this->config->tps_force_2;
break;
case Thtrottle::MODE3:
tps_force = this->config->tps_force_3;
break;
default:
tps_force = 0;
break;
}
};
// Return biggest of two sources
if(tps_force > (int8_t)this->user_force.force) return tps_force;
else return (int8_t)(this->user_force.force);
}
}
void dccd::DccdApp::dsp_logic(void)
{
// Display image
if(this->hbrake.is_new_mode)
{
this->hbrake.is_new_mode = 0;
uint8_t hbmode_image;
switch(this->hbrake.mode)
{
case Handbrake::LATCH0:
hbmode_image = 0x07;
break;
case Handbrake::LATCH1:
hbmode_image = 0x0E;
break;
case Handbrake::LATCH2:
hbmode_image = 0x1C;
break;
case Handbrake::LATCH3:
hbmode_image = 0x38;
break;
default:
hbmode_image = 0x07;
this->hbrake.mode = Handbrake::LATCH0;
break;
}
this->dsp.write(hbmode_image, 3, this->config->dsp_mode_lock_time);
}
else if(this->brakes.is_new_mode)
{
this->brakes.is_new_mode = 0;
uint8_t bmode_image;
switch(this->brakes.mode)
{
case Brakes::OPEN:
bmode_image = 0x07;
break;
case Brakes::KEEP:
bmode_image = 0x1E;
break;
case Brakes::LOCK:
bmode_image = 0x38;
break;
default:
bmode_image = 0x07;
this->brakes.mode = Brakes::OPEN;
break;
}
this->dsp.write(bmode_image, 3, this->config->dsp_mode_lock_time);
}
else if(this->tps.is_new_mode)
{
this->tps.is_new_mode = 0;
uint8_t tpsmode_image;
switch(this->tps.mode)
{
case Thtrottle::MODE0:
tpsmode_image = 20;
break;
case Thtrottle::MODE1:
tpsmode_image = 60;
break;
case Thtrottle::MODE2:
tpsmode_image = 80;
break;
case Thtrottle::MODE3:
tpsmode_image = 100;
break;
default:
tpsmode_image = 0;
this->tps.mode = Thtrottle::MODE0;
break;
}
this->dsp.write_percent(tpsmode_image, DccdDisplay::BAR20, 3, this->config->dsp_mode_lock_time);
}
else if(this->user_force.is_new_btn_force)
{
this->user_force.is_new_btn_force = 0;
this->dsp.write_percent(this->user_force.force, DccdDisplay::DOT10, 2, this->config->dsp_force_lock_time);
}
else if(this->coil_reg.is_fault())
{
this->dsp.write(0x33, 1, 0);
}
else
{
this->dsp.write_percent(this->coil_reg.read_act_force(), DccdDisplay::DOT10, 0, 0);
};
// Process display
this->dsp.process();
}
void dccd::DccdApp::read_nvmem_cfg(void)
{
if(this->config->force_def_config!=0) return;
Memory::staticmem_t mem_cfg;
this->nvmem.read_static(&mem_cfg);
// Process raw saved config
if(mem_cfg.is_nvmem_cfg != 0x01) return; // No valid config in memory
// Input mode
if((mem_cfg.inp_mode == 0x00)||(mem_cfg.inp_mode == 0x01))
{
this->config->pot_mode = mem_cfg.inp_mode;
};
// Handbrake
this->config->hbrake_latch_time_1 = (uint16_t)mem_cfg.hbrake_t1 * 100;
this->config->hbrake_latch_time_2 = (uint16_t)mem_cfg.hbrake_t2 * 100;
this->config->hbrake_latch_time_3 = (uint16_t)mem_cfg.hbrake_t3 * 100;
this->config->hbrake_dbnc = (uint16_t)mem_cfg.hbrake_dbnc * 10;
if((mem_cfg.hbrake_force <= 100)||(mem_cfg.hbrake_force == 0xFF))
{
this->config->hbrake_force = (int8_t)mem_cfg.hbrake_force;
};
// Brakes
this->config->brakes_dbnc = (uint16_t)mem_cfg.brakes_dnbc * 10;
if((mem_cfg.brakes_open_force <= 100)||(mem_cfg.brakes_open_force == 0xFF))
{
this->config->brakes_open_force = (int8_t)mem_cfg.brakes_open_force;
};
if((mem_cfg.brakes_lock_force <= 100)||(mem_cfg.brakes_lock_force == 0xFF))
{
this->config->brakes_lock_force = (int8_t)mem_cfg.brakes_lock_force;
};
// Throttle position
if((mem_cfg.tps_en == 0x00)||(mem_cfg.tps_en == 0x01))
{
this->config->tps_enabled = mem_cfg.tps_en;
};
if(mem_cfg.tps_on_th <= 100)
{
this->config->tps_treshold_on = mem_cfg.tps_on_th;
};
if(mem_cfg.tps_off_th <= 100)
{
this->config->tps_treshold_off = mem_cfg.tps_off_th;
};
this->config->tps_timeout = (uint16_t)mem_cfg.tps_timeout * 100;
if(mem_cfg.tps_force_1 <= 100)
{
this->config->tps_force_1 = (int8_t)mem_cfg.tps_force_1;
};
if(mem_cfg.tps_force_2 <= 100)
{
this->config->tps_force_2 = (int8_t)mem_cfg.tps_force_2;
};
if(mem_cfg.tps_force_3 <= 100)
{
this->config->tps_force_3 = (int8_t)mem_cfg.tps_force_3;
};
// Coil
if(mem_cfg.coil_lock_current <= 60)
{
this->config->coil_lock_current = (uint16_t)mem_cfg.coil_lock_current * 100;
};
if((mem_cfg.coil_ccm_resistance >= 10)&&(mem_cfg.coil_ccm_resistance <= 20))
{
this->config->coil_ref_resistance = (uint16_t)mem_cfg.coil_ccm_resistance * 100;
};
if((mem_cfg.coil_cvm_resistance >= 10)&&(mem_cfg.coil_cvm_resistance <= 30))
{
this->config->coil_out_max_resistance = (uint16_t)mem_cfg.coil_cvm_resistance * 100;
};
if((mem_cfg.coil_protection_dis == 0x00)||(mem_cfg.coil_protection_dis == 0x01))
{
this->config->coil_disable_protection = mem_cfg.coil_protection_dis;
};
if((mem_cfg.coil_cc_mode_en == 0x00)||(mem_cfg.coil_cc_mode_en == 0x01))
{
this->config->coil_cc_mode = mem_cfg.coil_cc_mode_en;
};
// Display
if(mem_cfg.dsp_brigth_pwm <= 100)
{
this->config->dsp_brigth_pwm = mem_cfg.dsp_brigth_pwm;
};
if(mem_cfg.dsp_dimm_pwm <= 100)
{
this->config->dsp_dimm_pwm = mem_cfg.dsp_dimm_pwm;
};
}

90
firmware/src/dccd/dccd.h Normal file
View File

@@ -0,0 +1,90 @@
#ifndef DCCD_APP_H_
#define DCCD_APP_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
#include "user_force.h"
#include "mode.h"
#include "handbrake.h"
#include "brakes.h"
#include "coil_reg.h"
#include "display.h"
#include "tps.h"
#include "memory.h"
namespace dccd {
/**** Public definitions ****/
class DccdApp
{
public:
typedef struct{
uint16_t user_btn_dbnc;
uint16_t user_btn_repeat_time;
uint8_t pot_mode;
uint8_t btn_step;
uint16_t mode_btn_repeat_time;
uint8_t tps_treshold_on;
uint8_t tps_treshold_off;
uint16_t tps_timeout;
uint16_t hbrake_latch_time_1;
uint16_t hbrake_latch_time_2;
uint16_t hbrake_latch_time_3;
uint16_t hbrake_dbnc;
uint16_t brakes_dbnc;
uint16_t coil_lock_current;
uint16_t coil_ref_resistance;
uint16_t coil_out_max_resistance;
uint16_t coil_out_min_resistance;
uint8_t coil_disable_protection;
uint8_t coil_cc_mode;
uint8_t dsp_brigth_pwm;
uint8_t dsp_dimm_pwm;
int8_t hbrake_force;
int8_t brakes_open_force;
int8_t brakes_lock_force;
uint8_t tps_enabled;
int8_t tps_force_1;
int8_t tps_force_2;
int8_t tps_force_3;
uint16_t dsp_mode_lock_time;
uint16_t dsp_force_lock_time;
uint8_t force_def_config;
} cfg_app_t;
DccdApp(void);
~DccdApp(void);
void init(DccdHw* dccd_hw, cfg_app_t* def_cfg);
void process(void);
UserForce user_force;
ModeBtn mode_btn;
Handbrake hbrake;
Brakes brakes;
CoilReg coil_reg;
DccdDisplay dsp;
Thtrottle tps;
Memory nvmem;
cfg_app_t* config;
#ifdef TESTING
protected:
#endif
DccdHw* hardware;
int8_t calc_next_force(void);
void dsp_logic(void);
void read_nvmem_cfg(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_APP_H_ */

View File

@@ -0,0 +1,190 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "dccd_hw.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
static const uint8_t def_dbnc_time = 10;
static const uint16_t def_pot_dead_bot = 500;
static const uint16_t def_pot_dead_top = 4500;
static const uint8_t def_cc_mode_en = 1;
static const uint16_t def_cnter_us = 900;
static const uint16_t def_out_voltage_under_treshold = 0;
static const uint16_t def_out_voltage_over_treshold = 9000;
static const uint16_t def_out_voltage_hold_time = 1000;
static const uint16_t def_out_voltage_cooldown_time = 0;
static const uint16_t def_out_current_under_treshold = 0;
static const uint16_t def_out_current_over_treshold = 6000;
static const uint16_t def_out_current_hold_time = 200;
static const uint16_t def_out_current_cooldown_time = 1000;
static const uint16_t def_battery_voltage_under_treshold = 9000;
static const uint16_t def_battery_voltage_over_treshold = 18000;
static const uint16_t def_battery_voltage_hold_time = 1000;
static const uint16_t def_battery_voltage_cooldown_time = 0;
static const uint16_t def_battery_current_under_treshold = 0;
static const uint16_t def_battery_current_over_treshold = 8000;
static const uint16_t def_battery_current_hold_time = 200;
static const uint16_t def_battery_current_cooldown_time = 1000;
static const uint16_t def_inital_bat_voltage = 12000;
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::DccdHw::DccdHw(void)
{
return;
}
dccd::DccdHw::~DccdHw(void)
{
return;
}
void dccd::DccdHw::init(dccdHwCfg_t* cfg)
{
// Apply config
bsp::Board::boardCfg_t board_cfg;
board_cfg.pwm_f_khz = cfg->pwm_f_khz;
board_cfg.od_common_is_pwm = 1;
this->board_hw.init(&board_cfg);
this->counter.init(0xFFFF, cfg->counter_step_us);
this->counter.disabled = 0;
this->out_voltage.init(&(this->board_hw.out_voltage), &(this->counter));
this->out_voltage.under_treshold = def_out_voltage_under_treshold;
this->out_voltage.over_treshold = def_out_voltage_over_treshold;
this->out_voltage.hold_time = def_out_voltage_hold_time;
this->out_voltage.cooldown_time = def_out_voltage_cooldown_time;
this->out_voltage.update_ain = 0;
this->out_voltage.auto_reset = 1;
this->out_current.init(&(this->board_hw.out_current), &(this->counter));
this->out_current.under_treshold = def_out_current_under_treshold;
this->out_current.over_treshold = def_out_current_over_treshold;
this->out_current.hold_time = def_out_current_hold_time;
this->out_current.cooldown_time = def_out_current_cooldown_time;
this->out_current.update_ain = 0;
this->out_current.auto_reset = 1;
this->battery_voltage.init(&(this->board_hw.battery_voltage), &(this->counter));
this->battery_voltage.under_treshold = def_battery_voltage_under_treshold;
this->battery_voltage.over_treshold = def_battery_voltage_over_treshold;
this->battery_voltage.hold_time = def_battery_voltage_hold_time;
this->battery_voltage.cooldown_time = def_battery_voltage_cooldown_time;
this->battery_voltage.update_ain = 0;
this->battery_voltage.auto_reset = 1;
this->battery_voltage.last_read = def_inital_bat_voltage;
this->battery_current.init(&(this->board_hw.battery_current), &(this->counter));
this->battery_current.under_treshold = def_battery_current_under_treshold;
this->battery_current.over_treshold = def_battery_current_over_treshold;
this->battery_current.hold_time = def_battery_current_hold_time;
this->battery_current.cooldown_time = def_battery_current_cooldown_time;
this->battery_current.update_ain = 0;
this->battery_current.auto_reset = 1;
this->btn_up.init(&(this->board_hw.din4), 0, &(this->counter), def_dbnc_time);
this->btn_up.update_din = 0;
this->btn_down.init(&(this->board_hw.din3), 0, &(this->counter), def_dbnc_time);
this->btn_down.update_din = 0;
this->btn_mode.init(&(this->board_hw.din1), 0, &(this->counter), def_dbnc_time);
this->btn_mode.update_din = 0;
this->handbrake.init(&(this->board_hw.hvdin3), 0, &(this->counter), def_dbnc_time);
this->handbrake.update_din = 0;
this->brakes.init(&(this->board_hw.hvdin2), 1, &(this->counter), def_dbnc_time);
this->brakes.update_din = 0;
this->dimm.init(&(this->board_hw.hvdin1), 1, &(this->counter), def_dbnc_time);
this->dimm.update_din = 0;
this->pot.init(&(this->board_hw.ain2), def_pot_dead_bot, def_pot_dead_top);
this->pot.update_ain = 0;
hw::OutReg::outRegCfg_t outreg_cfg;
outreg_cfg.pwm_high = &this->board_hw.out_pwm;
outreg_cfg.dout_low = &this->board_hw.out_low;
outreg_cfg.ubat = &this->board_hw.battery_voltage;
outreg_cfg.uout = &this->board_hw.out_voltage;
outreg_cfg.iout = &this->board_hw.out_current;
this->outreg.init(&outreg_cfg);
this->outreg.cc_mode_en = def_cc_mode_en;
this->outreg.update_ain = 0;
hw::LedDisplay::doutCfg_t dsp_cfg;
dsp_cfg.led0_dout_ch = &(this->board_hw.od1);
dsp_cfg.led1_dout_ch = &(this->board_hw.od2);
dsp_cfg.led2_dout_ch = &(this->board_hw.od3);
dsp_cfg.led3_dout_ch = &(this->board_hw.od4);
dsp_cfg.led4_dout_ch = &(this->board_hw.od5);
dsp_cfg.led5_dout_ch = &(this->board_hw.od6);
this->display.init(&dsp_cfg, 0, &(this->counter), &(this->board_hw.od_pwm));
// Apply configuration
if(cfg->handbrake_pull_up)
{
this->board_hw.hvdin3_pull.write(1);
}
else this->board_hw.hvdin3_pull.write(0);
if(cfg->speed_hall)
{
this->board_hw.freq_pull.write(1);
}
else this->board_hw.freq_pull.write(0);
// Set initial output states
this->outreg.write_voltage(0);
this->outreg.write_current(0);
this->outreg.write_on(0);
this->outreg.write_lock(0);
this->outreg.process();
this->display.write_backlight(100);
this->display.write(0x00);
}
void dccd::DccdHw::read(void)
{
// Update low level inputs
this->board_hw.read();
this->counter.increment();
this->out_voltage.process();
this->out_current.process();
this->battery_voltage.process();
this->battery_current.process();
this->btn_up.process();
this->btn_down.process();
this->btn_mode.process();
this->handbrake.process();
this->brakes.process();
this->dimm.process();
this->pot.read();
}
void dccd::DccdHw::write(void)
{
this->display.process();
this->outreg.process();
}
/**** Private function definitions ***/

View File

@@ -0,0 +1,69 @@
#ifndef DCCD_HW_H_
#define DCCD_HW_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/board.h"
#include "../utils/vcounter.h"
#include "../hw/button.h"
#include "../hw/led_display.h"
#include "../hw/potentiometer.h"
#include "../hw/out_driver.h"
#include "../hw/safe_ain.h"
#include "../hw/out_reg.h"
namespace dccd {
/**** Public definitions ****/
class DccdHw
{
public:
typedef struct {
uint8_t pwm_f_khz;
uint8_t handbrake_pull_up;
uint8_t speed_hall;
uint16_t counter_step_us;
} dccdHwCfg_t;
DccdHw(void);
~DccdHw(void);
void init(dccdHwCfg_t* cfg);
// Inputs
hw::SafeAin out_voltage;
hw::SafeAin out_current;
hw::SafeAin battery_voltage;
hw::SafeAin battery_current;
hw::Button btn_up;
hw::Button btn_down;
hw::Button btn_mode;
hw::Button handbrake;
hw::Button brakes;
hw::Button dimm;
hw::Potentiometer pot;
// Outputs
hw::LedDisplay display;
hw::OutReg outreg;
void read(void);
void write(void);
#ifdef TESTING
protected:
#endif
bsp::Board board_hw;
util::VCounter counter;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_HW_H_ */

View File

@@ -0,0 +1,208 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "display.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t img_gen_dot10(uint8_t percent);
static uint8_t img_gen_dot20(uint8_t percent);
static uint8_t img_gen_bar(uint8_t percent);
/**** Public function definitions ****/
dccd::DccdDisplay::DccdDisplay(void)
{
return;
}
dccd::DccdDisplay::~DccdDisplay(void)
{
return;
}
void dccd::DccdDisplay::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->brigth_pwm = 50;
this->dimm_pwm = 25;
this->next_image = 0x00;
this->next_lock_lvl = 0;
this->next_lock_time = 0;
this->act_image = 0x00;
this->act_lock_lvl = 0;
}
void dccd::DccdDisplay::cfg_debounce(uint16_t dbnc_time)
{
this->hardware->dimm.dbnc_lim = dbnc_time;
}
void dccd::DccdDisplay::write(uint8_t image, uint8_t lock_lvl, uint16_t lock_time)
{
this->next_image = image;
this->next_lock_lvl = lock_lvl;
this->next_lock_time = lock_time;
}
void dccd::DccdDisplay::write_percent(uint8_t percent, dspstyle_t style, uint8_t lock_lvl, uint16_t lock_time)
{
uint8_t img = 0x01;
switch(style)
{
case DOT20:
img = img_gen_dot20(percent);
break;
case BAR20:
img = img_gen_bar(percent);
break;
default:
img = img_gen_dot10(percent);
break;
}
this->write(img, lock_lvl, lock_time);
}
void dccd::DccdDisplay::force_backlight(uint8_t percent)
{
if(percent > this->brigth_pwm) percent = this->brigth_pwm;
this->hardware->display.write_backlight(percent);
}
void dccd::DccdDisplay::process(void)
{
// Process DIMM switch
if(this->hardware->dimm.is_new)
{
this->hardware->dimm.is_new = 0;
if(this->hardware->dimm.state) this->hardware->display.write_backlight(this->dimm_pwm);
else this->hardware->display.write_backlight(this->brigth_pwm);
};
// Image processor
uint8_t update_img = 0;
if(this->next_lock_lvl >= this->act_lock_lvl) update_img = 1;
else if(this->hardware->display.is_cycle_end()) update_img = 1;
if(update_img)
{
this->act_image = this->next_image;
this->act_lock_lvl = this->next_lock_lvl;
this->next_lock_lvl = 0;
if(this->next_lock_time > 0)
{
this->hardware->display.write(this->act_image, this->next_lock_time+1, this->next_lock_time, 1);
}
else
{
this->hardware->display.write(this->act_image);
this->act_lock_lvl = 0;
}
};
}
/**** Private function definitions ***/
static uint8_t img_gen_dot10(uint8_t percent)
{
switch(percent)
{
case 0 ... 5:
return 0x01;
case 6 ... 15:
return 0x03;
case 16 ... 25:
return 0x02;
case 26 ... 35:
return 0x06;
case 36 ... 45:
return 0x04;
case 46 ... 55:
return 0x0C;
case 56 ... 65:
return 0x08;
case 66 ... 75:
return 0x18;
case 76 ... 85:
return 0x10;
case 86 ... 95:
return 0x30;
case 96 ... 100:
return 0x20;
default:
return 0x20;
}
}
static uint8_t img_gen_dot20(uint8_t percent)
{
switch(percent)
{
case 0 ... 10:
return 0x01;
case 11 ... 30:
return 0x02;
case 31 ... 50:
return 0x04;
case 51 ... 70:
return 0x08;
case 71 ... 90:
return 0x10;
case 91 ... 100:
return 0x20;
default:
return 0x20;
}
}
static uint8_t img_gen_bar(uint8_t percent)
{
switch(percent)
{
case 0 ... 10:
return 0x01;
case 11 ... 30:
return 0x03;
case 31 ... 50:
return 0x07;
case 51 ... 70:
return 0x0F;
case 71 ... 90:
return 0x1F;
case 91 ... 100:
return 0x3F;
default:
return 0x3F;
}
}

View File

@@ -0,0 +1,55 @@
#ifndef DCCD_DISPLAY_H_
#define DCCD_DISPLAY_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class DccdDisplay
{
public:
typedef enum
{
DOT10 = 0,
DOT20 = 1,
BAR20 = 2
} dspstyle_t;
DccdDisplay(void);
~DccdDisplay(void);
void init(dccd::DccdHw* dccd_hw);
void cfg_debounce(uint16_t dbnc_time);
uint8_t brigth_pwm;
uint8_t dimm_pwm;
uint8_t next_image;
uint8_t next_lock_lvl;
uint16_t next_lock_time;
void write(uint8_t image, uint8_t lock_lvl, uint16_t lock_time);
void write_percent(uint8_t percent, dspstyle_t style, uint8_t lock_lvl, uint16_t lock_time);
void force_backlight(uint8_t percent);
void process(void);
#ifdef TESTING
protected:
#endif
dccd::DccdHw* hardware;
uint8_t act_image;
uint8_t act_lock_lvl;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_MODE_BTN_H_ */

View File

@@ -0,0 +1,175 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "handbrake.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::Handbrake::Handbrake(void)
{
return;
}
dccd::Handbrake::~Handbrake(void)
{
return;
}
void dccd::Handbrake::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->latch_time_1 = 750;
this->latch_time_2 = 1500;
this->latch_time_3 = 3000;
this->mode = LATCH0;
this->is_new_mode = 0;
this->is_active = 0;
this->latch_act = 0;
this->start_ts = 0;
}
void dccd::Handbrake::cfg_debounce(uint16_t dbnc_time)
{
this->hardware->handbrake.dbnc_lim = dbnc_time;
}
Handbrake::hbmode_t dccd::Handbrake::cycle_mode(void)
{
switch(this->mode)
{
case LATCH0:
this->mode = LATCH1;
break;
case LATCH1:
this->mode = LATCH2;
break;
case LATCH2:
this->mode = LATCH3;
break;
case LATCH3:
this->mode = LATCH0;
break;
default:
this->mode = LATCH0;
break;
}
this->is_new_mode = 1;
return this->mode;
}
uint8_t dccd::Handbrake::process(void)
{
uint16_t ts_now = this->hardware->counter.read();
if(this->hardware->handbrake.state > 0)
{
if(this->hardware->handbrake.is_new)
{
this->hardware->handbrake.is_new = 0;
// Note start time
this->start_ts = ts_now;
this->latch_act = 1;
};
this->is_active = 1;
}
else if((this->latch_act != 0)&&(this->act_latch_time() != 0))
{
uint16_t td = util::time_delta(this->start_ts, ts_now);
uint32_t td_ms = this->hardware->counter.convert_ms(td);
if(td_ms >= this->act_latch_time())
{
this->latch_act = 0;
if(this->hardware->handbrake.state > 0) this->is_active = 1;
else this->is_active = 0;
};
}
else
{
this->is_active = 0;
}
return this->is_active;
}
uint8_t dccd::Handbrake::get_mode_int(void)
{
switch(this->mode)
{
case LATCH0:
return 0;
case LATCH1:
return 1;
case LATCH2:
return 2;
case LATCH3:
return 3;
default:
return 0;
}
}
void dccd::Handbrake::set_mode_int(uint8_t mode_int)
{
switch(mode_int)
{
case 0:
this->mode = LATCH0;
break;
case 1:
this->mode = LATCH1;
break;
case 2:
this->mode = LATCH2;
break;
case 3:
this->mode = LATCH3;
break;
default:
this->mode = LATCH0;
break;
}
}
/**** Private function definitions ***/
uint16_t dccd::Handbrake::act_latch_time(void)
{
switch(this->mode)
{
case LATCH0:
return 0;
case LATCH1:
return this->latch_time_1;
case LATCH2:
return this->latch_time_2;
case LATCH3:
return this->latch_time_3;
default:
this->mode = LATCH0;
return 0;
}
}

View File

@@ -0,0 +1,57 @@
#ifndef DCCD_HANDBRAKE_H_
#define DCCD_HANDBRAKE_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class Handbrake
{
public:
typedef enum
{
LATCH0 = 0,
LATCH1 = 1,
LATCH2 = 2,
LATCH3 = 3
}hbmode_t;
Handbrake(void);
~Handbrake(void);
void init(dccd::DccdHw* dccd_hw);
hbmode_t mode;
uint16_t latch_time_1;
uint16_t latch_time_2;
uint16_t latch_time_3;
uint8_t is_new_mode;
uint8_t is_active;
uint8_t process(void);
void cfg_debounce(uint16_t dbnc_time);
hbmode_t cycle_mode(void);
uint8_t get_mode_int(void);
void set_mode_int(uint8_t mode_int);
#ifdef TESTING
protected:
#endif
dccd::DccdHw* hardware;
uint8_t latch_act;
uint16_t start_ts;
uint16_t act_latch_time(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_HANDBRAKE_H_ */

View File

@@ -0,0 +1,257 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "memory.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
static uint16_t static_cfg_addr_offset = 0x0000; //0-127
static uint16_t dynamic_cgf_addr_offset = 0x0080; //128+
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::Memory::Memory(void)
{
return;
}
dccd::Memory::~Memory(void)
{
return;
}
void dccd::Memory::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->read_from_nvmem();
}
void dccd::Memory::update(void)
{
uint16_t addr = dynamic_cgf_addr_offset;
if(this->dynamic_cfg.btn_force != this->dyn_cfg_shadow.btn_force)
{
this->hardware->board_hw.nvmem.write_8b(addr, this->dynamic_cfg.btn_force);
this->dyn_cfg_shadow.btn_force = this->dynamic_cfg.btn_force;
};
addr++;
if(this->dynamic_cfg.tps_mode != this->dyn_cfg_shadow.tps_mode)
{
this->hardware->board_hw.nvmem.write_8b(addr, this->dynamic_cfg.tps_mode);
this->dyn_cfg_shadow.tps_mode = this->dynamic_cfg.tps_mode;
};
addr++;
if(this->dynamic_cfg.hbrake_mode != this->dyn_cfg_shadow.hbrake_mode)
{
this->hardware->board_hw.nvmem.write_8b(addr, this->dynamic_cfg.hbrake_mode);
this->dyn_cfg_shadow.hbrake_mode = this->dynamic_cfg.hbrake_mode;
};
addr++;
if(this->dynamic_cfg.brakes_mode != this->dyn_cfg_shadow.brakes_mode)
{
this->hardware->board_hw.nvmem.write_8b(addr, this->dynamic_cfg.brakes_mode);
this->dyn_cfg_shadow.brakes_mode = this->dynamic_cfg.brakes_mode;
};
addr++;
}
void dccd::Memory::read_static(staticmem_t* cfg_out)
{
uint16_t addr = static_cfg_addr_offset;
cfg_out->is_nvmem_cfg = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->inp_mode = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->hbrake_t1 = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->hbrake_t2 = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->hbrake_t3 = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->hbrake_dbnc = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->brakes_dnbc = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->tps_en = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->tps_on_th = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->tps_off_th = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->tps_timeout = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->tps_force_1 = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->tps_force_2 = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->tps_force_3 = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->hbrake_force = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->brakes_open_force = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->brakes_lock_force = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->coil_lock_current = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->coil_ccm_resistance = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->coil_cvm_resistance = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->coil_protection_dis = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->coil_cc_mode_en = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->dsp_brigth_pwm = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
cfg_out->dsp_dimm_pwm = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
}
void dccd::Memory::write_static(staticmem_t* cfg_in)
{
uint16_t addr = static_cfg_addr_offset;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->is_nvmem_cfg);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->inp_mode);;
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->hbrake_t1);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->hbrake_t2);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->hbrake_t3);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->is_nvmem_cfg);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->brakes_dnbc);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->tps_en);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->tps_on_th);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->tps_off_th);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->tps_timeout);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->tps_force_1);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->tps_force_2);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->tps_force_3);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->hbrake_force);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->brakes_open_force);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->brakes_lock_force);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->coil_lock_current);;
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->coil_ccm_resistance);;
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->coil_cvm_resistance);;
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->coil_protection_dis);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->coil_cc_mode_en);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->dsp_brigth_pwm);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, cfg_in->dsp_dimm_pwm);
addr++;
}
/**** Private function definitions ***/
void dccd::Memory::read_from_nvmem(void)
{
uint16_t addr = dynamic_cgf_addr_offset;
this->dyn_cfg_shadow.btn_force = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
this->dyn_cfg_shadow.tps_mode = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
this->dyn_cfg_shadow.hbrake_mode = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
this->dyn_cfg_shadow.brakes_mode = this->hardware->board_hw.nvmem.read_8b(addr);
addr++;
this->dynamic_cfg.btn_force = this->dyn_cfg_shadow.btn_force;
this->dynamic_cfg.tps_mode = this->dyn_cfg_shadow.tps_mode;
this->dynamic_cfg.hbrake_mode = this->dyn_cfg_shadow.hbrake_mode;
this->dynamic_cfg.brakes_mode = this->dyn_cfg_shadow.brakes_mode;
}
void dccd::Memory::write_to_nvmem(void)
{
uint16_t addr = dynamic_cgf_addr_offset;
this->hardware->board_hw.nvmem.write_8b(addr, this->dyn_cfg_shadow.btn_force);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, this->dyn_cfg_shadow.tps_mode);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, this->dyn_cfg_shadow.hbrake_mode);
addr++;
this->hardware->board_hw.nvmem.write_8b(addr, this->dyn_cfg_shadow.brakes_mode);
addr++;
}

View File

@@ -0,0 +1,76 @@
#ifndef DCCD_MEMORY_H_
#define DCCD_MEMORY_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class Memory
{
public:
typedef struct{
uint8_t is_nvmem_cfg;
uint8_t inp_mode;
uint8_t hbrake_t1;
uint8_t hbrake_t2;
uint8_t hbrake_t3;
uint8_t hbrake_dbnc;
uint8_t hbrake_force;
uint8_t brakes_dnbc;
uint8_t brakes_open_force;
uint8_t brakes_lock_force;
uint8_t tps_en;
uint8_t tps_on_th;
uint8_t tps_off_th;
uint8_t tps_timeout;
uint8_t tps_force_1;
uint8_t tps_force_2;
uint8_t tps_force_3;
uint8_t coil_lock_current;
uint8_t coil_ccm_resistance;
uint8_t coil_cvm_resistance;
uint8_t coil_protection_dis;
uint8_t coil_cc_mode_en;
uint8_t dsp_brigth_pwm;
uint8_t dsp_dimm_pwm;
} staticmem_t;
typedef struct{
uint8_t btn_force;
uint8_t tps_mode;
uint8_t hbrake_mode;
uint8_t brakes_mode;
} dynamicmem_t;
Memory(void);
~Memory(void);
void init(dccd::DccdHw* dccd_hw);
dynamicmem_t dynamic_cfg;
void update(void);
void read_static(staticmem_t* cfg_out);
void write_static(staticmem_t* cfg_in);
#ifdef TESTING
protected:
#endif
DccdHw* hardware;
dynamicmem_t dyn_cfg_shadow;
void read_from_nvmem(void);
void write_to_nvmem(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_MEMORY_H_ */

View File

@@ -0,0 +1,45 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mode.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::ModeBtn::ModeBtn(void)
{
return;
}
dccd::ModeBtn::~ModeBtn(void)
{
return;
}
void dccd::ModeBtn::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->btn_repeat_time = 0;
this->is_new = 0;
}
void dccd::ModeBtn::cfg_debounce(uint16_t dbnc_time)
{
this->hardware->btn_mode.dbnc_lim = dbnc_time;
}
void dccd::ModeBtn::process(void)
{
if((this->hardware->btn_mode.state==1)&&((this->hardware->btn_mode.is_new)||((this->hardware->btn_mode.time_read() >= this->btn_repeat_time)&&(this->btn_repeat_time!=0))))
{
this->hardware->btn_mode.time_reset();
this->hardware->btn_mode.is_new = 0;
this->is_new = 1;
};
}
/**** Private function definitions ***/

39
firmware/src/dccd/mode.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef DCCD_MODE_BTN_H_
#define DCCD_MODE_BTN_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class ModeBtn
{
public:
ModeBtn(void);
~ModeBtn(void);
void init(dccd::DccdHw* dccd_hw);
void cfg_debounce(uint16_t dbnc_time);
uint16_t btn_repeat_time;
uint8_t is_new;
void process(void);
#ifdef TESTING
protected:
#endif
dccd::DccdHw* hardware;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_MODE_BTN_H_ */

158
firmware/src/dccd/tps.cpp Normal file
View File

@@ -0,0 +1,158 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "tps.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::Thtrottle::Thtrottle(void)
{
return;
}
dccd::Thtrottle::~Thtrottle(void)
{
return;
}
void dccd::Thtrottle::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->treshold_on = 55;
this->treshold_off = 45;
this->timeout_time = 0;
this->start_ts = 0;
this->is_timed_out = 0;
this->mode = MODE0;
this->is_new_mode = 0;
this->is_new = 0;
this->active = 0;
}
Thtrottle::tpsmode_t dccd::Thtrottle::cycle_mode(void)
{
switch(this->mode)
{
case MODE0:
this->mode = MODE1;
break;
case MODE1:
this->mode = MODE2;
break;
case MODE2:
this->mode = MODE3;
break;
case MODE3:
this->mode = MODE0;
break;
default:
this->mode = MODE0;
break;
}
this->is_new_mode = 1;
return this->mode;
}
void dccd::Thtrottle::process(void)
{
uint16_t ts_now = this->hardware->counter.read();
if(this->active)
{
uint16_t td = util::time_delta(this->start_ts, ts_now);
uint32_t td_ms = this->hardware->counter.convert_ms(td);
if((td_ms >= this->timeout_time)&&(this->timeout_time != 0))
{
this->is_timed_out = 1;
this->is_new = 1;
};
if(this->hardware->pot.last_percent <= this->treshold_off)
{
this->active = 0;
this->is_timed_out = 0;
this->start_ts = 0;
this->is_new = 1;
}
else this->active = 1;
}
else
{
if(this->hardware->pot.last_percent >= this->treshold_on)
{
this->start_ts = ts_now;
this->active = 1;
this->is_new = 1;
}
else this->active = 0;
}
}
uint8_t dccd::Thtrottle::get_mode_int(void)
{
switch(this->mode)
{
case MODE0:
return 0;
case MODE1:
return 1;
case MODE2:
return 2;
case MODE3:
return 3;
default:
return 0;
}
}
void dccd::Thtrottle::set_mode_int(uint8_t mode_int)
{
switch(mode_int)
{
case 0:
this->mode = MODE0;
break;
case 1:
this->mode = MODE1;
break;
case 2:
this->mode = MODE2;
break;
case 3:
this->mode = MODE3;
break;
default:
this->mode = MODE0;
break;
}
}
uint8_t dccd::Thtrottle::is_active(void)
{
if(this->is_timed_out) return 0;
else return this->active;
}
/**** Private function definitions ***/

58
firmware/src/dccd/tps.h Normal file
View File

@@ -0,0 +1,58 @@
#ifndef DCCD_TPS_H_
#define DCCD_TPS_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class Thtrottle
{
public:
typedef enum
{
MODE0 = 0,
MODE1 = 1,
MODE2 = 2,
MODE3 = 3
}tpsmode_t;
Thtrottle(void);
~Thtrottle(void);
void init(dccd::DccdHw* dccd_hw);
uint8_t treshold_on;
uint8_t treshold_off;
uint16_t timeout_time;
tpsmode_t mode;
uint8_t is_new_mode;
uint8_t is_new;
uint8_t is_active(void);
void process(void);
tpsmode_t cycle_mode(void);
uint8_t get_mode_int(void);
void set_mode_int(uint8_t mode_int);
#ifdef TESTING
protected:
#endif
dccd::DccdHw* hardware;
uint16_t start_ts;
uint8_t is_timed_out;
uint8_t active;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_TPS_H_ */

View File

@@ -0,0 +1,86 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "user_force.h"
using namespace dccd;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
dccd::UserForce::UserForce(void)
{
return;
}
dccd::UserForce::~UserForce(void)
{
return;
}
void dccd::UserForce::init(dccd::DccdHw* dccd_hw)
{
this->hardware = dccd_hw;
this->is_new_btn_force = 0;
this->btn_repeat_time = 0;
this->force = 0;
this->pot_mode = 0;
this->btn_force = 0;
this->btn_step = 20;
}
void dccd::UserForce::cfg_debounce(uint16_t dbnc_time)
{
this->hardware->btn_up.dbnc_lim = dbnc_time;
this->hardware->btn_down.dbnc_lim = dbnc_time;
}
void dccd::UserForce::cfg_pot(uint16_t dead_bot, uint16_t dead_top)
{
if(this->pot_mode==0) return;
this->hardware->pot.high_deadzone = dead_top;
this->hardware->pot.low_deadzone = dead_bot;
}
void dccd::UserForce::write_force(uint8_t force)
{
if(force > 100) force = 100;
this->btn_force = force;
this->force = force;
}
uint8_t dccd::UserForce::process(void)
{
if(this->pot_mode)
{
this->force = this->hardware->pot.last_percent;
return this->force;
};
if((this->hardware->btn_up.state==1)&&((this->hardware->btn_up.is_new)||((this->hardware->btn_up.time_read() >= this->btn_repeat_time)&&(this->btn_repeat_time!=0))))
{
this->hardware->btn_up.time_reset();
this->hardware->btn_up.is_new = 0;
// Increase user force
this->btn_force += this->btn_step;
if(this->btn_force > 100) this->btn_force = 100;
is_new_btn_force = 1;
};
if((this->hardware->btn_down.state==1)&&((this->hardware->btn_down.is_new)||((this->hardware->btn_down.time_read() >= this->btn_repeat_time)&&(this->btn_repeat_time!=0))))
{
this->hardware->btn_down.time_reset();
this->hardware->btn_down.is_new = 0;
// Decrease user force
this->btn_force -= this->btn_step;
if(this->btn_force > 100) this->btn_force = 0;
is_new_btn_force = 1;
};
this->force = this->btn_force;
return this->force;
}
/**** Private function definitions ***/

View File

@@ -0,0 +1,45 @@
#ifndef DCCD_USER_FORCE_H_
#define DCCD_USER_FORCE_H_
/**** Includes ****/
#include <stdint.h>
#include "dccd_hw.h"
namespace dccd {
/**** Public definitions ****/
class UserForce
{
public:
UserForce(void);
~UserForce(void);
void init(dccd::DccdHw* dccd_hw);
void cfg_debounce(uint16_t dbnc_time);
void cfg_pot(uint16_t dead_bot, uint16_t dead_top);
uint16_t btn_repeat_time;
uint8_t pot_mode;
uint8_t btn_step;
uint8_t force;
uint8_t is_new_btn_force;
uint8_t process(void);
void write_force(uint8_t force);
#ifdef TESTING
protected:
#endif
dccd::DccdHw* hardware;
uint8_t btn_force;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_USER_FORCE_H_ */

View File

@@ -1,45 +0,0 @@
/**** Includes ****/
#include "board/utils/utils.h"
#include "board/ain.h"
#include "analog.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t ain_mapping(uint8_t analog_ch, uint8_t* ain_ch);
/**** Public function definitions ****/
uint16_t analog_ch_get(uint8_t analog_ch)
{
uint8_t ain_ch;
// Get channel config
if(ain_mapping(analog_ch, &ain_ch)) return 0;
// Read input as mV
uint16_t ch_mv = bsp_ain_read(ain_ch);
// Return result
return ch_mv;
}
/**** Private function definitions ****/
static uint8_t ain_mapping(uint8_t analog_ch, uint8_t* ain_ch)
{
switch(analog_ch)
{
case ANALOG_1: // Pot
*ain_ch = BSP_AIN2;
return 0;
case ANALOG_2: // Mode
*ain_ch = BSP_AIN1;
return 0;
default: //Invalid channel
*ain_ch = BSP_AIN5;
return 1;
}
return 1;
}

View File

@@ -1,20 +0,0 @@
#ifndef ANALOG_H_
#define ANALOG_H_
/*
*/
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define ANALOG_1 1 //Potentiometer
#define ANALOG_2 2 //Mode
/**** Public function declarations ****/
uint16_t analog_ch_get(uint8_t analog_ch);
#ifdef TESTING
#endif
#endif /* ANALOG_H_ */

View File

@@ -1,77 +0,0 @@
/**** Includes ****/
#include "utils/utils.h"
#include "mcu/mcu_hal.h"
#include "ain.h"
/**** Private definitions ****/
typedef struct {
uint8_t adc_ch;
uint8_t mul;
uint8_t div;
int16_t offset;
} ainchcfg_t;
/**** Private constants ****/
static const uint8_t MV_MUL = BSP_AIN_DEF_MV_MUL;
static const uint8_t MV_DIV = BSP_AIN_DEF_MV_DIV;
static const int16_t MV_OFFSET = BSP_AIN_DEF_MV_OFFSET;
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t ain_mapping(uint8_t ain_ch, ainchcfg_t* ain_ch_cfg);
/**** Public function definitions ****/
uint16_t bsp_ain_read(uint8_t ch)
{
ainchcfg_t cfg;
// Get analog input config, and check validity
if(ain_mapping(ch, &cfg)) return 0;
//Read ADC
uint16_t raw = mcu_adc_read(cfg.adc_ch);
//Convert to mV
raw = util_convert_muldivoff(raw, cfg.mul, cfg.div, cfg.offset);
// Return result
return raw;
}
/**** Private function definitions ****/
static uint8_t ain_mapping(uint8_t ain_ch, ainchcfg_t* ain_ch_cfg)
{
// Default 10bit ADC with 5V reference to mV conversion
ain_ch_cfg->mul = MV_MUL;
ain_ch_cfg->div = MV_DIV;
ain_ch_cfg->offset = MV_OFFSET;
switch(ain_ch)
{
case BSP_AIN1: // Mode
ain_ch_cfg->adc_ch = MCU_ADC5;
return 0;
case BSP_AIN2: // Pot
ain_ch_cfg->adc_ch = MCU_ADC4;
return 0;;
case BSP_AIN3: // MCU Temp
ain_ch_cfg->adc_ch = MCU_ADC8;
return 0;
case BSP_AIN4: // MCU Internal reference
ain_ch_cfg->adc_ch = MCU_ADC14;
return 0;
case BSP_AIN5: // MCU Ground
ain_ch_cfg->adc_ch = MCU_ADC15;
return 0;
default: // Invalid channel
ain_ch_cfg->adc_ch = MCU_ADC15;
return 1;
}
return 1;
}

View File

@@ -1,26 +0,0 @@
#ifndef AIN_H_
#define AIN_H_
/*
AIN1 MODE
AIN2 POT
*/
/**** Includes ****/
#include <stdint.h>
#include "config.h"
/**** Public definitions ****/
#define BSP_AIN1 1 // Mode
#define BSP_AIN2 2 // Pot
#define BSP_AIN3 3 // MCU Temp
#define BSP_AIN4 4 // MCU Internal reference
#define BSP_AIN5 5 // MCU Ground
/**** Public function declarations ****/
uint16_t bsp_ain_read(uint8_t ch);
#ifdef TESTING
#endif
#endif /* AIN_H_ */

View File

@@ -1,32 +0,0 @@
#ifndef BSP_CONFIG_H_
#define BSP_CONFIG_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define BSP_AIN_DEF_MV_MUL 215
#define BSP_AIN_DEF_MV_DIV 44
#define BSP_AIN_DEF_MV_OFFSET 0
#define BSP_HB_MV_MUL BSP_AIN_DEF_MV_MUL
#define BSP_HB_MV_DIV BSP_AIN_DEF_MV_DIV
#define BSP_HB_MV_OFFSET BSP_AIN_DEF_MV_OFFSET
#define BSP_HB_UDIV_MUL 20
#define BSP_HB_UDIV_DIV 1
#define BSP_HB_UDIV_OFFSET 0
#define BSP_HB_ISUP_MUL 235
#define BSP_HB_ISUP_DIV 6
#define BSP_HB_ISUP_OFFSET 0
#define BSP_HB_IOUT_MUL 215
#define BSP_HB_IOUT_DIV 22
#define BSP_HB_IOUT_OFFSET 0
/**** Public function declarations ****/
#ifdef TESTING
#endif
#endif /* BSP_CONFIG_H_ */

View File

@@ -1,83 +0,0 @@
/**** Includes ****/
#include "utils/utils.h"
#include "mcu/mcu_hal.h"
#include "din.h"
/**** Private definitions ****/
typedef struct {
uint8_t gpio_ch;
uint8_t invert;
} dinchcfg_t;
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t din_mapping(uint8_t din_ch, dinchcfg_t* din_ch_cfg);
/**** Public function definitions ****/
uint8_t bsp_din_read(uint8_t ch)
{
dinchcfg_t cfg;
// Get digital input config, and check validity
if(din_mapping(ch, &cfg)) return BSP_DIN_LOW;
//Read GPIO
uint8_t raw = mcu_gpio_read(cfg.gpio_ch);
// Check config and invert
if(cfg.invert) raw = util_invert_8b(raw);
// Return result
return raw;
}
/**** Private function definitions ***/
static uint8_t din_mapping(uint8_t din_ch, dinchcfg_t* din_ch_cfg)
{
// By default ch is not inverted
din_ch_cfg->invert = 0;
switch(din_ch)
{
case BSP_DIN1: //Mode
din_ch_cfg->gpio_ch = MCU_GPIO0;
return 0;
case BSP_DIN2: //Pot
din_ch_cfg->gpio_ch = MCU_GPIO1;
return 0;
case BSP_DIN3: //Down
din_ch_cfg->gpio_ch = MCU_GPIO2;
return 0;
case BSP_DIN4: //Up
din_ch_cfg->gpio_ch = MCU_GPIO3;
return 0;
case BSP_DIN5: //Dimm
din_ch_cfg->gpio_ch = MCU_GPIO4;
din_ch_cfg->invert = 1;
return 0;
case BSP_DIN6: //Brakes
din_ch_cfg->gpio_ch = MCU_GPIO5;
din_ch_cfg->invert = 1;
return 0;
case BSP_DIN7: //Handbrake
din_ch_cfg->gpio_ch = MCU_GPIO6;
din_ch_cfg->invert = 1;
return 0;
case BSP_DIN7N: //Handbrake pull
din_ch_cfg->gpio_ch = MCU_GPIO7;
return 0;
default: //Invalid channel
din_ch_cfg->gpio_ch = 0;
return 1;
}
return 1;
}

View File

@@ -1,37 +0,0 @@
#ifndef DIN_H_
#define DIN_H_
/*
DIN1 MODE
DIN2 POT
DIN3 DOWN
DIN4 UP
DIN5 HV DIM
DIN6 HV BRAKES
DIN7 HV HANDBRAKE
DIN8 HBRAKE PULL
*/
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define BSP_DIN1 1
#define BSP_DIN2 2
#define BSP_DIN3 3
#define BSP_DIN4 4
#define BSP_DIN5 5
#define BSP_DIN6 6
#define BSP_DIN7 7
#define BSP_DIN7N 8
#define BSP_DIN_LOW 0
#define BSP_DIN_HIGH 1
/**** Public function declarations ****/
uint8_t bsp_din_read(uint8_t ch);
#ifdef TESTING
#endif
#endif /* DIN_H_ */

View File

@@ -1,58 +0,0 @@
/**** Includes ****/
#include "utils/utils.h"
#include "mcu/mcu_hal.h"
#include "dout.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t dout_mapping(uint8_t dout_ch, uint8_t* gpio_ch);
/**** Public function definitions ****/
void bsp_dout_write(uint8_t ch, int8_t lvl)
{
uint8_t gpio_ch;
// Get digital input config, and check validity
if(dout_mapping(ch, &gpio_ch)) return;
// Write GPIO
mcu_gpio_write(gpio_ch, lvl);
}
/**** Private function definitions ***/
static uint8_t dout_mapping(uint8_t dout_ch, uint8_t* gpio_ch)
{
switch(dout_ch)
{
case BSP_DOUT1: //Mode
*gpio_ch = MCU_GPIO0;
return 0;
case BSP_DOUT2: //Pot
*gpio_ch = MCU_GPIO1;
return 0;
case BSP_DOUT3: //Down
*gpio_ch = MCU_GPIO2;
return 0;
case BSP_DOUT4: //Up
*gpio_ch = MCU_GPIO3;
return 0;
case BSP_DOUT5: //Handbrake pull
*gpio_ch = MCU_GPIO7;
return 0;
case BSP_DOUT6: //Speed pull
*gpio_ch = MCU_GPIO8;
return 0;
default: //Invalid channel
*gpio_ch = 0;
return 1;
}
return 1;
}

View File

@@ -1,34 +0,0 @@
#ifndef DOUT_H_
#define DOUT_H_
/*
DOUT1 MODE
DOUT2 POT
DOUT3 DOWN
DOUT4 UP
DOUT5 HBRAKE PULL
DOUT6 SPEED PULL
*/
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define BSP_DOUT1 1
#define BSP_DOUT2 2
#define BSP_DOUT3 3
#define BSP_DOUT4 4
#define BSP_DOUT5 5
#define BSP_DOUT6 6
#define BSP_DOUT_LOW 0
#define BSP_DOUT_HIGH 1
#define BSP_DOUT_HIZ -1
/**** Public function declarations ****/
void bsp_dout_write(uint8_t ch, int8_t lvl);
#ifdef TESTING
#endif
#endif /* DOUT_H_ */

View File

@@ -1,179 +0,0 @@
/**** Includes ****/
#include "utils/utils.h"
#include "mcu/mcu_hal.h"
#include "halfbridge.h"
/**** Private definitions ****/
typedef struct {
uint8_t adc_ch;
uint8_t mul;
uint8_t div;
int16_t offset;
} ainchcfg_t;
typedef enum {
AIN_OUT_VOLTAGE,
AIN_OUT_CURRENT,
AIN_SUP_VOLTAGE,
AIN_SUP_CURRENT
} hb_ainch_t;
/**** Private constants ****/
// Analog channels conversion coefficients
static const uint8_t MV_MUL = BSP_HB_MV_MUL;
static const uint8_t MV_DIV = BSP_HB_MV_DIV;
static const int16_t MV_OFFSET = BSP_HB_MV_OFFSET;
static const uint8_t UDIV_MUL = BSP_HB_UDIV_MUL;
static const uint8_t UDIV_DIV = BSP_HB_UDIV_DIV;
static const int16_t UDIV_OFFSET = BSP_HB_UDIV_OFFSET;
static const uint8_t ISUP_MUL = BSP_HB_ISUP_MUL;
static const uint8_t ISUP_DIV = BSP_HB_ISUP_DIV;
static const int16_t ISUP_OFFSET = BSP_HB_ISUP_OFFSET;
static const uint8_t IOUT_MUL = BSP_HB_IOUT_MUL;
static const uint8_t IOUT_DIV = BSP_HB_IOUT_DIV;
static const int16_t IOUT_OFFSET = BSP_HB_IOUT_OFFSET;
/**** Private variables ****/
/**** Mapping function declarations ****/
static uint8_t hb_pwm_mapping(uint8_t* pwm_ch);
static uint8_t hb_low_side_mapping(uint8_t* gpio_ch);
static uint8_t hb_ain_mapping(hb_ainch_t ain_ch, ainchcfg_t* ain_ch_cfg);
/**** Private function declarations ****/
static uint16_t limit_pwm(uint16_t pwm_in);
static uint16_t read_ain(hb_ainch_t ch);
/**** Public function definitions ****/
void bsp_hb_write_low(uint8_t state)
{
uint8_t gpio_ch;
// Get GPIO channel, and check validity
if(hb_low_side_mapping(&gpio_ch)) return;
// Set low side on or off
if(state) mcu_gpio_write(gpio_ch, MCU_GPIO_HIGH);
else mcu_gpio_write(gpio_ch, MCU_GPIO_LOW);
}
void bsp_hb_write_pwm(uint16_t pwm)
{
uint8_t pwm_ch;
// Get PWM channel, and check validity
if(hb_pwm_mapping(&pwm_ch)) return;
// Limit PWM, because of charge pump
pwm = limit_pwm(pwm);
// Set pwm
mcu_pwm_write(pwm_ch, pwm);
}
void bsp_hb_read_meas(hb_meas_t* measurements)
{
// Read analog inputs
measurements->out_voltage = read_ain(AIN_OUT_VOLTAGE);
measurements->out_current = read_ain(AIN_OUT_CURRENT);
measurements->sup_voltage = read_ain(AIN_SUP_VOLTAGE);
measurements->sup_current = read_ain(AIN_SUP_CURRENT);
// Calculate secondary measurements
measurements->out_power = util_sat_mul_kilo(measurements->out_voltage, measurements->out_current);
measurements->sup_power = util_sat_mul_kilo(measurements->sup_voltage, measurements->sup_current);
measurements->out_impedance = util_sat_div_kilo(measurements->out_voltage, measurements->out_current);
uint8_t ch;
//Read low side control GPIO level
if(hb_low_side_mapping(&ch)) measurements->low_side_ctrl = 0;
else measurements->low_side_ctrl = mcu_gpio_read(ch);
//Read PWM duty cycle in 16b format
if(hb_pwm_mapping(&ch)) measurements->pwm = 0;
else measurements->pwm = mcu_pwm_read(ch);
}
/**** Private function declarations ****/
static uint16_t read_ain(hb_ainch_t ch)
{
ainchcfg_t cfg;
// Get analog input config, and check validity
if(hb_ain_mapping(ch, &cfg)) return 0;
//Read ADC
uint16_t raw = mcu_adc_read(cfg.adc_ch);
//Convert to target units
raw = util_convert_muldivoff(raw, cfg.mul, cfg.div, cfg.offset);
// Return result
return raw;
}
static uint16_t limit_pwm(uint16_t pwm_in)
{
// Limit to ~95%
if (pwm_in > 0xFC00) return 0xFC00;
else return pwm_in;
}
/**** Mapping function definitions ****/
static uint8_t hb_pwm_mapping(uint8_t* pwm_ch)
{
*pwm_ch = MCU_PWM0;
return 0;
}
static uint8_t hb_low_side_mapping(uint8_t* gpio_ch)
{
*gpio_ch = MCU_GPIO15;
return 0;
}
static uint8_t hb_ain_mapping(hb_ainch_t ain_ch, ainchcfg_t* ain_ch_cfg)
{
switch(ain_ch)
{
case AIN_OUT_VOLTAGE:
ain_ch_cfg->adc_ch = MCU_ADC1;
ain_ch_cfg->mul = UDIV_MUL;
ain_ch_cfg->div = UDIV_DIV;
ain_ch_cfg->offset = UDIV_OFFSET;
return 0;
case AIN_OUT_CURRENT:
ain_ch_cfg->adc_ch = MCU_ADC0;
ain_ch_cfg->mul = IOUT_MUL;
ain_ch_cfg->div = IOUT_DIV;
ain_ch_cfg->offset = IOUT_OFFSET;
return 0;
case AIN_SUP_VOLTAGE:
ain_ch_cfg->adc_ch = MCU_ADC2;
ain_ch_cfg->mul = UDIV_MUL;
ain_ch_cfg->div = UDIV_DIV;
ain_ch_cfg->offset = UDIV_OFFSET;
return 0;
case AIN_SUP_CURRENT:
ain_ch_cfg->adc_ch = MCU_ADC3;
ain_ch_cfg->mul = ISUP_MUL;
ain_ch_cfg->div = ISUP_DIV;
ain_ch_cfg->offset = ISUP_OFFSET;
return 0;
default: //Invalid channel
ain_ch_cfg->adc_ch = MCU_ADC15;
// Default 10bit ADC with 5V reference to mV conversion
ain_ch_cfg->mul = MV_MUL;
ain_ch_cfg->div = MV_DIV;
ain_ch_cfg->offset = MV_OFFSET;
return 1;
}
return 1;
}

View File

@@ -1,34 +0,0 @@
#ifndef HALFBRIDGE_H_
#define HALFBRIDGE_H_
/*
*/
/**** Includes ****/
#include <stdint.h>
#include "config.h"
/**** Public definitions ****/
typedef struct {
uint16_t out_voltage;
uint16_t out_current;
uint16_t sup_voltage;
uint16_t sup_current;
uint16_t out_power;
uint16_t sup_power;
uint16_t out_impedance;
uint8_t low_side_ctrl;
uint16_t pwm;
} hb_meas_t;
/**** Public function declarations ****/
void bsp_hb_write_low(uint8_t state);
void bsp_hb_write_pwm(uint16_t pwm);
// Feedback functions
void bsp_hb_read_meas(hb_meas_t* measurements);
#ifdef TESTING
#endif
#endif /* HALFBRIDGE_H_ */

View File

@@ -1,120 +0,0 @@
#ifndef MCU_HAL_H_
#define MCU_HAL_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
/*
GPIO0 Down
GPIO1 Up
GPIO2 Mode
GPIO3 Handbrake
GPIO4 Brakes
GPIO5 Dimm
GPIO6 LED0
GPIO7 LED1
GPIO8 LED2
GPIO9 LED3
GPIO10 LED4
GPIO11 LED5
GPIO12 DCCD Enable
GPIO13 Handbrake pull
GPIO14 Speed pull
GPIO15 DCCD PWM
GPIO16 LED PWM
ADC0 Output current
ADC1 Output voltage
ADC2 Battery current
ADC3 Battery voltage
ADC4 Potentiometer
ADC5 Mode
ADC8 MCU temperature
ADC14 MCU internal reference
ADC15 MCU ground
*/
#define MCU_GPIO0 0 //Mode
#define MCU_GPIO1 1 //Pot
#define MCU_GPIO2 2 //Down
#define MCU_GPIO3 3 //Up
#define MCU_GPIO4 4 //Dimm
#define MCU_GPIO5 5 //Brakes
#define MCU_GPIO6 6 //Handbrake
#define MCU_GPIO7 7 //Handbrake pull
#define MCU_GPIO8 8 //Speed pull
#define MCU_GPIO9 9 //LED0
#define MCU_GPIO10 10 //LED1
#define MCU_GPIO11 11 //LED2
#define MCU_GPIO12 12 //LED3
#define MCU_GPIO13 13 //LED4
#define MCU_GPIO14 14 //LED5
#define MCU_GPIO15 15 //DCCD Enable
#define MCU_GPIO16 16 //DCCD PWM
#define MCU_GPIO17 17 //LED PWM
#define MCU_GPIO_LOW 0
#define MCU_GPIO_HIGH 1
#define MCU_GPIO_HIZ -1
#define MCU_ADC0 0 //Output current
#define MCU_ADC1 1 //Output voltage
#define MCU_ADC2 2 //Battery voltage
#define MCU_ADC3 3 //Battery current
#define MCU_ADC4 4 //Potentiometer
#define MCU_ADC5 5 //Mode
#define MCU_ADC8 8 //MCU temperature
#define MCU_ADC14 14 //MCU internal reference
#define MCU_ADC15 15 //MCU ground
#define MCU_PWM0 0 //DCCD
#define MCU_PWM1 1 //LED
//ADC definitions
typedef enum {
MCU_ADC_DIV2 = 0x01,
MCU_ADC_DIV4 = 0x02,
MCU_ADC_DIV8 = 0x03,
MCU_ADC_DIV16 = 0x04,
MCU_ADC_DIV32 = 0x05,
MCU_ADC_DIV64 = 0x06,
MCU_ADC_DIV128 = 0x07
} adcClkDiv_t;
//Timer definitions
typedef enum {
MCU_TIM_DIV1 = 0x01,
MCU_TIM_DIV8 = 0x02,
MCU_TIM_DIV64 = 0x03,
MCU_TIM_DIV256 = 0x04,
MCU_TIM_DIV1024 = 0x05
} timerClkDiv_t;
typedef struct {
adcClkDiv_t adc_clk;
timerClkDiv_t pwm_clk;
uint16_t pwm_top;
uint8_t pwm_chb_en;
} startupCfg_t;
/**** Public function declarations ****/
void mcu_startup(startupCfg_t* hwCfg);
uint8_t mcu_gpio_read(uint8_t ch);
void mcu_gpio_write(uint8_t ch, int8_t lvl);
uint16_t mcu_adc_read(uint8_t ch);
void mcu_pwm_write(uint8_t ch, uint16_t dc);
uint16_t mcu_pwm_read(uint8_t ch);
uint8_t mcu_ee_read8b(uint16_t address);
uint16_t mcu_ee_read16b(uint16_t address);
uint32_t mcu_ee_read32b(uint16_t address);
void mcu_ee_write8b(uint16_t address, uint8_t value);
void mcu_ee_write16b(uint16_t address, uint16_t value);
void mcu_ee_write32b(uint16_t address, uint32_t value);
#endif /* MCU_HAL_H_ */

View File

@@ -1,80 +0,0 @@
/**** Includes ****/
#include "utils/utils.h"
#include "mcu/mcu_hal.h"
#include "odout.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t odout_pwm_mapping(uint8_t* pwm_ch);
static uint8_t odout_mapping(uint8_t od_ch, uint8_t* gpio_ch);
/**** Public function definitions ****/
void bsp_odout_write(uint8_t ch, int8_t lvl)
{
uint8_t gpio_ch;
// Get GPIO channel config, and check validity
if(odout_mapping(ch, &gpio_ch)) return;
// Set output level
if(lvl==0) mcu_gpio_write(gpio_ch, 1); // Output active
else mcu_gpio_write(gpio_ch, 0); // Output off
}
void bsp_odout_write_common(uint8_t percent)
{
uint8_t pwm_ch;
// Get PWM channel config, and check validity
if(odout_pwm_mapping(&pwm_ch)) return;
// Convert percent to 16b duty cycle
uint16_t dc = util_percent_to_16b(percent);
// Set PWM
mcu_pwm_write(pwm_ch, dc);
}
/**** Private function definitions ****/
static uint8_t odout_pwm_mapping(uint8_t* pwm_ch)
{
*pwm_ch = MCU_PWM1;
return 0;
}
static uint8_t odout_mapping(uint8_t od_ch, uint8_t* gpio_ch)
{
switch(od_ch)
{
case BSP_OD1: // LED0
*gpio_ch = MCU_GPIO9;
return 0;
case BSP_OD2: // LED1
*gpio_ch = MCU_GPIO10;
return 0;
case BSP_OD3: // LED2
*gpio_ch = MCU_GPIO11;
return 0;
case BSP_OD4: // LED3
*gpio_ch = MCU_GPIO12;
return 0;
case BSP_OD5: // LED4
*gpio_ch = MCU_GPIO13;
return 0;
case BSP_OD6: // LED5
*gpio_ch = MCU_GPIO14;
return 0;
default: //Invalid channel
*gpio_ch = 0;
return 1;
}
return 1;
}

View File

@@ -1,37 +0,0 @@
#ifndef ODOUT_H_
#define ODOUT_H_
/*
OD1 LED 0
OD2 LED 1
OD3 LED 2
OD4 LED 3
OD5 LED 4
OD6 LED 5
COMMON LED PWM
*/
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define BSP_OD1 1
#define BSP_OD2 2
#define BSP_OD3 3
#define BSP_OD4 4
#define BSP_OD5 5
#define BSP_OD6 6
#define BSP_ODOUT_LOW 0
#define BSP_ODOUT_HIGH 1
#define BSP_ODOUT_HIZ -1
/**** Public function declarations ****/
void bsp_odout_write(uint8_t ch, int8_t lvl);
void bsp_odout_write_common(uint8_t percent);
#ifdef TESTING
#endif
#endif /* ODOUT_H_ */

View File

@@ -1,23 +0,0 @@
/**** Includes ****/
#include "utils/utils.h"
#include "mcu/mcu_hal.h"
#include "setup.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
/**** Private function definitions ****/
void bsp_startup(void)
{
startupCfg_t mcu_cfg;
mcu_cfg.adc_clk = MCU_ADC_DIV2;
mcu_cfg.pwm_clk = MCU_TIM_DIV1;
mcu_cfg.pwm_top = 511;
mcu_cfg.pwm_chb_en = 1;
mcu_startup(&mcu_cfg);
}

View File

@@ -1,14 +0,0 @@
#ifndef BSP_SETUP_H_
#define BSP_SETUP_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
/**** Public function declarations ****/
void bsp_startup(void);
#ifdef TESTING
#endif
#endif /* BSP_SETUP_H_ */

View File

@@ -1,67 +0,0 @@
/**** Includes ****/
#include "faults.h"
#include "utils.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Mapping function declarations ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
#ifdef TESTING
#endif
uint8_t fault_process(fault_t* fault, uint8_t w_trig, uint8_t f_trig, fault_cfg_t* cfg)
{
// Override warning trigger in case of fault trigger
if(f_trig) w_trig = 1;
// Increase warning time, if reoccurring
if((w_trig)&&(fault->severity != FAULT_LVL_OK)) fault->w_time = util_sat_add_16b(fault->w_time, 1);
else fault->w_time = 0;
// Check if waring can be considered fault
if((cfg->wtof > 0)&&(fault->w_time > cfg->wtof)) f_trig = 1;
// Increase fault time, if reoccurring
if((f_trig)&&(fault->severity != FAULT_LVL_OK)) fault->f_time = util_sat_add_16b(fault->f_time, 1);
else fault->f_time = 0;
// Modify fault trigger
if((cfg->delay)&&(fault->f_time < cfg->delay)) f_trig = 0;
// Process fault level
if(f_trig)
{
fault->severity = FAULT_LVL_FAULT;
return 1;
}
else
{
if(w_trig) fault->severity = FAULT_LVL_WARNING;
else fault->severity = FAULT_LVL_OK;
}
return 0;
}
uint8_t fault_is_active(fault_t* fault)
{
if(fault->severity == FAULT_LVL_FAULT) return 1;
else return 0;
}
uint8_t fault_is_warning(fault_t* fault)
{
if(fault->severity != FAULT_LVL_OK) return 1;
else return 0;
}
void fault_reset(fault_t* fault)
{
fault->severity = FAULT_LVL_OK;
fault->w_time = 0;
fault->f_time = 0;
}
/**** Private function definitions ****/

View File

@@ -1,37 +0,0 @@
#ifndef FAULTS_H_
#define FAULTS_H_
/*
*/
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
typedef enum {
FAULT_LVL_OK,
FAULT_LVL_WARNING,
FAULT_LVL_FAULT
} fault_lvl_t;
typedef struct {
fault_lvl_t severity;
uint16_t w_time;
uint16_t f_time;
} fault_t;
typedef struct {
uint16_t delay;
uint16_t wtof;
} fault_cfg_t;
/**** Public function declarations ****/
uint8_t fault_process(fault_t* fault, uint8_t w_trig, uint8_t f_trig, fault_cfg_t* cfg);
uint8_t fault_is_active(fault_t* fault);
uint8_t fault_is_warning(fault_t* fault);
void fault_reset(fault_t* fault);
#ifdef TESTING
#endif
#endif /* FAULTS_H_ */

View File

@@ -1,81 +0,0 @@
/**** Includes ****/
#include "fuses.h"
#include "utils.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Mapping function declarations ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
#ifdef TESTING
#endif
void fuse_reset(fuse_t* fuse)
{
fuse->state = FUSE_OFF;
fuse->timer = 0;
fuse->count = 0;
}
uint8_t fuse_process(fuse_t* fuse, uint8_t fault, fuse_cfg_t* cfg)
{
// Active fault condition
if(fault)
{
// Note fuse time count
if((fuse->state == FUSE_OFF)||(fuse->state == FUSE_RETRY)) fuse->count++;
// Go to fused state in any case
fuse->state = FUSE_ACTIVE;
fuse->timer = 0;
return 1;
};
// No active fault condition
if(fuse->state==FUSE_ACTIVE)
{
// Go to cooldown
fuse->state = FUSE_COOLDOWN;
fuse->timer = cfg->cooldown_time;
};
// Wait for timeout
if(fuse->timer)
{
fuse->timer--;
if(fuse->state == FUSE_RETRY) return 0;
else return 1;
};
// Timeout end, transition logic
switch(fuse->state)
{
case FUSE_COOLDOWN:
// Cooldown end
if(cfg->retry_time)
{
fuse->state = FUSE_RETRY;
fuse->timer = cfg->retry_time;
}
else
{
fuse->state = FUSE_OFF;
fuse->timer = 0;
}
break;
case FUSE_RETRY:
// Go back to normal
fuse->state = FUSE_OFF;
break;
default:
// Nothing to do
break;
}
return 0;
}
/**** Private function definitions ****/

View File

@@ -1,36 +0,0 @@
#ifndef FUSES_H_
#define FUSES_H_
/*
*/
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
typedef enum {
FUSE_OFF,
FUSE_ACTIVE,
FUSE_COOLDOWN,
FUSE_RETRY
} fuse_state_t;
typedef struct {
fuse_state_t state;
uint8_t count;
uint16_t timer;
} fuse_t;
typedef struct {
uint16_t cooldown_time;
uint16_t retry_time;
} fuse_cfg_t;
/**** Public function declarations ****/
void fuse_reset(fuse_t* fuse);
uint8_t fuse_process(fuse_t* fuse, uint8_t fault, fuse_cfg_t* cfg);
#ifdef TESTING
#endif
#endif /* FUSES_H_ */

View File

@@ -1,272 +0,0 @@
/**** Includes ****/
#include "utils.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
#ifndef TESTING
static uint8_t find_interval_end_index(uint16_t val, uint16_t* axis_values, uint8_t len_axis);
static uint16_t interpolate_u16b(uint16_t x, uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1);
static uint16_t index2d_to_index1d(uint8_t ix, uint8_t iy, uint8_t len_x);
#endif
/**** Public function definitions ****/
uint8_t util_invert_8b(uint8_t x)
{
if(x!=0) return 0;
else return 1;
}
uint8_t util_sat_add_8b(uint8_t x, uint8_t y)
{
uint8_t z = x + y;
// Check for overflow
if((z < x)||(z < y)) return 0xFF;
else return z;
}
uint8_t util_sat_subtract_8b(uint8_t x, uint8_t y)
{
uint8_t z = x - y;
// Check for underflow
if(z > x) return 0;
else return z;
}
uint16_t util_sat_add_16b(uint16_t x, uint16_t y)
{
uint16_t z = x + y;
// Check for overflow
if((z < x)||(z < y)) return 0xFFFF;
else return z;
}
uint16_t util_sat_subtract_16b(uint16_t x, uint16_t y)
{
uint16_t z = x - y;
// Check for underflow
if(z > x) return 0;
else return z;
}
uint16_t util_limit_u32b_to_u16b(uint32_t in)
{
if(in == 0) return 0;
else if(in >= 0x0000FFFF) return 0xFFFF;
else return (uint16_t)in;
}
uint16_t util_limit_s32b_to_u16b(int32_t in)
{
if(in <= 0) return 0;
else if(in >= 0x0000FFFF) return 0xFFFF;
else return (uint16_t)in;
}
uint16_t util_convert_muldivoff(uint16_t raw, uint8_t mul, uint8_t div, int16_t offset)
{
int32_t temp = (int32_t)raw;
temp = temp * mul;
if(div>1) temp /= div;
temp += offset;
return util_limit_s32b_to_u16b(temp);
}
uint16_t util_sat_mul_kilo(uint16_t xk, uint16_t yk)
{
uint32_t temp = (uint32_t)xk * (uint32_t)yk;
temp /= 1000;
return util_limit_u32b_to_u16b(temp);
}
uint16_t util_sat_div_kilo(uint16_t top, uint16_t bot)
{
//Sanity check bot
if(bot==0) return 0xFFFF; //aka infinity
uint32_t temp = (uint32_t)top * 1000;
temp /= (uint32_t)bot;
return util_limit_u32b_to_u16b(temp);
}
uint16_t util_sat_ratio_16b(uint16_t top, uint16_t bot)
{
//Sanity check bot
if(bot==0) return 0xFFFF; //aka infinity
//Easy option
if(top>=bot) return 0xFFFF;
uint32_t temp = (uint32_t)top * 0x0000FFFF;
temp /= (uint32_t)bot;
return util_limit_u32b_to_u16b(temp);
}
uint16_t util_percent_to_16b(uint8_t percent)
{
uint32_t temp = (uint32_t)percent * 0x0000FFFF;
temp /= 100;
// Limit to 16 bits
uint16_t pwm = util_limit_u32b_to_u16b(temp);
return pwm;
}
uint16_t util_interpolate_1d_u16b(uint16_t x, uint16_t* x_axis, uint16_t* y_values, uint8_t len_axis)
{
// validate axis length
if(len_axis==0) return 0; // Empty data set
if(len_axis==1) return y_values[0]; // Only one data point
uint16_t y;
uint8_t i = find_interval_end_index(x, x_axis, len_axis);
if(i==0)
{
//Less then start
y = y_values[0];
}
else if(i==len_axis)
{
//More than end
y = y_values[len_axis-1];
}
else
{
// Do interpolate
y = interpolate_u16b(x, x_axis[i-1], x_axis[i], y_values[i-1], y_values[i]);
}
return y;
}
uint16_t util_interpolate_2d_u16b(uint16_t x, uint16_t y, uint16_t* x_axis, uint8_t len_x_axis, uint16_t* y_axis, uint8_t len_y_axis, uint16_t* z_values)
{
// validate axis length
if((len_x_axis==0)&&(len_y_axis==0)) return 0; // Empty data set
if((len_x_axis==1)&&(len_y_axis==1)) return z_values[0]; // Only one data point
uint8_t ix = find_interval_end_index(x, x_axis, len_x_axis);
uint8_t iy = find_interval_end_index(y, y_axis, len_y_axis);
// Check corners - easy answers
if((ix==0)&&(iy==0))
{
return z_values[0]; //[0][0] [Y][X]
}
else if((ix==len_x_axis)&&(iy==0))
{
return z_values[len_x_axis-1]; //[0][end]
}
else if((ix==0)&&(iy==len_y_axis))
{
uint16_t i = index2d_to_index1d(0, len_y_axis-1, len_x_axis);
return z_values[i]; //[end][0]
}
else if((ix==len_x_axis)&&(iy==len_y_axis))
{
uint16_t i = index2d_to_index1d(len_x_axis-1, len_y_axis-1, len_x_axis);
return z_values[i]; //[end][end]
};
// Check boundaries - 1D interpolation
if(ix==0)
{
// On ix=0 line
uint16_t i = 0;
uint16_t z0 = z_values[i];
i = index2d_to_index1d(0, len_y_axis-1, len_x_axis);
uint16_t z1 = z_values[i];
return interpolate_u16b(y, y_axis[0], y_axis[len_y_axis-1], z0, z1);
}
else if(ix==len_x_axis)
{
// On ix=END line
uint16_t i = len_x_axis-1;
uint16_t z0 = z_values[i];
i = index2d_to_index1d(len_x_axis-1, len_y_axis-1, len_x_axis);
uint16_t z1 = z_values[i];
return interpolate_u16b(y, y_axis[0], y_axis[len_y_axis-1], z0, z1);
}
else if(iy==0)
{
// On iy=0 line
uint16_t i = 0;
uint16_t z0 = z_values[i];
i = len_x_axis-1;
uint16_t z1 = z_values[i];
return interpolate_u16b(x, x_axis[0], x_axis[len_x_axis-1], z0, z1);
}
else if(iy==len_y_axis)
{
// On iy=END line
uint16_t i = index2d_to_index1d(0, len_y_axis-1, len_x_axis);
uint16_t z0 = z_values[i];
i = index2d_to_index1d(len_x_axis-1, len_y_axis-1, len_x_axis);
uint16_t z1 = z_values[i];
return interpolate_u16b(x, x_axis[0], x_axis[len_x_axis-1], z0, z1);
}
// Do interpolation
// Get axis values
uint16_t x0 = x_axis[ix-1];
uint16_t x1 = x_axis[ix];
uint16_t y0 = y_axis[iy-1];
uint16_t y1 = y_axis[iy];
// Do y0 line calculation
// Get z values at x0 and x1 points on y0 line
uint16_t i = index2d_to_index1d(ix-1, iy-1, len_x_axis);
uint16_t z0 = z_values[i];
uint16_t z1 = z_values[i+1];
// Interpolate z value on y0 line
uint16_t zy0 = interpolate_u16b(x, x0, x1, z0, z1);
// Do y1 line calculation
// Get z values at x0 and x1 points on y1 line
i = index2d_to_index1d(ix-1, iy, len_x_axis);
z0 = z_values[i];
z1 = z_values[i+1];
// Interpolate z value on y0 line
uint16_t zy1 = interpolate_u16b(x, x0, x1, z0, z1);
// Do calculation in y axis on xz line
return interpolate_u16b(y, y0, y1, zy0, zy1);
}
/**** Private function definitions ****/
static uint16_t interpolate_u16b(uint16_t x, uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1)
{
int32_t dy = (int32_t)y1 - (int32_t)y0;
int32_t dx = (int32_t)x1 - (int32_t)x0;
int32_t d = (int32_t)x - (int32_t)x0;
int32_t y = dy * d;
y /= dx;
y += y0;
return util_limit_s32b_to_u16b(y);
}
static uint8_t find_interval_end_index(uint16_t val, uint16_t* axis_values, uint8_t len_axis)
{
for(uint8_t i=0; i<len_axis; i++)
{
if(val < axis_values[i]) return i;
continue;
}
return len_axis;
}
static uint16_t index2d_to_index1d(uint8_t ix, uint8_t iy, uint8_t len_x)
{
return ((uint16_t)len_x * iy) + ix;
}

View File

@@ -1,37 +0,0 @@
#ifndef UTILS_H_
#define UTILS_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
/**** Public function declarations ****/
uint8_t util_invert_8b(uint8_t x);
uint16_t util_limit_u32b_to_u16b(uint32_t in);
uint16_t util_limit_s32b_to_u16b(int32_t in);
uint16_t util_convert_muldivoff(uint16_t raw, uint8_t mul, uint8_t div, int16_t offset);
uint16_t util_sat_mul_kilo(uint16_t xk, uint16_t yk);
uint16_t util_sat_div_kilo(uint16_t top, uint16_t bot);
uint16_t util_sat_ratio_16b(uint16_t top, uint16_t bot);
uint16_t util_percent_to_16b(uint8_t percent);
uint8_t util_sat_add_8b(uint8_t x, uint8_t y);
uint8_t util_sat_subtract_8b(uint8_t x, uint8_t y);
uint16_t util_sat_add_16b(uint16_t x, uint16_t y);
uint16_t util_sat_subtract_16b(uint16_t x, uint16_t y);
uint16_t util_interpolate_1d_u16b(uint16_t x, uint16_t* x_axis, uint16_t* y_values, uint8_t len_axis);
uint16_t util_interpolate_2d_u16b(uint16_t x, uint16_t y, uint16_t* x_axis, uint8_t len_x_axis, uint16_t* y_axis, uint8_t len_y_axis, uint16_t* z_values);
#ifdef TESTING
// Access to private functions for unit testing
static uint8_t find_interval_end_index(uint16_t val, uint16_t* axis_values, uint8_t len_axis);
static uint16_t interpolate_u16b(uint16_t x, uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1);
static uint16_t index2d_to_index1d(uint8_t ix, uint8_t iy, uint8_t len_x);
#endif
#endif /* UTILS_H_ */

116
firmware/src/hw/button.cpp Normal file
View File

@@ -0,0 +1,116 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "button.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::Button::Button(void)
{
return;
}
hw::Button::~Button(void)
{
return;
}
void hw::Button::init(bsp::DigitalIn* din_ch, uint8_t act_lvl, util::VCounter* timer, uint16_t dbnc_lim)
{
this->din_ch = din_ch;
this->timer = timer;
if(act_lvl) this->act_lvl = 1;
else this->act_lvl = 0;
this->state_start_ts = 0;
this->dbnc_ts = 0;
this->dbnc_lim = dbnc_lim;
this->state = BUTTON_OFF;
this->is_new = 0;
}
uint8_t hw::Button::process(void)
{
// Read din
if(this->update_din) this->din_ch->read();
// Get last read level
uint8_t lvl = this->din_ch->last_read;
// Determine next state
uint8_t next_state = BUTTON_OFF;
if(lvl==this->act_lvl) next_state = BUTTON_ON;
// Advance debounce sample counter
uint16_t ts_now = this->timer->read();
if(next_state != this->state)
{
if(this->dbnc_ts == 0) this->dbnc_ts = ts_now;
uint16_t td = util::time_delta(this->dbnc_ts, ts_now);
uint32_t td_ms = this->timer->convert_ms(td);
// Check for debounce end
if(td_ms >= this->dbnc_lim)
{
// Debounce end. Apply new state.
this->dbnc_ts = 0;
this->state = next_state;
this->state_start_ts = ts_now;
this->is_new = 1;
};
}
else this->dbnc_ts = 0;
return this->state;
}
uint8_t hw::Button::force_read(void)
{
// Read din
if(this->update_din) this->din_ch->read();
// Get last read level
uint8_t lvl = this->din_ch->last_read;
// Cancels active debounce
this->dbnc_ts = 0;
// Determine next state
uint8_t next_state = BUTTON_OFF;
if(lvl==this->act_lvl) next_state = BUTTON_ON;
if(next_state != this->state)
{
this->state_start_ts = this->timer->read();
this->state = next_state;
this->is_new = 1;
};
return this->state;
}
uint32_t hw::Button::time_read(void)
{
uint16_t ts_now = this->timer->read();
uint16_t td = util::time_delta(this->state_start_ts, ts_now);
return this->timer->convert_ms(td);
}
void hw::Button::time_reset(void)
{
this->state_start_ts = this->timer->read();
}
uint32_t hw::Button::time_read_max(void)
{
uint16_t ts_max = this->timer->read_top();
return this->timer->convert_ms(ts_max);
}
/**** Private function definitions ****/

49
firmware/src/hw/button.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef BUTTONS_H_
#define BUTTONS_H_
/**** Includes ****/
#include <stdint.h>
#include "../utils/vcounter.h"
#include "../bsp/board.h"
namespace hw {
/**** Public definitions ****/
const uint8_t BUTTON_OFF = 0;
const uint8_t BUTTON_ON = 1;
class Button
{
public:
Button(void);
~Button(void);
uint8_t state;
uint16_t dbnc_lim;
uint8_t is_new;
uint8_t update_din;
void init(bsp::DigitalIn* din_ch, uint8_t act_lvl, util::VCounter* timer, uint16_t dbnc_lim);
uint8_t process(void);
uint8_t force_read(void);
uint32_t time_read(void);
void time_reset(void);
uint32_t time_read_max(void);
#ifndef TESTING
protected:
#endif
bsp::DigitalIn* din_ch;
util::VCounter* timer;
uint8_t act_lvl;
uint16_t state_start_ts;
uint16_t dbnc_ts;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* BUTTONS_H_ */

View File

@@ -1,173 +0,0 @@
/**** Includes ****/
#include "board/utils/utils.h"
#include "board/din.h"
#include "board/dout.h"
#include "buttons.h"
/**** Private definitions ****/
/**** Private constants ****/
static const uint8_t DEF_DBNC_LIM = HW_BTN_DEF_DBNC_LIM;
static const uint16_t DEF_REPEAT_TIME = HW_BTN_DEF_REPEAT_TIME;
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t buttons_mapping(uint8_t btn_ch, uint8_t* din_ch, btn_cfg_t* cfg);
static uint8_t buttons_pull_mapping(uint8_t btn_ch, uint8_t* dout_ch);
/**** Public function definitions ****/
void btn_reset(btn_t* btn)
{
btn->state = BTN_INACTIVE;
btn->new_state = 0;
btn->state_time = 0;
btn->transition_cntr = 0;
btn->dbnc_active = 1;
}
uint8_t btn_ch_process(uint8_t btn_ch, btn_t* btn)
{
// Get channel config
uint8_t din_ch;
btn_cfg_t cfg;
if(buttons_mapping(btn_ch, &din_ch, &cfg)) return BTN_INACTIVE;
// Read din level
uint8_t lvl = bsp_din_read(din_ch);
// Process button logic
uint8_t btn_act = btn_process(lvl, btn, &cfg);
return btn_act;
}
uint8_t btn_process(uint8_t lvl, btn_t* btn, btn_cfg_t* cfg)
{
// Increase state time
btn->state_time = util_sat_add_16b(btn->state_time, 1);
// Check repeated new flag
if((cfg->repeat_time)&&(btn->state_time < 0xFFFF))
{
if((btn->state_time)%(cfg->repeat_time) == 0) btn->new_state = 1;
};
// Calculate saved level from state and active level cfg
uint8_t prev_lvl = 0;
if(((btn->dbnc_active)&&(btn->state))||((!btn->dbnc_active)&&(!btn->state))) prev_lvl = util_invert_8b(cfg->act_lvl);
else prev_lvl = cfg->act_lvl;
// Check if level changed
uint8_t lvl_chnaged = 0;
if(lvl!=prev_lvl) lvl_chnaged = 1;
//Process debounce logic
if(lvl_chnaged)
{
// Changed debounce state
if(!btn->dbnc_active) btn->dbnc_active = 1; // Start debounce
else btn->dbnc_active = 0; // Stop debounce
// Reset debounce counter
btn->transition_cntr = 0;
}
else
{
// Continue debounce
if(btn->dbnc_active) btn->transition_cntr += 1;
}
// Check for debounce end
if((btn->dbnc_active)&&(btn->transition_cntr >= cfg->dbnc_lim))
{
// Reset debounce
btn->dbnc_active = 0; //End debounce
btn->transition_cntr = 0;
// Set new state
if(lvl==cfg->act_lvl) btn->state = BTN_ACTIVE;
else btn->state = BTN_INACTIVE;
btn->state_time = 0; //Reset timer
btn->new_state = 1; //Set new flag
};
return btn->state;
}
void btn_ch_set_pull(uint8_t btn_ch, int8_t lvl)
{
// Get channel config
uint8_t dout_ch;
if(buttons_pull_mapping(btn_ch, &dout_ch)) return;
// Set button pull
bsp_dout_write(dout_ch, lvl);
}
/**** Private function definitions ****/
static uint8_t buttons_mapping(uint8_t btn_ch, uint8_t* din_ch, btn_cfg_t* cfg)
{
// Default, most common config
cfg->act_lvl = BSP_DIN_LOW;
cfg->dbnc_lim = DEF_DBNC_LIM;
cfg->repeat_time = DEF_REPEAT_TIME;
switch(btn_ch)
{
case BTN_1: // Mode
*din_ch = BSP_DIN1;
return 0;
case BTN_2: // Down
*din_ch = BSP_DIN3;
return 0;
case BTN_3: // Up
*din_ch = BSP_DIN4;
return 0;
case BTN_4: // Dimm
*din_ch = BSP_DIN5;
cfg->act_lvl = BSP_DIN_HIGH;
cfg->repeat_time = 0;
return 0;
case BTN_5: // Brakes
*din_ch = BSP_DIN6;
cfg->act_lvl = BSP_DIN_HIGH;
cfg->repeat_time = 0;
return 0;
case BTN_6: // Handbrake
*din_ch = BSP_DIN7;
cfg->repeat_time = 0;
return 0;
case BTN_6N: // Handbrake inverted
*din_ch = BSP_DIN7N;
cfg->repeat_time = 0;
return 0;
default: //Invalid channel
*din_ch = 0;
return 1;
}
return 1;
}
static uint8_t buttons_pull_mapping(uint8_t btn_ch, uint8_t* dout_ch)
{
switch(btn_ch)
{
case BTN_6: // Handbrake
*dout_ch = BSP_DOUT5;
return 0;
case BTN_6N: // Handbrake inverted
*dout_ch = BSP_DOUT5;
return 0;
default: //Invalid channel
*dout_ch = 0;
return 1;
}
return 1;
}

View File

@@ -1,54 +0,0 @@
#ifndef BUTTONS_H_
#define BUTTONS_H_
/*
*/
/**** Includes ****/
#include <stdint.h>
#include "config.h"
/**** Public definitions ****/
typedef struct {
uint8_t act_lvl;
uint8_t dbnc_lim;
uint16_t repeat_time;
} btn_cfg_t;
typedef struct {
uint8_t state;
uint8_t new_state;
uint16_t state_time;
uint8_t transition_cntr;
uint8_t dbnc_active;
} btn_t;
#define BTN_1 1 //DIN1 Mode
#define BTN_2 2 //DIN3 Down
#define BTN_3 3 //DIN4 Up
#define BTN_4 4 //DIN5 Dimm
#define BTN_5 5 //DIN6 Brakes
#define BTN_6 6 //DIN7 Handbrake
#define BTN_6N 7 //DIN7N Direct handbrake
#define BTN_INACTIVE 0
#define BTN_ACTIVE 1
#define BTN_PULL_LOW 0
#define BTN_PULL_HIGH 1
#define BTN_PULL_NONE -1
/**** Public function declarations ****/
void btn_reset(btn_t* btn);
// Using internal map
uint8_t btn_ch_process(uint8_t btn_ch, btn_t* btn);
void btn_ch_set_pull(uint8_t btn_ch, int8_t lvl);
// Manual process
uint8_t btn_process(uint8_t lvl, btn_t* btn, btn_cfg_t* cfg);
#ifdef TESTING
#endif
#endif /* BUTTONS_H_ */

View File

@@ -1,45 +0,0 @@
#ifndef HW_CONFIG_H_
#define HW_CONFIG_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define HW_BTN_DEF_DBNC_LIM 10
#define HW_BTN_DEF_REPEAT_TIME 1000
#define HW_HB_SUPPLY_VOLT_MIN_W 10000
#define HW_HB_SUPPLY_VOLT_MIN_F 8000
#define HW_HB_SUPPLY_VOLT_MAX_W 16000
#define HW_HB_SUPPLY_VOLT_MAX_F 19500
#define HW_HB_SUPPLY_CURRENT_MAX_W 6000
#define HW_HB_SUPPLY_CURRENT_MAX_F 8000
#define HW_HB_SUPPLY_POWER_MAX_W 30000
#define HW_HB_SUPPLY_POWER_MAX_F 45000
#define HW_HB_OUT_CURRENT_MAX_W 6000
#define HW_HB_OUT_CURRENT_MAX_F 8000
#define HW_HB_OUT_VOLTAGE_MAX_W 8000
#define HW_HB_OUT_VOLTAGE_MAX_F 10000
#define HW_HB_OUT_POWER_MAX_W 30000
#define HW_HB_OUT_POWER_MAX_F 40000
#define HW_HB_OUT_RESISTANCE_MIN_W 750
#define HW_HB_OUT_RESISTANCE_MIN_F 500
#define HW_HB_OUT_RESISTANCE_MAX_W 5000
#define HW_HB_OUT_RESISTANCE_MAX_F 10000
#define HW_HB_FAULT_DELAY 500
#define HW_HB_WTOF_DELAY 0
/**** Public function declarations ****/
#ifdef TESTING
#endif
#endif /* HW_CONFIG_H_ */

View File

@@ -1,399 +0,0 @@
/**** Includes ****/
#include "board/utils/utils.h"
#include "board/halfbridge.h"
#include "hb_control.h"
/**** Private definitions ****/
/**** Private constants ****/
// Fault condition thresholds
static const uint16_t SUPPLY_VOLT_MIN_W = HW_HB_SUPPLY_VOLT_MIN_W;
static const uint16_t SUPPLY_VOLT_MIN_F = HW_HB_SUPPLY_VOLT_MIN_F;
static const uint16_t SUPPLY_VOLT_MAX_W = HW_HB_SUPPLY_VOLT_MAX_W;
static const uint16_t SUPPLY_VOLT_MAX_F = HW_HB_SUPPLY_VOLT_MAX_F;
static const uint16_t SUPPLY_CURRENT_MAX_W = HW_HB_SUPPLY_CURRENT_MAX_W;
static const uint16_t SUPPLY_CURRENT_MAX_F = HW_HB_SUPPLY_CURRENT_MAX_F;
static const uint16_t SUPPLY_POWER_MAX_W = HW_HB_SUPPLY_POWER_MAX_W;
static const uint16_t SUPPLY_POWER_MAX_F = HW_HB_SUPPLY_POWER_MAX_F;
static const uint16_t OUT_CURRENT_MAX_W = HW_HB_OUT_CURRENT_MAX_W;
static const uint16_t OUT_CURRENT_MAX_F = HW_HB_OUT_CURRENT_MAX_F;
static const uint16_t OUT_VOLTAGE_MAX_W = HW_HB_OUT_VOLTAGE_MAX_W;
static const uint16_t OUT_VOLTAGE_MAX_F = HW_HB_OUT_VOLTAGE_MAX_F;
static const uint16_t OUT_POWER_MAX_W = HW_HB_OUT_POWER_MAX_W;
static const uint16_t OUT_POWER_MAX_F = HW_HB_OUT_POWER_MAX_F;
static const uint16_t OUT_RESISTANCE_MIN_W = HW_HB_OUT_RESISTANCE_MIN_W;
static const uint16_t OUT_RESISTANCE_MIN_F = HW_HB_OUT_RESISTANCE_MIN_F;
static const uint16_t OUT_RESISTANCE_MAX_W = HW_HB_OUT_RESISTANCE_MAX_W;
static const uint16_t OUT_RESISTANCE_MAX_F = HW_HB_OUT_RESISTANCE_MAX_F;
static const uint16_t FAULT_DELAY = HW_HB_FAULT_DELAY;
static const uint16_t WTOF_DELAY = HW_HB_WTOF_DELAY;
/**** Private variables ****/
/**** Private function declarations ****/
// Protection functions
static void faults_chs_reset(hb_fault_chs_t* ch_list);
static void faults_init(hb_faults_t* faults, hb_fault_chs_t* en_list);
static void faults_logic(hb_meas_t* measurements, hb_faults_t* faults);
static uint8_t faults_check(hb_faults_t* faults, hb_fault_chs_t* en_list, hb_fault_chs_t* fb_list, fault_lvl_t check);
static uint8_t warnings_feedback(hb_faults_t* faults, hb_fault_chs_t* en_list, hb_fault_chs_t* fb_list);
static uint8_t faults_feedback(hb_faults_t* faults, hb_fault_chs_t* en_list, hb_fault_chs_t* fb_list);
static uint8_t faults_is_any(hb_fault_chs_t* fb_list);
static uint8_t is_outside(uint16_t meas, uint16_t min, uint16_t max);
static uint8_t fuse_subprocess(hb_feedback_t* hb_fb, hb_control_t* hb_ctrl);
static void target_to_control(int16_t target, uint16_t ref_voltage, uint16_t* pwm_out, uint8_t* low_out, hb_fault_chs_t* fault_ch_en);
/**** Public function definitions ****/
void hb_init(hb_feedback_t* hb_fb, hb_control_t* hb_ctrl)
{
// Initialize control
hb_ctrl->enabled = 0;
// Initialize protection structures
faults_init(&hb_ctrl->out_faults, &hb_ctrl->out_faults_en);
fuse_reset(&hb_ctrl->out_fuse);
hb_ctrl->out_fuse_cfg.cooldown_time = 1000;
hb_ctrl->out_fuse_cfg.retry_time = 1000;
// Initialize feedback structure
bsp_hb_read_meas(&hb_fb->analog);
faults_chs_reset(&hb_fb->faults);
faults_chs_reset(&hb_fb->warnings);
hb_fb->enabled = 0;
hb_fb->warning_act = 0;
hb_fb->fault_act = 0;
hb_fb->fused = 0;
bsp_hb_write_pwm(0);
bsp_hb_write_low(0);
}
void hb_enable(hb_control_t* hb_ctrl)
{
bsp_hb_write_pwm(0);
bsp_hb_write_low(1);
hb_ctrl->enabled = 1;
}
void hb_disable(hb_control_t* hb_ctrl)
{
hb_ctrl->enabled = 0;
bsp_hb_write_pwm(0);
bsp_hb_write_low(0);
}
void hb_process(int16_t target, hb_feedback_t* hb_fb, hb_control_t* hb_ctrl)
{
uint16_t out_pwm = 0;
uint8_t low_on = 0;
// Read feedback
bsp_hb_read_meas(&hb_fb->analog);
// Process fuse
uint8_t fuse_act = fuse_subprocess(hb_fb, hb_ctrl);
// Act on fuse state
if((fuse_act)||(!hb_ctrl->enabled))
{
// Turn off output
bsp_hb_write_pwm(0);
bsp_hb_write_low(0);
return;
};
// Process new target
target_to_control(target, hb_fb->analog.sup_voltage, &out_pwm, &low_on, &hb_ctrl->out_faults_en);
// Apply new controls
bsp_hb_write_low(low_on);
bsp_hb_write_pwm(out_pwm);
}
/**** Private function definitions ****/
static void target_to_control(int16_t target, uint16_t ref_voltage, uint16_t* pwm_out, uint8_t* low_out, hb_fault_chs_t* fault_ch_en)
{
if(target < 0)
{
// Fast decay
*pwm_out = 0;
*low_out = 0;
// Set appropriate fault channels
fault_ch_en->out_short = 0;
fault_ch_en->out_ovp = 0;
}
else if(target == 0)
{
// Slow decay
*pwm_out = 0;
*low_out = 1;
// Set appropriate fault channels
fault_ch_en->out_short = 0;
fault_ch_en->out_ovp = 1;
}
else
{
// Calculate target PWM
*pwm_out = util_sat_ratio_16b((uint16_t)target, ref_voltage);
*low_out = 1;
fault_ch_en->out_short = 1;
fault_ch_en->out_ovp = 1;
}
}
static uint8_t fuse_subprocess(hb_feedback_t* hb_fb, hb_control_t* hb_ctrl)
{
// Process faults
faults_logic(&hb_fb->analog, &hb_ctrl->out_faults);
// Check if any enabled fault is active
uint8_t warn_act = warnings_feedback(&hb_ctrl->out_faults, &hb_ctrl->out_faults_en, &hb_fb->warnings);
uint8_t fault_act = faults_feedback(&hb_ctrl->out_faults, &hb_ctrl->out_faults_en, &hb_fb->faults);
// Process fuse state
uint8_t fuse_act = fuse_process(&hb_ctrl->out_fuse, fault_act, &hb_ctrl->out_fuse_cfg);
// Copy feedback data
hb_fb->enabled = hb_ctrl->enabled;
hb_fb->warning_act = warn_act;
hb_fb->fault_act = fault_act;
hb_fb->fused = fuse_act;
return fuse_act;
}
// Fault logic functions
static void faults_chs_reset(hb_fault_chs_t* ch_list)
{
// Zero all channels
ch_list->sup_uvp = 0;
ch_list->sup_ovp = 0;
ch_list->sup_ocp = 0;
ch_list->sup_opp = 0;
ch_list->out_ovp = 0;
ch_list->out_ocp = 0;
ch_list->out_opp = 0;
ch_list->out_short = 0;
ch_list->out_open = 0;
}
static void faults_init(hb_faults_t* faults, hb_fault_chs_t* en_list)
{
// Init state
fault_reset(&faults->sup_uvp);
fault_reset(&faults->sup_ovp);
fault_reset(&faults->sup_ocp);
fault_reset(&faults->sup_opp);
fault_reset(&faults->out_ovp);
fault_reset(&faults->out_ocp);
fault_reset(&faults->out_opp);
fault_reset(&faults->out_short);
fault_reset(&faults->out_open);
// Init enabled channels
faults_chs_reset(en_list);
en_list->sup_ocp = 1;
en_list->out_ocp = 1;
en_list->out_short = 1;
}
static void faults_logic(hb_meas_t* measurements, hb_faults_t* faults)
{
uint8_t w_trig = 0;
uint8_t f_trig = 0;
fault_cfg_t fault_cfg;
fault_cfg.delay = FAULT_DELAY;
fault_cfg.wtof = WTOF_DELAY;
// Check supply voltage
w_trig = is_outside(measurements->sup_voltage, SUPPLY_VOLT_MIN_W, 0);
f_trig = is_outside(measurements->sup_voltage, SUPPLY_VOLT_MIN_F, 0);
fault_process(&faults->sup_uvp, w_trig, f_trig, &fault_cfg);
w_trig = is_outside(measurements->sup_voltage, 0, SUPPLY_VOLT_MAX_W);
f_trig = is_outside(measurements->sup_voltage, 0, SUPPLY_VOLT_MAX_F);
fault_process(&faults->sup_ovp, w_trig, f_trig, &fault_cfg);
// Check supply current
w_trig = is_outside(measurements->sup_current, 0, SUPPLY_CURRENT_MAX_W);
f_trig = is_outside(measurements->sup_current, 0, SUPPLY_CURRENT_MAX_F);
fault_process(&faults->sup_ocp, w_trig, f_trig, &fault_cfg);
// Check supply power
w_trig = is_outside(measurements->sup_power, 0, SUPPLY_POWER_MAX_W);
f_trig = is_outside(measurements->sup_power, 0, SUPPLY_POWER_MAX_F);
fault_process(&faults->sup_opp, w_trig, f_trig, &fault_cfg);
// Check output voltage
w_trig = is_outside(measurements->out_voltage, 0, OUT_VOLTAGE_MAX_W);
f_trig = is_outside(measurements->out_voltage, 0, OUT_VOLTAGE_MAX_F);
fault_process(&faults->out_ovp, w_trig, f_trig, &fault_cfg);
// Check output current
w_trig = is_outside(measurements->out_current, 0, OUT_CURRENT_MAX_W);
f_trig = is_outside(measurements->out_current, 0, OUT_CURRENT_MAX_F);
fault_process(&faults->out_ocp, w_trig, f_trig, &fault_cfg);
// Check output power
w_trig = is_outside(measurements->out_power, 0, OUT_POWER_MAX_W);
f_trig = is_outside(measurements->out_power, 0, OUT_POWER_MAX_F);
fault_process(&faults->out_opp, w_trig, f_trig, &fault_cfg);
// Check output resistance
w_trig = is_outside(measurements->out_impedance, OUT_RESISTANCE_MIN_W, 0);
f_trig = is_outside(measurements->out_impedance, OUT_RESISTANCE_MIN_F, 0);
fault_process(&faults->out_short, w_trig, f_trig, &fault_cfg);
w_trig = is_outside(measurements->out_impedance, 0, OUT_RESISTANCE_MAX_W);
f_trig = is_outside(measurements->out_impedance, 0, OUT_RESISTANCE_MAX_F);
fault_process(&faults->out_open, w_trig, f_trig, &fault_cfg);
}
static uint8_t warnings_feedback(hb_faults_t* faults, hb_fault_chs_t* en_list, hb_fault_chs_t* fb_list)
{
return faults_check(faults, en_list, fb_list, FAULT_LVL_WARNING);
}
static uint8_t faults_feedback(hb_faults_t* faults, hb_fault_chs_t* en_list, hb_fault_chs_t* fb_list)
{
return faults_check(faults, en_list, fb_list, FAULT_LVL_FAULT);
}
// Utilities
static uint8_t is_outside(uint16_t meas, uint16_t min, uint16_t max)
{
if((meas < min)||((max!=0)&&(meas > max))) return 1;
else return 0;
}
static uint8_t faults_check(hb_faults_t* faults, hb_fault_chs_t* en_list, hb_fault_chs_t* fb_list, fault_lvl_t check)
{
if((en_list->sup_uvp)&&(faults->sup_uvp.severity == check)) fb_list->sup_uvp = 1;
if((en_list->sup_ovp)&&(faults->sup_ovp.severity == check)) fb_list->sup_ovp = 1;
if((en_list->sup_ocp)&&(faults->sup_ocp.severity == check)) fb_list->sup_ocp = 1;
if((en_list->sup_opp)&&(faults->sup_opp.severity == check)) fb_list->sup_opp = 1;
if((en_list->out_ovp)&&(faults->out_ovp.severity == check)) fb_list->out_ovp = 1;
if((en_list->out_ocp)&&(faults->out_ocp.severity == check)) fb_list->out_ocp = 1;
if((en_list->out_opp)&&(faults->out_opp.severity == check)) fb_list->out_opp = 1;
if((en_list->out_short)&&(faults->out_short.severity == check)) fb_list->out_short = 1;
if((en_list->out_open)&&(faults->out_open.severity == check)) fb_list->out_open = 1;
return faults_is_any(fb_list);
}
static uint8_t faults_is_any(hb_fault_chs_t* fb_list)
{
if(fb_list->sup_uvp) return 1;
if(fb_list->sup_ovp) return 1;
if(fb_list->sup_ocp) return 1;
if(fb_list->sup_opp) return 1;
if(fb_list->out_ovp) return 1;
if(fb_list->out_ocp) return 1;
if(fb_list->out_opp) return 1;
if(fb_list->out_short) return 1;
if(fb_list->out_open) return 1;
return 0;
}
#ifdef TESTING
uint8_t hb_is_equal_fb_struct(hb_feedback_t* f1, hb_feedback_t* f2)
{
if(f1->analog.out_voltage != f2->analog.out_voltage ) return 0;
if(f1->analog.out_current != f2->analog.out_current ) return 0;
if(f1->analog.sup_voltage != f2->analog.sup_voltage ) return 0;
if(f1->analog.sup_current != f2->analog.sup_current ) return 0;
if(f1->analog.out_power != f2->analog.out_power ) return 0;
if(f1->analog.sup_power != f2->analog.sup_power ) return 0;
if(f1->analog.out_impedance != f2->analog.out_impedance ) return 0;
if(f1->analog.low_side_ctrl != f2->analog.low_side_ctrl ) return 0;
if(f1->analog.pwm != f2->analog.pwm ) return 0;
if(f1->enabled != f2->enabled ) return 0;
if(f1->warning_act != f2->warning_act ) return 0;
if(f1->fault_act != f2->fault_act ) return 0;
if(f1->fused != f2->fused ) return 0;
if(f1->warnings.sup_uvp != f2->warnings.sup_uvp ) return 0;
if(f1->warnings.sup_ovp != f2->warnings.sup_ovp ) return 0;
if(f1->warnings.sup_ocp != f2->warnings.sup_ocp ) return 0;
if(f1->warnings.sup_opp != f2->warnings.sup_opp ) return 0;
if(f1->warnings.out_ovp != f2->warnings.out_ovp ) return 0;
if(f1->warnings.out_ocp != f2->warnings.out_ocp ) return 0;
if(f1->warnings.out_opp != f2->warnings.out_opp ) return 0;
if(f1->warnings.out_short != f2->warnings.out_short ) return 0;
if(f1->warnings.out_open != f2->warnings.out_open ) return 0;
if(f1->faults.sup_uvp != f2->faults.sup_uvp ) return 0;
if(f1->faults.sup_ovp != f2->faults.sup_ovp ) return 0;
if(f1->faults.sup_ocp != f2->faults.sup_ocp ) return 0;
if(f1->faults.sup_opp != f2->faults.sup_opp ) return 0;
if(f1->faults.out_ovp != f2->faults.out_ovp ) return 0;
if(f1->faults.out_ocp != f2->faults.out_ocp ) return 0;
if(f1->faults.out_opp != f2->faults.out_opp ) return 0;
if(f1->faults.out_short != f2->faults.out_short ) return 0;
if(f1->faults.out_open != f2->faults.out_open ) return 0;
return 1;
}
uint8_t hb_is_equal_ctrl_struct(hb_control_t* c1, hb_control_t* c2)
{
if(c1->enabled != c2->enabled ) return 0;
if(c1->out_faults.sup_uvp.severity != c2->out_faults.sup_uvp.severity ) return 0;
if(c1->out_faults.sup_uvp.w_time != c2->out_faults.sup_uvp.w_time ) return 0;
if(c1->out_faults.sup_uvp.f_time != c2->out_faults.sup_uvp.f_time ) return 0;
if(c1->out_faults.sup_ovp.severity != c2->out_faults.sup_ovp.severity ) return 0;
if(c1->out_faults.sup_ovp.w_time != c2->out_faults.sup_ovp.w_time ) return 0;
if(c1->out_faults.sup_ovp.f_time != c2->out_faults.sup_ovp.f_time ) return 0;
if(c1->out_faults.sup_ocp.severity != c2->out_faults.sup_ocp.severity ) return 0;
if(c1->out_faults.sup_ocp.w_time != c2->out_faults.sup_ocp.w_time ) return 0;
if(c1->out_faults.sup_ocp.f_time != c2->out_faults.sup_ocp.f_time ) return 0;
if(c1->out_faults.sup_opp.severity != c2->out_faults.sup_opp.severity ) return 0;
if(c1->out_faults.sup_opp.w_time != c2->out_faults.sup_opp.w_time ) return 0;
if(c1->out_faults.sup_opp.f_time != c2->out_faults.sup_opp.f_time ) return 0;
if(c1->out_faults.out_ovp.severity != c2->out_faults.out_ovp.severity ) return 0;
if(c1->out_faults.out_ovp.w_time != c2->out_faults.out_ovp.w_time ) return 0;
if(c1->out_faults.out_ovp.f_time != c2->out_faults.out_ovp.f_time ) return 0;
if(c1->out_faults.out_ocp.severity != c2->out_faults.out_ocp.severity ) return 0;
if(c1->out_faults.out_ocp.w_time != c2->out_faults.out_ocp.w_time ) return 0;
if(c1->out_faults.out_ocp.f_time != c2->out_faults.out_ocp.f_time ) return 0;
if(c1->out_faults.out_opp.severity != c2->out_faults.out_opp.severity ) return 0;
if(c1->out_faults.out_opp.w_time != c2->out_faults.out_opp.w_time ) return 0;
if(c1->out_faults.out_opp.f_time != c2->out_faults.out_opp.f_time ) return 0;
if(c1->out_faults.out_short.severity != c2->out_faults.out_short.severity ) return 0;
if(c1->out_faults.out_short.w_time != c2->out_faults.out_short.w_time ) return 0;
if(c1->out_faults.out_short.f_time != c2->out_faults.out_short.f_time ) return 0;
if(c1->out_faults.out_open.severity != c2->out_faults.out_open.severity ) return 0;
if(c1->out_faults.out_open.w_time != c2->out_faults.out_open.w_time ) return 0;
if(c1->out_faults.out_open.f_time != c2->out_faults.out_open.f_time ) return 0;
if(c1->out_faults_en.sup_uvp != c2->out_faults_en.sup_uvp ) return 0;
if(c1->out_faults_en.sup_ovp != c2->out_faults_en.sup_ovp ) return 0;
if(c1->out_faults_en.sup_ocp != c2->out_faults_en.sup_ocp ) return 0;
if(c1->out_faults_en.sup_opp != c2->out_faults_en.sup_opp ) return 0;
if(c1->out_faults_en.out_ovp != c2->out_faults_en.out_ovp ) return 0;
if(c1->out_faults_en.out_ocp != c2->out_faults_en.out_ocp ) return 0;
if(c1->out_faults_en.out_opp != c2->out_faults_en.out_opp ) return 0;
if(c1->out_faults_en.out_short != c2->out_faults_en.out_short ) return 0;
if(c1->out_faults_en.out_open != c2->out_faults_en.out_open ) return 0;
if(c1->out_fuse.state != c2->out_fuse.state ) return 0;
if(c1->out_fuse.count != c2->out_fuse.count ) return 0;
if(c1->out_fuse.timer != c2->out_fuse.timer ) return 0;
if(c1->out_fuse_cfg.cooldown_time != c2->out_fuse_cfg.cooldown_time ) return 0;
if(c1->out_fuse_cfg.retry_time != c2->out_fuse_cfg.retry_time ) return 0;
return 1;
}
#endif

View File

@@ -1,67 +0,0 @@
#ifndef HB_CONTROL_H_
#define HB_CONTROL_H_
/**** Includes ****/
#include <stdint.h>
#include "board/utils/faults.h"
#include "board/utils/fuses.h"
#include "board/halfbridge.h"
#include "config.h"
/**** Public definitions ****/
typedef struct {
fault_t sup_uvp;
fault_t sup_ovp;
fault_t sup_ocp;
fault_t sup_opp;
fault_t out_ovp;
fault_t out_ocp;
fault_t out_opp;
fault_t out_short;
fault_t out_open;
} hb_faults_t;
typedef struct {
uint8_t sup_uvp;
uint8_t sup_ovp;
uint8_t sup_ocp;
uint8_t sup_opp;
uint8_t out_ovp;
uint8_t out_ocp;
uint8_t out_opp;
uint8_t out_short;
uint8_t out_open;
} hb_fault_chs_t;
typedef struct {
hb_meas_t analog;
uint8_t enabled;
uint8_t warning_act;
uint8_t fault_act;
uint8_t fused;
hb_fault_chs_t warnings;
hb_fault_chs_t faults;
} hb_feedback_t;
typedef struct {
uint8_t enabled;
hb_faults_t out_faults;
hb_fault_chs_t out_faults_en;
fuse_t out_fuse;
fuse_cfg_t out_fuse_cfg;
} hb_control_t;
/**** Public function declarations ****/
void hb_init(hb_feedback_t* hb_fb, hb_control_t* hb_ctrl);
void hb_enable(hb_control_t* hb_ctrl);
void hb_disable(hb_control_t* hb_ctrl);
void hb_process(int16_t target, hb_feedback_t* hb_fb, hb_control_t* hb_ctrl);
#ifdef TESTING
uint8_t hb_is_equal_fb_struct(hb_feedback_t* f1, hb_feedback_t* f2);
uint8_t hb_is_equal_ctrl_struct(hb_control_t* c1, hb_control_t* c2);
#endif
#endif /* HB_CONTROL_H_ */

View File

@@ -1,38 +0,0 @@
/**** Includes ****/
#include "board/odout.h"
#include "led_display.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
void led_dsp_set_image(uint8_t image)
{
if(image&0x01) bsp_odout_write(BSP_OD1, BSP_ODOUT_LOW);
else bsp_odout_write(BSP_OD1, BSP_ODOUT_HIZ);
if(image&0x02) bsp_odout_write(BSP_OD2, BSP_ODOUT_LOW);
else bsp_odout_write(BSP_OD2, BSP_ODOUT_HIZ);
if(image&0x04) bsp_odout_write(BSP_OD3, BSP_ODOUT_LOW);
else bsp_odout_write(BSP_OD3, BSP_ODOUT_HIZ);
if(image&0x08) bsp_odout_write(BSP_OD4, BSP_ODOUT_LOW);
else bsp_odout_write(BSP_OD4, BSP_ODOUT_HIZ);
if(image&0x10) bsp_odout_write(BSP_OD5, BSP_ODOUT_LOW);
else bsp_odout_write(BSP_OD5, BSP_ODOUT_HIZ);
if(image&0x20) bsp_odout_write(BSP_OD6, BSP_ODOUT_LOW);
else bsp_odout_write(BSP_OD6, BSP_ODOUT_HIZ);
}
void led_dsp_backligth_set(uint8_t percent)
{
bsp_odout_write_common(percent);
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,160 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "led_display.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::LedDisplay::LedDisplay(void)
{
return;
}
hw::LedDisplay::~LedDisplay(void)
{
this->force(0x00);
this->write_backlight(0);
}
void hw::LedDisplay::init(doutCfg_t* dout_chs, uint8_t act_lvl, util::VCounter* timer, bsp::PwmOut* pwm_ch)
{
this->led0_dout_ch = dout_chs->led0_dout_ch;
this->led1_dout_ch = dout_chs->led1_dout_ch;
this->led2_dout_ch = dout_chs->led2_dout_ch;
this->led3_dout_ch = dout_chs->led3_dout_ch;
this->led4_dout_ch = dout_chs->led4_dout_ch;
this->led5_dout_ch = dout_chs->led5_dout_ch;
if(act_lvl) this->act_lvl = 1;
else this->act_lvl = 0;
this->timer = timer;
this->pwm_ch = pwm_ch;
this->on_time = 0;
this->period = 0;
this->cycle_cnt = 0;
this->cycle_limit = 0;
this->timestamp_start = 0;
this->image = 0x00;
this->force(0x00);
this->write_backlight(0);
}
void hw::LedDisplay::force(uint8_t image)
{
uint8_t led_state;
if(image&0x01) led_state = 1;
else led_state = 0;
this->set_single_led(led_state, this->led0_dout_ch);
if(image&0x02) led_state = 1;
else led_state = 0;
this->set_single_led(led_state, this->led1_dout_ch);
if(image&0x04) led_state = 1;
else led_state = 0;
this->set_single_led(led_state, this->led2_dout_ch);
if(image&0x08) led_state = 1;
else led_state = 0;
this->set_single_led(led_state, this->led3_dout_ch);
if(image&0x10) led_state = 1;
else led_state = 0;
this->set_single_led(led_state, this->led4_dout_ch);
if(image&0x20) led_state = 1;
else led_state = 0;
this->set_single_led(led_state, this->led5_dout_ch);
}
void hw::LedDisplay::write(uint8_t image)
{
// Static mode
this->on_time = 1;
this->period = 0;
this->cycle_cnt = 0;
this->cycle_limit = 0;
this->timestamp_start = 0;
this->image = image;
// Set initial state
this->force(this->image);
}
void hw::LedDisplay::write(uint8_t image, uint16_t on_time, uint16_t period, uint8_t cycle_limit)
{
// "PWM" mode
this->on_time = on_time;
this->period = period;
this->cycle_cnt = 0;
this->cycle_limit = cycle_limit;
this->image = image;
// Set initial state
if(this->on_time > 0) this->force(this->image);
else this->force(0x00);
// Cycle start time
this->timestamp_start = this->timer->read();
}
void hw::LedDisplay::process(void)
{
if(this->period == 0) return; // Nothing to do
// Update cycle timing
uint16_t ts_now = this->timer->read();
uint16_t td = util::time_delta(this->timestamp_start, ts_now);
uint32_t td_ms = this->timer->convert_ms(td);
if(td_ms >= this->period)
{
this->timestamp_start = ts_now;
this->cycle_cnt++;
};
// Check cycle limit
if((this->cycle_cnt >= this->cycle_limit)&&(this->cycle_limit))
{
this->on_time = 0;
this->period = 0;
this->timestamp_start = 0;
this->force(0x00);
return;
};
// Do output compare
if(td_ms < this->on_time) this->force(this->image);
else this->force(0x00);
}
uint8_t hw::LedDisplay::is_cycle_end(void)
{
if(this->cycle_cnt >= this->cycle_limit) return 1;
else return 0;
}
void hw::LedDisplay::write_backlight(uint8_t percent)
{
this->pwm_ch->write(percent);
}
void hw::LedDisplay::set_single_led(uint8_t state, bsp::DigitalOut* led_ch)
{
uint8_t lvl = 0;
if(((state==0)&&(this->act_lvl==0))||((state!=0)&&(this->act_lvl==1))) lvl = 1;
led_ch->write(lvl);
}
/**** Private function definitions ***/

View File

@@ -1,19 +1,66 @@
#ifndef LED_DISPLAY_H_
#define LED_DISPLAY_H_
/*
*/
/**** Includes ****/
#include <stdint.h>
#include "../utils/vcounter.h"
#include "../bsp/board.h"
namespace hw {
/**** Public definitions ****/
class LedDisplay
{
public:
typedef struct {
bsp::DigitalOut* led0_dout_ch;
bsp::DigitalOut* led1_dout_ch;
bsp::DigitalOut* led2_dout_ch;
bsp::DigitalOut* led3_dout_ch;
bsp::DigitalOut* led4_dout_ch;
bsp::DigitalOut* led5_dout_ch;
} doutCfg_t;
LedDisplay(void);
~LedDisplay(void);
uint16_t on_time;
uint16_t period;
uint8_t cycle_cnt;
uint8_t cycle_limit;
void init(doutCfg_t* dout_chs, uint8_t act_lvl, util::VCounter* timer, bsp::PwmOut* pwm_ch);
void write(uint8_t image);
void write(uint8_t image, uint16_t on_time, uint16_t period, uint8_t cycle_limit);
void process(void);
uint8_t is_cycle_end(void);
void force(uint8_t image);
void write_backlight(uint8_t percent);
#ifdef TESTING
protected:
#endif
bsp::DigitalOut* led0_dout_ch;
bsp::DigitalOut* led1_dout_ch;
bsp::DigitalOut* led2_dout_ch;
bsp::DigitalOut* led3_dout_ch;
bsp::DigitalOut* led4_dout_ch;
bsp::DigitalOut* led5_dout_ch;
uint8_t act_lvl;
util::VCounter* timer;
bsp::PwmOut* pwm_ch;
uint16_t timestamp_start;
uint8_t image;
void set_single_led(uint8_t state, bsp::DigitalOut* led_ch);
};
/**** Public function declarations ****/
void led_dsp_set_image(uint8_t image);
void led_dsp_backligth_set(uint8_t percent);
#ifdef TESTING
#endif
#endif /* LED_DISPLAY_H_ */
} //namespace
#endif /* LED_DISPLAY_H_ */

View File

@@ -0,0 +1,105 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "out_driver.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::OutDriver::OutDriver(void)
{
return;
}
hw::OutDriver::~OutDriver(void)
{
return;
}
void hw::OutDriver::init(bsp::PwmOut* pwm_high, bsp::DigitalOut* dout_low)
{
this->pwm_high = pwm_high;
this->dout_low = dout_low;
this->target_duty = 0;
this->target_low = 0;
this->disabled = 1;
}
void hw::OutDriver::write(uint16_t numerator)
{
this->target_duty = numerator;
this->target_low = 1;
// Check if enabled
if(this->disabled)
{
return;
};
// Set low side
if(this->dout_low->last_writen == 0)
{
this->dout_low->write(this->target_low);
};
// Set PWM
this->pwm_high->write(this->target_duty);
}
void hw::OutDriver::write(uint8_t percent)
{
// Convert to numerator/0xFFFF
this->write(util::percent_to_16b(percent));
}
void hw::OutDriver::write_hiz(void)
{
this->target_duty = 0;
this->target_low = 0;
// Check if enabled
if(this->disabled)
{
return;
};
// Set PWM
this->pwm_high->write((uint16_t)0);
// Set low side
this->dout_low->write(0);
}
void hw::OutDriver::enable(void)
{
if(this->disabled==0) return;
this->disabled = 0;
if(this->target_low==0) this->write_hiz();
else this->write(this->target_duty);
}
void hw::OutDriver::disable(void)
{
if(this->disabled!=0) return;
// Set PWM
this->pwm_high->write((uint16_t)0);
// Set low side
this->dout_low->write(0);
this->disabled = 1;
}
uint8_t hw::OutDriver::is_disabled(void)
{
return this->disabled;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,45 @@
#ifndef OUT_DRIVER_H_
#define OUT_DRIVER_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/board.h"
namespace hw {
/**** Public definitions ****/
class OutDriver
{
public:
OutDriver(void);
~OutDriver(void);
void init(bsp::PwmOut* pwm_high, bsp::DigitalOut* dout_low);
uint16_t target_duty;
uint8_t target_low;
void write(uint16_t numerator);
void write(uint8_t percent);
void write_hiz(void);
void enable(void);
void disable(void);
uint8_t is_disabled(void);
#ifndef TESTING
protected:
#endif
bsp::PwmOut* pwm_high;
bsp::DigitalOut* dout_low;
uint8_t disabled;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* OUT_DRIVER_H_ */

139
firmware/src/hw/out_reg.cpp Normal file
View File

@@ -0,0 +1,139 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "out_reg.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::OutReg::OutReg(void)
{
return;
}
hw::OutReg::~OutReg(void)
{
return;
}
void hw::OutReg::init(outRegCfg_t* cfg)
{
this->pwm_high = cfg->pwm_high;
this->dout_low = cfg->dout_low;
this->ubat = cfg->ubat;
this->uout = cfg->uout;
this->iout = cfg->iout;
this->voltage = 0;
this->current = 0;
this->out_on = 0;
this->lock = 0;
this->cc_mode_en = 0;
this->update_ain = 0;
this->cc_tolerance = 75;
}
void hw::OutReg::write_voltage(uint16_t voltage)
{
this->voltage = voltage;
}
void hw::OutReg::write_current(uint16_t current)
{
this->current = current;
this->current_bot = util::sat_subtract(current, this->cc_tolerance);
this->current_top = util::sat_add(current, this->cc_tolerance);
}
void hw::OutReg::write_on(uint8_t state)
{
this->out_on = state;
}
void hw::OutReg::write_lock(uint8_t state)
{
this->lock = state;
}
uint16_t hw::OutReg::read_voltage(void)
{
return this->voltage;
}
uint16_t hw::OutReg::read_current(void)
{
return this->current;
}
void hw::OutReg::process(void)
{
// Update analog input
if(this->update_ain)
{
this->ubat->read();
this->uout->read();
this->iout->read();
};
// Check if turned off
if((out_on == 0)||(this->lock != 0))
{
this->pwm_high->write((uint16_t)0);
this->dout_low->write(0);
return;
}
else if(this->dout_low->last_writen == 0)
{
this->dout_low->write(1);
};
// Calculate next duty cycle setting
uint16_t next_duty = this->pwm_high->get_set_duty();
if((this->voltage==0)||(this->current==0))
{
// Off but not HiZ
next_duty = 0;
}
else if((this->cc_mode_en)&&(this->iout->last_read > this->current_bot))
{
// Constant current mode - Change voltage to be within current limit
if(util::is_in_range(this->iout->last_read, this->current_bot, this->current_top)==0)
{
// Current outside of tolerance. Recalculate duty cycle.
uint32_t temp = (uint32_t)this->pwm_high->get_set_duty() * (uint32_t)this->current;
temp /= this->iout->last_read;
next_duty = util::sat_cast(temp);
};
}
else
{
// Constant voltage mode
next_duty = util::sat_ratio(this->voltage, this->ubat->last_read);
}
this->pwm_high->write(next_duty);
return;
}
void hw::OutReg::force_off(void)
{
// Turn off output - HiZ
this->pwm_high->write((uint16_t)0);
this->dout_low->write(0);
// Update targets
this->voltage = 0;
this->current = 0;
this->out_on = 0;
this->lock = 1;
}
/**** Private function definitions ****/

66
firmware/src/hw/out_reg.h Normal file
View File

@@ -0,0 +1,66 @@
#ifndef OUTPUT_REGULATOR_H_
#define OUTPUT_REGULATOR_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/board.h"
namespace hw {
/**** Public definitions ****/
class OutReg
{
public:
typedef struct {
bsp::PwmOut* pwm_high;
bsp::DigitalOut* dout_low;
bsp::AnalogIn* ubat;
bsp::AnalogIn* uout;
bsp::AnalogIn* iout;
} outRegCfg_t;
OutReg(void);
~OutReg(void);
void init(outRegCfg_t* cfg);
uint8_t cc_mode_en;
uint8_t update_ain;
uint16_t cc_tolerance;
void write_voltage(uint16_t voltage);
void write_current(uint16_t current);
void write_on(uint8_t state);
void write_lock(uint8_t state);
uint16_t read_voltage(void);
uint16_t read_current(void);
void process(void);
void force_off(void);
#ifndef TESTING
protected:
#endif
bsp::PwmOut* pwm_high;
bsp::DigitalOut* dout_low;
bsp::AnalogIn* ubat;
bsp::AnalogIn* uout;
bsp::AnalogIn* iout;
uint16_t voltage;
uint16_t current;
uint16_t current_top;
uint16_t current_bot;
uint8_t out_on;
uint8_t lock;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* OUTPUT_REGULATOR_H_ */

View File

@@ -0,0 +1,46 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "../utils/interpolate.h"
#include "potentiometer.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::Potentiometer::Potentiometer(void)
{
return;
}
hw::Potentiometer::~Potentiometer(void)
{
return;
}
void hw::Potentiometer::init(bsp::AnalogIn* ain_ch, uint16_t low_deadzone, uint16_t high_deadzone)
{
this->ain_ch = ain_ch;
this->low_deadzone = low_deadzone;
this->high_deadzone = high_deadzone;
this->last_percent = 0;
this->update_ain = 1;
}
uint8_t hw::Potentiometer::read(void)
{
// Update analog input
if(this->update_ain) this->ain_ch->read();
// Calculate percent
if(this->ain_ch->last_read <= this->low_deadzone) this->last_percent = 0;
else if(this->ain_ch->last_read >= this->high_deadzone ) this->last_percent = 100;
else this->last_percent = util::interpolate(this->ain_ch->last_read, this->low_deadzone, this->high_deadzone, 0, 100);
return this->last_percent;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,40 @@
#ifndef POTENTIOMETER_H_
#define POTENTIOMETER_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/board.h"
namespace hw {
/**** Public definitions ****/
class Potentiometer
{
public:
Potentiometer(void);
~Potentiometer(void);
void init(bsp::AnalogIn* ain_ch, uint16_t low_deadzone, uint16_t high_deadzone);
uint16_t low_deadzone;
uint16_t high_deadzone;
uint8_t last_percent;
uint8_t update_ain;
uint8_t read(void);
#ifndef TESTING
protected:
#endif
bsp::AnalogIn* ain_ch;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* POTENTIOMETER_H_ */

View File

@@ -0,0 +1,107 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "safe_ain.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::SafeAin::SafeAin(void)
{
return;
}
hw::SafeAin::~SafeAin(void)
{
return;
}
void hw::SafeAin::init(bsp::AnalogIn* ain_ch, util::VCounter* timer)
{
this->ain_ch = ain_ch;
this->timer = timer;
this->under_treshold = 0;
this->over_treshold = 0xFFFF;
this->hold_time = 0;
this->cooldown_time = 0;
this->update_ain = 0;
this->auto_reset = 0;
this->warning = 0;
this->fault = 0;
this->last_read = 0;
this->ts_state_chnage = 0;
}
void hw::SafeAin::process(void)
{
// Update analog input
if(this->update_ain) this->ain_ch->read();
this->last_read = this->ain_ch->last_read;
// Get current time
uint16_t ts_now = this->timer->read();
// Update over current and warning condition
uint8_t is_outside = 0;
if(this->last_read < this->under_treshold) is_outside = 1;
if(this->last_read > this->over_treshold) is_outside = 1;
// Note start time if new OC condition
if((is_outside!=0)&&(this->warning==0))
{
this->ts_state_chnage = ts_now;
};
// Update warning
if(this->warning)
{
if(is_outside == 0)
{
this->warning = 0;
};
}
else
{
if(is_outside == 1)
{
this->warning = 1;
};
}
//this->warning = is_outside;
if((this->warning==0)&&(this->fault==0)) return;
// Calculate warning condition time
uint16_t td = util::time_delta(this->ts_state_chnage, ts_now);
uint32_t time_ms = this->timer->convert_ms(td);
// Check for fault set
if((this->fault==0)&&(time_ms > (uint32_t)this->hold_time)&&(this->warning!=0))
{
this->fault = 1;
return;
};
// Check if allowed auto reset
if(this->auto_reset==0) return;
// Check for fault reset
if((this->fault!=0)&&(time_ms > (uint32_t)this->cooldown_time))
{
this->fault = 0;
return;
};
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,50 @@
#ifndef SAFE_AIN_H_
#define SAFE_AIN_H_
/**** Includes ****/
#include <stdint.h>
#include "../utils/vcounter.h"
#include "../bsp/board.h"
namespace hw {
/**** Public definitions ****/
class SafeAin
{
public:
SafeAin(void);
~SafeAin(void);
void init(bsp::AnalogIn* ain_ch, util::VCounter* timer);
uint8_t warning;
uint8_t fault;
uint16_t last_read;
uint16_t under_treshold;
uint16_t over_treshold;
uint16_t hold_time;
uint16_t cooldown_time;
uint8_t update_ain;
uint8_t auto_reset;
void process(void);
#ifndef TESTING
protected:
#endif
bsp::AnalogIn* ain_ch;
util::VCounter* timer;
uint16_t ts_state_chnage;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* SAFE_AIN_H_ */

View File

@@ -1,16 +0,0 @@
/**** Includes ****/
#include "board/utils/utils.h"
#include "board/setup.h"
#include "startup.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
void hw_startup(void)
{
bsp_startup();
}
/**** Private function definitions ****/

View File

@@ -1,14 +0,0 @@
#ifndef HW_STARTUP_H_
#define HW_STARTUP_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
/**** Public function declarations ****/
void hw_startup(void);
#ifdef TESTING
#endif
#endif /* HW_STARTUP_H_ */

View File

@@ -1,41 +0,0 @@
/**** Includes ****/
#include "coil.h"
/**** Private definitions ****/
/**** Private constants ****/
static const int16_t TARGET_HANDBRAKE = COIL_TARGET_HANDBRAKE;
static const int16_t LOCK_VOLTAGE = COIL_LOCK_VOLTAGE;
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
int16_t coil_target(uint8_t force, uint8_t hbrake_act)
{
if(hbrake_act)
{
return TARGET_HANDBRAKE;
}
else if(force==0)
{
return 0;
}
else if(force >= 100)
{
return LOCK_VOLTAGE;
}
else
{
// Calculate target
uint32_t t = (uint32_t)force * LOCK_VOLTAGE;
t /= 100;
if(t > LOCK_VOLTAGE) return LOCK_VOLTAGE;
else if(t < 0) return 0;
else return (int16_t)t;
}
return 0;
}
/**** Private function definitions ****/

View File

@@ -1,17 +0,0 @@
#ifndef COIL_H_
#define COIL_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define COIL_TARGET_HANDBRAKE -1
#define COIL_LOCK_VOLTAGE 6500
/**** Public function declarations ****/
int16_t coil_target(uint8_t force, uint8_t hbrake_act);
#ifdef TESTING
#endif
#endif /* COIL_H_ */

View File

@@ -1,108 +0,0 @@
/**** Includes ****/
#include "display.h"
/**** Private definitions ****/
/**** Private constants ****/
static const uint8_t BACKLIGHT_DIMM = DSP_BACKLIGHT_DIMM_PERCENT;
static const uint8_t BACKLIGHT_BRIGTH = DSP_BACKLIGHT_BRIGTH_PERCENT;
/**** Private variables ****/
/**** Private function declarations ****/
static uint8_t img_gen_dot10(uint8_t percent);
static uint8_t img_gen_dot20(uint8_t percent);
static uint8_t img_gen_bar(uint8_t percent);
/**** Public function definitions ****/
void dsp_init_ctrl(dsp_ctrl_t* ctrl)
{
ctrl->img_lock = 0;
ctrl->act_img = 0x00;
}
void dsp_set_lock(dsp_ctrl_t* ctrl)
{
ctrl->img_lock = 1;
}
void dsp_reset_lock(dsp_ctrl_t* ctrl)
{
ctrl->img_lock = 0;
}
uint8_t dsp_img_percent(uint8_t value, dsp_style_t style, dsp_ctrl_t* ctrl)
{
if(ctrl->img_lock) return ctrl->act_img;
switch(style)
{
case LED_DSP_BAR:
ctrl->act_img = img_gen_bar(value);
break;
case LED_DSP_DOT10:
ctrl->act_img = img_gen_dot10(value);
break;
default:
ctrl->act_img = img_gen_dot20(value);
break;
}
return ctrl->act_img;
}
uint8_t dsp_img_raw(uint8_t image, dsp_ctrl_t* ctrl)
{
if(ctrl->img_lock) return ctrl->act_img;
ctrl->act_img = image & 0x3F;
return ctrl->act_img;
}
uint8_t dsp_get_act_img(dsp_ctrl_t* ctrl)
{
return ctrl->act_img;
}
uint8_t dsp_backlight(uint8_t dimm_act)
{
if(dimm_act) return BACKLIGHT_DIMM;
else return BACKLIGHT_BRIGTH;
}
/**** Private function definitions ****/
static uint8_t img_gen_dot10(uint8_t percent)
{
if(percent<6) return 0x01;
else if(percent<16) return 0x03;
else if(percent<26) return 0x02;
else if(percent<36) return 0x06;
else if(percent<46) return 0x04;
else if(percent<56) return 0x0C;
else if(percent<66) return 0x08;
else if(percent<76) return 0x18;
else if(percent<86) return 0x10;
else if(percent<96) return 0x30;
else return 0x20;
}
static uint8_t img_gen_dot20(uint8_t percent)
{
if(percent<11) return 0x01;
else if(percent<31) return 0x02;
else if(percent<51) return 0x04;
else if(percent<71) return 0x08;
else if(percent<91) return 0x10;
else return 0x20;
}
static uint8_t img_gen_bar(uint8_t percent)
{
if(percent<11) return 0x01;
else if(percent<31) return 0x03;
else if(percent<51) return 0x07;
else if(percent<71) return 0x0F;
else if(percent<91) return 0x1F;
else return 0x3F;
}

View File

@@ -1,37 +0,0 @@
#ifndef LOGIC_DISPLAY_H_
#define LOGIC_DISPLAY_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define DSP_BACKLIGHT_DIMM_PERCENT 50
#define DSP_BACKLIGHT_BRIGTH_PERCENT 100
typedef enum {
LED_DSP_DOT20,
LED_DSP_DOT10,
LED_DSP_BAR
} dsp_style_t;
typedef struct {
uint8_t img_lock;
uint8_t act_img;
} dsp_ctrl_t;
/**** Public function declarations ****/
void dsp_init_ctrl(dsp_ctrl_t* ctrl);
void dsp_set_lock(dsp_ctrl_t* ctrl);
void dsp_reset_lock(dsp_ctrl_t* ctrl);
uint8_t dsp_img_percent(uint8_t value, dsp_style_t style, dsp_ctrl_t* ctrl);
uint8_t dsp_img_raw(uint8_t image, dsp_ctrl_t* ctrl);
uint8_t dsp_get_act_img(dsp_ctrl_t* ctrl);
uint8_t dsp_backlight(uint8_t dimm_act);
#ifdef TESTING
#endif
#endif /* LOGIC_DISPLAY_H_ */

View File

@@ -1,63 +0,0 @@
/**** Includes ****/
#include "force.h"
/**** Private definitions ****/
/**** Private constants ****/
static const uint16_t MAX_HBRAKE_HOLD_TIME = FORCE_MAX_HBRAKE_HOLD_TIME;
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
#ifdef TESTING
#endif
uint8_t force_next(uint8_t handbrake, uint8_t brakes, fbrake_mode_t bmode, uint8_t user_force, uint16_t hbarke_act_time)
{
// Do force logic
if((handbrake)&&(hbarke_act_time < MAX_HBRAKE_HOLD_TIME))
{
return 0;
}
else if(brakes)
{
switch(bmode)
{
case FORCE_BMODE_KEEP:
return user_force;
break;
case FORCE_BMODE_LOCK:
return 100;
break;
default: //FORCE_BMODE_OPEN
return 0;
break;
}
}
else
{
return user_force;
}
return 0;
}
fbrake_mode_t force_cycle_bmode(fbrake_mode_t bmode)
{
switch(bmode)
{
case FORCE_BMODE_OPEN:
return FORCE_BMODE_KEEP;
case FORCE_BMODE_KEEP:
return FORCE_BMODE_LOCK;
default:
return FORCE_BMODE_OPEN;
}
}
/**** Private function definitions ****/

View File

@@ -1,23 +0,0 @@
#ifndef FORCE_H_
#define FORCE_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define FORCE_MAX_HBRAKE_HOLD_TIME 1000
typedef enum {
FORCE_BMODE_OPEN,
FORCE_BMODE_KEEP,
FORCE_BMODE_LOCK
} fbrake_mode_t;
/**** Public function declarations ****/
uint8_t force_next(uint8_t handbrake, uint8_t brakes, fbrake_mode_t bmode, uint8_t user_force, uint16_t hbarke_act_time);
fbrake_mode_t force_cycle_bmode(fbrake_mode_t bmode);
#ifdef TESTING
#endif
#endif /* FORCE_H_ */

View File

@@ -1,42 +0,0 @@
/**** Includes ****/
#include "pot.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
#ifdef TESTING
#endif
uint8_t pot_mv_to_percent(uint16_t value, pot_cfg_t* cfg)
{
// Setup limits
uint16_t bottom = 0;
uint16_t top = cfg->reference;
// Adjust for top and bottom deadband
if(bottom < cfg->deadband) bottom = cfg->deadband;
if(top > cfg->deadband) top -= cfg->deadband;
// Calculate percent
if(value <= bottom) return 0;
else if(value >= top) return 100;
else
{
// Adjust values for offset
if(bottom)
{
value = value - bottom;
top = top - bottom;
};
uint32_t y = (uint32_t)value * 100;
y = y/(uint32_t)top;
return (uint16_t)y;
}
}
/**** Private function definitions ****/

View File

@@ -1,19 +0,0 @@
#ifndef POTENTIOMETER_H_
#define POTENTIOMETER_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
typedef struct {
uint16_t reference;
uint16_t deadband;
} pot_cfg_t;
/**** Public function declarations ****/
uint8_t pot_mv_to_percent(uint16_t value, pot_cfg_t* cfg);
#ifdef TESTING
#endif
#endif /* POTENTIOMETER_H_ */

View File

@@ -1,52 +0,0 @@
/**** Includes ****/
#include "user_force.h"
/**** Private definitions ****/
/**** Private constants ****/
static const uint8_t MAX_PERCENT = USER_FORCE_MAX_PERCENT;
static const uint8_t MIN_PERCENT = USER_FORCE_MIN_PERCENT;
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
#ifdef TESTING
#endif
uint8_t user_force_btn(uint8_t prev_force, uint8_t up_act, uint8_t down_act, uint8_t delta)
{
uint8_t new_froce = prev_force;
if(up_act)
{
new_froce = prev_force + delta;
// Limit overflow and top value
if(new_froce < prev_force) new_froce = 100;
else if(new_froce < MIN_PERCENT) new_froce = MIN_PERCENT;
};
if(down_act)
{
new_froce = prev_force - delta;
// Limit overflow and top value
if(new_froce > prev_force) new_froce = 0;
else if(new_froce > MAX_PERCENT) new_froce = MAX_PERCENT;
};
// Do deadband
if(new_froce < MIN_PERCENT) new_froce = 0;
else if(new_froce > MAX_PERCENT) new_froce = 100;
return new_froce;
}
uint8_t user_force_pot(uint8_t prev_force, uint8_t pot, uint8_t hyst)
{
uint8_t new_froce = pot;
if(new_froce < MIN_PERCENT) new_froce = 0;
else if(new_froce > MAX_PERCENT) new_froce = 100;
return new_froce;
}
/**** Private function definitions ****/

View File

@@ -1,18 +0,0 @@
#ifndef USER_FORCE_H_
#define USER_FORCE_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
#define USER_FORCE_MAX_PERCENT 90
#define USER_FORCE_MIN_PERCENT 10
/**** Public function declarations ****/
uint8_t user_force_btn(uint8_t prev_force, uint8_t up_act, uint8_t down_act, uint8_t delta);
uint8_t user_force_pot(uint8_t prev_force, uint8_t pot, uint8_t hyst);
#ifdef TESTING
#endif
#endif /* USER_FORCE_H_ */

View File

@@ -1,127 +0,0 @@
/**** Includes ****/
#include <stdint.h>
// Hardware IO
#include "hw/startup.h"
#include "hw/analog.h"
#include "hw/buttons.h"
#include "hw/hb_control.h"
#include "hw/led_display.h"
// Logic blocks
#include "logic/coil.h"
#include "logic/display.h"
#include "logic/force.h"
#include "logic/pot.h"
#include "logic/user_force.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
static volatile uint8_t user_force = 0;
static volatile uint8_t user_force_step = 10;
static volatile fbrake_mode_t bmode = FORCE_BMODE_OPEN;
static volatile uint8_t next_force = 0;
static volatile int16_t next_target = 0;
static volatile hb_feedback_t hb_feedback;
static volatile hb_control_t hb_ctrl;
static volatile uint8_t backlight = 0;
static volatile dsp_ctrl_t dsp_logic_ctrl;
/**** Private function declarations ****/
/**** Public function definitions ****/
int main(void)
{
hw_startup();
// Create objects for all buttons
btn_t btn_mode;
btn_t btn_down;
btn_t btn_up;
btn_t btn_dimm;
btn_t btn_brakes;
btn_t btn_handbrake;
btn_t btn_handbrake_dir;
// Set button pulls
//btn_ch_set_pull(BTN_1, BTN_PULL_HIGH);
//btn_ch_set_pull(BTN_2, BTN_PULL_HIGH);
//btn_ch_set_pull(BTN_3, BTN_PULL_HIGH);
btn_ch_set_pull(BTN_6, BTN_PULL_HIGH);
// Create object for half-bridge control
// Initialize half-bridge
hb_init(&hb_feedback, &hb_ctrl);
hb_enable(&hb_ctrl);
// Init display backlight
dsp_init_ctrl(&dsp_logic_ctrl);
backlight = dsp_backlight(1);
led_dsp_backligth_set(backlight);
while(1)
{
// Read buttons
btn_ch_process(BTN_1, &btn_mode);
btn_ch_process(BTN_2, &btn_down);
btn_ch_process(BTN_3, &btn_up);
btn_ch_process(BTN_4, &btn_dimm);
btn_ch_process(BTN_5, &btn_brakes);
btn_ch_process(BTN_6, &btn_handbrake);
btn_ch_process(BTN_6N, &btn_handbrake_dir);
// Process user force changes
if((btn_up.new_state)||(btn_down.new_state))
{
uint8_t up_act = btn_up.new_state & btn_up.state;
uint8_t down_act = btn_down.new_state & btn_down.state;
user_force = user_force_btn(user_force, up_act, down_act, user_force_step);
btn_up.new_state = 0;
btn_down.new_state = 0;
};
// Process brake mode changes
if(btn_mode.new_state)
{
if(btn_mode.state) bmode = force_cycle_bmode(bmode);
btn_mode.new_state = 0;
};
// Calculate next force
next_force = force_next(btn_handbrake.state, btn_brakes.state, bmode, user_force, btn_handbrake.state_time);
// Calculate next coil target
next_target = coil_target(next_force, btn_handbrake.state);
// Read Half-bridge status and apply next target
hb_process(next_target, &hb_feedback, &hb_ctrl);
// Generate image of current force
uint8_t img = 0x00;
if(hb_feedback.fused) img = 0xAA;
else img = dsp_img_percent(next_force, LED_DSP_DOT10);
// Apply image
led_dsp_set_image(img);
// Process display backlight
if(btn_dimm.new_state)
{
backlight = dsp_backlight(btn_dimm.state);
led_dsp_backligth_set(backlight);
btn_dimm.new_state = 0;
};
}
return 0;
}
/**** Private function definitions ****/

75
firmware/src/main.cpp Normal file
View File

@@ -0,0 +1,75 @@
/**** Includes ****/
#include "utils/utils.h"
#include "dccd/dccd_hw.h"
#include "dccd/dccd.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
static dccd::DccdHw dccd_hw;
static dccd::DccdApp dccd_app;
static dccd::DccdApp::cfg_app_t def_cfg;
/**** Private function declarations ****/
/**** Public function definitions ****/
int main(void)
{
// Hardware setup
dccd::DccdHw::dccdHwCfg_t cfg;
cfg.handbrake_pull_up = 1;
cfg.pwm_f_khz = 16;
cfg.speed_hall = 0;
cfg.counter_step_us = 2000;
dccd_hw.init(&cfg);
// App default config
def_cfg.user_btn_dbnc = 10;
def_cfg.user_btn_repeat_time = 500;
def_cfg.pot_mode = 1;
def_cfg.btn_step = 10;
def_cfg.mode_btn_repeat_time = 700;
def_cfg.tps_treshold_on = 65;
def_cfg.tps_treshold_off = 55;
def_cfg.tps_timeout = 0;
def_cfg.hbrake_latch_time_1 = 750;
def_cfg.hbrake_latch_time_2 = 1500;
def_cfg.hbrake_latch_time_3 = 3000;
def_cfg.hbrake_dbnc = 100;
def_cfg.brakes_dbnc = 100;
def_cfg.coil_lock_current = 4500;
def_cfg.coil_ref_resistance = 1500;
def_cfg.coil_out_max_resistance = 2000;
def_cfg.coil_out_min_resistance = 1000;
def_cfg.coil_disable_protection = 1;
def_cfg.coil_cc_mode = 1;
def_cfg.dsp_brigth_pwm = 40;
def_cfg.dsp_dimm_pwm = 25;
def_cfg.hbrake_force = -1;
def_cfg.brakes_open_force = -1;
def_cfg.brakes_lock_force = 100;
def_cfg.tps_enabled = 0;
def_cfg.tps_force_1 = 60;
def_cfg.tps_force_2 = 80;
def_cfg.tps_force_3 = 100;
def_cfg.dsp_mode_lock_time = 2000;
def_cfg.dsp_force_lock_time = 1000;
def_cfg.force_def_config = 0;
// App setup
dccd_app.init(&dccd_hw, &def_cfg);
// Super loop
while(1)
{
// Do stuff
dccd_app.process();
// End of super loop
continue;
}
// Escape the matrix
return 0;
}
/**** Private function definitions ***/

View File

@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Atmel Studio Solution File, Format Version 11.00
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "uDCCD_Controller", "uDCCD_Controller.cproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "uDCCD", "uDCCD.cppproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution

View File

@@ -41,7 +41,7 @@
<Attribute>template</Attribute>
<Category>source</Category>
<Condition>C Exe</Condition>
<FileContentHash>YLr2MkKo6ZooP7MhARWYNA==</FileContentHash>
<FileContentHash>KjvOcFWd++tbnsEMfVPd/w==</FileContentHash>
<FileVersion></FileVersion>
<Name>templates/main.c</Name>
<SelectString>Main file (.c)</SelectString>
@@ -52,7 +52,7 @@
<Attribute>template</Attribute>
<Category>source</Category>
<Condition>C Exe</Condition>
<FileContentHash>mkKaE95TOoATsuBGv6jmxg==</FileContentHash>
<FileContentHash>w5aB/d0+DbxGZ7yY0aMMjw==</FileContentHash>
<FileVersion></FileVersion>
<Name>templates/main.cpp</Name>
<SelectString>Main file (.cpp)</SelectString>

View File

@@ -3,18 +3,18 @@
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProjectVersion>7.0</ProjectVersion>
<ToolchainName>com.Atmel.AVRGCC8.C</ToolchainName>
<ToolchainName>com.Atmel.AVRGCC8.CPP</ToolchainName>
<ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>
<avrdevice>ATmega328PB</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>C</Language>
<Language>CPP</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>uDCCD_Controller</AssemblyName>
<Name>uDCCD_Controller</Name>
<RootNamespace>uDCCD_Controller</RootNamespace>
<AssemblyName>uDCCD</AssemblyName>
<Name>uDCCD</Name>
<RootNamespace>uDCCD</RootNamespace>
<ToolchainFlavour>Native</ToolchainFlavour>
<KeepTimersRunning>true</KeepTimersRunning>
<OverrideVtor>false</OverrideVtor>
@@ -26,17 +26,17 @@
<OverrideVtorValue>exception_table</OverrideVtorValue>
<BootSegment>2</BootSegment>
<ResetRule>0</ResetRule>
<eraseonlaunchrule>1</eraseonlaunchrule>
<eraseonlaunchrule>0</eraseonlaunchrule>
<EraseKey />
<AsfFrameworkConfig>
<framework-data>
<framework-data xmlns="">
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.44.1" />
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.52.0" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
@@ -48,18 +48,18 @@
<InterfaceProperties>
<IspClock>125000</IspClock>
</InterfaceProperties>
<InterfaceName>debugWIRE</InterfaceName>
<InterfaceName>ISP</InterfaceName>
</ToolOptions>
<ToolType>com.atmel.avrdbg.tool.atmelice</ToolType>
<ToolNumber>J42700001490</ToolNumber>
<ToolName>Atmel-ICE</ToolName>
</com_atmel_avrdbg_tool_atmelice>
<avrtoolinterface>debugWIRE</avrtoolinterface>
<avrtoolinterface>ISP</avrtoolinterface>
<avrtoolinterfaceclock>125000</avrtoolinterfaceclock>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<AvrGcc>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega328pb -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\gcc\dev\atmega328pb"</avrgcc.common.Device>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
@@ -82,22 +82,38 @@
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.linker.libraries.Libraries>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>libm</Value>
<Value>NDEBUG</Value>
</ListValues>
</avrgcc.linker.libraries.Libraries>
<avrgcc.assembler.general.IncludePaths>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcc.assembler.general.IncludePaths>
</AvrGcc>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.level>Optimize for size (-Os)</avrgcccpp.compiler.optimization.level>
<avrgcccpp.compiler.optimization.PackStructureMembers>True</avrgcccpp.compiler.optimization.PackStructureMembers>
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
</AvrGccCpp>
</ToolchainSettings>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<AvrGcc>
<AvrGccCpp>
<avrgcc.common.Device>-mmcu=atmega328pb -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\gcc\dev\atmega328pb"</avrgcc.common.Device>
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
@@ -116,161 +132,215 @@
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize debugging experience (-Og)</avrgcc.compiler.optimization.level>
<avrgcc.compiler.optimization.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.linker.libraries.Libraries>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>libm</Value>
<Value>DEBUG</Value>
</ListValues>
</avrgcc.linker.libraries.Libraries>
<avrgcc.assembler.general.IncludePaths>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcc.assembler.general.IncludePaths>
<avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>
</AvrGcc>
</avrgcccpp.compiler.directories.IncludePaths>
<avrgcccpp.compiler.optimization.level>Optimize debugging experience (-Og)</avrgcccpp.compiler.optimization.level>
<avrgcccpp.compiler.optimization.PackStructureMembers>True</avrgcccpp.compiler.optimization.PackStructureMembers>
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcccpp.compiler.optimization.DebugLevel>Default (-g2)</avrgcccpp.compiler.optimization.DebugLevel>
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
<avrgcccpp.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcccpp.linker.libraries.Libraries>
<avrgcccpp.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcccpp.assembler.general.IncludePaths>
<avrgcccpp.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcccpp.assembler.debugging.DebugLevel>
</AvrGccCpp>
</ToolchainSettings>
</PropertyGroup>
<ItemGroup>
<Compile Include="hw\analog.c">
<Compile Include="bsp\ain.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\analog.h">
<Compile Include="bsp\ain.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\config.h">
<Compile Include="bsp\ain_lpf.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\dout.c">
<Compile Include="bsp\ain_lpf.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\dout.h">
<Compile Include="bsp\board.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\setup.c">
<Compile Include="bsp\board.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\setup.h">
<Compile Include="bsp\din.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\utils\faults.c">
<Compile Include="bsp\din.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\utils\faults.h">
<Compile Include="bsp\dout.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\utils\fuses.c">
<Compile Include="bsp\dout.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\utils\fuses.h">
<Compile Include="bsp\memory.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\buttons.c">
<Compile Include="bsp\memory.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\buttons.h">
<Compile Include="bsp\pwm_out.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\ain.c">
<Compile Include="bsp\pwm_out.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\ain.h">
<Compile Include="bsp\mcu\mcu_hal.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\din.c">
<Compile Include="bsp\mcu\mcu_hal_r8.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\din.h">
<Compile Include="dccd\brakes.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\halfbridge.c">
<Compile Include="dccd\brakes.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\halfbridge.h">
<Compile Include="dccd\dccd.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\mcu\mcu_hal.h">
<Compile Include="dccd\dccd.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\mcu\mcu_hal_r8.c">
<Compile Include="dccd\dccd_hw.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\odout.c">
<Compile Include="dccd\dccd_hw.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\odout.h">
<Compile Include="dccd\display.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\utils\utils.c">
<Compile Include="dccd\display.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\board\utils\utils.h">
<Compile Include="dccd\coil_reg.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\config.h">
<Compile Include="dccd\coil_reg.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\hb_control.c">
<Compile Include="dccd\handbrake.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\hb_control.h">
<Compile Include="dccd\handbrake.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\led_display.c">
<Compile Include="dccd\memory.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="dccd\memory.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="dccd\mode.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="dccd\mode.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="dccd\tps.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="dccd\tps.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="dccd\user_force.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="dccd\user_force.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\button.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\button.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\led_display.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\led_display.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\startup.c">
<Compile Include="hw\out_reg.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\startup.h">
<Compile Include="hw\out_reg.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\coil.c">
<Compile Include="hw\safe_ain.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\coil.h">
<Compile Include="hw\safe_ain.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\display.c">
<Compile Include="hw\out_driver.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\display.h">
<Compile Include="hw\out_driver.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\force.c">
<Compile Include="hw\potentiometer.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\force.h">
<Compile Include="hw\potentiometer.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\pot.c">
<Compile Include="main.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\pot.h">
<Compile Include="utils\interpolate.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\user_force.c">
<Compile Include="utils\interpolate.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\user_force.h">
<Compile Include="utils\utils.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="main.c">
<Compile Include="utils\utils.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="utils\vcounter.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="utils\vcounter.h">
<SubType>compile</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="bsp" />
<Folder Include="bsp\mcu" />
<Folder Include="hw" />
<Folder Include="hw\board" />
<Folder Include="hw\board\mcu" />
<Folder Include="hw\board\utils" />
<Folder Include="logic" />
<Folder Include="dccd" />
<Folder Include="utils" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>

View File

@@ -0,0 +1,163 @@
/**** Includes ****/
#include "utils.h"
#include "interpolate.h"
using namespace util;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
uint16_t util::interpolate_1d(uint16_t x, uint16_t* x_axis, uint16_t* y_values, uint8_t len_axis)
{
// validate axis length
if(len_axis==0) return 0; // Empty data set
if(len_axis==1) return y_values[0]; // Only one data point
uint16_t y;
uint8_t i = find_interval_end_index(x, x_axis, len_axis);
if(i==0)
{
//Less then start
y = y_values[0];
}
else if(i==len_axis)
{
//More than end
y = y_values[len_axis-1];
}
else
{
// Do interpolate
y = interpolate(x, x_axis[i-1], x_axis[i], y_values[i-1], y_values[i]);
}
return y;
}
uint16_t util::interpolate_2d(uint16_t x, uint16_t y, uint16_t* x_axis, uint8_t len_x_axis, uint16_t* y_axis, uint8_t len_y_axis, uint16_t* z_values)
{
// validate axis length
if((len_x_axis==0)&&(len_y_axis==0)) return 0; // Empty data set
if((len_x_axis==1)&&(len_y_axis==1)) return z_values[0]; // Only one data point
uint8_t ix = find_interval_end_index(x, x_axis, len_x_axis);
uint8_t iy = find_interval_end_index(y, y_axis, len_y_axis);
// Check corners - easy answers
if((ix==0)&&(iy==0))
{
return z_values[0]; //[0][0] [Y][X]
}
else if((ix==len_x_axis)&&(iy==0))
{
return z_values[len_x_axis-1]; //[0][end]
}
else if((ix==0)&&(iy==len_y_axis))
{
uint16_t i = index2d_to_index1d(0, len_y_axis-1, len_x_axis);
return z_values[i]; //[end][0]
}
else if((ix==len_x_axis)&&(iy==len_y_axis))
{
uint16_t i = index2d_to_index1d(len_x_axis-1, len_y_axis-1, len_x_axis);
return z_values[i]; //[end][end]
};
// Check boundaries - 1D interpolation
if(ix==0)
{
// On ix=0 line
uint16_t i = 0;
uint16_t z0 = z_values[i];
i = index2d_to_index1d(0, len_y_axis-1, len_x_axis);
uint16_t z1 = z_values[i];
return interpolate(y, y_axis[0], y_axis[len_y_axis-1], z0, z1);
}
else if(ix==len_x_axis)
{
// On ix=END line
uint16_t i = len_x_axis-1;
uint16_t z0 = z_values[i];
i = index2d_to_index1d(len_x_axis-1, len_y_axis-1, len_x_axis);
uint16_t z1 = z_values[i];
return interpolate(y, y_axis[0], y_axis[len_y_axis-1], z0, z1);
}
else if(iy==0)
{
// On iy=0 line
uint16_t i = 0;
uint16_t z0 = z_values[i];
i = len_x_axis-1;
uint16_t z1 = z_values[i];
return interpolate(x, x_axis[0], x_axis[len_x_axis-1], z0, z1);
}
else if(iy==len_y_axis)
{
// On iy=END line
uint16_t i = index2d_to_index1d(0, len_y_axis-1, len_x_axis);
uint16_t z0 = z_values[i];
i = index2d_to_index1d(len_x_axis-1, len_y_axis-1, len_x_axis);
uint16_t z1 = z_values[i];
return interpolate(x, x_axis[0], x_axis[len_x_axis-1], z0, z1);
}
// Do interpolation
// Get axis values
uint16_t x0 = x_axis[ix-1];
uint16_t x1 = x_axis[ix];
uint16_t y0 = y_axis[iy-1];
uint16_t y1 = y_axis[iy];
// Do y0 line calculation
// Get z values at x0 and x1 points on y0 line
uint16_t i = index2d_to_index1d(ix-1, iy-1, len_x_axis);
uint16_t z0 = z_values[i];
uint16_t z1 = z_values[i+1];
// Interpolate z value on y0 line
uint16_t zy0 = interpolate(x, x0, x1, z0, z1);
// Do y1 line calculation
// Get z values at x0 and x1 points on y1 line
i = index2d_to_index1d(ix-1, iy, len_x_axis);
z0 = z_values[i];
z1 = z_values[i+1];
// Interpolate z value on y0 line
uint16_t zy1 = interpolate(x, x0, x1, z0, z1);
// Do calculation in y axis on xz line
return interpolate(y, y0, y1, zy0, zy1);
}
uint16_t util::interpolate(uint16_t x, uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1)
{
int32_t dy = (int32_t)y1 - (int32_t)y0;
int32_t dx = (int32_t)x1 - (int32_t)x0;
int32_t d = (int32_t)x - (int32_t)x0;
int32_t y = dy * d;
y /= dx;
y += y0;
return util::sat_cast(y);
}
uint8_t util::find_interval_end_index(uint16_t val, uint16_t* axis_values, uint8_t len_axis)
{
for(uint8_t i=0; i<len_axis; i++)
{
if(val < axis_values[i]) return i;
continue;
}
return len_axis;
}
uint16_t util::index2d_to_index1d(uint8_t ix, uint8_t iy, uint8_t len_x)
{
return ((uint16_t)len_x * iy) + ix;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,23 @@
#ifndef UTILS_INTERPOLATE_H_
#define UTILS_INTERPOLATE_H_
/**** Includes ****/
#include <stdint.h>
namespace util {
/**** Public definitions ****/
/**** Public function declarations ****/
uint16_t interpolate_1d(uint16_t x, uint16_t* x_axis, uint16_t* y_values, uint8_t len_axis);
uint16_t interpolate_2d(uint16_t x, uint16_t y, uint16_t* x_axis, uint8_t len_x_axis, uint16_t* y_axis, uint8_t len_y_axis, uint16_t* z_values);
uint8_t find_interval_end_index(uint16_t val, uint16_t* axis_values, uint8_t len_axis);
uint16_t interpolate(uint16_t x, uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1);
uint16_t index2d_to_index1d(uint8_t ix, uint8_t iy, uint8_t len_x);
#ifdef TESTING
#endif
} //namespace
#endif /* UTILS_INTERPOLATE_H_ */

View File

@@ -0,0 +1,216 @@
/**** Includes ****/
#include "utils.h"
using namespace util;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
#ifndef TESTING
#endif
/**** Public function definitions ****/
uint8_t util::invert(uint8_t x)
{
if(x!=0) return 0;
else return 1;
}
uint16_t util::invert(uint16_t x)
{
if(x!=0) return 0;
else return 1;
}
uint32_t util::invert(uint32_t x)
{
if(x!=0) return 0;
else return 1;
}
uint8_t util::sat_add(uint8_t x, uint8_t y)
{
uint8_t z = x + y;
// Check for overflow
if((z < x)||(z < y)) return 0xFF;
else return z;
}
uint16_t util::sat_add(uint16_t x, uint16_t y)
{
uint16_t z = x + y;
// Check for overflow
if((z < x)||(z < y)) return 0xFF;
else return z;
}
uint32_t util::sat_add(uint32_t x, uint32_t y)
{
uint32_t z = x + y;
// Check for overflow
if((z < x)||(z < y)) return 0xFF;
else return z;
}
uint8_t util::sat_subtract(uint8_t x, uint8_t y)
{
uint8_t z = x - y;
// Check for underflow
if(z > x) return 0;
else return z;
}
uint16_t util::sat_subtract(uint16_t x, uint16_t y)
{
uint16_t z = x - y;
// Check for underflow
if(z > x) return 0;
else return z;
}
uint32_t util::sat_subtract(uint32_t x, uint32_t y)
{
uint32_t z = x - y;
// Check for underflow
if(z > x) return 0;
else return z;
}
uint8_t util::abs_subtract(uint8_t x, uint8_t y)
{
if(x > y) return x - y;
else return y-x;
}
uint16_t util::abs_subtract(uint16_t x, uint16_t y)
{
if(x > y) return x - y;
else return y-x;
}
uint32_t util::abs_subtract(uint32_t x, uint32_t y)
{
if(x > y) return x - y;
else return y-x;
}
uint16_t util::sat_cast(uint32_t x)
{
if(x > 0x0000FFFF) return 0xFFFF;
else return (uint16_t)x;
}
uint16_t util::sat_cast(int32_t x)
{
if(x < 0) return 0x0000;
else if(x > 0x0000FFFF) return 0xFFFF;
else return (uint16_t)x;
}
uint8_t util::is_timed_out(uint16_t time, uint16_t limit)
{
if(time >= limit) return 1;
else return 0;
}
uint8_t util::is_in_range(uint16_t value, uint16_t min, uint16_t max)
{
if((value >= min)&&(value <= max)) return 1;
else return 0;
}
uint16_t util::time_delta(uint16_t start, uint16_t end)
{
if(end >= start) return (end-start);
uint16_t temp = 0xFFFF - start;
return temp + end;
}
uint32_t util::time_delta(uint32_t start, uint32_t end)
{
if(end >= start) return (end-start);
uint32_t temp = 0xFFFFFFFF - start;
return temp + end;
}
uint16_t util::time_delta(uint16_t start, uint16_t end, uint16_t max)
{
if(end >= start) return (end-start);
uint16_t temp = max - start;
return temp + end;
}
uint32_t util::time_delta(uint32_t start, uint32_t end, uint32_t max)
{
if(end >= start) return (end-start);
uint32_t temp = max - start;
return temp + end;
}
uint16_t util::convert_muldivoff(uint16_t raw, uint8_t mul, uint8_t div, int16_t offset)
{
int32_t temp = (int32_t)raw;
temp = temp * mul;
if(div>1) temp /= div;
temp += offset;
return sat_cast(temp);
}
uint16_t util::sat_mul_kilo(uint16_t xk, uint16_t yk)
{
uint32_t temp = (uint32_t)xk * (uint32_t)yk;
temp /= 1000;
return sat_cast(temp);
}
uint16_t util::sat_div_kilo(uint16_t top, uint16_t bot)
{
//Sanity check bot
if(bot==0) return 0xFFFF; //aka infinity
uint32_t temp = (uint32_t)top * 1000;
temp /= (uint32_t)bot;
return sat_cast(temp);
}
uint16_t util::sat_ratio(uint16_t top, uint16_t bot)
{
//Sanity check bot
if(bot==0) return 0xFFFF; //aka infinity
//Easy option
if(top>=bot) return 0xFFFF;
uint32_t temp = (uint32_t)top * 0x0000FFFF;
temp /= (uint32_t)bot;
return sat_cast(temp);
}
uint16_t util::percent_to_16b(uint8_t percent)
{
uint32_t temp = (uint32_t)percent * 0x0000FFFF;
temp /= 100;
// Limit to 16 bits
uint16_t pwm = sat_cast(temp);
return pwm;
}
uint16_t util::percent_of(uint8_t percent, uint16_t value)
{
if(percent == 0) return 0;
else if(percent >= 100) return value;
uint32_t temp = (uint32_t)value * percent;
return temp/100;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,52 @@
#ifndef UTILS_H_
#define UTILS_H_
/**** Includes ****/
#include <stdint.h>
namespace util {
/**** Public definitions ****/
/**** Public function declarations ****/
uint8_t invert(uint8_t x);
uint16_t invert(uint16_t x);
uint32_t invert(uint32_t x);
uint8_t sat_add(uint8_t x, uint8_t y);
uint16_t sat_add(uint16_t x, uint16_t y);
uint32_t sat_add(uint32_t x, uint32_t y);
uint8_t sat_subtract(uint8_t x, uint8_t y);
uint16_t sat_subtract(uint16_t x, uint16_t y);
uint32_t sat_subtract(uint32_t x, uint32_t y);
uint8_t abs_subtract(uint8_t x, uint8_t y);
uint16_t abs_subtract(uint16_t x, uint16_t y);
uint32_t abs_subtract(uint32_t x, uint32_t y);
uint16_t sat_cast(uint32_t x);
uint16_t sat_cast(int32_t x);
uint8_t is_timed_out(uint16_t time, uint16_t limit);
uint8_t is_in_range(uint16_t value, uint16_t min, uint16_t max);
uint16_t time_delta(uint16_t start, uint16_t end);
uint32_t time_delta(uint32_t start, uint32_t end);
uint16_t time_delta(uint16_t start, uint16_t end, uint16_t max);
uint32_t time_delta(uint32_t start, uint32_t end, uint32_t max);
uint16_t convert_muldivoff(uint16_t raw, uint8_t mul, uint8_t div, int16_t offset);
uint16_t sat_mul_kilo(uint16_t xk, uint16_t yk);
uint16_t sat_div_kilo(uint16_t top, uint16_t bot);
uint16_t sat_ratio(uint16_t top, uint16_t bot);
uint16_t percent_to_16b(uint8_t percent);
uint16_t percent_of(uint8_t percent, uint16_t value);
#ifdef TESTING
#endif
} //namespace
#endif /* UTILS_H_ */

View File

@@ -0,0 +1,71 @@
/**** Includes ****/
#include "utils.h"
#include "vcounter.h"
using namespace util;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
util::VCounter::VCounter(void)
{
this->counter = 0;
this->top = 0xFFFF;
this->step_us = 1;
this->disabled = 1;
return;
}
util::VCounter::~VCounter(void)
{
return;
}
void util::VCounter::init(uint16_t top, uint16_t step_us)
{
this->counter = 0;
this->top = top;
this->step_us = step_us;
this->disabled = 1;
}
void util::VCounter::reset(void)
{
this->counter = 0;
}
void util::VCounter::increment(void)
{
if(this->disabled) return;
this->counter++;
if(this->counter > this->top) this->counter = 0;
}
uint16_t util::VCounter::read(void)
{
return this->counter;
}
uint32_t util::VCounter::read_ms(void)
{
return this->convert_ms(this->counter);
}
uint16_t util::VCounter::read_top(void)
{
return this->top;
}
uint32_t util::VCounter::convert_ms(uint16_t raw)
{
if(this->step_us==0) return 0;
uint32_t out = (uint32_t)raw * (uint32_t)this->step_us;
return out/1000;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,42 @@
#ifndef VIRTUAL_COUNTER_H_
#define VIRTUAL_COUNTER_H_
/**** Includes ****/
#include <stdint.h>
namespace util {
/**** Public definitions ****/
class VCounter
{
public:
VCounter(void);
~VCounter(void);
void init(uint16_t top, uint16_t step_us);
uint8_t disabled;
void reset(void);
void increment(void);
uint16_t read(void);
uint32_t read_ms(void);
uint16_t read_top(void);
uint32_t convert_ms(uint16_t raw);
#ifndef TESTING
protected:
#endif
uint16_t step_us;
uint16_t counter;
uint16_t top;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* VIRTUAL_COUNTER_H_ */

Some files were not shown because too many files have changed in this diff Show More