Skip to content

Commit

Permalink
Improve documentation for power source instrument
Browse files Browse the repository at this point in the history
  • Loading branch information
bessman committed Jan 15, 2024
1 parent eb71924 commit 237a471
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 59 deletions.
167 changes: 117 additions & 50 deletions src/instruments/powersource.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,54 @@
#include "../bus/uart/uart.h"
#include "../bus/i2c/i2c.h"
#include "../bus/spi/spi.h"
#include "../helpers/delay.h"
#include "../registers/system/pin_manager.h"
#include "powersource.h"


#ifndef V5_HW

/*********/
/* Types */
/*********/

/// @brief DAC selection bit.
enum DAC {
DAC_A,
DAC_B
/** @brief Channel selection.
* @details
* V5 hardware has four independent channels:
* 0: PCS
* 1: PV3
* 2: PV2
* 3: PV1
* V6 hardware has two pairs of paired channels:
* 0: PVS1 & PVS3
* 1: PVS2 & PCS
* Paired channels share relative output levels, i.e. if PV1 outputs 5 V
* then PV3 outputs 3.3 V.
*/
enum Channel {
PCS,
PV3,
PV2,
PV1,
NUM_V5_CHANNELS,
PVS1_PVS3 = 0,
PVS2_PCS,
NUM_V6_CHANNELS,
};

/// @brief Output gain selection bit.
/** @brief Output gain selection bit.
* @details
* The gain values are reversed between the MCP4822 (v6) and the
* MCP4728 (v5). Thanks, Microchip!
*/
enum Gain {
#ifndef V5_HW
GAIN_X2,
GAIN_X1,
#else
GAIN_X1,
GAIN_X2,
GAIN_X1
#endif // V5_HW
GAINS
};
int GAINVAL[GAINS] = {[GAIN_X1] = 1, [GAIN_X2] = 2};

#ifndef V5_HW

/// @brief Output shutdown control bit.
enum Output {
Expand All @@ -36,19 +62,54 @@ enum Output {
union MCP4822Command {
struct {
uint16_t DATA : 12;
enum Output SHDN : 1;
enum Gain GA : 1;
uint16_t SHDN : 1;
uint16_t GA : 1;
uint16_t : 1;
enum DAC AB : 1;
uint16_t AB : 1;
};
uint16_t reg;
};

#else // V5_HW

/** @brief Output shutdown control bit.
* @details
* Also reversed compared to MCP4822. When not on, DAC output is pulled to
* ground via a 1K, 100K, or 500K resistor.
*/
enum Output {
OUTPUT_ON,
OUTPUT_OFF_1K,
OUTPUT_OFF_100K,
OUTPUT_OFF, // 500K
};

union MCP4728Command {
struct {
uint16_t : 1; // UDAC
uint16_t DAC : 2;
uint16_t CMD : 5;

uint16_t DATA_H : 4;
uint16_t GX : 1;
uint16_t PDSEL : 2;
uint16_t VREF : 1;

uint16_t DATA_L : 8;
};
uint8_t buffer[3];
};

#endif // V5_HW

/********************/
/* Static functions */
/********************/

static bool initialize(void) {
#ifndef V5_HW

static bool initialize(void)
{
const SPI_Config conf = {{{
.PPRE = SPI_SCLK125000 >> 3,
.SPRE = SPI_SCLK125000 & 7,
Expand All @@ -64,65 +125,71 @@ static bool initialize(void) {
return SPI_configure(conf);
}

/*********************/
/**
* @brief Convert a V5 pin number to the corresponding pin number for the V6.
* @details See documentation for Channel.
* @param channel
* @return enum Channel
*/
static enum Channel v5_to_v6_channel(enum Channel const channel)
{
return (channel + 1) % 2;
}

/************************/
/* Command functions */
/*********************/
/************************/

response_t POWER_SOURCE_SetPower(void) {
enum DAC const dac = (UART1_Read() + 1) % 2;
uint16_t const voltage = UART1_ReadInt() & 0xFFF;
response_t POWER_SOURCE_SetPower(void)
{
enum Channel const channel = v5_to_v6_channel(UART1_Read() & 0x03);
uint16_t const output = UART1_ReadInt() & 0xFFF;
union MCP4822Command cmd = {{
.DATA = voltage,
.DATA = output,
.SHDN = OUTPUT_ON,
.GA = GAIN_X2,
.AB = dac
.AB = channel,
}};

if(initialize()) {
return (
SPI_exchange_int(SPI_PS, &cmd.reg) ? SUCCESS : FAILED
);
}

return FAILED;
}

#else

union MCP4728Command {
struct {
uint16_t : 1; // UDAC
uint16_t DAC : 2;
uint16_t CMD : 5;

uint16_t DATA_H : 4;
uint16_t GX : 1;
uint16_t PDSEL : 2;
uint16_t VREF : 1;

uint16_t DATA_L : 8;
};
uint8_t buffer[3];
};
#else // V5_HW

response_t POWER_SOURCE_SetPower(void) {
uint8_t const dac = UART1_Read() & 0x03;
uint16_t const voltage = UART1_ReadInt() & 0xFFF;
enum VRef {
VREF_EXTERNAL,
VREF_INTERNAL,
};
enum Command {
SINGLE_WRITE = 0b01011,
};
uint8_t const channel = UART1_Read() & 0x03;
uint16_t const output = UART1_ReadInt() & 0xFFF;
union MCP4728Command cmd = {{
.CMD = 0b01011, // Single write
.DAC = dac,
.VREF = 1, // Internal
.PDSEL = 0, // Normal mode
.GX = 1, // Gain x2
.DATA_L = voltage & 0xFF,
.DATA_H = (voltage >> 8) & 0xF
.CMD = SINGLE_WRITE,
.DAC = channel,
.VREF = VREF_INTERNAL,
.PDSEL = OUTPUT_ON,
.GX = GAIN_X2,
.DATA_L = output & 0xFF,
.DATA_H = output >> 8
}};
I2C_InitializeIfNot(I2C_BAUD_RATE_400KHZ, I2C_ENABLE_INTERRUPTS);

enum MCP4728Address {
ADDRESS = 0x60,
};

return I2C_BulkWrite(
cmd.buffer,
sizeof(cmd.buffer),
MCP4728_I2C_DEVICE_ADDRESS
ADDRESS
);
}

Expand Down
21 changes: 12 additions & 9 deletions src/instruments/powersource.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
#ifndef POWER_SOURCE_H
#define POWER_SOURCE_H

#include <xc.h>

#define MCP4728_I2C_DEVICE_ADDRESS 0x60

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
Expand All @@ -22,10 +18,18 @@ extern "C" {
* 1 (0b01) - PV3
* 2 (0b10) - PV2
* 3 (0b11) - PV1
* @param voltage uint16
* Integer value between 0 and 3300, corresponding to the channel's
* output voltage with 0 corresponding to the lowest voltage and
* 3300 to the highest.
* @param output uint16
* Channel output level in mV relative to the VDD line (3300 mV). A
* value of 0 produces an output equal to the low end of the channel's
* range; a value of 3300 produces an output equal to the high end of
* the channel's range:
* channel output==0 output==3300
* PV(S)1 -5 V 5 V
* PV(S)2 -3.3 V 3.3 V
* PV(S)3 0 V 3.3 V
* PCS 3.3 mA 0 A
* Note that the direction of the output range for the PCS channel is
* inverted compared to the other channels.
*
* @return SUCCESS, FAILED
*/
Expand All @@ -36,4 +40,3 @@ extern "C" {
#endif

#endif /* POWER_SOURCE_H */

0 comments on commit 237a471

Please sign in to comment.