35 Commits

Author SHA1 Message Date
e4bd6d2e04 New feature update 2024-04-13 12:29:03 +03:00
c3bc42fa18 Added dccd logic config 2024-04-13 12:28:47 +03:00
a3d4ffd548 Handbrake timeout fix 2024-04-13 12:28:30 +03:00
8449ca098e Added lock 2024-04-13 12:27:58 +03:00
57ab8bda6a Interpolation bug fix 2024-04-13 12:27:29 +03:00
e7797e8d1c Added hbrake timeout and adjustable brake force 2024-04-12 17:40:00 +03:00
82838c25cb Reduced magic numbers 2024-04-12 17:33:13 +03:00
2647e1cf14 Added display user setting persist 2024-04-12 17:26:09 +03:00
0a2a040cf0 Added memory config class 2024-04-12 17:16:58 +03:00
f8b62d4b00 Could be working version 2024-04-12 15:18:31 +03:00
5bb3ebe1bf Created current fuse logic 2024-04-12 11:51:21 +03:00
22ac8240a2 Added absolute subtract 2024-04-12 11:51:10 +03:00
Andis Zīle
f1edc6e15a Changed logic 2024-04-11 23:03:33 +03:00
Andis Zīle
a05c53401f Saved work 2024-04-10 22:44:02 +03:00
Andis Zīle
8bac1f4787 Finished const voltage output 2024-04-10 21:04:31 +03:00
4adcb7eba9 saved work 2024-04-10 17:53:54 +03:00
f320bfefb7 Changes 2024-04-10 15:46:26 +03:00
8f7e5036e7 Started coil driver class 2024-04-10 15:46:17 +03:00
78de20e05b Created pot class 2024-04-10 15:46:07 +03:00
417ecf4128 Created LED display class 2024-04-10 15:46:00 +03:00
dda6c7a2ad Created button class 2024-04-10 15:45:50 +03:00
6199f3c43f Created default mapping 2024-04-10 15:45:32 +03:00
6d5c8d226f Created OD common pwm class 2024-04-10 15:45:17 +03:00
0b9d6fa780 Created digital IO classes 2024-04-10 15:45:03 +03:00
989d5a1f13 Will redo this 2024-04-10 15:44:41 +03:00
c50b3d90bf board abstraction 2024-04-08 19:40:48 +03:00
dd4ff43515 Prepared for Cpp version 2024-03-12 21:27:25 +02:00
02cb3a9c70 Repo unification 2024-03-12 21:22:26 +02:00
7aa7edba33 Migration refresh 2023-12-11 12:59:44 +02:00
8f8a80f05f Migration part 1 2023-12-11 12:59:26 +02:00
299429cb92 Started test board 2023-12-11 01:22:03 +02:00
98b5333126 PCB Revision 9 2023-12-11 01:18:55 +02:00
a54aaa9827 Created case End-plates 2023-12-11 01:14:56 +02:00
365dadc23d Created docs 2023-12-11 01:14:31 +02:00
51e20be598 LED board Revision 1 2023-12-11 01:12:31 +02:00
80 changed files with 5447 additions and 115 deletions

21
.gitignore vendored
View File

@@ -1,3 +1,23 @@
# Ignore list for Atmel studio files
# Hidden folder
.vs/
#Build Directories
Debug/
Release/
#Build Results
*.o
*.d
*.eep
*.elf
*.hex
*.map
*.srec
#User Specific Files
*.atsuo
# Ignore list for Altium temp files # Ignore list for Altium temp files
History/ History/
__Previews/ __Previews/
@@ -9,3 +29,4 @@ Project Logs for*
# Ignore list for Generated output files # Ignore list for Generated output files
*.step *.step
OUTPUTS/ OUTPUTS/

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
docs/MCU_Pinout.pdf Normal file

Binary file not shown.

BIN
docs/MCU_Pinout.xlsx Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

@@ -0,0 +1,35 @@
/**** 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(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;
}
uint16_t bsp::AnalogIn::read(void)
{
//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 ****/

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

@@ -0,0 +1,37 @@
#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
{
protected:
uint8_t adc_ch;
public:
AnalogIn(uint8_t adc_ch);
uint8_t mul;
uint8_t div;
int16_t offset;
uint16_t last_read;
uint16_t read(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* ANALOG_IN_H_ */

View File

@@ -0,0 +1,63 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "board.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
void board_init(void)
{
// MCU setup
mcu::startupCfg_t mcu_cfg;
mcu_cfg.adc_clk = mcu::ADC_DIV2;
mcu_cfg.pwm_clk = mcu::TIM_DIV1;
mcu_cfg.pwm_top = 200;
mcu_cfg.pwm_ch1_en = 1;
mcu::startup(&mcu_cfg);
// Board setup
// Fixed function AIN mV and mA scale
dccd_i.mul = 215;
dccd_i.div = 22;
dccd_i.offset = 0;
dccd_i.last_read = 0;
dccd_u.mul = 20;
dccd_u.div = 1;
dccd_u.offset = 0;
dccd_u.last_read = 0;
bat_u.mul = 20;
bat_u.div = 1;
bat_u.offset = 0;
bat_u.last_read = 12000;
bat_i.mul = 235;
bat_i.div = 6;
bat_i.offset = 0;
bat_i.last_read = 0;
}
void board_read(void)
{
dccd_i.read();
dccd_u.read();
bat_u.read();
bat_i.read();
ain1.read();
ain2.read();
din1.read();
din2.read();
din3.read();
din4.read();
hvdin1.read();
hvdin2.read();
hvdin3.read();
}
/**** Private function definitions ****/

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

@@ -0,0 +1,41 @@
#ifndef BSP_BOARD_H_
#define BSP_BOARD_H_
/**** Includes ****/
#include <stdint.h>
#include "mcu/mcu_hal.h"
#include "ain.h"
#include "din.h"
#include "dout.h"
#include "dio.h"
#include "halfbridge.h"
#include "pwm.h"
static bsp::AnalogIn dccd_i = bsp::AnalogIn(mcu::ADC0);
static bsp::AnalogIn dccd_u = bsp::AnalogIn(mcu::ADC1);
static bsp::AnalogIn bat_u = bsp::AnalogIn(mcu::ADC2);
static bsp::AnalogIn bat_i = bsp::AnalogIn(mcu::ADC3);
static bsp::Hafbridge hbridge = bsp::Hafbridge(mcu::PWM0, mcu::GPIO15, 95);
static bsp::AnalogIn ain1 = bsp::AnalogIn(mcu::ADC5); // mode
static bsp::AnalogIn ain2 = bsp::AnalogIn(mcu::ADC4); // pot
static bsp::DigitalIn din1 = bsp::DigitalIn(mcu::GPIO0, 0, bsp::DIN_HIGH); //mode
static bsp::DigitalIn din2 = bsp::DigitalIn(mcu::GPIO1, 0, bsp::DIN_HIGH); //pot
static bsp::DigitalIn din3 = bsp::DigitalIn(mcu::GPIO2, 0, bsp::DIN_HIGH); //down
static bsp::DigitalIn din4 = bsp::DigitalIn(mcu::GPIO3, 0, bsp::DIN_HIGH); //up
static bsp::DigitalIn hvdin1 = bsp::DigitalIn(mcu::GPIO4, 1, bsp::DIN_LOW); //dimm
static bsp::DigitalIn hvdin2 = bsp::DigitalIn(mcu::GPIO5, 1, bsp::DIN_LOW); //brakes
static bsp::DigitalIn hvdin3 = bsp::DigitalIn(mcu::GPIO6, 1, bsp::DIN_LOW); //hbrake
static bsp::DigitalIO hvdin3_pull = bsp::DigitalIO(mcu::GPIO7, bsp::DIN_HIGH); //hbrake pull
static bsp::DigitalOut odout1 = bsp::DigitalOut(mcu::GPIO9, 1);
static bsp::DigitalOut odout2 = bsp::DigitalOut(mcu::GPIO10, 1);
static bsp::DigitalOut odout3 = bsp::DigitalOut(mcu::GPIO11, 1);
static bsp::DigitalOut odout4 = bsp::DigitalOut(mcu::GPIO12, 1);
static bsp::DigitalOut odout5 = bsp::DigitalOut(mcu::GPIO13, 1);
static bsp::DigitalOut odout6 = bsp::DigitalOut(mcu::GPIO14, 1);
static bsp::PWMout od_pwm = bsp::PWMout(mcu::PWM1);
void board_init(void);
void board_read(void);
#endif /* BSP_BOARD_H_ */

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

@@ -0,0 +1,40 @@
/**** 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(uint8_t gpio_ch, uint8_t inverted, uint8_t init_value)
{
this->gpio_ch = gpio_ch;
this->invert = inverted;
if(init_value) this->last_read = DIN_HIGH;
else this->last_read = DIN_LOW;
}
bsp::DigitalIn::~DigitalIn(void)
{
return;
}
uint8_t bsp::DigitalIn::read(void)
{
uint8_t lvl = mcu::gpio_read(this->gpio_ch);
if(this->invert) lvl = util::invert(lvl);
if(lvl>0) this->last_read = DIN_HIGH;
else this->last_read = DIN_LOW;
return this->last_read;
}
/**** Private function definitions ****/

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

@@ -0,0 +1,35 @@
#ifndef DIGITAL_INPUT_H_
#define DIGITAL_INPUT_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
const uint8_t DIN_LOW = 0;
const uint8_t DIN_HIGH = 1;
class DigitalIn
{
protected:
uint8_t gpio_ch;
uint8_t invert;
public:
DigitalIn(uint8_t gpio_ch, uint8_t inverted, uint8_t init_value);
~DigitalIn(void);
uint8_t last_read;
uint8_t read(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DIGITAL_INPUT_H_ */

34
firmware/src/bsp/dio.cpp Normal file
View File

@@ -0,0 +1,34 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "dio.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::DigitalIO::DigitalIO(uint8_t gpio_ch, uint8_t init_value) : DigitalIn(gpio_ch, 0, init_value), DigitalOut(gpio_ch, 0)
{
return;
}
bsp::DigitalIO::~DigitalIO(void)
{
this->write(DOUT_HIZ);
}
uint8_t bsp::DigitalIO::is_io_match(void)
{
if(this->last_set == DOUT_HIZ) return 1;
uint8_t read_lvl = this->read();
if(read_lvl == (uint8_t)this->last_set) return 1;
else return 0;
}
/**** Private function definitions ****/

32
firmware/src/bsp/dio.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef DIGITAL_IO_H_
#define DIGITAL_IO_H_
/**** Includes ****/
#include <stdint.h>
#include "din.h"
#include "dout.h"
namespace bsp {
/**** Public definitions ****/
const int8_t DIO_LOW = 0;
const int8_t DIO_HIGH = 1;
const int8_t DIO_HIZ = -1;
class DigitalIO : public DigitalIn, public DigitalOut
{
public:
DigitalIO(uint8_t gpio_ch, uint8_t init_value);
~DigitalIO(void);
uint8_t is_io_match(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DIGITAL_IO_H_ */

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

@@ -0,0 +1,52 @@
/**** 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(uint8_t gpio_ch, uint8_t inverted)
{
this->gpio_ch = gpio_ch;
this->invert = inverted;
this->write(DOUT_HIZ);
}
bsp::DigitalOut::~DigitalOut(void)
{
this->write(DOUT_HIZ);
}
void bsp::DigitalOut::write(int8_t level)
{
if(level > 0)
{
this->last_set = DOUT_HIGH;
if(this->invert) mcu::gpio_write(this->gpio_ch, mcu::LEVEL_LOW);
else mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIGH);
}
else if(level == 0)
{
this->last_set = DOUT_LOW;
if(this->invert) mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIGH);
else mcu::gpio_write(this->gpio_ch, mcu::LEVEL_LOW);
}
else
{
this->last_set = DOUT_HIZ;
mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIZ);
}
}
int8_t bsp::DigitalOut::get_set_level(void)
{
return this->last_set;
}
/**** Private function definitions ****/

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

@@ -0,0 +1,36 @@
#ifndef DIGITAL_OUTPUT_H_
#define DIGITAL_OUTPUT_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
const int8_t DOUT_LOW = 0;
const int8_t DOUT_HIGH = 1;
const int8_t DOUT_HIZ = -1;
class DigitalOut
{
protected:
uint8_t gpio_ch;
uint8_t invert;
int8_t last_set;
public:
DigitalOut(uint8_t gpio_ch, uint8_t inverted);
~DigitalOut(void);
void write(int8_t level);
int8_t get_set_level(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DIGITAL_OUTPUT_H_ */

View File

@@ -0,0 +1,74 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "halfbridge.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::Hafbridge::Hafbridge(uint8_t hs_pwm_ch, uint8_t ls_gpio_ch, uint8_t max_dc)
{
this->pwm_ch = hs_pwm_ch;
this->gpio_ch = ls_gpio_ch;
if(max_dc>100) max_dc = 100;
this->max_dc = util::percent_to_16b(max_dc);
this->disable();
}
bsp::Hafbridge::~Hafbridge(void)
{
this->last_duty = 0;
this->disable();
}
void bsp::Hafbridge::write(uint16_t dividend)
{
// Limit duty
if(dividend > this->max_dc) dividend = this->max_dc;
this->last_duty = dividend;
if(this->enabled == 0) return;
// Set PWM
mcu::pwm_write(this->pwm_ch, dividend);
}
void bsp::Hafbridge::write(uint8_t percent)
{
// Convert to dividend/0xFFFF
this->write(util::percent_to_16b(percent));
}
void bsp::Hafbridge::enable(void)
{
mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIGH);
this->enabled = 1;
this->write(this->last_duty);
}
void bsp::Hafbridge::disable(void)
{
mcu::pwm_write(this->pwm_ch, 0);
mcu::gpio_write(this->gpio_ch, mcu::LEVEL_LOW);
this->enabled = 0;
}
uint8_t bsp::Hafbridge::get_set_duty(void)
{
return this->last_duty;
}
uint8_t bsp::Hafbridge::is_enabled(void)
{
return this->enabled;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,38 @@
#ifndef HALFBRIDGE_H_
#define HALFBRIDGE_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
class Hafbridge
{
protected:
uint8_t pwm_ch;
uint8_t gpio_ch;
uint16_t last_duty;
uint8_t enabled;
uint16_t max_dc;
public:
Hafbridge(uint8_t hs_pwm_ch, uint8_t ls_gpio_ch, uint8_t max_dc);
~Hafbridge(void);
void write(uint16_t dividend);
void write(uint8_t percent);
void enable(void);
void disable(void);
uint8_t get_set_duty(void);
uint8_t is_enabled(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* HALFBRIDGE_H_ */

View File

@@ -0,0 +1,98 @@
#ifndef MCU_HAL_H_
#define MCU_HAL_H_
/**** Includes ****/
#include <stdint.h>
namespace mcu {
/**** Public definitions ****/
/*
*/
const uint8_t GPIO0 = 0; //PC5 Mode
const uint8_t GPIO1 = 1; //PC4 Pot
const uint8_t GPIO2 = 2; //PE1 Down
const uint8_t GPIO3 = 3; //PE3 Up
const uint8_t GPIO4 = 4; //PD7 Dimm
const uint8_t GPIO5 = 5; //PB7 Brakes
const uint8_t GPIO6 = 6; //PB6 Handbrake
const uint8_t GPIO7 = 7; //PB5 Handbrake pull
const uint8_t GPIO8 = 8; //PD6 Speed pull
const uint8_t GPIO9 = 9; //PD0 LED0
const uint8_t GPIO10 = 10; //PD1 LED1
const uint8_t GPIO11 = 11; //PD2 LED2
const uint8_t GPIO12 = 12; //PD3 LED3
const uint8_t GPIO13 = 13; //PD4 LED4
const uint8_t GPIO14 = 14; //PD5 LED5
const uint8_t GPIO15 = 15; //PB0 DCCD Enable
const uint8_t GPIO16 = 16; //PB1 DCCD PWM
const uint8_t GPIO17 = 17; //PB2 LED PWM
const uint8_t LEVEL_LOW = 0;
const uint8_t LEVEL_HIGH = 1;
const int8_t LEVEL_HIZ = -1;
const uint8_t ADC0 = 0; //Output current
const uint8_t ADC1 = 1; //Output voltage
const uint8_t ADC2 = 2; //Battery voltage
const uint8_t ADC3 = 3; //Battery current
const uint8_t ADC4 = 4; //Potentiometer
const uint8_t ADC5 = 5; //Mode
const uint8_t ADC8 = 8; //MCU temperature
const uint8_t ADC14 = 14; //MCU internal reference
const uint8_t ADC15 = 15; //MCU ground
const uint8_t PWM0 = 0; //DCCD
const uint8_t PWM1 = 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 pwm_ch1_en;
} startupCfg_t;
/**** Public function declarations ****/
void startup(startupCfg_t* hwCfg);
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);
uint16_t adc_read(uint8_t ch);
void pwm_write(uint8_t ch, uint16_t dc);
uint16_t pwm_read(uint8_t ch);
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

@@ -0,0 +1,464 @@
/**** Includes ****/
#include <avr/io.h>
#include <avr/eeprom.h>
#include "mcu_hal.h"
using namespace mcu;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
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)
{
// Fail-safe GPIO init
PORTB = 0xF8; // Set PORTB pull-ups
DDRB = 0x00; // Set all as inputs
PORTC = 0x40; // Set PORTC pull-ups
DDRC = 0x00; // Set all as inputs
PORTD = 0x80; // Set PORTD pull-ups
DDRD = 0x00; // Set all as inputs
PORTE = 0x0A; // Set PORTE pull-ups
DDRE = 0x00; // Set all as inputs
// Half-bridge related pins
PORTB &= ~0x03; //Set low
DDRB |= 0x03; //Set as output
// Common OD PWM pin
if(hwCfg->pwm_ch1_en) PORTB &= ~0x04; //Set low
else PORTB |= 0x04; //Set high
DDRB |= 0x04; //Set as output
// OD control pins
PORTD &= ~0x3F; //Set low (off)
DDRD |= 0x3F; //Set as outputs
// Handbrake pull-up pin
PORTB |= 0x20; //Set high
DDRB |= 0x20; //Set as output
// Handbrake and brakes pins
PORTB |= 0xC0; //Set pull-up on
DDRB &= ~0xC0; //Set as inputs
// Dimm
PORTD |= 0x80; //Set pull-up on
DDRD &= ~0x80; //Set as input
// Up and Down
PORTE |= 0x0A; //Set pull-up on
DDRE &= ~0x0A; //Set as inputs
// Internal ADC inputs
PORTC &= ~0x0F; //Pull-up off
DDRC &= ~0x0F; //Set as inputs
// Potentiometer & Mode
PORTC &= ~0x30; //Pull-up off
DDRC &= ~0x30; //Set as inputs
//ADC configuration
PRR0 &= ~0x01; //Enable ADC power
DIDR0 |= 0x0F; //Disable digital inputs, ADC0-ADC3
ADMUX = 0x40; //Set AVCC reference, Right adjust
ADCSRA = 0x00; //ADC Disabled, Single conversion, no IT
ADCSRA |= (uint8_t)hwCfg->adc_clk;
ADCSRB = 0x00; //no trigger input
ADCSRA |= 0x80; //Enable ADC
//DCCD and LED PWM configuration
PRR0 &= ~0x80; //Enable Timer1 power
TCCR1A = 0xC2; //Connect OC1A, inverted mode
if(hwCfg->pwm_ch1_en) TCCR1A |= 0x30; //Connect OC1B, inverted mode
TCCR1B = 0x18; //PWM, Phase & Frequency Correct ICR1 top, no clock, WGM:0xE
TCCR1C = 0x00;
TCNT1 = 0x0000;
OCR1A = 0xFFFF;
OCR1B = 0xFFFF;
ICR1 = hwCfg->pwm_top;
TIMSK1 = 0x00; //No interrupts
TIFR1 = 0x00; //Clear all flags
uint8_t tim1_prescaler = (uint8_t)hwCfg->pwm_clk;
TCCR1B |= tim1_prescaler; //Enable timer
}
// ADC Interface functions
uint16_t mcu::adc_read(uint8_t ch)
{
//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 Timer Interface functions
void mcu::pwm_write(uint8_t ch, uint16_t dc)
{
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)
{
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;
}
uint8_t mcu::gpio_read(uint8_t ch)
{
switch(ch)
{
case GPIO0: // Mode DIN1
return gpio_read_level(PINC,0x20);
case GPIO1: // Pot DIN2
return gpio_read_level(PINC,0x10);
case GPIO2: // Down DIN3
return gpio_read_level(PINE,0x02);
case GPIO3: // Up DIN4
return gpio_read_level(PINE,0x08);
case GPIO4: // Dimm DIN5
return gpio_read_level(PIND,0x80);
case GPIO5: // Brakes DIN6
return gpio_read_level(PINB,0x80);
case GPIO6: // Handbrake DIN7
return gpio_read_level(PINB,0x40);
case GPIO7: // Handbrake pull DIN8
return gpio_read_level(PINB,0x20);
case GPIO8: // Speed-pull
return gpio_read_level(PIND,0x40);
case GPIO9: // LED 0
return gpio_read_level(PIND,0x01);
case GPIO10: // LED 1
return gpio_read_level(PIND,0x02);
case GPIO11: // LED 2
return gpio_read_level(PIND,0x04);
case GPIO12: // LED 3
return gpio_read_level(PIND,0x08);
case GPIO13: // LED 4
return gpio_read_level(PIND,0x10);
case GPIO14: // LED 5
return gpio_read_level(PIND,0x20);
case GPIO15: // DCCD Enable
return gpio_read_level(PINB,0x01);
case GPIO16: // DCCD PWM
return gpio_read_level(PINB,0x02);
case GPIO17: // LED PWM
return gpio_read_level(PINB,0x04);
default:
return 0;
}
}
void mcu::gpio_write(uint8_t ch, int8_t lvl)
{
switch(ch)
{
case GPIO0: // Mode DIN1
if(lvl>0)
{
PORTC |= 0x20;
DDRC |= 0x20;
}
else if(lvl<0)
{
DDRC &= ~0x20;
PORTC &= ~0x20;
}
else
{
PORTC &= ~0x20;
DDRC |= 0x20;
}
return;
case GPIO1: // Pot DIN2
if(lvl>0)
{
PORTC |= 0x10;
DDRC |= 0x10;
}
else if(lvl<0)
{
DDRC &= ~0x10;
PORTC &= ~0x10;
}
else
{
PORTC &= ~0x10;
DDRC |= 0x10;
}
return;
case GPIO2: // Down DIN3
if(lvl>0)
{
PORTE |= 0x02;
DDRE |= 0x02;
}
else if(lvl<0)
{
DDRE &= ~0x02;
PORTE &= ~0x02;
}
else
{
PORTE &= ~0x02;
DDRE |= 0x02;
}
return;
case GPIO3: // Up DIN4
if(lvl>0)
{
PORTE |= 0x08;
DDRE |= 0x08;
}
else if(lvl<0)
{
DDRE &= ~0x08;
PORTE &= ~0x08;
}
else
{
PORTE &= ~0x08;
DDRE |= 0x08;
}
return;
case GPIO7: // Handbrake pull DIN
if(lvl>0)
{
PORTB |= 0x20;
DDRB |= 0x20;
}
else if(lvl<0)
{
DDRB &= ~0x20;
PORTB &= ~0x20;
}
else
{
PORTB &= ~0x20;
DDRB |= 0x20;
}
return;
case GPIO8: // Speed-pull
if(lvl>0) PORTD |= 0x40;
else PORTD &= ~0x40;
return;
case GPIO9: // LED 0
if(lvl>0) PORTD |= 0x01;
else PORTD &= ~0x01;
return;
case GPIO10: // LED 1
if(lvl>0) PORTD |= 0x02;
else PORTD &= ~0x02;
return;
case GPIO11: // LED 2
if(lvl>0) PORTD |= 0x04;
else PORTD &= ~0x04;
return;
case GPIO12: // LED 3
if(lvl>0) PORTD |= 0x08;
else PORTD &= ~0x08;
return;
case GPIO13: // LED 4
if(lvl>0) PORTD |= 0x10;
else PORTD &= ~0x10;
return;
case GPIO14: // LED 5
if(lvl>0) PORTD |= 0x20;
else PORTD &= ~0x20;
return;
case GPIO15: // DCCD Enable
if(lvl>0) PORTB |= 0x01;
else PORTB &= ~0x01;
return;
default:
return;
}
}
void mcu::gpio_write_pull(uint8_t ch, int8_t lvl)
{
switch(ch)
{
case GPIO0: // Mode DIN1
if(lvl>0) PORTC |= 0x20;
else PORTC &= ~0x20;
return;
case GPIO1: // Pot DIN2
if(lvl>0) PORTC |= 0x10;
else PORTC &= ~0x10;
return;
case GPIO2: // Down DIN3
if(lvl>0) PORTE |= 0x02;
else PORTE &= ~0x02;
return;
case GPIO3: // Up DIN4
if(lvl>0) PORTE |= 0x08;
else PORTE &= ~0x08;
return;
case GPIO4: // Dimm
if(lvl>0) PORTD |= 0x80;
else PORTD &= ~0x80;
return;
case GPIO5: // Brakes
if(lvl>0) PORTB |= 0x80;
else PORTB &= ~0x80;
return;
case GPIO6: // Handbrake
if(lvl>0) PORTB |= 0x40;
else PORTB &= ~0x40;
return;
default:
return;
}
}
uint8_t mcu::eeprom_read8b(uint16_t address)
{
return eeprom_read_byte((uint8_t*)address);
}
uint16_t mcu::eeprom_read16b(uint16_t address)
{
return eeprom_read_word((uint16_t*)address);
}
uint32_t mcu::eeprom_read32b(uint16_t address)
{
return eeprom_read_dword((uint32_t*)address);
}
void mcu::eeprom_write8b(uint16_t address, uint8_t value)
{
eeprom_write_byte((uint8_t*)address, value);
}
void mcu::eeprom_write16b(uint16_t address, uint16_t value)
{
eeprom_write_word((uint16_t*)address, 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_level(uint8_t pin_reg, uint8_t mask)
{
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 PWM0:
OCR1A = value;
return;
case PWM1:
OCR1B = value;
return;
default:
return;
}
}
static uint16_t pwm_read_ocx(uint8_t ch)
{
switch(ch)
{
case PWM0:
return OCR1A;
case PWM1:
return OCR1B ;
default:
return 0x0000;
}
}

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

@@ -0,0 +1,40 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "pwm.h"
using namespace bsp;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
bsp::PWMout::PWMout(uint8_t pwm_ch)
{
this->pwm_ch = pwm_ch;
this->write(0);
}
bsp::PWMout::~PWMout(void)
{
this->write(0);
}
void bsp::PWMout::write(uint8_t duty)
{
// Convert percent to 16b duty cycle
uint16_t dc = util::percent_to_16b(duty);
// Set PWM
mcu::pwm_write(this->pwm_ch, dc);
this->last_duty = duty;
}
uint8_t bsp::PWMout::get_set_duty(void)
{
return this->last_duty;
}
/**** Private function definitions ****/

31
firmware/src/bsp/pwm.h Normal file
View File

@@ -0,0 +1,31 @@
#ifndef PWM_H_
#define PWM_H_
/**** Includes ****/
#include <stdint.h>
namespace bsp {
/**** Public definitions ****/
class PWMout
{
protected:
uint8_t pwm_ch;
uint8_t last_duty;
public:
PWMout(uint8_t pwm_ch);
~PWMout(void);
void write(uint8_t duty);
uint8_t get_set_duty(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* PWM_H_ */

View File

@@ -0,0 +1,94 @@
/**** 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(bsp::DigitalIn* din_ch, uint8_t act_lvl, uint8_t dbnc_lim, uint8_t init_state)
{
this->din_ch = din_ch;
if(act_lvl) this->act_lvl = bsp::DIN_HIGH;
else this->act_lvl = bsp::DIN_LOW;
this->dbnc_cnter = 0;
this->dbnc_lim = dbnc_lim;
if(init_state) this->state = BUTTON_ON;
else this->state = BUTTON_OFF;
this->time = 0;
this->is_new = 0;
this->hold_time = 0;
}
hw::Button::~Button(void)
{
return;
}
uint8_t hw::Button::update(void)
{
// Read din level
uint8_t lvl = this->din_ch->last_read;
// Increase state counter
this->time = util::sat_add(this->time, 1);
// Repeat new flag after hold time
if((this->state == BUTTON_ON)&&(this->time > this->hold_time)&&(this->hold_time > 0))
{
this->time = 0;
this->is_new = 1;
};
// Determine next state
uint8_t next_state = BUTTON_OFF;
if(lvl==this->act_lvl) next_state = BUTTON_ON;
// Advance debounce sample counter
if(next_state != this->state) this->dbnc_cnter++;
else this->dbnc_cnter = 0;
// Check for debounce end
if(this->dbnc_cnter < this->dbnc_lim) return this->state;
// Debounce end. Apply new state.
this->state = next_state;
this->time = 0;
this->is_new = 1;
this->dbnc_cnter = 0;
return this->state;
}
uint8_t hw::Button::force_update(void)
{
// Read din level
uint8_t lvl = this->din_ch->read();
// Cancels active debounce
this->dbnc_cnter = 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 = next_state;
this->time = 0;
this->is_new = 1;
};
return this->state;
}
/**** Private function definitions ****/

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

@@ -0,0 +1,42 @@
#ifndef BUTTON_H_
#define BUTTON_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/din.h"
namespace hw {
/**** Public definitions ****/
const uint8_t BUTTON_OFF = 0;
const uint8_t BUTTON_ON = 1;
class Button
{
protected:
bsp::DigitalIn* din_ch;
uint8_t act_lvl;
uint8_t dbnc_cnter;
public:
Button(bsp::DigitalIn* din_ch, uint8_t act_lvl, uint8_t dbnc_lim, uint8_t init_state);
~Button(void);
uint8_t state;
uint16_t time;
uint8_t dbnc_lim;
uint8_t is_new;
uint16_t hold_time;
uint8_t update(void);
uint8_t force_update(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* BUTTON_H_ */

View File

@@ -0,0 +1,41 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "cc_output.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::CCoutput::CCoutput(bsp::Hafbridge* hbridge, bsp::AnalogIn* supply_u, bsp::AnalogIn* out_u, bsp::AnalogIn* out_i) : CVoutput(hbridge, supply_u)
{
this->out_voltage = out_u;
this->out_currnet = out_i;
this->out_impedance = 0xFFFF;
this->target_voltage = 0;
}
void hw::CCoutput::update(void)
{
// Calculate output impedance
if((this->out_currnet == 0)||(this->out_voltage->last_read == 0)) this->out_impedance = 0xFFFF;
else
{
this->out_impedance = util::sat_div_kilo(this->out_voltage->last_read, this->out_currnet->last_read);
}
// Check target
if((this->target < this->min_out)&&(this->target > 0)) this->target = this->min_out;
// Convert target current to voltage
this->target_voltage = util::sat_mul_kilo(this->target, this->out_impedance);
// Set output
this->hbridge->write(util::sat_ratio(this->target_voltage, this->supply->last_read));
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,35 @@
#ifndef CONST_CURRENT_OUTPUT_H_
#define CONST_CURRENT_OUTPUT_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/ain.h"
#include "cv_output.h"
namespace hw {
/**** Public definitions ****/
class CCoutput : public CVoutput
{
protected:
bsp::AnalogIn* out_voltage;
bsp::AnalogIn* out_currnet;
public:
CCoutput(bsp::Hafbridge* hbridge, bsp::AnalogIn* supply_u, bsp::AnalogIn* out_u, bsp::AnalogIn* out_i);
void update(void);
uint16_t out_impedance;
uint16_t target_voltage;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* CONST_VOLTAGE_OUTPUT_H_ */

View File

@@ -0,0 +1,53 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "cv_output.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::CVoutput::CVoutput(bsp::Hafbridge* hbridge, bsp::AnalogIn* supply_u)
{
this->hbridge = hbridge;
this->supply = supply_u;
this->target = 0;
this->min_out = 0;
this->hbridge->disable();
}
hw::CVoutput::~CVoutput(void)
{
this->hbridge->write((uint16_t)0x0000);
this->hbridge->disable();
return;
}
void hw::CVoutput::update(void)
{
// Check target
if((this->target < this->min_out)&&(this->target > 0)) this->target = this->min_out;
// Set output
this->hbridge->write(util::sat_ratio(this->target, this->supply->last_read));
}
void hw::CVoutput::enable(void)
{
this->hbridge->enable();
}
void hw::CVoutput::disable(void)
{
this->hbridge->disable();
}
uint8_t hw::CVoutput::is_enabled(void)
{
return this->hbridge->is_enabled();
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,39 @@
#ifndef CONST_VOLTAGE_OUTPUT_H_
#define CONST_VOLTAGE_OUTPUT_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/ain.h"
#include "../bsp/halfbridge.h"
namespace hw {
/**** Public definitions ****/
class CVoutput
{
protected:
bsp::Hafbridge* hbridge;
bsp::AnalogIn* supply;
public:
CVoutput(bsp::Hafbridge* hbridge, bsp::AnalogIn* supply_u);
~CVoutput(void);
uint16_t target;
uint16_t min_out;
void update(void);
void enable(void);
void disable(void);
uint8_t is_enabled(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* CONST_VOLTAGE_OUTPUT_H_ */

View File

@@ -0,0 +1,65 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "devices.h"
/**** Private definitions ****/
/**** Private constants ****/
static const uint16_t def_button_hold_time = 1000;
static const uint16_t def_min_current = 100;
static const uint16_t def_fuse_treshold = 6000;
static const uint16_t def_fuse_hold_cycles = 50;
static const uint16_t def_fuse_cooldown_cycles = 1000;
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
void devices_init(void)
{
board_init();
btn_up.hold_time = def_button_hold_time;
btn_down.hold_time = def_button_hold_time;
ccout.target = 0;
ccout.min_out = def_min_current;
sup_fuse.hold_current = def_fuse_treshold;
sup_fuse.trip_cycles = def_fuse_hold_cycles;
sup_fuse.cooldown_cycles = def_fuse_cooldown_cycles;
out_fuse.hold_current = def_fuse_treshold;
out_fuse.trip_cycles = def_fuse_hold_cycles;
out_fuse.cooldown_cycles = def_fuse_cooldown_cycles;
hvdin3_pull.write(bsp::DOUT_HIGH);
devices_update_inputs();
display.write(0x00);
display.set_brigthness(100);
ccout.update();
ccout.enable();
}
void devices_update_inputs(void)
{
board_read();
pot.update();
btn_mode.update();
btn_up.update();
btn_down.update();
sw_dimm.update();
sw_brakes.update();
sw_hbrake.update();
sup_fuse.update();
out_fuse.update();
display.process_timer();
}
/**** Private function definitions ****/

35
firmware/src/hw/devices.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef HW_DEVICES_H_
#define HW_DEVICES_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/board.h"
#include "button.h"
#include "potentiometer.h"
#include "display_led.h"
#include "cv_output.h"
#include "cc_output.h"
#include "fuse.h"
static hw::Button btn_mode = hw::Button(&din1, bsp::DIN_LOW, 10, hw::BUTTON_OFF);
static hw::Button btn_up = hw::Button(&din4, bsp::DIN_LOW, 10, hw::BUTTON_OFF);
static hw::Button btn_down = hw::Button(&din3, bsp::DIN_LOW, 10, hw::BUTTON_OFF);
static hw::Button sw_dimm = hw::Button(&hvdin1, bsp::DIN_HIGH, 10, hw::BUTTON_OFF);
static hw::Button sw_brakes = hw::Button(&hvdin2, bsp::DIN_HIGH, 10, hw::BUTTON_OFF);
static hw::Button sw_hbrake = hw::Button(&hvdin3, bsp::DIN_LOW, 10, hw::BUTTON_OFF);
static hw::Potentiometer pot = hw::Potentiometer(&ain2, 500, 4500);
static hw::DisplayLed display = hw::DisplayLed(&odout1, &odout2, &odout3, &odout4, &odout5, &odout6, &od_pwm);
static hw::CCoutput ccout = hw::CCoutput(&hbridge, &bat_u, &dccd_u, &dccd_i);
static hw::Fuse sup_fuse = hw::Fuse(&bat_i);
static hw::Fuse out_fuse = hw::Fuse(&dccd_i);
void devices_init(void);
void devices_update_inputs(void);
#endif /* BSP_BOARD_H_ */

View File

@@ -0,0 +1,195 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "display_led.h"
using namespace hw;
/**** 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 ****/
hw::DisplayLed::DisplayLed(bsp::DigitalOut* led0, bsp::DigitalOut* led1, bsp::DigitalOut* led2, bsp::DigitalOut* led3, bsp::DigitalOut* led4, bsp::DigitalOut* led5, bsp::PWMout* common)
{
this->led0 = led0;
this->led1 = led1;
this->led2 = led2;
this->led3 = led3;
this->led4 = led4;
this->led5 = led5;
this->common = common;
this->led0->write(0);
this->led1->write(0);
this->led2->write(0);
this->led3->write(0);
this->led4->write(0);
this->led5->write(0);
this->common->write(0);
this->lock_counter = 0;
this->locked = 1;
}
hw::DisplayLed::~DisplayLed(void)
{
this->led0->write(0);
this->led1->write(0);
this->led2->write(0);
this->led3->write(0);
this->led4->write(0);
this->led5->write(0);
this->common->write(0);
}
void hw::DisplayLed::show_percent(uint8_t percent, style_t style)
{
uint8_t image = 0x00;
switch(style)
{
case LED_DSP_BAR:
image = img_gen_bar(percent);
break;
case LED_DSP_DOT10:
image = img_gen_dot10(percent);
break;
default:
image = img_gen_dot20(percent);
break;
}
this->write(image);
}
void hw::DisplayLed::write(uint8_t image)
{
if(image&0x01) this->led0->write(1);
else this->led0->write(0);
if(image&0x02) this->led1->write(1);
else this->led1->write(0);
if(image&0x04) this->led2->write(1);
else this->led2->write(0);
if(image&0x08) this->led3->write(1);
else this->led3->write(0);
if(image&0x10) this->led4->write(1);
else this->led4->write(0);
if(image&0x20) this->led5->write(1);
else this->led5->write(0);
}
void hw::DisplayLed::set_brigthness(uint8_t percent)
{
this->common->write(percent);
}
void hw::DisplayLed::set_lock(uint16_t timeout)
{
this->lock_counter = timeout;
this->locked = 1;
}
void hw::DisplayLed::process_timer(void)
{
if(this->lock_counter) this->lock_counter--;
else this->locked = 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;
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;
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;
default:
return 0x3F;
}
}

View File

@@ -0,0 +1,54 @@
#ifndef DISPLAY_LED_H_
#define DISPLAY_LED_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/dout.h"
#include "../bsp/pwm.h"
namespace hw {
/**** Public definitions ****/
class DisplayLed
{
protected:
bsp::DigitalOut* led0;
bsp::DigitalOut* led1;
bsp::DigitalOut* led2;
bsp::DigitalOut* led3;
bsp::DigitalOut* led4;
bsp::DigitalOut* led5;
bsp::PWMout* common;
uint16_t lock_counter;
public:
typedef enum {
LED_DSP_DOT20,
LED_DSP_DOT10,
LED_DSP_BAR
} style_t;
DisplayLed(bsp::DigitalOut* led0, bsp::DigitalOut* led1, bsp::DigitalOut* led2, bsp::DigitalOut* led3, bsp::DigitalOut* led4, bsp::DigitalOut* led5, bsp::PWMout* common);
~DisplayLed(void);
void show_percent(uint8_t percent, style_t style);
void write(uint8_t image);
void set_brigthness(uint8_t percent);
void set_lock(uint16_t timeout);
void process_timer(void);
uint8_t locked;
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DISPLAY_LED_H_ */

66
firmware/src/hw/fuse.cpp Normal file
View File

@@ -0,0 +1,66 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "fuse.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::Fuse::Fuse(bsp::AnalogIn* ain_ch)
{
this->hold_current = 0;
this->trip_cycles = 0;
this->warning = 0;
this->fault = 0;
this->cooldown_counter = 0;
this->cooldown_cycles = 0;
this->retry_cnt = 0;
}
hw::Fuse::~Fuse(void)
{
return;
}
void hw::Fuse::update(void)
{
// Under threshold
if(this->ain_ch->last_read <= this->hold_current)
{
// Clear warning flag
this->warning = 0;
// OC energy counter
if(this->oc_counter > 0) this->oc_counter--;
// Cool down fuse
if(this->cooldown_counter > 0) this->cooldown_counter--;
// Auto reset logic
if((this->fault)&&(this->cooldown_counter==0))
{
this->fault = 0;
this->retry_cnt = util::sat_add(this->retry_cnt, 1);
};
return;
};
// Over current condition
this->warning = 1;
// PC energy counter
this->oc_counter = util::sat_add(this->oc_counter, 1);
// Check for trip threshold
if(this->oc_counter < this->trip_cycles) return;
// Trip fuse
this->fault = 1;
this->cooldown_counter = this->cooldown_cycles;
}
/**** Private function definitions ****/

40
firmware/src/hw/fuse.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef FUSE_H_
#define FUSE_H_
/**** Includes ****/
#include <stdint.h>
#include "../bsp/ain.h"
namespace hw {
/**** Public definitions ****/
class Fuse
{
protected:
bsp::AnalogIn* ain_ch;
uint16_t oc_counter;
uint16_t cooldown_counter;
public:
Fuse(bsp::AnalogIn* ain_ch);
~Fuse(void);
uint16_t hold_current;
uint16_t trip_cycles;
uint8_t warning;
uint8_t fault;
uint16_t cooldown_cycles;
uint8_t retry_cnt;
void update(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* POTENTIOMETER_H_ */

View File

@@ -0,0 +1,37 @@
/**** 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(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->percent = 0;
}
hw::Potentiometer::~Potentiometer(void)
{
return;
}
uint8_t hw::Potentiometer::update(void)
{
// Calculate percent
if(this->ain_ch->last_read <= this->low_deadzone) this->percent = 0;
else if(this->ain_ch->last_read >= this->high_deadzone ) this->percent = 100;
else this->percent = util::interpolate(this->ain_ch->last_read, this->low_deadzone, this->high_deadzone, 0, 100);
return this->percent;
}
/**** Private function definitions ****/

View File

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

View File

@@ -0,0 +1,51 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "button_force.h"
using namespace logic;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
logic::ButtonForce::ButtonForce(hw::Button* btn_up, hw::Button* btn_down)
{
this->btn_up = btn_up;
this->btn_down = btn_down;
this->force = 0;
this->step = 10;
this->is_new = 0;
}
logic::ButtonForce::~ButtonForce(void)
{
return;
}
uint8_t logic::ButtonForce::update(void)
{
uint8_t next_force = 0;
if((this->btn_up->is_new)&&(this->btn_up->state == hw::BUTTON_ON))
{
next_force = util::sat_add(this->force, this->step);
if(next_force > 100) next_force = 100;
this->btn_up->is_new = 0;
};
if((this->btn_down->is_new)&&(this->btn_down->state == hw::BUTTON_ON))
{
next_force = util::sat_subtract(this->force, this->step);
this->btn_down->is_new = 0;
};
if(next_force != this->force) this->is_new = 1;
this->force = next_force;
return this->force;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,36 @@
#ifndef BUTTON_FORCE_H_
#define BUTTON_FORCE_H_
/**** Includes ****/
#include <stdint.h>
#include "../hw/button.h"
namespace logic {
/**** Public definitions ****/
class ButtonForce
{
protected:
hw::Button* btn_up;
hw::Button* btn_down;
public:
ButtonForce(hw::Button* btn_up, hw::Button* btn_down);
~ButtonForce(void);
uint8_t force;
uint8_t step;
uint8_t is_new;
uint8_t update(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* BUTTON_FORCE_H_ */

View File

@@ -0,0 +1,185 @@
/**** Includes ****/
#include "cfg_mem.h"
#include "../bsp/mcu/mcu_hal.h"
using namespace logic;
/**** Private definitions ****/
/**** Private constants ****/
static const uint16_t addr_btn_force = 0x0000;
static const uint16_t addr_bmode = 0x0001;
static const uint16_t addr_pot_mode = 0x0002;
static const uint16_t addr_dsp_brigth = 0x0003;
static const uint16_t addr_dsp_dimm = 0x0004;
static const uint16_t addr_brake_force = 0x0005;
static const uint16_t addr_max_hbrake_time = 0x0006;
static const uint16_t addr_lock_current = 0x0008;
static const uint8_t def_btn_force = 0;
static const uint8_t def_pot_mode = 0;
static const uint8_t def_bmode = 0;
static const uint8_t def_dimm = 50;
static const uint8_t def_brigth = 100;
static const uint8_t def_brake_force = 100;
static const uint16_t def_max_hbrake_time = 1000;
static const uint16_t def_lock_current = 4500;
static const uint16_t max_lock_current = 6000;
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
logic::CfgMemory::CfgMemory(void)
{
this->mem_btn_force = 0;
this->mem_bmode = 0;
this->mem_pot_mode = 0;
this->mem_dsp_brigth = 0;
this->mem_dsp_dimm = 0;
this->mem_brake_force = 0;
this->mem_max_hbrake_time = 0;
this->mem_lock_current = 0;
this->restore();
}
logic::CfgMemory::~CfgMemory(void)
{
return;
}
void logic::CfgMemory::init(void)
{
this->mem_btn_force = mcu::eeprom_read8b(addr_btn_force);
this->mem_bmode = mcu::eeprom_read8b(addr_bmode);
this->mem_pot_mode = mcu::eeprom_read8b(addr_pot_mode);
this->mem_dsp_brigth = mcu::eeprom_read8b(addr_dsp_brigth);
this->mem_dsp_dimm = mcu::eeprom_read8b(addr_dsp_dimm);
this->mem_brake_force = mcu::eeprom_read8b(addr_brake_force);
this->mem_max_hbrake_time = mcu::eeprom_read16b(addr_max_hbrake_time);
this->mem_lock_current = mcu::eeprom_read16b(addr_lock_current);
// Validate EEPROM data
if(this->mem_btn_force > 100)
{
this->mem_btn_force = def_btn_force;
mcu::eeprom_write8b(addr_btn_force, this->mem_btn_force);
};
if(this->mem_bmode > 2)
{
this->mem_bmode = def_bmode;
mcu::eeprom_write8b(addr_bmode, this->mem_bmode);
};
if(this->mem_pot_mode > 1)
{
this->mem_pot_mode = def_pot_mode;
mcu::eeprom_write8b(addr_pot_mode, this->mem_pot_mode);
};
if(this->mem_dsp_brigth > 100)
{
this->mem_dsp_brigth = def_brigth;
mcu::eeprom_write8b(addr_dsp_brigth, this->mem_dsp_brigth);
};
if(this->mem_dsp_dimm > 100)
{
this->mem_dsp_dimm = def_dimm;
mcu::eeprom_write8b(addr_dsp_dimm, this->mem_dsp_dimm);
};
if(this->mem_brake_force > 100)
{
this->mem_brake_force = def_brake_force;
mcu::eeprom_write8b(addr_brake_force, this->mem_brake_force);
};
/*
No wrong value
if(this->mem_max_hbrake_time > 1000)
{
this->mem_max_hbrake_time = def_max_hbrake_time;
mcu::eeprom_write16b(addr_lock_current, this->mem_max_hbrake_time);
};
*/
if(this->mem_lock_current > max_lock_current)
{
this->mem_lock_current = def_lock_current;
mcu::eeprom_write16b(addr_lock_current, this->mem_lock_current);
};
this->restore();
}
void logic::CfgMemory::save(void)
{
if(this->btn_force != this->mem_btn_force)
{
this->mem_btn_force = this->btn_force;
mcu::eeprom_write8b(addr_btn_force, this->mem_btn_force);
};
if(this->bmode != this->mem_bmode)
{
this->mem_bmode = this->bmode;
mcu::eeprom_write8b(addr_bmode, this->mem_bmode);
};
}
void logic::CfgMemory::save_all(void)
{
this->save();
if(this->pot_mode != this->mem_pot_mode)
{
this->mem_pot_mode = this->pot_mode;
mcu::eeprom_write8b(addr_pot_mode, this->mem_pot_mode);
};
if(this->dsp_brigth != this->mem_dsp_brigth)
{
this->mem_dsp_brigth = this->dsp_brigth;
mcu::eeprom_write8b(addr_dsp_brigth, this->mem_dsp_brigth);
};
if(this->dsp_dimm != this->mem_dsp_dimm)
{
this->mem_dsp_dimm = this->dsp_dimm;
mcu::eeprom_write8b(addr_dsp_dimm, this->mem_dsp_dimm);
};
if(this->brake_force != this->mem_brake_force)
{
this->mem_brake_force = this->brake_force;
mcu::eeprom_write8b(addr_brake_force, this->mem_brake_force);
};
if(this->max_hbrake_time != this->mem_max_hbrake_time)
{
this->mem_max_hbrake_time = this->max_hbrake_time;
mcu::eeprom_write16b(addr_max_hbrake_time, this->mem_max_hbrake_time);
};
if(this->lock_current != this->mem_lock_current)
{
this->mem_lock_current = this->lock_current;
mcu::eeprom_write16b(addr_lock_current, this->mem_lock_current);
};
}
void logic::CfgMemory::restore(void)
{
this->btn_force = this->mem_btn_force;
this->bmode = this->mem_bmode;
this->pot_mode = this->mem_pot_mode;
this->dsp_brigth = this->mem_dsp_brigth;
this->dsp_dimm = this->mem_dsp_dimm;
this->brake_force = this->mem_brake_force;
this->max_hbrake_time = this->mem_max_hbrake_time;
this->lock_current = this->mem_lock_current;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,50 @@
#ifndef CONFIG_H_
#define CONFIG_H_
/**** Includes ****/
#include <stdint.h>
#include "../hw/button.h"
namespace logic {
/**** Public definitions ****/
class CfgMemory
{
protected:
uint8_t mem_btn_force;
uint8_t mem_bmode;
uint8_t mem_pot_mode;
uint8_t mem_dsp_brigth;
uint8_t mem_dsp_dimm;
uint8_t mem_brake_force;
uint16_t mem_max_hbrake_time;
uint16_t mem_lock_current;
public:
CfgMemory(void);
~CfgMemory(void);
uint8_t btn_force;
uint8_t bmode;
uint8_t pot_mode;
uint8_t dsp_brigth;
uint8_t dsp_dimm;
uint8_t brake_force;
uint16_t max_hbrake_time;
uint16_t lock_current;
void init(void);
void save(void);
void save_all(void);
void restore(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_FORCE_H_ */

View File

@@ -0,0 +1,84 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "dccd_force.h"
using namespace logic;
/**** Private definitions ****/
/**** Private constants ****/
static const uint16_t def_max_hbrake_time = 1000;
static const uint16_t def_brake_force = 100;
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
logic::DccdForce::DccdForce(hw::Button* btn_mode, hw::Button* sw_hbrake, hw::Button* sw_brakes)
{
this->mode = btn_mode;
this->handbrake = sw_hbrake;
this->brakes = sw_brakes;
this->is_new = 0;
this->force = 0;
this->brake_mode = 0;
this->max_hbrake_time = def_max_hbrake_time;
this->brake_force = def_brake_force;
}
logic::DccdForce::~DccdForce(void)
{
return;
}
uint8_t logic::DccdForce::update(uint8_t user_force)
{
// Process mode button
if((this->mode->is_new)&&(this->mode->state == hw::BUTTON_ON))
{
// Cycle brake mode
switch(this->brake_mode)
{
case 0:
this->brake_mode = 1;
case 1:
this->brake_mode = 2;
default:
this->brake_mode = 0;
}
this->mode->is_new = 0;
this->is_new_bmode = 1;
};
// Determine target force source
uint8_t next_force = user_force;
if((this->handbrake->state == hw::BUTTON_ON)&&((this->handbrake->time < this->max_hbrake_time)||(this->max_hbrake_time == 0)))
{
next_force = 0;
}
else if(this->brakes->state == hw::BUTTON_ON)
{
switch(this->brake_mode)
{
case 0:
next_force = 0;
case 1:
next_force = user_force;
default:
next_force = this->brake_force;
}
};
if(next_force != this->force) this->is_new = 1;
this->force = next_force;
return this->force;
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,42 @@
#ifndef DCCD_FORCE_H_
#define DCCD_FORCE_H_
/**** Includes ****/
#include <stdint.h>
#include "../hw/button.h"
namespace logic {
/**** Public definitions ****/
class DccdForce
{
protected:
hw::Button* mode;
hw::Button* handbrake;
hw::Button* brakes;
public:
DccdForce(hw::Button* btn_mode, hw::Button* sw_hbrake, hw::Button* sw_brakes);
~DccdForce(void);
uint8_t force;
uint8_t is_new;
uint8_t brake_mode;
uint8_t is_new_bmode;
uint16_t max_hbrake_time;
uint8_t brake_force;
uint8_t update(uint8_t user_force);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* DCCD_FORCE_H_ */

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

@@ -0,0 +1,110 @@
/**** Includes ****/
#include "utils/utils.h"
#include "hw/devices.h"
#include "logic/button_force.h"
#include "logic/dccd_force.h"
#include "logic/cfg_mem.h"
/**** Private definitions ****/
/**** Private constants ****/
static const uint16_t dsp_lock_bmode = 1000;
static const uint16_t dsp_lock_force = 50;
/**** Private variables ****/
static logic::CfgMemory cfg_mem = logic::CfgMemory();
static logic::ButtonForce button_force = logic::ButtonForce(&btn_up, &btn_down);
static logic::DccdForce dccd_force = logic::DccdForce(&btn_mode, &sw_hbrake, &sw_brakes);
/**** Private function declarations ****/
/**** Public function definitions ****/
int main(void)
{
// HW setup
devices_init();
// Read saved config
cfg_mem.init();
uint8_t user_force = 0;
button_force.force = cfg_mem.btn_force;
dccd_force.brake_mode = cfg_mem.bmode;
dccd_force.max_hbrake_time = cfg_mem.max_hbrake_time;
dccd_force.brake_force = cfg_mem.brake_force;
// Super loop
while(1)
{
// Update inputs
devices_update_inputs();
// Update user setting
button_force.update();
// Select user force input
if(cfg_mem.pot_mode) user_force = pot.percent;
else user_force = button_force.force;
// Calculate next target force
dccd_force.update(user_force);
// Override force in case of fault
if((sup_fuse.fault)||(out_fuse.fault)) dccd_force.force = 0;
// Convert force to current
ccout.target = util::percent_of(dccd_force.force, cfg_mem.lock_current);
// Execute outputs
ccout.update();
// Set display
if(dccd_force.is_new_bmode)
{
uint8_t bmode_img = 0x03;
switch(dccd_force.brake_mode)
{
case 1:
bmode_img = 0x0C;
break;
case 2:
bmode_img = 0x30;
break;
default:
bmode_img = 0x03;
break;
}
display.write(bmode_img);
display.set_lock(dsp_lock_bmode);
dccd_force.is_new_bmode = 0;
}
else if((button_force.is_new)&&(cfg_mem.pot_mode==0))
{
display.show_percent(dccd_force.force, hw::DisplayLed::LED_DSP_DOT10);
display.set_lock(dsp_lock_force);
button_force.is_new = 0;
}
else if(display.locked==0) display.show_percent(dccd_force.force, hw::DisplayLed::LED_DSP_DOT10);
// Process dimm
if(sw_dimm.state == hw::BUTTON_ON) display.set_brigthness(cfg_mem.dsp_dimm);
else display.set_brigthness(cfg_mem.dsp_brigth);
// Save user setting changes
cfg_mem.btn_force = button_force.force;
cfg_mem.bmode = dccd_force.brake_mode;
cfg_mem.save();
continue; // End of super loop
}
// Escape the matrix
return 0;
}
/**** Private function definitions ***/

22
firmware/src/uDCCD.atsln Normal file
View File

@@ -0,0 +1,22 @@

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("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "uDCCD", "uDCCD.cppproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|AVR = Debug|AVR
Release|AVR = Release|AVR
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.ActiveCfg = Debug|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Debug|AVR.Build.0 = Debug|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR
{DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<Store xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="AtmelPackComponentManagement">
<ProjectComponents>
<ProjectComponent z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<CApiVersion></CApiVersion>
<CBundle></CBundle>
<CClass>Device</CClass>
<CGroup>Startup</CGroup>
<CSub></CSub>
<CVariant></CVariant>
<CVendor>Atmel</CVendor>
<CVersion>1.7.0</CVersion>
<DefaultRepoPath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs</DefaultRepoPath>
<DependentComponents xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" />
<Description></Description>
<Files xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.7.374\include\</AbsolutePath>
<Attribute></Attribute>
<Category>include</Category>
<Condition>C</Condition>
<FileContentHash i:nil="true" />
<FileVersion></FileVersion>
<Name>include/</Name>
<SelectString></SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.7.374\include\avr\iom328pb.h</AbsolutePath>
<Attribute></Attribute>
<Category>header</Category>
<Condition>C</Condition>
<FileContentHash>TU9y07FA4IWGxznrvGv9rQ==</FileContentHash>
<FileVersion></FileVersion>
<Name>include/avr/iom328pb.h</Name>
<SelectString></SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.7.374\templates\main.c</AbsolutePath>
<Attribute>template</Attribute>
<Category>source</Category>
<Condition>C Exe</Condition>
<FileContentHash>KjvOcFWd++tbnsEMfVPd/w==</FileContentHash>
<FileVersion></FileVersion>
<Name>templates/main.c</Name>
<SelectString>Main file (.c)</SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.7.374\templates\main.cpp</AbsolutePath>
<Attribute>template</Attribute>
<Category>source</Category>
<Condition>C Exe</Condition>
<FileContentHash>w5aB/d0+DbxGZ7yY0aMMjw==</FileContentHash>
<FileVersion></FileVersion>
<Name>templates/main.cpp</Name>
<SelectString>Main file (.cpp)</SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
<d4p1:anyType i:type="FileInfo">
<AbsolutePath>C:/Program Files (x86)\Atmel\Studio\7.0\Packs\atmel\ATmega_DFP\1.7.374\gcc\dev\atmega328pb</AbsolutePath>
<Attribute></Attribute>
<Category>libraryPrefix</Category>
<Condition>GCC</Condition>
<FileContentHash i:nil="true" />
<FileVersion></FileVersion>
<Name>gcc/dev/atmega328pb</Name>
<SelectString></SelectString>
<SourcePath></SourcePath>
</d4p1:anyType>
</Files>
<PackName>ATmega_DFP</PackName>
<PackPath>C:/Program Files (x86)/Atmel/Studio/7.0/Packs/atmel/ATmega_DFP/1.7.374/Atmel.ATmega_DFP.pdsc</PackPath>
<PackVersion>1.7.374</PackVersion>
<PresentInProject>true</PresentInProject>
<ReferenceConditionId>ATmega328PB</ReferenceConditionId>
<RteComponents xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:string></d4p1:string>
</RteComponents>
<Status>Resolved</Status>
<VersionMode>Fixed</VersionMode>
<IsComponentInAtProject>true</IsComponentInAtProject>
</ProjectComponent>
</ProjectComponents>
</Store>

288
firmware/src/uDCCD.cppproj Normal file
View File

@@ -0,0 +1,288 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProjectVersion>7.0</ProjectVersion>
<ToolchainName>com.Atmel.AVRGCC8.CPP</ToolchainName>
<ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>
<avrdevice>ATmega328PB</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>CPP</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>uDCCD</AssemblyName>
<Name>uDCCD</Name>
<RootNamespace>uDCCD</RootNamespace>
<ToolchainFlavour>Native</ToolchainFlavour>
<KeepTimersRunning>true</KeepTimersRunning>
<OverrideVtor>false</OverrideVtor>
<CacheFlash>true</CacheFlash>
<ProgFlashFromRam>true</ProgFlashFromRam>
<RamSnippetAddress>0x20000000</RamSnippetAddress>
<UncachedRange />
<preserveEEPROM>true</preserveEEPROM>
<OverrideVtorValue>exception_table</OverrideVtorValue>
<BootSegment>2</BootSegment>
<ResetRule>0</ResetRule>
<eraseonlaunchrule>0</eraseonlaunchrule>
<EraseKey />
<AsfFrameworkConfig>
<framework-data xmlns="">
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.52.0" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<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>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcc.compiler.directories.IncludePaths>
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
<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>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>NDEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</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>
<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>
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcc.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcc.compiler.symbols.DefSymbols>
<avrgcc.compiler.directories.IncludePaths>
<ListValues>
<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>
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
<avrgcccpp.compiler.symbols.DefSymbols>
<ListValues>
<Value>DEBUG</Value>
</ListValues>
</avrgcccpp.compiler.symbols.DefSymbols>
<avrgcccpp.compiler.directories.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</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="bsp\ain.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\ain.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\board.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\board.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\din.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\din.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\dio.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\dio.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\halfbridge.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\halfbridge.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\mcu\mcu_hal.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\mcu\mcu_hal_r8.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\dout.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\dout.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\pwm.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="bsp\pwm.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\cc_output.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\cc_output.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\cv_output.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\cv_output.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\display_led.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\display_led.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\fuse.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\fuse.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\devices.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\devices.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\potentiometer.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\potentiometer.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\button_force.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\button_force.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\cfg_mem.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\cfg_mem.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\dccd_force.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\dccd_force.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="main.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="utils\interpolate.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="utils\interpolate.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="utils\utils.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="utils\utils.h">
<SubType>compile</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="bsp" />
<Folder Include="bsp\mcu" />
<Folder Include="hw" />
<Folder Include="logic" />
<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,164 @@
/**** 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;
}
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;
}
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,44 @@
#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 sat_cast(uint32_t x);
uint16_t sat_cast(int32_t x);
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);
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 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);
#ifdef TESTING
#endif
} //namespace
#endif /* UTILS_H_ */

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -305,24 +305,24 @@ DocumentPath=Project Outputs for uDCCD_Controller\Design Rule Check - uDCCD_Cont
DItemRevisionGUID= DItemRevisionGUID=
[Parameter1] [Parameter1]
Name=UT_BOM_Version Name=UT_Project_Name
Value=V1 Value=uDCCD Controller
[Parameter2] [Parameter2]
Name=UT_Output_file_name Name=UT_PCB_Revision
Value=uDCCD Controller Value=R9
[Parameter3] [Parameter3]
Name=UT_PCB_Designer Name=UT_PCB_Designer
Value=Andis Zīle Value=Andis Zīle
[Parameter4] [Parameter4]
Name=UT_PCB_Revision Name=UT_Output_file_name
Value=R8 Value=uDCCD_Controller
[Parameter5] [Parameter5]
Name=UT_Project_Name Name=UT_BOM_Version
Value=uDCCD Controller Value=V1
[Configuration1] [Configuration1]
Name=Sources Name=Sources
@@ -544,6 +544,12 @@ OutputDocumentPath13=
OutputVariantName13=[No Variations] OutputVariantName13=[No Variations]
OutputDefault13=0 OutputDefault13=0
PageOptions13=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-3|MediaType=1|DitherType=10|PrintScaleMode=1|PaperKind=A4|PaperIndex=9 PageOptions13=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-3|MediaType=1|DitherType=10|PrintScaleMode=1|PaperKind=A4|PaperIndex=9
OutputType14=PCBDrawing
OutputName14=Draftsman
OutputDocumentPath14=
OutputVariantName14=[No Variations]
OutputDefault14=0
PageOptions14=Record=PageOptions|CenterHorizontal=True|CenterVertical=True|PrintScale=1.00|XCorrection=1.00|YCorrection=1.00|PrintKind=1|BorderSize=5000000|LeftOffset=0|BottomOffset=0|Orientation=2|PaperLength=1000|PaperWidth=1000|Scale=100|PaperSource=7|PrintQuality=-3|MediaType=1|DitherType=10|PrintScaleMode=1|PaperKind=A4|PaperIndex=9
[OutputGroup4] [OutputGroup4]
Name=Assembly Outputs Name=Assembly Outputs