33#include "../bus/uart/uart.h"
44#include "../bus/i2c/i2c.h"
55#include "../bus/spi/spi.h"
6- #include "../helpers/delay.h"
7- #include "../registers/system/pin_manager.h"
86#include "powersource.h"
97
10-
11- #ifndef V5_HW
12-
138/*********/
149/* Types */
1510/*********/
1611
17- /// @brief DAC selection bit.
18- enum DAC {
19- DAC_A ,
20- DAC_B
12+ /** @brief Channel selection.
13+ * @details
14+ * V5 hardware has four independent channels:
15+ * 0: PCS
16+ * 1: PV3
17+ * 2: PV2
18+ * 3: PV1
19+ * V6 hardware has two pairs of paired channels:
20+ * 0: PVS1 & PVS3
21+ * 1: PVS2 & PCS
22+ * Paired channels share relative output levels, i.e. if PV1 outputs 5 V
23+ * then PV3 outputs 3.3 V.
24+ */
25+ enum Channel {
26+ PCS ,
27+ PV3 ,
28+ PV2 ,
29+ PV1 ,
30+ NUM_V5_CHANNELS ,
31+ PVS1_PVS3 = 0 ,
32+ PVS2_PCS ,
33+ NUM_V6_CHANNELS ,
2134};
2235
23- /// @brief Output gain selection bit.
36+ /** @brief Output gain selection bit.
37+ * @details
38+ * The gain values are reversed between the MCP4822 (v6) and the
39+ * MCP4728 (v5). Thanks, Microchip!
40+ */
2441enum Gain {
42+ #ifndef V5_HW
43+ GAIN_X2 ,
44+ GAIN_X1 ,
45+ #else
46+ GAIN_X1 ,
2547 GAIN_X2 ,
26- GAIN_X1
48+ #endif // V5_HW
49+ GAINS
2750};
51+ int GAINVAL [GAINS ] = {[GAIN_X1 ] = 1 , [GAIN_X2 ] = 2 };
52+
53+ #ifndef V5_HW
2854
2955/// @brief Output shutdown control bit.
3056enum Output {
@@ -36,19 +62,54 @@ enum Output {
3662union MCP4822Command {
3763 struct {
3864 uint16_t DATA : 12 ;
39- enum Output SHDN : 1 ;
40- enum Gain GA : 1 ;
65+ uint16_t SHDN : 1 ;
66+ uint16_t GA : 1 ;
4167 uint16_t : 1 ;
42- enum DAC AB : 1 ;
68+ uint16_t AB : 1 ;
4369 };
4470 uint16_t reg ;
4571};
4672
73+ #else // V5_HW
74+
75+ /** @brief Output shutdown control bit.
76+ * @details
77+ * Also reversed compared to MCP4822. When not on, DAC output is pulled to
78+ * ground via a 1K, 100K, or 500K resistor.
79+ */
80+ enum Output {
81+ OUTPUT_ON ,
82+ OUTPUT_OFF_1K ,
83+ OUTPUT_OFF_100K ,
84+ OUTPUT_OFF , // 500K
85+ };
86+
87+ union MCP4728Command {
88+ struct {
89+ uint16_t : 1 ; // UDAC
90+ uint16_t DAC : 2 ;
91+ uint16_t CMD : 5 ;
92+
93+ uint16_t DATA_H : 4 ;
94+ uint16_t GX : 1 ;
95+ uint16_t PDSEL : 2 ;
96+ uint16_t VREF : 1 ;
97+
98+ uint16_t DATA_L : 8 ;
99+ };
100+ uint8_t buffer [3 ];
101+ };
102+
103+ #endif // V5_HW
104+
47105/********************/
48106/* Static functions */
49107/********************/
50108
51- static bool initialize (void ) {
109+ #ifndef V5_HW
110+
111+ static bool initialize (void )
112+ {
52113 const SPI_Config conf = {{{
53114 .PPRE = SPI_SCLK125000 >> 3 ,
54115 .SPRE = SPI_SCLK125000 & 7 ,
@@ -64,65 +125,71 @@ static bool initialize(void) {
64125 return SPI_configure (conf );
65126}
66127
67- /*********************/
128+ /**
129+ * @brief Convert a V5 pin number to the corresponding pin number for the V6.
130+ * @details See documentation for Channel.
131+ * @param channel
132+ * @return enum Channel
133+ */
134+ static enum Channel v5_to_v6_channel (enum Channel const channel )
135+ {
136+ return (channel + 1 ) % 2 ;
137+ }
138+
139+ /************************/
68140/* Command functions */
69- /*********************/
141+ /************************ /
70142
71- response_t POWER_SOURCE_SetPower (void ) {
72- enum DAC const dac = (UART1_Read () + 1 ) % 2 ;
73- uint16_t const voltage = UART1_ReadInt () & 0xFFF ;
143+ response_t POWER_SOURCE_SetPower (void )
144+ {
145+ enum Channel const channel = v5_to_v6_channel (UART1_Read () & 0x03 );
146+ uint16_t const output = UART1_ReadInt () & 0xFFF ;
74147 union MCP4822Command cmd = {{
75- .DATA = voltage ,
148+ .DATA = output ,
76149 .SHDN = OUTPUT_ON ,
77150 .GA = GAIN_X2 ,
78- .AB = dac
151+ .AB = channel ,
79152 }};
80153
81154 if (initialize ()) {
82155 return (
83156 SPI_exchange_int (SPI_PS , & cmd .reg ) ? SUCCESS : FAILED
84157 );
85158 }
86-
87159 return FAILED ;
88160}
89161
90- #else
91-
92- union MCP4728Command {
93- struct {
94- uint16_t : 1 ; // UDAC
95- uint16_t DAC : 2 ;
96- uint16_t CMD : 5 ;
97-
98- uint16_t DATA_H : 4 ;
99- uint16_t GX : 1 ;
100- uint16_t PDSEL : 2 ;
101- uint16_t VREF : 1 ;
102-
103- uint16_t DATA_L : 8 ;
104- };
105- uint8_t buffer [3 ];
106- };
162+ #else // V5_HW
107163
108164response_t POWER_SOURCE_SetPower (void ) {
109- uint8_t const dac = UART1_Read () & 0x03 ;
110- uint16_t const voltage = UART1_ReadInt () & 0xFFF ;
165+ enum VRef {
166+ VREF_EXTERNAL ,
167+ VREF_INTERNAL ,
168+ };
169+ enum Command {
170+ SINGLE_WRITE = 0b01011 ,
171+ };
172+ uint8_t const channel = UART1_Read () & 0x03 ;
173+ uint16_t const output = UART1_ReadInt () & 0xFFF ;
111174 union MCP4728Command cmd = {{
112- .CMD = 0b01011 , // Single write
113- .DAC = dac ,
114- .VREF = 1 , // Internal
115- .PDSEL = 0 , // Normal mode
116- .GX = 1 , // Gain x2
117- .DATA_L = voltage & 0xFF ,
118- .DATA_H = ( voltage >> 8 ) & 0xF
175+ .CMD = SINGLE_WRITE ,
176+ .DAC = channel ,
177+ .VREF = VREF_INTERNAL ,
178+ .PDSEL = OUTPUT_ON ,
179+ .GX = GAIN_X2 ,
180+ .DATA_L = output & 0xFF ,
181+ .DATA_H = output >> 8
119182 }};
120183 I2C_InitializeIfNot (I2C_BAUD_RATE_400KHZ , I2C_ENABLE_INTERRUPTS );
121184
185+ enum MCP4728Address {
186+ ADDRESS = 0x60 ,
187+ };
188+
122189 return I2C_BulkWrite (
123190 cmd .buffer ,
124191 sizeof (cmd .buffer ),
125- MCP4728_I2C_DEVICE_ADDRESS
192+ ADDRESS
126193 );
127194}
128195
0 commit comments