-
Notifications
You must be signed in to change notification settings - Fork 34
/
outputs.c
155 lines (128 loc) · 3.82 KB
/
outputs.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* Copyright (C) 2015 Baruch Even
*
* This file is part of the B3603 alternative firmware.
*
* B3603 alternative firmware is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* B3603 alternative firmware is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with B3603 alternative firmware. If not, see <http://www.gnu.org/licenses/>.
*/
#include "outputs.h"
#include "fixedpoint.h"
#include "uart.h"
#include "stm8s.h"
#define PWM_VAL 0x2000
#define PWM_HIGH (PWM_VAL >> 8)
#define PWM_LOW (PWM_VAL & 0xFF)
void pwm_init(void)
{
/* Timer 1 Channel 1 for Iout control */
TIM1_CR1 = 0x10; // Down direction
TIM1_ARRH = PWM_HIGH; // Reload counter = 16384
TIM1_ARRL = PWM_LOW;
TIM1_PSCRH = 0; // Prescaler 0 means division by 1
TIM1_PSCRL = 0;
TIM1_RCR = 0; // Continuous
TIM1_CCMR1 = 0x70; // Set up to use PWM mode 2.
TIM1_CCER1 = 0x03; // Output is enabled for channel 1, active low
TIM1_CCR1H = 0x00; // Start with the PWM signal off
TIM1_CCR1L = 0x00;
TIM1_BKR = 0x80; // Enable the main output.
/* Timer 2 Channel 1 for Vout control */
TIM2_ARRH = PWM_HIGH; // Reload counter = 16384
TIM2_ARRL = PWM_LOW;
TIM2_PSCR = 0; // Prescaler 0 means division by 1
TIM2_CR1 = 0x00;
TIM2_CCMR1 = 0x70; // Set up to use PWM mode 2.
TIM2_CCER1 = 0x03; // Output is enabled for channel 1, active low
TIM2_CCR1H = 0x00; // Start with the PWM signal off
TIM2_CCR1L = 0x00;
// Timers are still off, will be turned on when output is turned on
}
inline void cvcc_led_cc(void)
{
PA_ODR |= (1<<3);
PA_DDR |= (1<<3);
}
inline void cvcc_led_cv(void)
{
PA_ODR &= ~(1<<3);
PA_DDR |= (1<<3);
}
inline void cvcc_led_off(void)
{
PA_DDR &= ~(1<<3);
}
uint16_t pwm_from_set(fixed_t set, calibrate_t *cal)
{
uint32_t tmp;
// x*a
tmp = set * cal->a;
// x*a + b
tmp += cal->b;
// PWM is 0x8000 and as such amounts to a shift by 13 so to multiple by PWM
// we simply shift all calculations by 3 and this avoids overflows and loss
// of precision.
return fixed_round(tmp);
}
inline void control_voltage(cfg_output_t *cfg, cfg_system_t *sys)
{
uint16_t ctr = pwm_from_set(cfg->vset, &sys->vout_pwm);
uart_write_str("PWM VOLTAGE ");
uart_write_int(ctr);
uart_write_str("\r\n");
TIM2_CCR1H = ctr >> 8;
TIM2_CCR1L = ctr & 0xFF;
TIM2_CR1 |= 0x01; // Enable timer
}
inline void control_current(cfg_output_t *cfg, cfg_system_t *sys)
{
uint16_t ctr = pwm_from_set(cfg->cset, &sys->cout_pwm);
uart_write_str("PWM CURRENT ");
uart_write_int(ctr);
uart_write_str("\r\n");
TIM1_CCR1H = ctr >> 8;
TIM1_CCR1L = ctr & 0xFF;
TIM1_CR1 |= 0x01; // Enable timer
}
void output_commit(cfg_output_t *cfg, cfg_system_t *sys, uint8_t state_constant_current)
{
// Startup and shutdown orders need to be in reverse order
if (sys->output) {
control_voltage(cfg, sys);
control_current(cfg, sys);
// We turned on the PWMs above already
PB_ODR &= ~(1<<4);
output_check_state(sys, state_constant_current);
} else {
// Set Output Enable OFF
PB_ODR |= (1<<4);
// Turn off PWM for Iout
TIM1_CCR1H = 0;
TIM1_CCR1L = 0;
TIM1_CR1 &= 0xFE; // Disable timer
// Turn off PWM for Vout
TIM2_CCR1H = 0;
TIM2_CCR1L = 0;
TIM2_CR1 &= 0xFE; // Disable timer
// Turn off CV/CC led
cvcc_led_off();
}
}
void output_check_state(cfg_system_t *sys, uint8_t state_constant_current)
{
if (sys->output) {
if (state_constant_current)
cvcc_led_cc();
else
cvcc_led_cv();
}
}