1 Commits

Author SHA1 Message Date
ddf9d263b1 Legacy branch migration 2024-03-12 21:23:47 +02:00
61 changed files with 2656 additions and 2268 deletions

120
firmware/devices/analog.c Normal file
View File

@@ -0,0 +1,120 @@
/**** Includes ****/
#include "hal/udccd_hal.h"
#include "analog.h"
/**** Private variables ****/
static const uint8_t ICOIL_MUL = 215;
static const uint8_t ICOIL_DIV = 22;
static const int16_t ICOIL_OFF = 0;
static const uint8_t ICOIL_CNT = 1;
static const uint8_t UCOIL_MUL = 20;
static const uint8_t UCOIL_DIV = 1;
static const int16_t UCOIL_OFF = 0;
static const uint8_t UCOIL_CNT = 1;
static const uint8_t UBAT_MUL = 20;
static const uint8_t UBAT_DIV = 1;
static const int16_t UBAT_OFF = 0;
static const uint8_t UBAT_CNT = 1;
static const uint8_t IBAT_MUL = 235;
static const uint8_t IBAT_DIV = 6;
static const int16_t IBAT_OFF = 0;
static const uint8_t IBAT_CNT = 1;
static const uint8_t POT_MUL = 215;
static const uint8_t POT_DIV = 44;
static const int16_t POT_OFF = 0;
static const uint8_t POT_CNT = 1;
static const uint8_t MODE_MUL = 215;
static const uint8_t MODE_DIV = 44;
static const int16_t MODE_OFF = 0;
static const uint8_t MODE_CNT = 1;
/**** Private function declarations ****/
static uint16_t ConvertSIntShort(int32_t in);
static uint16_t ConvertUintShort(uint32_t in);
static uint16_t read_ch(adcCh_t ch, uint16_t gnd_raw, uint8_t mul, uint8_t div, int16_t offset, uint8_t samples);
/**** Public function definitions ****/
void Analog_UpdateAll(analog_t* meas)
{
uint16_t gnd_lvl = HAL_ADC_Read(ADC_GND);
meas->hb_currnet = read_ch(ADC_ICOIL, 0, ICOIL_MUL, ICOIL_DIV, ICOIL_OFF, ICOIL_CNT ); //mA
meas->hb_voltage = read_ch(ADC_UCOIL, 0, UCOIL_MUL, UCOIL_DIV, UCOIL_OFF, UCOIL_CNT ); //mV
meas->supply_current = read_ch(ADC_IBAT , 0, IBAT_MUL , IBAT_DIV , IBAT_OFF , IBAT_CNT ); //mA
meas->supply_voltage = read_ch(ADC_UBAT , 0, UBAT_MUL , UBAT_DIV , UBAT_OFF , UBAT_CNT ); //mV
meas->pot_voltage = read_ch(ADC_POT , 0, POT_MUL , POT_DIV , POT_OFF , POT_CNT ); //mV
meas->mode_voltage = read_ch(ADC_MODE , 0, MODE_MUL , MODE_DIV , MODE_OFF , MODE_CNT ); //mV
// Calculate derived measurements
// Halfbridge output power
uint32_t temp = (uint32_t)meas->hb_currnet * (uint32_t)meas->hb_voltage;
temp /= 1000;
meas->hb_power = ConvertUintShort(temp);
// Halfbridge output resistance
if(meas->hb_currnet == 0) meas->hb_resistance = 0xFFFF;
else if(meas->hb_voltage == 0) meas->hb_resistance = 0;
else
{
temp = (uint32_t)meas->hb_voltage * 1000;
temp /= (uint32_t)meas->hb_currnet;
meas->hb_resistance = ConvertUintShort(temp);
}
// Supply power
temp = (uint32_t)meas->supply_current * (uint32_t)meas->supply_voltage;
temp /= 1000;
meas->supply_power = ConvertUintShort(temp);
}
static uint16_t read_ch(adcCh_t ch, uint16_t gnd_raw, uint8_t mul, uint8_t div, int16_t offset, uint8_t samples)
{
//Sanity check
if(div==0) return 0xFFFF;
// Do at least one sample
if(samples<1) samples = 1;
// Read ADC value
int32_t raw = 0;
for(uint8_t i=0; i<samples; i++)
{
raw += (int32_t)HAL_ADC_Read(ch);
}
// Do average
if(samples != 1)
{
raw /= samples;
};
// Remove GND level
if(gnd_raw) raw = raw - (int32_t)gnd_raw;
// Convert to target units
raw = raw * mul;
if(div!=1) raw /= div;
raw += offset;
return ConvertSIntShort(raw);
}
static uint16_t ConvertSIntShort(int32_t in)
{
if(in <= 0) return 0;
else if(in >= 0x0000FFFF) return 0xFFFF;
else return (uint16_t)in;
}
static uint16_t ConvertUintShort(uint32_t in)
{
if(in == 0) return 0;
else if(in >= 0x0000FFFF) return 0xFFFF;
else return (uint16_t)in;
}

23
firmware/devices/analog.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef ANALOG_H_
#define ANALOG_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
typedef struct {
uint16_t hb_currnet;
uint16_t hb_voltage;
uint16_t hb_power;
uint16_t hb_resistance;
uint16_t supply_current;
uint16_t supply_voltage;
uint16_t supply_power;
uint16_t pot_voltage;
uint16_t mode_voltage;
} analog_t;
/**** Public function declarations ****/
void Analog_UpdateAll(analog_t* meas);
#endif /* ANALOG_H_ */

View File

@@ -0,0 +1,11 @@
#ifndef LEVEL_T_H_
#define LEVEL_T_H_
/**** Public definitions ****/
typedef enum {
HIZ = -1,
LOW = 0,
HIGH = 1
} level_t;
#endif /* LEVEL_T_H_ */

24
firmware/devices/config.c Normal file
View File

@@ -0,0 +1,24 @@
/**** Includes ****/
#include "hal/udccd_hal.h"
#include "config.h"
/**** Public function definitions ****/
void Init_HW(void)
{
hwConfig_t hwCfg;
hwCfg.adc_clk_prescaler = ADC_DIV2;
hwCfg.adc_auto_wake = 1;
// 64kHz PWM
hwCfg.pwm_timer_prescaler = TIM_DIV1;
hwCfg.pwm_timer_top = 0x01FF;
// 1.9Hz..62.5kHz Speed input
hwCfg.freq_timer_prescaler = TIM_DIV64;
// 1kHz systick
hwCfg.systick_timer_top = 125;
hwCfg.systick_timer_prescaler = TIM_DIV64;
// No extra features
hwCfg.uart_prescaler = 0;
hwCfg.disable_unused = 0;
hwCfg.en_watchdog = 0;
HAL_Init_Min(&hwCfg);
}

10
firmware/devices/config.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef CONFIG_H_
#define CONFIG_H_
/**** Includes ****/
#include <stdint.h>
/**** Public function declarations ****/
void Init_HW(void);
#endif /* CONFIG_H_ */

View File

@@ -0,0 +1,21 @@
/**** Includes ****/
#include "filter_iir_lpf.h"
/**** Private variables ****/
/**** Public function definitions ****/
uint16_t LPF_Update(uint16_t new, uint16_t last, uint8_t strength)
{
if(strength==0) return new;
else if(strength==255) return last;
else
{
uint32_t temp = (uint32_t)last * strength;
temp += new * (255-strength);
temp /= 255;
//Limit to 16bits
if(temp > 0x0000FFFF) return 0xFFFF;
else return (uint16_t) temp;
}
}

View File

@@ -0,0 +1,10 @@
#ifndef FILTER_IIR_LPF_H_
#define FILTER_IIR_LPF_H_
/**** Includes ****/
#include <stdint.h>
/**** Public function declarations ****/
uint16_t LPF_Update(uint16_t new, uint16_t last, uint8_t strength);
#endif /* FILTER_IIR_LPF_H_ */

View File

@@ -0,0 +1,102 @@
#ifndef UDCCD_R8_BSP_H_
#define UDCCD_R8_BSP_H_
/**** Includes ****/
#include <stdint.h>
#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_ */

View File

@@ -0,0 +1,463 @@
/**** Includes ****/
#include <avr/io.h>
#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;
}
}

View File

@@ -0,0 +1,127 @@
/**** Includes ****/
#include "hal/udccd_hal.h"
#include "halfbridge.h"
/**** Private variables ****/
static const uint16_t min_dc = 3277; //5%
static const uint16_t max_dc = 62258; //95%
static uint16_t target = 0;
static uint8_t low_side_on = 1;
static uint16_t active_dc = 0;
static uint8_t is_en = 0;
/**** Private function declarations ****/
static uint16_t CalculateDuty16b(uint16_t target, uint16_t supply);
/**** Public function definitions ****/
void HB_SetTarget(uint16_t voltage)
{
target = voltage;
}
void HB_SetLowSide(uint8_t on)
{
low_side_on = on;
}
uint16_t HB_GetTarget(void)
{
return target;
}
void HB_UpdateOutput(uint16_t supply)
{
uint16_t temp_dc = CalculateDuty16b(target, supply);
HB_SetDirect(temp_dc);
}
void HB_SetDirect(uint16_t duty)
{
/// Limit duty cycle
if(duty > max_dc) active_dc = max_dc;
else if(duty < min_dc) active_dc = 0;
else active_dc = duty;
// Set duty cycle
if(!is_en) return;
HAL_Coil_SetLowSide(low_side_on);
HAL_Coil_SetPWM16b(active_dc);
}
uint8_t HB_IsLowOn(void)
{
if(HAL_ReadLvl_CoilLow() == HIGH) return 1;
else return 0;
}
void HB_Enable(void)
{
// Restore low side
if(low_side_on) HAL_Coil_SetLowSide(1);
// Restore duty cycle
HAL_Coil_SetPWM(active_dc);
is_en = 1;
}
void HB_Disable(void)
{
// Set 0 DC
HAL_Coil_SetPWM(0);
// Disable low side
HAL_Coil_SetLowSide(0);
is_en = 0;
}
uint8_t HB_IsEnabled(void)
{
if(is_en) return 1;
else return 0;
}
int8_t HB_IsOutputMatch(uint16_t fb_output_voltage, uint16_t limit)
{
// No fault if output not enabled
if(!is_en) return -1;
// Can't check voltage if low side is off
if(!low_side_on) return -1;
if(target==0)
{
// Output can be only 0
if(fb_output_voltage != 0) return 0;
else return 1;
};
// Calculate upper and lower bounds
uint16_t max = target + limit;
uint16_t min = target - limit;
//Sanity check
if(max < target) max = 0xFFFF;
if(min > target) min = 0;
//Do check
if((fb_output_voltage < min)||(fb_output_voltage > max)) return 0;
else return 1;
}
/**** Private function definitions ****/
static uint16_t CalculateDuty16b(uint16_t target, uint16_t supply)
{
if(target==0) return 0;
if(supply==0) return 0;
if(target > supply) return 0xFFFF;
// Calculate Duty cycle, in 16bit format
uint32_t temp = (uint32_t)target * 0x0000FFFF;
temp = temp / supply;
//Limit output to 16 bits
if(temp > 0x0000FFFF) return 0xFFFF;
else return (uint16_t)temp;
}

View File

@@ -0,0 +1,24 @@
#ifndef HALFBRIDGE_H_
#define HALFBRIDGE_H_
/**** Includes ****/
#include <stdint.h>
/**** Public function declarations ****/
void HB_UpdateOutput(uint16_t supply);
void HB_SetTarget(uint16_t voltage);
void HB_SetLowSide(uint8_t on);
void HB_SetDirect(uint16_t duty);
void HB_Enable(void);
void HB_Disable(void);
uint16_t HB_GetTarget(void);
uint8_t HB_IsLowOn(void);
uint8_t HB_IsEnabled(void);
int8_t HB_IsOutputMatch(uint16_t fb_output_voltage, uint16_t limit);
#endif /* HALFBRIDGE_H_ */

82
firmware/devices/inputs.c Normal file
View File

@@ -0,0 +1,82 @@
/**** Includes ****/
#include "hal/udccd_hal.h"
#include "inputs.h"
/**** Private definitions ****/
/**** Private variables ****/
static const uint8_t def_debounce_lim = 10;
/**** Private function declarations ****/
static void InitDefaultInput(inCh_t* inp);
static void ProcessInput(uint8_t read_lvl, inCh_t* inp);
/**** Public function definitions ****/
void Inputs_DefInit(inputs_t* inputs)
{
InitDefaultInput(&inputs->handbrake);
InitDefaultInput(&inputs->brakes);
InitDefaultInput(&inputs->dimm);
InitDefaultInput(&inputs->up);
InitDefaultInput(&inputs->down);
InitDefaultInput(&inputs->mode);
}
void Inputs_UpdateAll(inputs_t* inputs)
{
// Chassis inputs
ProcessInput(HAL_ReadLvl_Handbrake(), &inputs->handbrake);
ProcessInput(HAL_ReadLvl_Brake(), &inputs->brakes);
ProcessInput(HAL_ReadLvl_Dimm(), &inputs->dimm);
// User inputs
ProcessInput(HAL_ReadLvl_BtnUp(), &inputs->up);
ProcessInput(HAL_ReadLvl_BtnDown(), &inputs->down);
ProcessInput(HAL_ReadLvl_BtnMode(), &inputs->mode);
}
void Inputs_SetHanbrakePullUp(uint8_t on)
{
if(on) HAL_SetPull_Handbrake(HIGH);
else HAL_SetPull_Handbrake(HIZ);
}
/**** Private function definitions ****/
static void InitDefaultInput(inCh_t* inp)
{
inp->is_active = 0;
inp->is_new = 0;
inp->state_timer = 0;
inp->cfg.act_level = LOW;
inp->cfg.dbnc_treshold = def_debounce_lim;
inp->proc.level = LOW;
inp->proc.dbnc_counter = 0;
}
static void ProcessInput(uint8_t read_lvl, inCh_t* inp)
{
if(inp->state_timer < 0xFFFF) inp->state_timer++;
if(read_lvl != inp->proc.level)
{
//Debounce ongoing
inp->proc.dbnc_counter++;
if(inp->proc.dbnc_counter < inp->cfg.dbnc_treshold) return;
//Save level
inp->proc.level = read_lvl;
//Change state
if(inp->proc.level == inp->cfg.act_level) inp->is_active = 1;
else inp->is_active = 0;
// Update new flag
inp->is_new = 1;
// Reset state timer
inp->state_timer = 0;
return;
}
else
{
//Debounce failed
if(inp->proc.dbnc_counter) inp->proc.dbnc_counter = 0;
}
}

43
firmware/devices/inputs.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef INPUTS_H_
#define INPUTS_H_
/**** Includes ****/
#include <stdint.h>
#include "common/level.h"
/**** Public definitions ****/
typedef struct {
level_t act_level;
uint8_t dbnc_treshold;
} inChCfg_t;
typedef struct {
level_t level;
uint8_t dbnc_counter;
} inChRaw_t;
typedef struct {
uint8_t is_active;
uint8_t is_new;
uint16_t state_timer;
inChRaw_t proc;
inChCfg_t cfg;
} inCh_t;
typedef struct {
inCh_t handbrake;
inCh_t brakes;
inCh_t dimm;
inCh_t up;
inCh_t down;
inCh_t mode;
} inputs_t;
/**** Public function declarations ****/
void Inputs_DefInit(inputs_t* inputs);
void Inputs_UpdateAll(inputs_t* inputs);
void Inputs_SetHanbrakePullUp(uint8_t on);
#endif /* INPUTS_H_ */

View File

@@ -0,0 +1,20 @@
/**** Includes ****/
#include "hal/udccd_hal.h"
#include "led_display.h"
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
void LED_DSP_ShowImage(uint8_t image)
{
HAL_LEDS_Set(image);
}
void LED_DSP_SetBrightness(uint8_t percent)
{
HAL_LEDS_SetPWM(percent);
}
/**** Private function definitions ****/

View File

@@ -0,0 +1,13 @@
#ifndef LED_DISPLAY_H_
#define LED_DISPLAY_H_
/**** Includes ****/
#include <stdint.h>
/**** Public definitions ****/
/**** Public function declarations ****/
void LED_DSP_ShowImage(uint8_t image);
void LED_DSP_SetBrightness(uint8_t percent);
#endif /* LED_DISPLAY_H_ */

34
firmware/devices/memory.c Normal file
View File

@@ -0,0 +1,34 @@
/**** Includes ****/
#include <avr/eeprom.h>
#include "memory.h"
/**** Public function definitions ****/
uint8_t MEM_Read8b(uint8_t address)
{
return eeprom_read_byte((uint8_t*)address);
}
uint16_t MEM_Read16b(uint8_t address)
{
return eeprom_read_word((uint8_t*)address);
}
uint32_t MEM_Read32b(uint8_t address)
{
return eeprom_read_dword((uint8_t*)address);
}
void MEM_Write8b(uint8_t address, uint8_t value)
{
return eeprom_write_byte((uint8_t*)address, value);
}
void MEM_Write16b(uint8_t address, uint16_t value)
{
return eeprom_write_word((uint8_t*)address, value);
}
void MEM_Write32b(uint8_t address, uint32_t value)
{
return eeprom_write_dword((uint8_t*)address, value);
}

16
firmware/devices/memory.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef MEMORY_H_
#define MEMORY_H_
/**** Includes ****/
#include <stdint.h>
/**** Public function declarations ****/
uint8_t MEM_Read8b(uint8_t address);
uint16_t MEM_Read16b(uint8_t address);
uint32_t MEM_Read32b(uint8_t address);
void MEM_Write8b(uint8_t address, uint8_t value);
void MEM_Write16b(uint8_t address, uint16_t value);
void MEM_Write32b(uint8_t address, uint32_t value);
#endif /* MEMORY_H_ */

125
firmware/drivers/display.c Normal file
View File

@@ -0,0 +1,125 @@
/**** Includes ****/
#include "display.h"
/**** Private definitions ****/
/**** Private variables ****/
static uint8_t PWM_DIMM = 50;
static uint8_t PWM_BRIGTH = 100;
static uint8_t set_image = 0x00;
static uint16_t lock_timer = 0;
/**** Private function declarations ****/
static uint8_t ImageGen_Dot10(uint8_t percent);
static uint8_t ImageGen_Dot20(uint8_t percent);
static uint8_t ImageGen_Bar(uint8_t percent);
/**** Public function definitions ****/
void Display_CfgBacklight(uint8_t brigth, uint8_t dimm)
{
//Limit values
if(brigth>100) brigth = 100;
else if(brigth==0) brigth = 1;
if(dimm>100) dimm = 100;
else if(dimm==0) dimm = 1;
//Save values
PWM_BRIGTH = brigth;
PWM_DIMM = dimm;
}
void Display_SetImage(uint8_t image)
{
if(lock_timer) return;
set_image = image & 0x3F;
}
void Display_SetPercent(uint8_t value, dspStyle_t style)
{
switch(style)
{
case BAR:
Display_SetImage(ImageGen_Bar(value));
break;
case DOT10:
Display_SetImage(ImageGen_Dot10(value));
break;
default:
Display_SetImage(ImageGen_Dot20(value));
break;
}
}
void Display_SetScale(uint16_t value, uint16_t max_value ,dspStyle_t style)
{
//Convert value to percent
uint32_t temp = (uint32_t)value *100;
temp /= max_value;
//Limit value to 100 percent
uint8_t percent = 0;
if(temp >= 100) percent = 100;
else if(temp == 0) percent = 0;
else percent = (uint8_t)temp;
Display_SetPercent(percent, style);
}
void Display_SetLock(uint16_t time)
{
lock_timer = time;
}
void Display_Update(inputs_t* inputs)
{
// Brightness control
if(inputs->dimm.is_active) LED_DSP_SetBrightness(PWM_DIMM);
else LED_DSP_SetBrightness(PWM_BRIGTH);
if(lock_timer) lock_timer--;
// Set image
LED_DSP_ShowImage(set_image);
}
/**** Private function definitions ****/
static uint8_t ImageGen_Dot10(uint8_t percent)
{
if(percent<6) return 0x01;
else if(percent<16) return 0x03;
else if(percent<26) return 0x02;
else if(percent<36) return 0x06;
else if(percent<46) return 0x04;
else if(percent<56) return 0x0C;
else if(percent<66) return 0x08;
else if(percent<76) return 0x18;
else if(percent<86) return 0x10;
else if(percent<96) return 0x30;
else return 0x20;
}
static uint8_t ImageGen_Dot20(uint8_t percent)
{
if(percent<11) return 0x01;
else if(percent<31) return 0x02;
else if(percent<51) return 0x04;
else if(percent<71) return 0x08;
else if(percent<91) return 0x10;
else return 0x20;
}
static uint8_t ImageGen_Bar(uint8_t percent)
{
if(percent<11) return 0x01;
else if(percent<31) return 0x03;
else if(percent<51) return 0x07;
else if(percent<71) return 0x0F;
else if(percent<91) return 0x1F;
else return 0x3F;
}

View File

@@ -0,0 +1,27 @@
#ifndef DISPLAY_DRV_H_
#define DISPLAY_DRV_H_
/**** Includes ****/
#include <avr/io.h>
#include "../devices/led_display.h"
#include "../devices/inputs.h"
/**** Public definitions ****/
typedef enum {
DOT20,
DOT10,
BAR
} dspStyle_t;
/**** Public function declarations ****/
void Display_SetImage(uint8_t image);
void Display_SetPercent(uint8_t value, dspStyle_t style);
void Display_SetScale(uint16_t value, uint16_t max_value ,dspStyle_t style);
void Display_SetLock(uint16_t time);
void Display_Update(inputs_t* inputs);
void Display_CfgBacklight(uint8_t brigth, uint8_t dimm);
#endif /* DISPLAY_DRV_H_ */

341
firmware/drivers/output.c Normal file
View File

@@ -0,0 +1,341 @@
/**** Includes ****/
#include "output.h"
/**** Private definitions ****/
typedef struct {
uint8_t active;
uint8_t time;
} warn_t;
typedef struct {
warn_t supply_voltage;
warn_t supply_current;
warn_t supply_power;
warn_t output_voltage;
warn_t output_current;
warn_t output_power;
warn_t output_open;
warn_t output_short;
warn_t output_mismatch;
} warnings_t;
typedef struct {
uint8_t supply_uvlo;
uint8_t supply_ovp;
uint8_t supply_ocp;
uint8_t supply_opp;
uint8_t output_ovp;
uint8_t output_ocp;
uint8_t output_opp;
uint8_t output_open;
uint8_t output_short;
} faults_t;
/**** Private constants ****/
static const uint16_t LIM_SUPPLY_UVLO = 8000; //mV
static const uint16_t LIM_SUPPLY_OVP = 18000; //mV
static const uint16_t LIM_SUPPLY_OCP = 7000; //mA
static const uint16_t LIM_SUPPLY_OPP = 40000; //mW
static const uint16_t LIM_OUTPUT_OVP = 12000; //mV
static const uint16_t LIM_OUTPUT_OCP = 7000; //mA
static const uint16_t LIM_OUTPUT_OPP = 40000; //mW
static const uint16_t LIM_OUTPUT_OPEN = 40000; //mR
static const uint16_t LIM_OUTPUT_SHORT = 750; //mR
static const uint16_t LIM_OUTPUT_MATCH = 100; //mV
static const uint8_t OCP_WARNING_LIMIT = 10; //cycles
static const uint8_t SHORT_WARNING_LIMIT = 50; //cycles
static const uint16_t MAX_OUTPUT_VOLTAGE = 10000; //mV
static const uint16_t MIN_OUTPUT_VOLTAGE = 100; //mV
static const uint16_t COOLDOWN_TIME = 5000;
/**** Private variables ****/
static warnings_t warnings;
static faults_t faults;
static uint16_t target_output = 0;
static uint16_t adj_target = 0;
static int32_t hb_volt_sum = 0;
static uint8_t new_target = 1;
static uint8_t steady_state = 0;
static faultState_t fault_state = F_NONE;
static uint16_t cooldown_timer = 0;
static outState_t out_state = O_OFF;
/**** Private function declarations ****/
static void Process_Warnings(analog_t* meas);
static uint8_t Process_Faults(void);
static void ProcessWarningTime(warn_t* w);
static uint8_t isAnyFaultActive(faults_t* f);
static uint8_t isFaultWarningActive(warnings_t* w, faults_t* f);
static void ResetFaults(faults_t* f);
/**** Public function definitions ****/
void Output_Enable(void)
{
ResetFaults(&faults);
target_output = 0;
out_state = O_ACTIVE;
HB_SetTarget(0) ;
HB_SetLowSide(1);
HB_Enable();
}
void Output_Update(analog_t* meas)
{
Process_Warnings(meas);
// Convert Warnings to Faults
uint8_t active_fault = Process_Faults();
/// Ignore faults
active_fault = 0;
// Determine coil state
switch(out_state)
{
case O_ACTIVE:
if(active_fault)
{
// Disable output
HB_Disable();
out_state = O_FAULTED;
break;
};
//Do target adjustment logic
if(steady_state >= 10)
{
//Calculate average HB voltage
hb_volt_sum /= 11;
// Calculate feedback adjusted HB output
int32_t error = hb_volt_sum - (int32_t)target_output;
int32_t temp = (int32_t)adj_target - error;
// Limit to 16bits
if(temp<=0) adj_target = 0;
else if(temp >= 0x0000FFFF) adj_target = 0xFFFF;
else adj_target = (uint16_t)temp;
steady_state = 0;
hb_volt_sum = 0;
}
else
{
hb_volt_sum += meas->hb_voltage;
steady_state++;
}
// Closed loop or open loop target set
if(new_target)
{
// Set open-loop HB output
HB_SetTarget(target_output);
adj_target = target_output;
steady_state = 0;
new_target = 0;
hb_volt_sum = 0;
}
else
{
HB_SetTarget(adj_target);
}
// Update output
HB_UpdateOutput(meas->supply_voltage);
break;
case O_FAULTED:
if(!active_fault)
{
//Return to normal state
HB_Enable();
out_state = O_ACTIVE;
}
break;
default: //OFF
if(HB_IsEnabled()) HB_Disable();
break;
}
}
void Output_SetTarget(uint16_t voltage)
{
if(voltage > MAX_OUTPUT_VOLTAGE) voltage = MAX_OUTPUT_VOLTAGE;
else if((voltage > 0)&&(voltage < MIN_OUTPUT_VOLTAGE)) voltage = MIN_OUTPUT_VOLTAGE;
if(voltage != target_output) new_target = 1;
target_output = voltage;
}
outState_t Output_GetOutputState(void)
{
return out_state;
}
/**** Private function definitions ****/
static void Process_Warnings(analog_t* meas)
{
// Supply UVLO and OVP
if((meas->supply_voltage > LIM_SUPPLY_OVP)||(meas->supply_voltage < LIM_SUPPLY_UVLO)) warnings.supply_voltage.active = 1;
else warnings.supply_voltage.active = 0;
// Supply OCP
if(meas->supply_current > LIM_SUPPLY_OCP) warnings.supply_current.active = 1;
else warnings.supply_current.active = 0;
// Supply OPP
if(meas->supply_power > LIM_SUPPLY_OPP) warnings.supply_power.active = 1;
else warnings.supply_power.active = 0;
// Halfbridge output conditions
// Output Target mismatch
if(HB_IsOutputMatch(meas->hb_voltage, LIM_OUTPUT_MATCH) == 0) warnings.output_mismatch.active = 1;
else warnings.output_mismatch.active = 0;
// Output OCP
if((HB_IsLowOn())&&(meas->hb_currnet > LIM_OUTPUT_OCP)) warnings.output_current.active = 1;
else warnings.output_current.active = 0;
// Output OVP
if((HB_IsLowOn())&&(meas->hb_voltage > LIM_OUTPUT_OVP)) warnings.output_voltage.active = 1;
else warnings.output_voltage.active = 0;
// Output OPP
if((HB_IsEnabled())&&(meas->hb_power > LIM_OUTPUT_OPP)) warnings.output_power.active = 1;
else warnings.output_power.active = 0;
// Output Short
if((HB_IsEnabled())&&(meas->hb_resistance < LIM_OUTPUT_SHORT)) warnings.output_short.active = 1;
else warnings.output_short.active = 0;
// Output Open - Load loss
if((HB_IsEnabled())&&(meas->hb_resistance > LIM_OUTPUT_OPEN)) warnings.output_open.active = 1;
else warnings.output_open.active = 0;
ProcessWarningTime(&warnings.supply_voltage);
ProcessWarningTime(&warnings.supply_current);
ProcessWarningTime(&warnings.supply_power);
ProcessWarningTime(&warnings.output_mismatch);
ProcessWarningTime(&warnings.output_voltage);
ProcessWarningTime(&warnings.output_current);
ProcessWarningTime(&warnings.output_power);
ProcessWarningTime(&warnings.output_open);
ProcessWarningTime(&warnings.output_short);
}
static uint8_t Process_Faults(void)
{
// Check warnings to escalate to fault
// Supply OCP
if(warnings.supply_current.time > OCP_WARNING_LIMIT) faults.supply_ocp = 1;
// Output OCP
if(warnings.output_current.time > OCP_WARNING_LIMIT) faults.output_ocp = 1;
// Output short
if(warnings.output_short.time > SHORT_WARNING_LIMIT) faults.output_short = 1;
switch(fault_state)
{
case F_ACTIVE:
// Check if fault still active
if(!isFaultWarningActive(&warnings, &faults))
{
// Fault cause ended, go to cooldown
cooldown_timer = COOLDOWN_TIME;
fault_state = F_COOLDOWN;
};
break;
case F_COOLDOWN:
// Check if fault reoccurs
if(isFaultWarningActive(&warnings, &faults))
{
fault_state = F_ACTIVE;
break;
};
// Wait for cooldown timer, reset fault flags
if(cooldown_timer) cooldown_timer--;
else
{
ResetFaults(&faults);
fault_state = F_NONE;
}
break;
default: //NONE
// Check for new faults
if(isAnyFaultActive(&faults))
{
// Start fault process
fault_state = F_ACTIVE;
};
break;
}
if(fault_state != F_NONE) return 1;
else return 0;
}
static void ProcessWarningTime(warn_t* w)
{
if((w->active)&&(w->time < 0xFF)) w->time++;
else if(w->active == 0) w->time = 0;
}
static uint8_t isAnyFaultActive(faults_t* f)
{
if(f->supply_uvlo) return 1;
if(f->supply_ovp) return 1;
if(f->supply_ocp) return 1;
if(f->supply_opp) return 1;
if(f->output_ovp) return 1;
if(f->output_ocp) return 1;
if(f->output_opp) return 1;
if(f->output_open) return 1;
if(f->output_short) return 1;
return 0;
}
static uint8_t isFaultWarningActive(warnings_t* w, faults_t* f)
{
if((f->supply_uvlo) && (w->supply_voltage.active)) return 1;
if((f->supply_ovp) && (w->supply_voltage.active)) return 1;
if((f->supply_ocp) && (w->supply_current.active)) return 1;
if((f->supply_opp) && (w->supply_power.active) ) return 1;
if((f->output_ovp) && (w->output_voltage.active)) return 1;
if((f->output_ocp) && (w->output_current.active)) return 1;
if((f->output_opp) && (w->output_power.active) ) return 1;
if((f->output_open) && (w->output_open.active) ) return 1;
if((f->output_short) && (w->output_short.active) ) return 1;
return 0;
}
static void ResetFaults(faults_t* f)
{
f->supply_uvlo = 0;
f->supply_ovp = 0;
f->supply_ocp = 0;
f->supply_opp = 0;
f->output_ovp = 0;
f->output_ocp = 0;
f->output_opp = 0;
f->output_open = 0;
f->output_short = 0;
}

30
firmware/drivers/output.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef OUTPUT_DRV_H_
#define OUTPUT_DRV_H_
/**** Includes ****/
#include <avr/io.h>
#include "../devices/analog.h"
#include "../devices/halfbridge.h"
/**** Public definitions ****/
typedef enum {
F_NONE,
F_ACTIVE,
F_COOLDOWN
} faultState_t;
typedef enum {
O_OFF,
O_ACTIVE,
O_FAULTED
} outState_t;
/**** Public function declarations ****/
void Output_Enable(void);
void Output_Update(analog_t* meas);
void Output_SetTarget(uint16_t voltage);
outState_t Output_GetOutputState(void);
#endif /* OUTPUT_DRV_H_ */

127
firmware/logic/coil.c Normal file
View File

@@ -0,0 +1,127 @@
/**** Includes ****/
#include "coil.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
static uint16_t lock_current = 4500; //mA
static uint16_t min_current = 100; //mA
static uint16_t target_current = 0; //mA
static uint8_t new_target = 1;
static uint16_t adj_target_current = 0; //mA
static uint16_t target_voltage = 0; //mV
static uint8_t act_force = 0;
static uint16_t nominal_resitance = 1500; //mR
static int32_t sum_current = 0;
static uint8_t sum_cnt = 0;
/**** Private function declarations ****/
static uint16_t UpdateVoltage(uint16_t cur, uint16_t res);
/**** Public function definitions ****/
void Coil_SetLockCurrent(uint16_t lock_i)
{
lock_current = lock_i;
}
void Coil_SetTarget_Force(uint8_t force)
{
// Check if worth doing
if(force == act_force) return;
// Calculate new target current
act_force = force;
// Check simple answer
uint16_t new_current = 0;
if(force==0) new_current = 0;
else if(force >= 100) new_current = lock_current;
else
{
uint32_t temp = (uint32_t)force * lock_current;
temp /= 100;
if(temp > 0x0000FFFF) new_current = lock_current;
else new_current = (uint16_t) temp;
}
// Update new target
Coil_SetTarget_Current(new_current);
}
void Coil_SetTarget_Current(uint16_t current)
{
if(current >= lock_current) current = lock_current;
else if((current > 0)&&(current <= min_current)) current = min_current;
if(current != target_current) new_target = 1;
target_current = current;
}
uint16_t Coil_GetTargetVolatge(void)
{
return target_voltage;
}
uint16_t Coil_Update(analog_t* meas)
{
// Collect average current
sum_current += meas->hb_currnet;
sum_cnt++;
// Update measurement
if(sum_cnt >= 10)
{
// Calculate average
sum_current /= sum_cnt;
// Calculate error
int32_t error = sum_current - (int32_t)target_current;
int32_t temp = (int32_t)adj_target_current - error;
// Limit to 16bits
if(temp<0) adj_target_current = 0;
else if(temp > 0x0000FFFF) adj_target_current = 0xFFFF;
else adj_target_current = (uint16_t)temp;
sum_cnt = 0;
sum_current = 0;
};
// Closed loop or open loop target set
if(new_target)
{
// Set open-loop HB output
target_voltage = UpdateVoltage(target_current, nominal_resitance);
adj_target_current = target_current;
new_target = 0;
sum_cnt = 0;
sum_current = 0;
}
else
{
target_voltage = UpdateVoltage(adj_target_current, nominal_resitance);
}
return target_voltage;
}
/**** Private function definitions ****/
static uint16_t UpdateVoltage(uint16_t cur, uint16_t res)
{
// Update settable voltage
if(cur==0) return 0;
else
{
uint32_t volt = (uint32_t)cur * res;
volt /= 1000;
if(volt > 0x0000FFFF) return 0xFFFF;
else return (uint16_t)volt;
}
}

19
firmware/logic/coil.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef COIL_LOGIC_H_
#define COIL_LOGIC_H_
/**** Includes ****/
#include <stdint.h>
#include "../devices/analog.h"
/**** Public definitions ****/
/**** Public function declarations ****/
void Coil_SetTarget_Force(uint8_t force);
void Coil_SetTarget_Current(uint16_t current);
uint16_t Coil_GetTargetVolatge(void);
uint16_t Coil_Update(analog_t* meas);
void Coil_SetLockCurrent(uint16_t lock_i);
#endif /* COIL_LOGIC_H_ */

186
firmware/logic/force.c Normal file
View File

@@ -0,0 +1,186 @@
/**** Includes ****/
#include "force.h"
/**** Private definitions ****/
/**** Private constants ****/
static const int8_t BUTTONS_STEP = 10;
static const uint16_t BUTTON_HOLD_TIME = 250;
static const uint16_t MODE_HOLD_TIME = 500;
/**** Private variables ****/
static inputMode_t input_mode = IM_BUTTONS;
static uint8_t user_force = 0;
static uint8_t new_user_force = 0;
static brakeMode_t brake_mode = BM_OPEN;
static uint8_t new_brake_mode = 1;
/**** Private function declarations ****/
static uint8_t SaturatedAdd(uint8_t base, int8_t delta);
/**** Public function definitions ****/
inputMode_t Force_GetInputMode(void)
{
return input_mode;
}
void Force_CfgInputMode(inputMode_t in_mode)
{
input_mode = in_mode;
}
void Force_SetUserForce(uint8_t force)
{
if(force > 100) force = 100;
user_force = force;
}
void Force_SetBrakeMode(uint8_t bmode)
{
brake_mode = bmode;
}
uint8_t Force_Update(inputs_t* inputs, analog_t* meas)
{
// Process user inputs
if(input_mode==IM_POT)
{
// Process potentiometer
if(meas->pot_voltage <= 500) user_force = 0;
else if(meas->pot_voltage >= 4500 ) user_force = 100;
else
{
uint16_t pot_u = meas->pot_voltage;
pot_u /= 50;
//Limit to 100
if(pot_u > 100) user_force = 100;
else if(pot_u < 10) user_force = 10;
else user_force = (uint8_t)pot_u;
}
}
else
{
// Process +/- timer
if((inputs->down.is_active)&&(inputs->down.state_timer > BUTTON_HOLD_TIME))
{
inputs->down.is_new = 1;
inputs->down.state_timer = 0;
};
if((inputs->up.is_active)&&(inputs->up.state_timer > BUTTON_HOLD_TIME))
{
inputs->up.is_new = 1;
inputs->up.state_timer = 0;
};
// Process +/- logic
if((inputs->down.is_new)&&(inputs->down.is_active))
{
user_force = SaturatedAdd(user_force, -1 * BUTTONS_STEP);
new_user_force = 1;
}
else if((inputs->up.is_new)&&(inputs->up.is_active))
{
user_force = SaturatedAdd(user_force, BUTTONS_STEP);
new_user_force = 1;
};
inputs->down.is_new = 0;
inputs->up.is_new = 0;
}
// Process mode timer
if((inputs->mode.is_active)&&(inputs->mode.state_timer > MODE_HOLD_TIME))
{
inputs->mode.is_new = 1;
inputs->mode.state_timer = 0;
};
// Process mode logic
if((inputs->mode.is_new)&&(inputs->mode.is_active))
{
//Cycle mode
switch(brake_mode)
{
case BM_OPEN:
brake_mode = BM_KEEP;
break;
case BM_KEEP:
brake_mode = BM_LOCK;
break;
case BM_LOCK:
brake_mode = BM_OPEN;
break;
default:
brake_mode = BM_OPEN;
break;
}
new_brake_mode = 1;
};
inputs->mode.is_new = 0;
// Determine next target force from inputs
if(inputs->handbrake.is_active)
{
return 0;
}
else if(inputs->brakes.is_active)
{
switch(brake_mode)
{
case BM_LOCK:
return 100;
case BM_KEEP:
return user_force;
default:
return 0;
}
}
else
{
return user_force;
}
}
uint8_t Force_IsNewUserForce(void)
{
return new_user_force;
}
void Force_ResetNewUserForce(void)
{
new_user_force = 0;
}
brakeMode_t Force_GetBrakeMode(void)
{
return brake_mode;
}
uint8_t Force_IsNewBrakeMode(void)
{
return new_brake_mode;
}
void Force_ResetNewBrakeMode(void)
{
new_brake_mode = 0;
}
/**** Private function definitions ****/
static uint8_t SaturatedAdd(uint8_t base, int8_t delta)
{
int16_t temp = (int16_t)base + delta;
if(temp < 0) return 0;
else if(temp >= 100) return 100;
else return (uint8_t)temp;
}

36
firmware/logic/force.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef FORCE_LOGIC_H_
#define FORCE_LOGIC_H_
/**** Includes ****/
#include <stdint.h>
#include "../devices/analog.h"
#include "../devices/inputs.h"
/**** Public definitions ****/
typedef enum {
BM_OPEN,
BM_KEEP,
BM_LOCK
} brakeMode_t;
typedef enum {
IM_BUTTONS,
IM_POT
} inputMode_t;
/**** Public function declarations ****/
void Force_CfgInputMode(inputMode_t in_mode);
inputMode_t Force_GetInputMode(void);
uint8_t Force_Update(inputs_t* inputs, analog_t* meas);
void Force_SetBrakeMode(uint8_t bmode);
brakeMode_t Force_GetBrakeMode(void);
uint8_t Force_IsNewBrakeMode(void);
void Force_ResetNewBrakeMode(void);
void Force_SetUserForce(uint8_t force);
uint8_t Force_IsNewUserForce(void);
void Force_ResetNewUserForce(void);
#endif /* FORCE_LOGIC_H_ */

184
firmware/logic/settings.c Normal file
View File

@@ -0,0 +1,184 @@
/**** Includes ****/
#include "settings.h"
/**** Private definitions ****/
/**** Private constants ****/
static const uint8_t addr_force = 0x01;
static const uint8_t addr_bmode = 0x02;
static const uint8_t addr_inmode = 0x03;
static const uint8_t addr_dsp_bright = 0x04;
static const uint8_t addr_dsp_dimm = 0x05;
static const uint8_t addr_lock_amps = 0x06;
/**** Private variables ****/
static uint16_t save_force_timer = 0;
static uint16_t save_bmode_timer = 0;
/**** Private function declarations ****/
/**** Public function definitions ****/
void Setings_Update(uint8_t is_new_force, uint8_t force, uint8_t is_new_bmode, brakeMode_t bmode)
{
if(is_new_force) save_force_timer = 5000;
if(is_new_bmode) save_bmode_timer = 5000;
if(save_force_timer)
{
save_force_timer--;
if(!save_force_timer)
{
// Save force setting
Setings_SaveForce(force);
};
};
if(save_bmode_timer)
{
save_bmode_timer--;
if(!save_bmode_timer)
{
// Save mode setting
Setings_SaveBrakeMode(bmode);
};
};
}
void Setings_SaveForce(uint8_t value)
{
MEM_Write8b(addr_force, value);
}
uint8_t Setings_GetForce(void)
{
uint8_t val = MEM_Read8b(addr_force);
if(val > 100) return 0;
else return val;
}
void Setings_SaveBrakeMode(brakeMode_t bmode)
{
// Convert and save input mode setting
// Convert and save mode setting
uint8_t val = 0x00;
switch(bmode)
{
case BM_LOCK:
val = 'L';
break;
case BM_KEEP:
val = 'K';
break;
default:
val = 'O';
break;
}
MEM_Write8b(addr_bmode, val);
}
brakeMode_t Setings_GetBrakeMode(void)
{
// Convert and return mode setting
uint8_t val = MEM_Read8b(addr_bmode);
switch(val)
{
case 'L':
return BM_LOCK;
case 'K':
return BM_KEEP;
default:
return BM_OPEN;
}
}
void Setings_SaveInputMode(inputMode_t inmode)
{
// Convert and save input mode setting
uint8_t val = 0x00;
switch(inmode)
{
case IM_POT:
val = 'P';
break;
default:
val = 'B';
break;
}
MEM_Write8b(addr_inmode, val);
}
inputMode_t Setings_GetInputMode(void)
{
// Convert and return input mode setting
uint8_t val = MEM_Read8b(addr_inmode);
switch(val)
{
case 'P':
return IM_POT;
default:
return IM_BUTTONS;
}
}
void Setings_SaveDisplayBrigthLvl(uint8_t value)
{
MEM_Write8b(addr_dsp_bright, value);
}
uint8_t Setings_GetDisplayBrigthLvl(void)
{
uint8_t val = MEM_Read8b(addr_dsp_bright);
if(val > 100) return 100;
else return val;
}
void Setings_SaveDisplayDimmLvl(uint8_t value)
{
MEM_Write8b(addr_dsp_dimm, value);
}
uint8_t Setings_GetDisplayDimmLvl(void)
{
uint8_t val = MEM_Read8b(addr_dsp_dimm);
if(val > 100) return 50;
else return val;
}
void Setings_SaveLockCurrent(uint16_t value)
{
MEM_Write16b(addr_lock_amps, value);
}
uint16_t Setings_GetLockCurrent(void)
{
uint16_t val = MEM_Read16b(addr_lock_amps);
if(val > 6000) return 4500;
else return val;
}
void Setings_SaveDefault(void)
{
Setings_SaveForce(0);
Setings_SaveBrakeMode(BM_OPEN);
Setings_SaveInputMode(IM_BUTTONS);
Setings_SaveDisplayBrigthLvl(100);
Setings_SaveDisplayDimmLvl(50);
Setings_SaveLockCurrent(4500);
}
/**** Private function definitions ****/

34
firmware/logic/settings.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef SETTINGS_LOGIC_H_
#define SETTINGS_LOGIC_H_
/**** Includes ****/
#include <stdint.h>
#include "../devices/memory.h"
#include "force.h"
/**** Public definitions ****/
/**** Public function declarations ****/
void Setings_Update(uint8_t is_new_force, uint8_t force, uint8_t is_new_bmode, brakeMode_t bmode);
void Setings_SaveForce(uint8_t value);
uint8_t Setings_GetForce(void);
void Setings_SaveBrakeMode(brakeMode_t bmode);
brakeMode_t Setings_GetBrakeMode(void);
void Setings_SaveInputMode(inputMode_t inmode);
inputMode_t Setings_GetInputMode(void);
void Setings_SaveDisplayBrigthLvl(uint8_t value);
uint8_t Setings_GetDisplayBrigthLvl(void);
void Setings_SaveDisplayDimmLvl(uint8_t value);
uint8_t Setings_GetDisplayDimmLvl(void);
void Setings_SaveLockCurrent(uint16_t value);
uint16_t Setings_GetLockCurrent(void);
void Setings_SaveDefault(void);
#endif /* SETTINGS_LOGIC_H_ */

170
firmware/main.c Normal file
View File

@@ -0,0 +1,170 @@
/**** Includes ****/
#include <stdint.h>
#include "devices/config.h"
#include "devices/analog.h"
#include "devices/inputs.h"
#include "devices/memory.h"
#include "drivers/output.h"
#include "drivers/display.h"
#include "logic/force.h"
#include "logic/coil.h"
#include "logic/settings.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
inputs_t inputs;
analog_t analog;
/**** Private function declarations ****/
void Setup(void);
void GatherData(uint8_t times);
/**** Public function definitions ****/
int main(void)
{
Setup();
while(1)
{
// Read all inputs
GatherData(1);
// Process force logic
uint8_t force = Force_Update(&inputs, &analog);
// Save values
uint8_t new_bmode = Force_IsNewBrakeMode();
uint8_t new_force = Force_IsNewUserForce();
if(Force_GetInputMode()==IM_POT) new_force = 0;
Setings_Update(new_force, force, new_bmode, Force_GetBrakeMode());
// Set coil current target
Coil_SetTarget_Force(force);
// Calculate next target voltage
uint16_t next_u = Coil_Update(&analog);
// Set next output voltage
Output_SetTarget(next_u);
// Update output
Output_Update(&analog);
// Display logic
if(Output_GetOutputState()==O_FAULTED)
{
// Show fault code
Display_SetLock(0);
Display_SetImage(0x33);
}
else if(Force_IsNewBrakeMode())
{
Display_SetLock(0);
switch(Force_GetBrakeMode())
{
case BM_LOCK:
Display_SetImage(0x38);
break;
case BM_KEEP:
Display_SetImage(0x1E);
break;
default:
Display_SetImage(0x07);
break;
}
Display_SetLock(1000);
}
else
{
Display_SetPercent(force, DOT10);
}
// Update display
Display_Update(&inputs);
// Reset new flags
Force_ResetNewBrakeMode();
Force_ResetNewUserForce();
}
return 0;
}
/**** Private function definitions ****/
void Setup(void)
{
// Initialize low level hardware
Init_HW();
// Prime EEPROM
//Setings_SaveDefault();
// Configure inputs
Inputs_DefInit(&inputs);
inputs.handbrake.cfg.act_level = HIGH;
inputs.handbrake.cfg.dbnc_treshold = 10;
inputs.brakes.cfg.act_level = LOW;
inputs.brakes.cfg.dbnc_treshold = 20;
inputs.dimm.cfg.act_level = LOW;
inputs.dimm.cfg.dbnc_treshold = 20;
inputs.up.cfg.act_level = LOW;
inputs.up.cfg.dbnc_treshold = 20;
inputs.down.cfg.act_level = LOW;
inputs.down.cfg.dbnc_treshold = 20;
inputs.mode.cfg.act_level = LOW;
inputs.mode.cfg.dbnc_treshold = 20;
Inputs_SetHanbrakePullUp(0);
// Configure display
Display_CfgBacklight(100,50);
// Show startup display
Display_SetImage(0xFF);
Display_Update(&inputs);
// Configure force logic
Force_CfgInputMode(IM_POT); //IM_BUTTONS IM_POT
// Restore saved force
Force_SetUserForce(Setings_GetForce());
// Restore saved brake mode
Force_SetBrakeMode(Setings_GetBrakeMode());
// Prime analog channels
GatherData(100);
// Show default display
Display_SetImage(0x01);
Display_Update(&inputs);
// Enable output
Output_Enable();
Output_SetTarget(0);
}
void GatherData(uint8_t times)
{
do
{
Analog_UpdateAll(&analog);
Inputs_UpdateAll(&inputs);
if(times) times--;
}
while(times);
}

View File

@@ -1,35 +0,0 @@
/**** 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 ****/

View File

@@ -1,37 +0,0 @@
#ifndef ANALOG_IN_H_
#define ANALOG_IN_H_
/**** Includes ****/
#include <stdint.h>
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_ */

View File

@@ -1,40 +0,0 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "din.h"
using namespace board;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
board::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;
}
board::DigitalIn::~DigitalIn(void)
{
return;
}
uint8_t board::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 ****/

View File

@@ -1,35 +0,0 @@
#ifndef DIGITAL_INPUT_H_
#define DIGITAL_INPUT_H_
/**** Includes ****/
#include <stdint.h>
namespace board {
/**** 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_ */

View File

@@ -1,34 +0,0 @@
/**** 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_value) : DigitalIn(gpio_ch, 0, init_value), DigitalOut(gpio_ch, 0)
{
return;
}
board::DigitalIO::~DigitalIO(void)
{
this->write(DOUT_HIZ);
}
uint8_t board::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 ****/

View File

@@ -1,32 +0,0 @@
#ifndef DIGITAL_IO_H_
#define DIGITAL_IO_H_
/**** Includes ****/
#include <stdint.h>
#include "din.h"
#include "dout.h"
namespace board {
/**** 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_ */

View File

@@ -1,52 +0,0 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "dout.h"
using namespace board;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
board::DigitalOut::DigitalOut(uint8_t gpio_ch, uint8_t inverted)
{
this->gpio_ch = gpio_ch;
this->invert = inverted;
this->write(DOUT_HIZ);
}
board::DigitalOut::~DigitalOut(void)
{
this->write(DOUT_HIZ);
}
void board::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 board::DigitalOut::get_set_level(void)
{
return this->last_set;
}
/**** Private function definitions ****/

View File

@@ -1,36 +0,0 @@
#ifndef DIGITAL_OUTPUT_H_
#define DIGITAL_OUTPUT_H_
/**** Includes ****/
#include <stdint.h>
namespace board {
/**** 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

@@ -1,68 +0,0 @@
/**** 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 ****/

View File

@@ -1,37 +0,0 @@
#ifndef HALFBRIDGE_H_
#define HALFBRIDGE_H_
/**** Includes ****/
#include <stdint.h>
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_ */

View File

@@ -1,125 +0,0 @@
#ifndef MCU_HAL_H_
#define MCU_HAL_H_
/**** Includes ****/
#include <stdint.h>
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_ */

View File

@@ -1,464 +0,0 @@
/**** 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;
}
}

View File

@@ -1,40 +0,0 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "mcu/mcu_hal.h"
#include "pwm.h"
using namespace board;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
board::PWMout::PWMout(uint8_t pwm_ch)
{
this->pwm_ch = pwm_ch;
this->write(0);
}
board::PWMout::~PWMout(void)
{
this->write(0);
}
void board::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 board::PWMout::get_set_duty(void)
{
return this->last_duty;
}
/**** Private function definitions ****/

View File

@@ -1,31 +0,0 @@
#ifndef PWM_H_
#define PWM_H_
/**** Includes ****/
#include <stdint.h>
namespace board {
/**** 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

@@ -1,44 +0,0 @@
#ifndef UDCCD_BOARD_H_
#define UDCCD_BOARD_H_
/**** Includes ****/
#include <stdint.h>
using namespace board;
/**** Public definitions ****/
static AnalogIn dccd_i(mcu::ADC0);
static AnalogIn dccd_u(mcu::ADC1);
static AnalogIn bat_u(mcu::ADC2);
static AnalogIn bat_i(mcu::ADC3);
static Hafbridge hbridge(mcu::PWM0, mcu::GPIO15, 95);
static AnalogIn ain1(mcu::ADC5);
static AnalogIn ain2(mcu::ADC4);
static DigitalIn din1(mcu::GPIO0, 0, board::DIN_HIGH);
static DigitalIn din2(mcu::GPIO1, 0, board::DIN_HIGH);
static DigitalIn din3(mcu::GPIO2, 0, board::DIN_HIGH);
static DigitalIn din4(mcu::GPIO3, 0, board::DIN_HIGH);
static DigitalIn hvdin1(mcu::GPIO4, 1, board::DIN_LOW);
static DigitalIn hvdin2(mcu::GPIO5, 1, board::DIN_LOW);
static DigitalIn hvdin3(mcu::GPIO6, 1, board::DIN_LOW);
static DigitalIO hvdin3_pull(mcu::GPIO3, board::DIN_HIGH);
static DigitalOut odout1(mcu::GPIO9, 1);
static DigitalOut odout2(mcu::GPIO10, 1);
static DigitalOut odout3(mcu::GPIO11, 1);
static DigitalOut odout4(mcu::GPIO12, 1);
static DigitalOut odout5(mcu::GPIO13, 1);
static DigitalOut odout6(mcu::GPIO14, 1);
static PWMout od_pwm(mcu::PWM1);
/**** Public function declarations ****/
#ifdef TESTING
#endif
#endif /* UDCCD_BOARD_H_ */

View File

@@ -1,85 +0,0 @@
/**** 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(board::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 = board::DIN_HIGH;
else this->act_lvl = board::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;
}
hw::Button::~Button(void)
{
return;
}
uint8_t hw::Button::read(void)
{
// Read din level
uint8_t lvl = this->din_ch->read();
// Increase state counter
this->time = util::sat_add(this->time, 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_read(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 ****/

View File

@@ -1,41 +0,0 @@
#ifndef BUTTON_H_
#define BUTTON_H_
/**** Includes ****/
#include <stdint.h>
#include "../board/din.h"
namespace hw {
/**** Public definitions ****/
const uint8_t BUTTON_OFF = 0;
const uint8_t BUTTON_ON = 1;
class Button
{
protected:
board::DigitalIn* din_ch;
uint8_t act_lvl;
uint8_t dbnc_cnter;
public:
Button(board::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;
uint8_t read(void);
uint8_t force_read(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* BUTTON_H_ */

View File

@@ -1,40 +0,0 @@
/**** Includes ****/
#include "../utils/utils.h"
#include "cv_driver.h"
using namespace hw;
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
hw::CVdriver::CVdriver(board::AnalogIn* sup_voltage, board::AnalogIn* out_voltage, board::Hafbridge* hbridge)
{
this->sup_voltage = sup_voltage;
this->hbridge = hbridge;
this->target = 0;
this->off = 1;
}
hw::CVdriver::~CVdriver(void)
{
return;
}
void hw::CVdriver::update(void)
{
// Update all inputs
this->sup_voltage->read();
// Calculate ratio
uint16_t ratio = util::sat_ratio(this->target, this->sup_voltage->last_read);
// Set output
this->hbridge->write(ratio);
}
/**** Private function definitions ****/

View File

@@ -1,37 +0,0 @@
#ifndef CONST_VOLTAGE_DRIVER_H_
#define CONST_VOLTAGE_DRIVER_H_
/**** Includes ****/
#include <stdint.h>
#include "../board/ain.h"
#include "../board/halfbridge.h"
namespace hw {
/**** Public definitions ****/
class CVdriver
{
protected:
board::AnalogIn* sup_voltage;
board::Hafbridge* hbridge;
public:
CVdriver(board::AnalogIn* sup_voltage, board::Hafbridge* hbridge);
~CVdriver(void);
uint16_t target = 0;
uint8_t off = 0;
void process(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* CONST_VOLTAGE_DRIVER_H_ */

View File

@@ -1,180 +0,0 @@
/**** 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(board::DigitalOut* led0, board::DigitalOut* led1, board::DigitalOut* led2, board::DigitalOut* led3, board::DigitalOut* led4, board::DigitalOut* led5, board::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);
}
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);
}
/**** 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

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

View File

@@ -1,38 +0,0 @@
/**** 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(board::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::read(void)
{
// Update input
this->ain_ch->read();
// Calculate percent
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

@@ -1,35 +0,0 @@
#ifndef POTENTIOMETER_H_
#define POTENTIOMETER_H_
/**** Includes ****/
#include <stdint.h>
#include "../board/ain.h"
namespace hw {
/**** Public definitions ****/
class Potentiometer
{
protected:
board::AnalogIn* ain_ch;
public:
Potentiometer(board::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 read(void);
};
/**** Public function declarations ****/
#ifdef TESTING
#endif
} //namespace
#endif /* POTENTIOMETER_H_ */

View File

@@ -1,43 +0,0 @@
/**** Includes ****/
#include "utils/utils.h"
#include "board/mcu/mcu_hal.h"
#include "board/ain.h"
#include "board/din.h"
#include "board/dout.h"
#include "board/dio.h"
#include "board/halfbridge.h"
#include "board/pwm.h"
#include "hw/button.h"
#include "hw/potentiometer.h"
#include "hw/display_led.h"
#include "board/udccd_board.h"
/**** Private definitions ****/
/**** Private constants ****/
/**** Private variables ****/
/**** Private function declarations ****/
/**** Public function definitions ****/
int main(void)
{
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);
// Super loop
while(1)
{
continue; // End of super loop
}
// Escape the matrix
return 0;
}
/**** Private function definitions ***/

View File

@@ -1,248 +0,0 @@
<?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 />
<UncachedRange />
<preserveEEPROM>true</preserveEEPROM>
<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="board\ain.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\ain.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\din.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\din.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\dio.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\dio.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\halfbridge.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\halfbridge.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\mcu\mcu_hal.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\mcu\mcu_hal_r8.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\dout.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\dout.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\pwm.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\pwm.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="board\udccd_board.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\cv_driver.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\cv_driver.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\potentiometer.cpp">
<SubType>compile</SubType>
</Compile>
<Compile Include="hw\potentiometer.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="board" />
<Folder Include="board\mcu" />
<Folder Include="hw" />
<Folder Include="utils" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>

View File

@@ -1,163 +0,0 @@
/**** 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<len_axis; i++)
{
if(val < axis_values[i]) return i;
continue;
}
return len_axis;
}
uint16_t 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

@@ -1,23 +0,0 @@
#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

@@ -1,137 +0,0 @@
/**** 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 ****/

View File

@@ -1,38 +0,0 @@
#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);
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_ */

View File

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

View File

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

View File

@@ -0,0 +1,231 @@
<?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.C</ToolchainName>
<ProjectGuid>dce6c7e3-ee26-4d79-826b-08594b9ad897</ProjectGuid>
<avrdevice>ATmega328PB</avrdevice>
<avrdeviceseries>none</avrdeviceseries>
<OutputType>Executable</OutputType>
<Language>C</Language>
<OutputFileName>$(MSBuildProjectName)</OutputFileName>
<OutputFileExtension>.elf</OutputFileExtension>
<OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory>
<AssemblyName>uDCCD_Controller</AssemblyName>
<Name>uDCCD_Controller</Name>
<RootNamespace>uDCCD_Controller</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>
<options />
<configurations />
<files />
<documentation help="" />
<offline-documentation help="" />
<dependencies>
<content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.42.0" />
</dependencies>
</framework-data>
</AsfFrameworkConfig>
<avrtool>com.atmel.avrdbg.tool.atmelice</avrtool>
<avrtoolserialnumber>J42700001490</avrtoolserialnumber>
<avrdeviceexpectedsignature>0x1E9516</avrdeviceexpectedsignature>
<com_atmel_avrdbg_tool_atmelice>
<ToolOptions>
<InterfaceProperties>
<IspClock>125000</IspClock>
</InterfaceProperties>
<InterfaceName>ISP</InterfaceName>
</ToolOptions>
<ToolType>com.atmel.avrdbg.tool.atmelice</ToolType>
<ToolNumber>J42700001490</ToolNumber>
<ToolName>Atmel-ICE</ToolName>
</com_atmel_avrdbg_tool_atmelice>
<avrtoolinterface>ISP</avrtoolinterface>
<avrtoolinterfaceclock>125000</avrtoolinterfaceclock>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<ToolchainSettings>
<AvrGcc>
<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>
<avrgcc.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcc.linker.libraries.Libraries>
<avrgcc.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcc.assembler.general.IncludePaths>
</AvrGcc>
</ToolchainSettings>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<ToolchainSettings>
<AvrGcc>
<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.PackStructureMembers>True</avrgcc.compiler.optimization.PackStructureMembers>
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
<avrgcc.compiler.optimization.DebugLevel>Default (-g2)</avrgcc.compiler.optimization.DebugLevel>
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
<avrgcc.linker.libraries.Libraries>
<ListValues>
<Value>libm</Value>
</ListValues>
</avrgcc.linker.libraries.Libraries>
<avrgcc.assembler.general.IncludePaths>
<ListValues>
<Value>%24(PackRepoDir)\atmel\ATmega_DFP\1.7.374\include\</Value>
</ListValues>
</avrgcc.assembler.general.IncludePaths>
<avrgcc.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcc.assembler.debugging.DebugLevel>
</AvrGcc>
</ToolchainSettings>
</PropertyGroup>
<ItemGroup>
<Compile Include="devices\analog.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\analog.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\common\level.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\config.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\config.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\led_display.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\led_display.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\filter_iir_lpf.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\filter_iir_lpf.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\halfbridge.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\halfbridge.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\hal\udccd_r7_hal.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\hal\udccd_hal.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\inputs.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\inputs.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\memory.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="devices\memory.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="drivers\display.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="drivers\display.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="drivers\output.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="drivers\output.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\coil.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\coil.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\force.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\force.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\settings.c">
<SubType>compile</SubType>
</Compile>
<Compile Include="logic\settings.h">
<SubType>compile</SubType>
</Compile>
<Compile Include="main.c">
<SubType>compile</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="devices" />
<Folder Include="devices\hal" />
<Folder Include="devices\common" />
<Folder Include="drivers" />
<Folder Include="logic" />
</ItemGroup>
<Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" />
</Project>