diff --git a/docs/uDCCD_Controller_R9V1_Schematic.PDF b/docs/uDCCD_Controller_R9V1_Schematic.PDF new file mode 100644 index 0000000..3d8c63f Binary files /dev/null and b/docs/uDCCD_Controller_R9V1_Schematic.PDF differ diff --git a/firmware/src/board/ain.cpp b/firmware/src/board/ain.cpp new file mode 100644 index 0000000..ab87212 --- /dev/null +++ b/firmware/src/board/ain.cpp @@ -0,0 +1,35 @@ +/**** Includes ****/ +#include "../utils/utils.h" +#include "mcu/mcu_hal.h" +#include "ain.h" + +using namespace board; + +/**** Private definitions ****/ +/**** Private constants ****/ +/**** Private variables ****/ +/**** Private function declarations ****/ + +/**** Public function definitions ****/ +board::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 board::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 ****/ + diff --git a/firmware/src/board/ain.h b/firmware/src/board/ain.h new file mode 100644 index 0000000..55809da --- /dev/null +++ b/firmware/src/board/ain.h @@ -0,0 +1,37 @@ +#ifndef ANALOG_IN_H_ +#define ANALOG_IN_H_ + +/**** Includes ****/ +#include + +namespace board { + +/**** 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_ */ \ No newline at end of file diff --git a/firmware/src/board/dio.cpp b/firmware/src/board/dio.cpp new file mode 100644 index 0000000..c70f4d0 --- /dev/null +++ b/firmware/src/board/dio.cpp @@ -0,0 +1,72 @@ +/**** Includes ****/ +#include "../utils/utils.h" +#include "mcu/mcu_hal.h" +#include "dio.h" + +using namespace board; + +/**** Private definitions ****/ +/**** Private constants ****/ +/**** Private variables ****/ +/**** Private function declarations ****/ + +/**** Public function definitions ****/ +board::DigitalIO::DigitalIO(uint8_t gpio_ch, uint8_t init_read) +{ + this->gpio_ch = gpio_ch; + + if(init_read) this->last_read = (uint8_t)DIO_HIGH; + else this->last_read = (uint8_t)DIO_LOW; + + this->write(DIO_HIZ); +} + +board::DigitalIO::~DigitalIO(void) +{ + this->write(DIO_HIZ); +} + +uint8_t board::DigitalIO::read(void) +{ + uint8_t lvl = mcu::gpio_read(this->gpio_ch); + if(lvl>0) this->last_read = (uint8_t)DIO_HIGH; + else this->last_read = (uint8_t)DIO_LOW; + + return this->last_read; +} + +void board::DigitalIO::write(int8_t level) +{ + if(level > 0) + { + this->last_set = DIO_HIGH; + mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIGH); + } + else if(level < 0) + { + this->last_set = DIO_HIZ; + mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIZ); + } + else + { + this->last_set = DIO_LOW; + mcu::gpio_write(this->gpio_ch, mcu::LEVEL_LOW); + } +} + +uint8_t board::DigitalIO::is_io_match(void) +{ + if(this->last_set == DIO_HIZ) return 1; + + uint8_t read_lvl = this->read(); + + if(read_lvl == (uint8_t)this->last_set) return 1; + else return 0; +} + +int8_t board::DigitalIO::get_set_level(void) +{ + return this->last_set; +} + +/**** Private function definitions ****/ diff --git a/firmware/src/board/dio.h b/firmware/src/board/dio.h new file mode 100644 index 0000000..96585f4 --- /dev/null +++ b/firmware/src/board/dio.h @@ -0,0 +1,39 @@ +#ifndef DIGITAL_OUT_H_ +#define DIGITAL_OUT_H_ + +/**** Includes ****/ +#include + +namespace board { + +/**** Public definitions ****/ +const int8_t DIO_LOW = 0; +const int8_t DIO_HIGH = 1; +const int8_t DIO_HIZ = -1; + +class DigitalIO +{ + protected: + uint8_t gpio_ch; + int8_t last_set; + + public: + DigitalIO(uint8_t gpio_ch, uint8_t init_read); + ~DigitalIO(void); + + uint8_t last_read; + + uint8_t read(void); + void write(int8_t level); + uint8_t is_io_match(void); + int8_t get_set_level(void); +}; + +/**** Public function declarations ****/ + +#ifdef TESTING +#endif + +} //namespace + +#endif /* DIGITAL_OUT_H_ */ \ No newline at end of file diff --git a/firmware/src/board/halfbridge.cpp b/firmware/src/board/halfbridge.cpp new file mode 100644 index 0000000..6ede670 --- /dev/null +++ b/firmware/src/board/halfbridge.cpp @@ -0,0 +1,68 @@ +/**** Includes ****/ +#include "../utils/utils.h" +#include "mcu/mcu_hal.h" +#include "halfbridge.h" + +using namespace board; + +/**** Private definitions ****/ +/**** Private constants ****/ +/**** Private variables ****/ +/**** Private function declarations ****/ + +/**** Public function definitions ****/ +board::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) this->max_dc = 100; + else this->max_dc = max_dc; + this->disable(); +} + +board::Hafbridge::~Hafbridge(void) +{ + this->last_duty = 0; + this->disable(); +} + +void board::Hafbridge::write(uint8_t duty) +{ + // Limit duty + if(duty > this->max_dc) duty = this->max_dc; + this->last_duty = duty; + + if(this->enabled == 0) return; + + // Convert percent to 16b duty cycle + uint16_t dc = util::percent_to_16b(duty); + // Set PWM + mcu::pwm_write(this->pwm_ch, dc); +} + +void board::Hafbridge::enable(void) +{ + mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIGH); + this->enabled = 1; + this->write(this->last_duty); +} + +void board::Hafbridge::disable(void) +{ + mcu::pwm_write(this->pwm_ch, 0); + mcu::gpio_write(this->gpio_ch, mcu::LEVEL_LOW); + this->enabled = 0; +} + +uint8_t board::Hafbridge::get_set_duty(void) +{ + return this->last_duty; +} + +uint8_t board::Hafbridge::is_enabled(void) +{ + return this->enabled; +} + +/**** Private function definitions ****/ diff --git a/firmware/src/board/halfbridge.h b/firmware/src/board/halfbridge.h new file mode 100644 index 0000000..ef6414f --- /dev/null +++ b/firmware/src/board/halfbridge.h @@ -0,0 +1,37 @@ +#ifndef HALFBRIDGE_H_ +#define HALFBRIDGE_H_ + +/**** Includes ****/ +#include + +namespace board { + +/**** Public definitions ****/ +class Hafbridge +{ + protected: + uint8_t pwm_ch; + uint8_t gpio_ch; + uint8_t last_duty; + uint8_t enabled; + uint8_t max_dc; + + public: + Hafbridge(uint8_t hs_pwm_ch, uint8_t ls_gpio_ch, uint8_t max_dc); + ~Hafbridge(void); + + void write(uint8_t duty); + 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_ */ \ No newline at end of file diff --git a/firmware/src/board/hvdin.cpp b/firmware/src/board/hvdin.cpp new file mode 100644 index 0000000..8757efd --- /dev/null +++ b/firmware/src/board/hvdin.cpp @@ -0,0 +1,37 @@ +/**** Includes ****/ +#include "../utils/utils.h" +#include "mcu/mcu_hal.h" +#include "hvdin.h" + +using namespace board; + +/**** Private definitions ****/ +/**** Private constants ****/ +/**** Private variables ****/ +/**** Private function declarations ****/ + +/**** Public function definitions ****/ +board::HVDigitalIn::HVDigitalIn(uint8_t gpio_ch, uint8_t init_read) +{ + this->gpio_ch = gpio_ch; + + if(init_read) this->last_read = HVDIN_HIGH; + else this->last_read = HVDIN_LOW; +} + +board::HVDigitalIn::~HVDigitalIn(void) +{ + return; +} + +uint8_t board::HVDigitalIn::read(void) +{ + // Auto inverts level to match board external connectors + uint8_t lvl = mcu::gpio_read(this->gpio_ch); + if(lvl>0) this->last_read = HVDIN_LOW; + else this->last_read = HVDIN_HIGH; + + return this->last_read; +} + +/**** Private function definitions ****/ diff --git a/firmware/src/board/hvdin.h b/firmware/src/board/hvdin.h new file mode 100644 index 0000000..b0e6244 --- /dev/null +++ b/firmware/src/board/hvdin.h @@ -0,0 +1,34 @@ +#ifndef HV_DIN_H_ +#define HV_DIN_H_ + +/**** Includes ****/ +#include + +namespace board { + +/**** Public definitions ****/ +const uint8_t HVDIN_LOW = 0; +const uint8_t HVDIN_HIGH = 1; + +class HVDigitalIn +{ + protected: + uint8_t gpio_ch; + + public: + HVDigitalIn(uint8_t gpio_ch, uint8_t init_read); + ~HVDigitalIn(void); + + uint8_t last_read; + + uint8_t read(void); +}; + +/**** Public function declarations ****/ + +#ifdef TESTING +#endif + +} //namespace + +#endif /* HV_DIN_H_ */ \ No newline at end of file diff --git a/firmware/src/board/mcu/mcu_hal.h b/firmware/src/board/mcu/mcu_hal.h new file mode 100644 index 0000000..42a6495 --- /dev/null +++ b/firmware/src/board/mcu/mcu_hal.h @@ -0,0 +1,125 @@ +#ifndef MCU_HAL_H_ +#define MCU_HAL_H_ + +/**** Includes ****/ +#include + +namespace mcu { + +/**** 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 +*/ + +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_ */ diff --git a/firmware/src/board/mcu/mcu_hal_r8.cpp b/firmware/src/board/mcu/mcu_hal_r8.cpp new file mode 100644 index 0000000..6b2d1de --- /dev/null +++ b/firmware/src/board/mcu/mcu_hal_r8.cpp @@ -0,0 +1,464 @@ +/**** Includes ****/ +#include +#include +#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; + } +} diff --git a/firmware/src/board/od_com.cpp b/firmware/src/board/od_com.cpp new file mode 100644 index 0000000..634b622 --- /dev/null +++ b/firmware/src/board/od_com.cpp @@ -0,0 +1,40 @@ +/**** Includes ****/ +#include "../utils/utils.h" +#include "mcu/mcu_hal.h" +#include "od_com.h" + +using namespace board; + +/**** Private definitions ****/ +/**** Private constants ****/ +/**** Private variables ****/ +/**** Private function declarations ****/ + +/**** Public function definitions ****/ +board::ODCommon::ODCommon(uint8_t pwm_ch) +{ + this->pwm_ch = pwm_ch; + this->write(0); +} + +board::ODCommon::~ODCommon(void) +{ + this->write(0); +} + +void board::ODCommon::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 board::ODCommon::get_set_duty(void) +{ + return this->last_duty; +} + +/**** Private function definitions ****/ diff --git a/firmware/src/board/od_com.h b/firmware/src/board/od_com.h new file mode 100644 index 0000000..f9fa3cd --- /dev/null +++ b/firmware/src/board/od_com.h @@ -0,0 +1,31 @@ +#ifndef OD_COMMON_H_ +#define OD_COMMON_H_ + +/**** Includes ****/ +#include + +namespace board { + +/**** Public definitions ****/ +class ODCommon +{ + protected: + uint8_t pwm_ch; + uint8_t last_duty; + + public: + ODCommon(uint8_t pwm_ch); + ~ODCommon(void); + + void write(uint8_t duty); + uint8_t get_set_duty(void); +}; + +/**** Public function declarations ****/ + +#ifdef TESTING +#endif + +} //namespace + +#endif /* OD_COMMON_H_ */ \ No newline at end of file diff --git a/firmware/src/board/odout.cpp b/firmware/src/board/odout.cpp new file mode 100644 index 0000000..a933e4b --- /dev/null +++ b/firmware/src/board/odout.cpp @@ -0,0 +1,44 @@ +/**** Includes ****/ +#include "../utils/utils.h" +#include "mcu/mcu_hal.h" +#include "odout.h" + +using namespace board; + +/**** Private definitions ****/ +/**** Private constants ****/ +/**** Private variables ****/ +/**** Private function declarations ****/ + +/**** Public function definitions ****/ +board::OpenDrainOut::OpenDrainOut(uint8_t gpio_ch) +{ + this->gpio_ch = gpio_ch; + this->write(OD_OFF); +} + +board::OpenDrainOut::~OpenDrainOut(void) +{ + this->write(OD_OFF); +} + +void board::OpenDrainOut::write(uint8_t state) +{ + if(state) + { + mcu::gpio_write(this->gpio_ch, mcu::LEVEL_HIGH); + this->last_set = OD_ON; + } + else + { + mcu::gpio_write(this->gpio_ch, mcu::LEVEL_LOW); + this->last_set = OD_OFF; + } +} + +uint8_t board::OpenDrainOut::get_set_state(void) +{ + return this->last_set; +} + +/**** Private function definitions ****/ diff --git a/firmware/src/board/odout.h b/firmware/src/board/odout.h new file mode 100644 index 0000000..3e6b80e --- /dev/null +++ b/firmware/src/board/odout.h @@ -0,0 +1,34 @@ +#ifndef OD_OUT_H_ +#define OD_OUT_H_ + +/**** Includes ****/ +#include + +namespace board { + +/**** Public definitions ****/ +const uint8_t OD_OFF = 0; +const uint8_t OD_ON = 1; + +class OpenDrainOut +{ + protected: + uint8_t gpio_ch; + uint8_t last_set; + + public: + OpenDrainOut(uint8_t gpio_ch); + ~OpenDrainOut(void); + + void write(uint8_t state); + uint8_t get_set_state(void); +}; + +/**** Public function declarations ****/ + +#ifdef TESTING +#endif + +} //namespace + +#endif /* OD_OUT_H_ */ \ No newline at end of file diff --git a/firmware/src/hw/mcu/mcu_hal.h b/firmware/src/hw/mcu/mcu_hal.h deleted file mode 100644 index 468975b..0000000 --- a/firmware/src/hw/mcu/mcu_hal.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef UDCCD_R8_BSP_H_ -#define UDCCD_R8_BSP_H_ - -/**** Includes ****/ -#include -#include "../common/level.h" - -/**** Public definitions ****/ -//ADC definitions -typedef enum { - ADC_ICOIL = 0x00, - ADC_UCOIL = 0x01, - ADC_UBAT = 0x02, - ADC_IBAT = 0x03, - ADC_POT = 0x04, - ADC_MODE = 0x05, - ADC_TEMP = 0x08, - ADC_INTREF = 0x0E, - ADC_GND = 0x0F -} adcCh_t; - -typedef enum { - ADC_DIV2 = 0x01, - ADC_DIV4 = 0x02, - ADC_DIV8 = 0x03, - ADC_DIV16 = 0x04, - ADC_DIV32 = 0x05, - ADC_DIV64 = 0x06, - ADC_DIV128 = 0x07 -} adcDiv_t; - -//Timer definitions -typedef enum { - TIM_DIV1 = 0x01, - TIM_DIV8 = 0x02, - TIM_DIV64 = 0x03, - TIM_DIV256 = 0x04, - TIM_DIV1024 = 0x05 -} timerDiv_t; - -typedef enum { - PWM_COIL = 'A', - PWM_LED = 'B' -} pwmCh_t; - -typedef enum { - SPEED_1 = 3, - SPEED_0 = 4 -} speedCh_t; - -typedef struct { - adcDiv_t adc_clk_prescaler; - uint8_t adc_auto_wake; - timerDiv_t pwm_timer_prescaler; - uint16_t pwm_timer_top; - timerDiv_t freq_timer_prescaler; - uint16_t uart_prescaler; - uint8_t systick_timer_top; - timerDiv_t systick_timer_prescaler; - uint8_t disable_unused; - uint8_t en_watchdog; -} hwConfig_t; - -/**** Public function declarations ****/ -void HAL_Init_Min(hwConfig_t* hwCfg); -void HAL_Init_Extra(hwConfig_t* hwCfg); - -level_t HAL_ReadLvl_Handbrake(void); -level_t HAL_ReadLvl_Brake(void); -level_t HAL_ReadLvl_Dimm(void); -level_t HAL_ReadLvl_BtnUp(void); -level_t HAL_ReadLvl_BtnDown(void); -level_t HAL_ReadLvl_BtnMode(void); -level_t HAL_ReadLvl_HandbrakePull(void); -level_t HAL_ReadLvl_CoilLow(void); -level_t HAL_ReadLvl_CoilHigh(void); -level_t HAL_ReadLvl_LedsPwm(void); -level_t HAL_ReadLvl_Speed0(void); -level_t HAL_ReadLvl_Speed1(void); -level_t HAL_ReadLvl_SpeedPull(void); - -void HAL_SetPull_Handbrake(level_t lvl); -void HAL_SetPull_Speed(level_t lvl); - -void HAL_ADC_Wake(void); -void HAL_ADC_Sleep(void); -uint16_t HAL_ADC_Read(adcCh_t ch); - -void HAL_Coil_SetLowSide(uint8_t on); -void HAL_Coil_SetPWM(uint8_t percent); -void HAL_Coil_SetPWM16b(uint16_t value); - -void HAL_LEDS_Set(uint8_t image); -uint8_t HAL_LEDS_Get(void); -void HAL_LEDS_SetPWM(uint8_t percent); - -void HAL_PWM_Wake(void); -void HAL_PWM_Sleep(void); -void HAL_PWM_SetDuty16b(pwmCh_t ch, uint16_t value); -void HAL_PWM_SetDuty100(pwmCh_t ch, uint8_t percent); - -#endif /* UDCCD_R8_BSP_H_ */ diff --git a/firmware/src/hw/mcu/mcu_r8_hal.cpp b/firmware/src/hw/mcu/mcu_r8_hal.cpp deleted file mode 100644 index fb28bcb..0000000 --- a/firmware/src/hw/mcu/mcu_r8_hal.cpp +++ /dev/null @@ -1,463 +0,0 @@ -/**** Includes ****/ -#include -#include "udccd_hal.h" - -/**** Private variables ****/ -static uint8_t tim0_prescaler = 0x00; -static uint8_t tim1_prescaler = 0x00; -static uint8_t tim3_prescaler = 0x00; -static uint8_t tim4_prescaler = 0x00; - -/**** Private function declarations ****/ -static void PWM_SetOCx(pwmCh_t ch, uint16_t value); - -/**** Public function definitions ****/ -void HAL_Init_Min(hwConfig_t* hwCfg) -{ - // PIN Configuration - //DCCD Enable and PWM - PORTB &= ~0x03; //Set low - DDRB |= 0x03; //Set as outputs - - //LED PWM - PORTB &= ~0x04; //Set low - DDRB |= 0x04; //Set as output - - //UART TX - PORTB |= 0x18; //Set high / pull-up on - DDRB |= 0x08; //Set as output - DDRB &= ~0x10; //Set as input - - //Handbrake pull-up - PORTB |= 0x20; //Set high - DDRB |= 0x20; //Set as output - - //Handbrake and Brake inputs - PORTB |= 0xC0; //Pull-up on - DDRB &= ~0xC0; //Set as input - - // ADC inputs - PORTC &= ~0x3F; //Pull-up off - DDRC &= ~0x3F; //Set as inputs - - // Reset - PORTC |= 0x40; //Pull-up on - DDRC &= ~0x40; //Set as input - - // LED control - PORTD &= ~0x3F; //Set low - DDRD |= 0x3F; //Set as outputs - - // Speed pull - PORTD &= ~0x40; //Set low - DDRD |= 0x40; //Set as outputs - - // Dim input - PORTD |= 0x80; //Set pull-up on - DDRD &= ~0x80; //Set as input - - // Speed inputs - PORTE &= ~0x05; //Set pull-down - DDRE |= 0x05; //Set as output - - // Up/Down inputs - PORTE |= 0x0A; //Set pull-up on - DDRE &= ~0x0A; //Set as input - - - //ADC configuration - PRR0 &= ~0x01; //Enable ADC power - DIDR0 |= 0x1F; //Disable digital inputs, ADC0-ADC4 - - ADMUX = 0x40; //Set AVCC reference, Right adjust - ADCSRA = 0x00; //ADC Disabled, Single conversion, no IT - ADCSRA |= (uint8_t)hwCfg->adc_clk_prescaler; - ADCSRB = 0x00; //no trigger input - - if(hwCfg->adc_auto_wake) ADCSRA |= 0x80; //Enable ADC - else PRR0 |= 0x01; - - - //DCCD and LED PWM configuration - PRR0 &= ~0x80; //Enable Timer1 power - TCCR1A = 0xF2; //Connect OC1A and OC1B, normal logic - TCCR1B = 0x18; //PWM, Phase & Frequency Correct ICR1 top, no clock, WGM:0xE - TCCR1C = 0x00; - TCNT1 = 0x0000; - OCR1A = 0x0000; - OCR1B = 0x0000; - ICR1 = (hwCfg->pwm_timer_top); - TIMSK1 = 0x00; //No interrupts - TIFR1 = 0x00; //Clear all flags - - tim1_prescaler = (uint8_t)hwCfg->pwm_timer_prescaler; - TCCR1B |= tim1_prescaler; //Enable timer -} - -void HAL_Init_Extra(hwConfig_t* hwCfg) -{ - //Speed 1 input timer configuration - PRR1 &= ~0x01; //Enable Timer3 power - TCCR3A = 0x00; //OCx disconnected, WGM:0x0 - TCCR3B = 0x80; //ICP Noise filter, Falling edge, no clock - TCCR3C = 0x00; - TCNT3 = 0x0000; - OCR3A = 0x0000; - OCR3B = 0x0000; - ICR3 = 0x0000; - TIMSK3 = 0x00; - //TIMSK3 |= 0x21; //ICP and OVF interrupts - TIFR3 = 0x00; //Clear all flags - - tim3_prescaler = (uint8_t)hwCfg->freq_timer_prescaler; - TCCR3B |= tim3_prescaler; //Enable timer - - - //Speed 0 input timer configuration - PRR1 &= ~0x08; //Enable Timer4 power - TCCR4A = 0x00; //OCx disconnected, WGM:0x0 - TCCR4B = 0x80; //ICP Noise filter, Falling edge, no clock - TCCR4C = 0x00; - TCNT4 = 0x0000; - OCR4A = 0x0000; - OCR4B = 0x0000; - ICR4 = 0x0000; - TIMSK4 = 0x00; - //TIMSK4 |= 0x21; //ICP and OVF interrupts - TIFR4 = 0x00; //Clear all flags - - tim4_prescaler = (uint8_t)hwCfg->freq_timer_prescaler; - TCCR4B |= tim4_prescaler; //Enable timer - - - //UART1 configuration - PRR0 &= 0x10; //Enable UART1 power - UCSR1A = 0x00; //Clear flags, Single UART speed, Single processor mode - UCSR1B = 0x18; //Enable RX/TX hardware, 8bit char - //UCSR1B |= 0xC0; //Enable RX/TX interrupt, - UCSR1C = 0x06; ; //async, No parity, 1 stop bit, 8bit char, - UBRR1 = hwCfg->uart_prescaler; //UART baud rate select - - - //"Systick" timer configuration - PRR0 &= ~0x20; //Enable Timer0 power - TCCR0A = 0x02 ;//OC0x not connected, WGM 0x01-CTC OC0A TOP - TCCR0B = 0x00; //WGM 0x01-CTC, No clock - TIMSK0 = 0x00; - //TIMSK0 |= 0x01; //OVF interrupt enabled - TCNT0 = 0x00; - OCR0A = hwCfg->systick_timer_top; - OCR0B= 0x00; - TIFR0 = 0x00; //Reset all flags - - tim0_prescaler = (uint8_t)hwCfg->systick_timer_prescaler; - TCCR0B |= tim0_prescaler; - - - //Disabled not used power configuration - if(hwCfg->disable_unused) - { - //Disable power to not used peripherals - PRR0 |= 0xC6; //Disable TWI0, TIM2, SPI0, UART0 - PRR1 |= 0x34; //Disable TWI1, PRTC, SPI1 - } - - //Watchdog configuration - if(hwCfg->en_watchdog) - { - //watchdog timer setup - WDTCSR |= 0x10; //Change enable - WDTCSR |= 0x0D; //System reset mode, 0.5s period. - //use special instruction to reset watchdog timer - }; -} - - -// Handbrake input -level_t HAL_ReadLvl_Handbrake(void) -{ - if(PINB & 0x40) return HIGH; - else return LOW; -} - -// Brakes input -level_t HAL_ReadLvl_Brake(void) -{ - if(PINB & 0x80) return HIGH; - else return LOW; -} - -// Dimm input -level_t HAL_ReadLvl_Dimm(void) -{ - if(PIND & 0x80) return HIGH; - else return LOW; -} - -// UP button -level_t HAL_ReadLvl_BtnUp(void) -{ - if(PINE & 0x08) return HIGH; - else return LOW; -} - -// Down button -level_t HAL_ReadLvl_BtnDown(void) -{ - if(PINE & 0x02) return HIGH; - else return LOW; -} - -// Mode button -level_t HAL_ReadLvl_BtnMode(void) -{ - if(PINC & 0x20) return HIGH; - else return LOW; -} - -// Handbrake pull -level_t HAL_ReadLvl_HandbrakePull(void) -{ - if(PINB & 0x20) return HIGH; - else return LOW; -} - -// Coil driver control low -level_t HAL_ReadLvl_CoilLow(void) -{ - if(PINB & 0x01) return HIGH; - else return LOW; -} - -// Coil driver control high -level_t HAL_ReadLvl_CoilHigh(void) -{ - if(PINB & 0x02) return HIGH; - else return LOW; -} - -// LED PWM control -level_t HAL_ReadLvl_LedsPwm(void) -{ - if(PINB & 0x04) return HIGH; - else return LOW; -} - -// Speed 0 input pin -level_t HAL_ReadLvl_Speed0(void) -{ - if(PINE & 0x04) return HIGH; - else return LOW; -} - -// Speed 1 input pin -level_t HAL_ReadLvl_Speed1(void) -{ - if(PINE & 0x01) return HIGH; - else return LOW; -} - -// Speed common pull pin -level_t HAL_ReadLvl_SpeedPull(void) -{ - if(PIND & 0x40) return HIGH; - else return LOW; -} - - -// Set handbrake pull-up -void HAL_SetPull_Handbrake(level_t lvl) -{ - switch(lvl) - { - case HIGH: - PORTB |= 0x20; //Set high - DDRB |= 0x20; //Set as output - break; - - case LOW: - PORTB &= ~0x20; //Set low - DDRB |= 0x20; //Set as output - - default: - DDRB &= ~0x20; //Set as input - PORTB |= 0x20; //Set high - break; - } -} - -// Set speed inputs common pull -void HAL_SetPull_Speed(level_t lvl) -{ - switch(lvl) - { - case HIGH: - PORTD |= 0x40; //Set high - break; - - default: - PORTD &= ~0x40; //Set low - break; - } -} - - -// ADC Wake -void HAL_ADC_Wake(void) -{ - //Enable ADC power - PRR0 &= ~0x01; - //Enable ADC - ADCSRA |= 0x80; -} - -// ADC Sleep -void HAL_ADC_Sleep(void) -{ - //wait to finish - while(ADCSRA&0x40); - //Disable ADC - ADCSRA &= ~0x80; - //Disable ADC power - PRR0 |= 0x01; -} - -// ADC Read -uint16_t HAL_ADC_Read(adcCh_t ch) -{ - //check if ADC is enabled - if(!(ADCSRA&0x80)) return 0xFFFF; - - uint8_t mux = (uint8_t)ch; - //Safe guard mux - if(mux > 15) return 0xFFFF; - // Not available channels - if((mux > 8) && (mux<14)) return 0xFFFF; - - ADMUX &= ~0x0F; - ADMUX |= mux; - ADCSRA |= 0x40; - while(ADCSRA&0x40); //wait to finish - return ADC; -} - - -// Coil Driver Low Side control -void HAL_Coil_SetLowSide(uint8_t on) -{ - if(on) PORTB |= 0x01; - else PORTB &= ~0x01; -} - -void HAL_Coil_SetPWM(uint8_t percent) -{ - HAL_PWM_SetDuty100(PWM_COIL, percent); -} - -void HAL_Coil_SetPWM16b(uint16_t value) -{ - HAL_PWM_SetDuty16b(PWM_COIL, value); -} - - -// LED Display -void HAL_LEDS_Set(uint8_t image) -{ - //Read current PORTD pin6, pin7 - uint8_t keep = PORTD & 0xC0; - - //Safe guard display - image &= 0x3F; - - //Calculate new PORTD - keep |= image; - - //Set PORTD - PORTD = keep; -} - -uint8_t HAL_LEDS_Get(void) -{ - return (PIND & 0x3F); -} - -void HAL_LEDS_SetPWM(uint8_t percent) -{ - HAL_PWM_SetDuty100(PWM_LED, percent); -} - - -// PWM Direct functions -void HAL_PWM_Wake(void) -{ - //Enable Timer1 power - PRR0 &= ~0x80; - //Prepare Timer1 settings - TCNT1 = 0x0000; - OCR1A = 0x0000; - OCR1B = 0x0000; - //Enable clock - TCCR1B |= tim1_prescaler; //Enable timer -} - -void HAL_PWM_Sleep(void) -{ - // Turn off outputs - OCR1A = 0x0000; - OCR1B = 0x0000; - // Force timer to bottom - TCNT1 = (ICR1-1); - // Wait for outputs to be off - while((PINB&0x06)!=0x00) continue; - // Disable clock - TCCR1B &= ~0x07; - // Disable Timer1 power - PRR0 |= 0x80; -} - -void HAL_PWM_SetDuty16b(pwmCh_t ch, uint16_t value) -{ - value = 0xFFFF - value; - - uint32_t top = (uint32_t)ICR1; - uint32_t temp = (uint32_t)value * top; - temp = temp/0x0000FFFF; - //Limit temp - if(temp>0x0000FFFF) temp = 0x0000FFFF; - uint16_t ocrx = (uint16_t) temp; - - PWM_SetOCx(ch, ocrx); -} - -void HAL_PWM_SetDuty100(pwmCh_t ch, uint8_t percent) -{ - if(percent > 100) percent = 100; - percent = 100 - percent; - - uint32_t top = (uint32_t)ICR1; - uint32_t temp = (uint32_t)percent * top; - temp = temp/100; - //Limit temp - if(temp>0x0000FFFF) temp = 0x0000FFFF; - uint16_t ocrx = (uint16_t) temp; - - PWM_SetOCx(ch, ocrx); -} - -/**** Private function definitions ****/ -static void PWM_SetOCx(pwmCh_t ch, uint16_t value) -{ - switch(ch) - { - case PWM_COIL: - OCR1A = value; - return; - - case PWM_LED: - OCR1B = value; - return; - - default: - return; - } -} \ No newline at end of file diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index 77f92f9..16d5bba 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -1,18 +1,85 @@ -/* - * uDCCD.cpp - * - * Created: 12.03.2024 20:39:27 - * Author : User - */ +/**** Includes ****/ +#include "utils/utils.h" +#include "board/mcu/mcu_hal.h" +#include "board/ain.h" +#include "board/dio.h" +#include "board/hvdin.h" +#include "board/halfbridge.h" +#include "board/od_com.h" +#include "board/odout.h" -#include +/**** Private definitions ****/ +/**** Private constants ****/ +/**** Private variables ****/ +static board::AnalogIn dccd_i(mcu::ADC0); +static board::AnalogIn dccd_u(mcu::ADC1); +static board::AnalogIn bat_u(mcu::ADC2); +static board::AnalogIn bat_i(mcu::ADC3); +static board::AnalogIn ain1(mcu::ADC5); +static board::AnalogIn ain2(mcu::ADC4); +static board::DigitalIO din1(mcu::GPIO0, board::DIO_HIGH); +static board::DigitalIO din2(mcu::GPIO1, board::DIO_HIGH); +static board::DigitalIO din3(mcu::GPIO2, board::DIO_HIGH); +static board::DigitalIO din4(mcu::GPIO3, board::DIO_HIGH); + +static board::HVDigitalIn hvdin1(mcu::GPIO4, board::HVDIN_LOW); +static board::HVDigitalIn hvdin2(mcu::GPIO5, board::HVDIN_LOW); +static board::HVDigitalIn hvdin3(mcu::GPIO6, board::HVDIN_LOW); + +/**** Private function declarations ****/ +/**** Public function definitions ****/ int main(void) { - /* Replace with your application code */ - while (1) - { - } + 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); + + dccd_i.mul = 1; + dccd_i.div = 1; + dccd_i.offset = 0; + + dccd_u.mul = 1; + dccd_u.div = 1; + dccd_u.offset = 0; + + bat_u.mul = 1; + bat_u.div = 1; + bat_u.offset = 0; + + bat_i.mul = 1; + bat_i.div = 1; + bat_i.offset = 0; + + // Super loop + while(1) + { + 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(); + + continue; // End of super loop + } + + // Escape the matrix + return 0; } +/**** Private function definitions ***/ diff --git a/firmware/src/uDCCD.cppproj b/firmware/src/uDCCD.cppproj index de25ed8..327eb2a 100644 --- a/firmware/src/uDCCD.cppproj +++ b/firmware/src/uDCCD.cppproj @@ -30,132 +30,191 @@ - - - - - - - - - + + + + + + + + + - -mmcu=atmega328pb -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\gcc\dev\atmega328pb" - True - True - True - True - False - True - True - - - NDEBUG - - - - - %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ - - - Optimize for size (-Os) - True - True - True - True - True - - - NDEBUG - - - - - %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ - - - Optimize for size (-Os) - True - True - True - - - libm - - - - - %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ - - - + -mmcu=atmega328pb -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\gcc\dev\atmega328pb" + True + True + True + True + False + True + True + + + NDEBUG + + + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ + + + Optimize for size (-Os) + True + True + True + True + True + + + NDEBUG + + + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ + + + Optimize for size (-Os) + True + True + True + + + libm + + + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ + + + - -mmcu=atmega328pb -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\gcc\dev\atmega328pb" - True - True - True - True - False - True - True - - - DEBUG - - - - - %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ - - - Optimize debugging experience (-Og) - True - True - Default (-g2) - True - True - True - - - DEBUG - - - - - %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ - - - Optimize debugging experience (-Og) - True - True - Default (-g2) - True - - - libm - - - - - %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ - - - Default (-Wa,-g) - + -mmcu=atmega328pb -B "%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\gcc\dev\atmega328pb" + True + True + True + True + False + True + True + + + DEBUG + + + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ + + + Optimize debugging experience (-Og) + True + True + Default (-g2) + True + True + True + + + DEBUG + + + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ + + + Optimize debugging experience (-Og) + True + True + Default (-g2) + True + + + libm + + + + + %24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\ + + + Default (-Wa,-g) + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + compile + + compile + + + compile + + + compile + + + compile + + + + + + \ No newline at end of file diff --git a/firmware/src/utils/interpolate.cpp b/firmware/src/utils/interpolate.cpp new file mode 100644 index 0000000..fee0cfc --- /dev/null +++ b/firmware/src/utils/interpolate.cpp @@ -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 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 find_interval_end_index(uint16_t val, uint16_t* axis_values, uint8_t len_axis) +{ + for(uint8_t i=0; i + +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_ */ \ No newline at end of file diff --git a/firmware/src/utils/utils.cpp b/firmware/src/utils/utils.cpp new file mode 100644 index 0000000..fae8eda --- /dev/null +++ b/firmware/src/utils/utils.cpp @@ -0,0 +1,137 @@ +/**** 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; +} + +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; +} + +/**** Private function definitions ****/ \ No newline at end of file diff --git a/firmware/src/utils/utils.h b/firmware/src/utils/utils.h new file mode 100644 index 0000000..d411a15 --- /dev/null +++ b/firmware/src/utils/utils.h @@ -0,0 +1,38 @@ +#ifndef UTILS_H_ +#define UTILS_H_ + +/**** Includes ****/ +#include + +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); + +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); + +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_ */ \ No newline at end of file