kopia lustrzana https://github.com/pimoroni/pimoroni-pico
further module implementation
rodzic
30547952f2
commit
52a8246dee
|
@ -3,14 +3,14 @@
|
|||
namespace pimoroni {
|
||||
IO::IO(uint pin) :
|
||||
pin(pin) {
|
||||
gpio_init(pin);
|
||||
};
|
||||
gpio_init(pin);
|
||||
};
|
||||
|
||||
IO::IO(uint pin, bool out, bool pull_up, bool pull_down) :
|
||||
pin(pin) {
|
||||
gpio_init(pin);
|
||||
direction(out, pull_up, pull_down);
|
||||
};
|
||||
gpio_init(pin);
|
||||
direction(out, pull_up, pull_down);
|
||||
};
|
||||
|
||||
bool IO::direction() {
|
||||
return gpio_is_dir_out(pin);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "audio_amp.hpp"
|
||||
#include "../../logging.hpp"
|
||||
#include "../../errors.hpp"
|
||||
#include "tas_regs.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
|
@ -15,7 +16,10 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
AudioAmpModule::AudioAmpModule() :
|
||||
YukonModule() {
|
||||
YukonModule(),
|
||||
slow_sda(nullptr),
|
||||
slow_scl(nullptr),
|
||||
amp_en(nullptr) {
|
||||
}
|
||||
|
||||
AudioAmpModule::~AudioAmpModule() {
|
||||
|
@ -26,6 +30,13 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void AudioAmpModule::initialise(const SLOT& slot, SlotAccessor& accessor) {
|
||||
// Create the "I2C" pin objects
|
||||
slow_sda = new TCA_IO(slot.SLOW1, accessor);
|
||||
slow_scl = new TCA_IO(slot.SLOW2, accessor);
|
||||
|
||||
// Create the enable pin object
|
||||
amp_en = new TCA_IO(slot.SLOW3, accessor);
|
||||
|
||||
// Configure strip and power pins
|
||||
configure();
|
||||
|
||||
|
@ -34,27 +45,99 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void AudioAmpModule::configure() {
|
||||
|
||||
slow_sda->to_output(true);
|
||||
slow_scl->to_output(true);
|
||||
amp_en->to_output(false);
|
||||
}
|
||||
|
||||
void AudioAmpModule::enable() {
|
||||
CHECK_INITIALISED
|
||||
amp_en->value(true);
|
||||
|
||||
// Pre-Reset Configuration
|
||||
write_i2c_reg(PAGE, 0x01); // Page 1
|
||||
write_i2c_reg(0x37, 0x3a); // Bypass
|
||||
|
||||
write_i2c_reg(PAGE, 0xFD); // Page FD
|
||||
write_i2c_reg(0x0D, 0x0D); // Access page
|
||||
write_i2c_reg(0x06, 0xC1); // Set Dmin
|
||||
|
||||
write_i2c_reg(PAGE, 0x01); // Page 1
|
||||
write_i2c_reg(0x19, 0xC0); // Force modulation
|
||||
write_i2c_reg(PAGE, 0xFD); // Page FD
|
||||
write_i2c_reg(0x0D, 0x0D); // Access page
|
||||
write_i2c_reg(0x06, 0xD5); // Set Dmin
|
||||
|
||||
// Software Reset
|
||||
write_i2c_reg(PAGE, 0x00); // Page 0
|
||||
write_i2c_reg(0x7F, 0x00); // Book 0
|
||||
write_i2c_reg(0x01, 0x01); // Software Reset
|
||||
|
||||
// Post-Reset Configuration
|
||||
write_i2c_reg(PAGE, 0x01); // Page 1
|
||||
write_i2c_reg(0x37, 0x3a); // Bypass
|
||||
|
||||
write_i2c_reg(PAGE, 0xFD); // Page FD
|
||||
write_i2c_reg(0x0D, 0x0D); // Access page
|
||||
write_i2c_reg(0x06, 0xC1); // Set Dmin
|
||||
write_i2c_reg(0x06, 0xD5); // Set Dmin
|
||||
|
||||
// Initial Device Configuration - PWR_MODE0
|
||||
write_i2c_reg(PAGE, 0x00); // Page 0
|
||||
write_i2c_reg(0x0E, 0x44); // TDM tx vsns transmit enable with slot 4
|
||||
write_i2c_reg(0x0F, 0x40); // TDM tx isns transmit enable with slot 0
|
||||
|
||||
write_i2c_reg(PAGE, 0x01); // Page 1
|
||||
write_i2c_reg(0x21, 0x00); // Disable Comparator Hysterisis
|
||||
write_i2c_reg(0x17, 0xC8); // SARBurstMask=0
|
||||
write_i2c_reg(0x19, 0x00); // LSR Mode
|
||||
write_i2c_reg(0x35, 0x74); // Noise minimized
|
||||
|
||||
write_i2c_reg(PAGE, 0xFD); // Page FD
|
||||
write_i2c_reg(0x0D, 0x0D); // Access page
|
||||
write_i2c_reg(0x3E, 0x4A); // Optimal Dmin
|
||||
write_i2c_reg(0x0D, 0x00); // Remove access
|
||||
|
||||
write_i2c_reg(PAGE, 0x00); // Page 0
|
||||
write_i2c_reg(CHNL_0, 0xA8); // PWR_MODE0 selected
|
||||
write_i2c_reg(PVDD_UVLO, 0x00); // PVDD UVLO set to 2.76V
|
||||
// My addition
|
||||
write_i2c_reg(DC_BLK0, 0xA1); // VBAT1S_MODE set to internally generated
|
||||
write_i2c_reg(DVC, 0x68); // Go to a low default
|
||||
write_i2c_reg(INT_CLK_CFG, 0x99 + 0b0100000); // CLK_PWR_UD_EN abled, with long time. This causes output to stay active without mute.
|
||||
|
||||
write_i2c_reg(INT_MASK0, 0xFF);
|
||||
write_i2c_reg(INT_MASK1, 0xFF);
|
||||
write_i2c_reg(INT_MASK2, 0xFF);
|
||||
write_i2c_reg(INT_MASK3, 0xFF);
|
||||
write_i2c_reg(INT_MASK4, 0xFF);
|
||||
|
||||
write_i2c_reg(MODE_CTRL, 0x80); // Play audio, power up with playback, IV enabled
|
||||
// A second play command is required for some reason, to take it out of software shutdown
|
||||
// Temp commented out self.write_i2c_reg(MODE_CTRL, 0x80) # Play audio, power up with playback, IV enabled
|
||||
}
|
||||
|
||||
void AudioAmpModule::disable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
amp_en->value(false);
|
||||
}
|
||||
|
||||
bool AudioAmpModule::is_enabled() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return amp_en->value();
|
||||
}
|
||||
|
||||
void AudioAmpModule::exit_soft_shutdown() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
write_i2c_reg(MODE_CTRL, 0x80); // Calling this after a play seems to wake the amp up, but adds around 16ms
|
||||
}
|
||||
|
||||
void AudioAmpModule::set_volume(float volume) {
|
||||
if(volume < 0.0f || volume > 1.0f) {
|
||||
throw std::invalid_argument("Volume out of range. Expected 0.0 to 1.0\n");
|
||||
}
|
||||
|
||||
write_i2c_reg(DVC, (uint8_t)((1.0f - volume) * 0xC8));
|
||||
}
|
||||
|
||||
float AudioAmpModule::read_temperature() {
|
||||
|
|
|
@ -44,10 +44,9 @@ namespace pimoroni {
|
|||
uint I2S_CLK;
|
||||
uint I2S_FS;
|
||||
private:
|
||||
TCA slow_sda;
|
||||
TCA slow_scl;
|
||||
TCA amp_en;
|
||||
|
||||
TCA_IO* slow_sda;
|
||||
TCA_IO* slow_scl;
|
||||
TCA_IO* amp_en;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
namespace pimoroni {
|
||||
|
||||
enum TASRegs {
|
||||
// PAGE 0 Regs
|
||||
PAGE = 0x00, // Device Page Section 8.9.5
|
||||
SW_RESET = 0x01, // Software Reset Section 8.9.6
|
||||
MODE_CTRL = 0x02, // Device operational mode Section 8.9.7
|
||||
CHNL_0 = 0x03, // Y Bridge and Channel settings Section 8.9.8
|
||||
DC_BLK0 = 0x04, // SAR Filter and DC Path Blocker Section 8.9.9
|
||||
DC_BLK1 = 0x05, // Record DC Blocker Section 8.9.10
|
||||
MISC_CFG1 = 0x06, // Misc Configuration 1 Section 8.9.11
|
||||
MISC_CFG2 = 0x07, // Misc Configuration 2 Section 8.9.12
|
||||
TDM_CFG0 = 0x08, // TDM Configuration 0 Section 8.9.13
|
||||
TDM_CFG1 = 0x09, // TDM Configuration 1 Section 8.9.14
|
||||
TDM_CFG2 = 0x0A, // TDM Configuration 2 Section 8.9.15
|
||||
LIM_MAX_ATTN = 0x0B, // Limiter Section 8.9.16
|
||||
TDM_CFG3 = 0x0C, // TDM Configuration 3 Section 8.9.17
|
||||
TDM_CFG4 = 0x0D, // TDM Configuration 4 Section 8.9.18
|
||||
TDM_CFG5 = 0x0E, // TDM Configuration 5 Section 8.9.19
|
||||
TDM_CFG6 = 0x0F, // TDM Configuration 6 Section 8.9.20
|
||||
TDM_CFG7 = 0x10, // TDM Configuration 7 Section 8.9.21
|
||||
TDM_CFG8 = 0x11, // TDM Configuration 8 Section 8.9.22
|
||||
TDM_CFG9 = 0x12, // TDM Configuration 9 Section 8.9.23
|
||||
TDM_CFG10 = 0x13, // TDM Configuration 10 Section 8.9.24
|
||||
TDM_CFG11 = 0x14, // TDM Configuration 11 Section 8.9.25
|
||||
ICC_CNFG2 = 0x15, // ICC Mode Section 8.9.26
|
||||
TDM_CFG12 = 0x16, // TDM Configuration 12 Section 8.9.27
|
||||
ICLA_CFG0 = 0x17, // Inter Chip Limiter Alignment 0 Section 8.9.28
|
||||
ICLA_CFG1 = 0x18, // Inter Chip Gain Alignment 1 Section 8.9.29
|
||||
DG_0 = 0x19, // Diagnostic Signal Section 8.9.30
|
||||
DVC = 0x1A, // Digital Volume Control Section 8.9.31
|
||||
LIM_CFG0 = 0x1B, // Limiter Configuration 0 Section 8.9.32
|
||||
LIM_CFG1 = 0x1C, // Limiter Configuration 1 Section 8.9.33
|
||||
BOP_CFG0 = 0x1D, // Brown Out Prevention 0 Section 8.9.34
|
||||
BOP_CFG1 = 0x1E, // Brown Out Prevention 1 Section 8.9.35
|
||||
BOP_CFG2 = 0x1F, // Brown Out Prevention 2 Section 8.9.36
|
||||
BOP_CFG3 = 0x20, // Brown Out Prevention 3 Section 8.9.37
|
||||
BOP_CFG4 = 0x21, // Brown Out Prevention 4 Section 8.9.38
|
||||
BOP_CFG5 = 0x22, // BOP Configuration 5 Section 8.9.40
|
||||
BOP_CFG6 = 0x23, // Brown Out Prevention 6 Section 8.9.41
|
||||
BOP_CFG7 = 0x24, // Brown Out Prevention 7 Section 8.9.42
|
||||
BOP_CFG8 = 0x25, // Brown Out Prevention 8 Section 8.9.43
|
||||
BOP_CFG9 = 0x26, // Brown Out Prevention 9 Section 8.9.44
|
||||
BOP_CFG10 = 0x27, // BOP Configuration 10 Section 8.9.45
|
||||
BOP_CFG11 = 0x28, // Brown Out Prevention 11 Section 8.9.46
|
||||
BOP_CFG12 = 0x29, // Brown Out Prevention 12 Section 8.9.47
|
||||
BOP_CFG13 = 0x2A, // Brown Out Prevention 13 Section 8.9.48
|
||||
BOP_CFG14 = 0x2B, // Brown Out Prevention 14 Section 8.9.49
|
||||
BOP_CFG15 = 0x2C, // BOP Configuration 15 Section 8.9.50
|
||||
BOP_CFG17 = 0x2D, // Brown Out Prevention 16 Section 8.9.51
|
||||
BOP_CFG18 = 0x2E, // Brown Out Prevention 17 Section 8.9.52
|
||||
BOP_CFG19 = 0x2F, // Brown Out Prevention 18 Section 8.9.53
|
||||
BOP_CFG20 = 0x30, // Brown Out Prevention 19 Section 8.9.54
|
||||
BOP_CFG21 = 0x31, // BOP Configuration 21 Section 8.9.55
|
||||
BOP_CFG22 = 0x32, // Brown Out Prevention 22 Section 8.9.56
|
||||
BOP_CFG23 = 0x33, // Lowest PVDD Measured Section 8.9.57
|
||||
BOP_CFG24 = 0x34, // Lowest BOP Attack Rate Section 8.9.57
|
||||
NG_CFG0 = 0x35, // Noise Gate 0 Section 8.9.60
|
||||
NG_CFG1 = 0x36, // Noise Gate 1 Section 8.9.61
|
||||
LVS_CFG0 = 0x37, // Low Voltage Signaling Section 8.9.62
|
||||
DIN_PD = 0x38, // Digital Input Pin Pull Down Section 8.9.63
|
||||
IO_DRV0 = 0x39, // Output Driver Strength Section 8.9.64
|
||||
IO_DRV1 = 0x3A, // Output Driver Strength Section 8.9.65
|
||||
INT_MASK0 = 0x3B, // Interrupt Mask 0 Section 8.9.66
|
||||
INT_MASK1 = 0x3C, // Interrupt Mask 1 Section 8.9.67
|
||||
INT_MASK4 = 0x3D, // Interrupt Mask 4 Section 8.9.68
|
||||
INT_MASK2 = 0x40, // Interrupt Mask 2 Section 8.9.69
|
||||
INT_MASK3 = 0x41, // Interrupt Mask 3 Section 8.9.70
|
||||
INT_LIVE0 = 0x42, // Live Interrupt Read-back 0 Section 8.9.71
|
||||
INT_LIVE1 = 0x43, // Live Interrupt Read-back 1 Section 8.9.72
|
||||
INT_LIVE1_0 = 0x44, // Live Interrupt Read-back 1_0 Section 8.9.73
|
||||
INT_LIVE2 = 0x47, // Live Interrupt Read-back 2 Section 8.9.74
|
||||
INT_LIVE3 = 0x48, // Live Interrupt Read-back 3 Section 8.9.75
|
||||
INT_LTCH0 = 0x49, // Latched Interrupt Read-back 0 Section 8.9.76
|
||||
INT_LTCH1 = 0x4A, // Latched Interrupt Read-back 1 Section 8.9.77
|
||||
INT_LTCH1_0 = 0x4B, // Latched Interrupt Read-back 1_0 Section 8.9.78
|
||||
INT_LTCH2 = 0x4F, // Latched Interrupt Read-back 2 Section 8.9.79
|
||||
INT_LTCH3 = 0x50, // Latched Interrupt Read-back 3 Section 8.9.80
|
||||
INT_LTCH4 = 0x51, // Latched Interrupt Read-back 4 Section 8.9.81
|
||||
VBAT_MSB = 0x52, // SAR VBAT1S 0 Section 8.9.82
|
||||
VBAT_LSB = 0x53, // SAR VBAT1S 1 Section 8.9.83
|
||||
PVDD_MSB = 0x54, // SAR PVDD 0 Section 8.9.84
|
||||
PVDD_LSB = 0x55, // SAR PVDD 1 Section 8.9.85
|
||||
TEMP = 0x56, // SAR ADC Conversion 2 Section 8.9.86
|
||||
INT_CLK_CFG = 0x5C, // Clock Setting and IRQZ Section 8.9.87
|
||||
MISC_CFG3 = 0x5D, // Misc Configuration 3 Section 8.9.88
|
||||
CLOCK_CFG = 0x60, // Clock Configuration Section 8.9.89
|
||||
IDLE_IND = 0x63, // Idle channel current optimization Section 8.9.90
|
||||
MISC_CFG4 = 0x65, // Misc Configuration 4 Section 8.9.91
|
||||
TG_CFG0 = 0x67, // Tone Generator Section 8.9.92
|
||||
CLK_CFG = 0x68, // Detect Clock Ration and Sample Rate Section 8.9.93
|
||||
LV_EN_CFG = 0x6A, // Class-D and LVS Delays Section 8.9.94
|
||||
NG_CFG2 = 0x6B, // Noise Gate 2 Section 8.9.95
|
||||
NG_CFG3 = 0x6C, // Noise Gate 3 Section 8.9.96
|
||||
NG_CFG4 = 0x6D, // Noise Gate 4 Section 8.9.97
|
||||
NG_CFG5 = 0x6E, // Noise Gate 5 Section 8.9.98
|
||||
NG_CFG6 = 0x6F, // Noise Gate 6 Section 8.9.99
|
||||
NG_CFG7 = 0x70, // Noise Gate 7 Section 8.9.100
|
||||
PVDD_UVLO = 0x71, // UVLO Threshold Section 8.9.101
|
||||
DMD = 0x73, // DAC Modulator Dither Section 8.9.102
|
||||
I2C_CKSUM = 0x7E, // I2C Checksum Section 8.9.104
|
||||
BOOK = 0x7F, // Device Book Section 8.9.105
|
||||
|
||||
// PAGE 1 Regs
|
||||
LSR = 0x19, // Modulation Section 8.9.106
|
||||
INT_LDO = 0x36, // Internal LDO Setting Section 8.9.107
|
||||
SDOUT_HIZ_1 = 0x3D, // Slots Control Section 8.9.108
|
||||
SDOUT_HIZ_2 = 0x3E, // Slots Control Section 8.9.109
|
||||
SDOUT_HIZ_3 = 0x3F, // Slots Control Section 8.9.110
|
||||
SDOUT_HIZ_4 = 0x40, // Slots Control Section 8.9.111
|
||||
SDOUT_HIZ_5 = 0x41, // Slots Control Section 8.9.112
|
||||
SDOUT_HIZ_6 = 0x42, // Slots Control Section 8.9.113
|
||||
SDOUT_HIZ_7 = 0x43, // Slots Control Section 8.9.114
|
||||
SDOUT_HIZ_8 = 0x44, // Slots Control Section 8.9.115
|
||||
SDOUT_HIZ_9 = 0x45, // Slots Control Section 8.9.116
|
||||
TG_EN = 0x47, // Thermal Detection Enable Section 8.9.117
|
||||
};
|
||||
|
||||
}
|
|
@ -34,6 +34,13 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void BenchPowerModule::initialise(const SLOT& slot, SlotAccessor& accessor) {
|
||||
// Create the voltage pwm object
|
||||
voltage_pwm = new PWMCluster(pio0, 0, slot.FAST2, 1, true);
|
||||
|
||||
// Create the power control pin objects
|
||||
power_en = new IO(slot.FAST1);
|
||||
power_good = new TCA_IO(slot.SLOW1, accessor);
|
||||
|
||||
// Configure strip and power pins
|
||||
configure();
|
||||
|
||||
|
@ -42,47 +49,87 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void BenchPowerModule::configure() {
|
||||
// Calculate a suitable pwm wrap period for this frequency
|
||||
uint32_t period; uint32_t div256;
|
||||
if(pimoroni::PWMCluster::calculate_pwm_factors(250000, period, div256)) {
|
||||
pwm_period = period;
|
||||
|
||||
// Update the pwm before setting the new wrap
|
||||
voltage_pwm->set_chan_level(0, 0, false);
|
||||
voltage_pwm->set_chan_offset(0, 0, false);
|
||||
|
||||
// Set the new wrap (should be 1 less than the period to get full 0 to 100%)
|
||||
voltage_pwm->set_wrap(pwm_period, true); // NOTE Minus 1 not needed here. Maybe should change Wrap behaviour so it is needed, for consistency with hardware pwm?
|
||||
|
||||
// Apply the new divider
|
||||
// This is done after loading new PWM values to avoid a lockup condition
|
||||
uint8_t div = div256 >> 8;
|
||||
uint8_t mod = div256 % 256;
|
||||
voltage_pwm->set_clkdiv_int_frac(div, mod);
|
||||
}
|
||||
|
||||
power_en->to_output(false);
|
||||
power_good->to_input();
|
||||
}
|
||||
|
||||
void BenchPowerModule::enable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
power_en->value(true);
|
||||
}
|
||||
|
||||
void BenchPowerModule::disable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
power_en->value(false);
|
||||
}
|
||||
|
||||
bool BenchPowerModule::is_enabled() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return power_en->value();
|
||||
}
|
||||
|
||||
void BenchPowerModule::set_pwm(float percent) {
|
||||
|
||||
voltage_pwm->set_chan_level(0, (uint32_t)(percent * (float)pwm_period));
|
||||
}
|
||||
|
||||
void BenchPowerModule::set_target_voltage(float voltage) {
|
||||
|
||||
CHECK_INITIALISED
|
||||
float percent;
|
||||
if(voltage >= VOLTAGE_MID) {
|
||||
percent = (voltage - VOLTAGE_MID) * 0.5f / (VOLTAGE_MAX - VOLTAGE_MID) + 0.5f;
|
||||
percent = MIN(percent, 1.0f);
|
||||
}
|
||||
else {
|
||||
percent = (voltage - VOLTAGE_MIN) * 0.5f / (VOLTAGE_MID - VOLTAGE_MIN);
|
||||
percent = MAX(percent, 0.0);
|
||||
}
|
||||
set_target(percent);
|
||||
}
|
||||
|
||||
void BenchPowerModule::set_target(float percent) {
|
||||
CHECK_INITIALISED
|
||||
if(percent < 0.0f || percent > 1.0f) {
|
||||
throw std::invalid_argument("percent out of range. Expected 0.0 to 1.0\n");
|
||||
}
|
||||
|
||||
set_pwm((percent * (PWM_MAX - PWM_MIN)) + PWM_MIN);
|
||||
}
|
||||
|
||||
float BenchPowerModule::read_voltage() {
|
||||
// return (self.__shared_adc_voltage() * (100 + 22)) / 22
|
||||
float value = __read_adc1();
|
||||
float voltage;
|
||||
if(value >= VOLTAGE_MID_MEASURE) {
|
||||
return ((value - VOLTAGE_MID_MEASURE) * (VOLTAGE_MAX - VOLTAGE_MID)) / (VOLTAGE_MAX_MEASURE - VOLTAGE_MID_MEASURE) + VOLTAGE_MID;
|
||||
voltage = ((value - VOLTAGE_MID_MEASURE) * (VOLTAGE_MAX - VOLTAGE_MID)) / (VOLTAGE_MAX_MEASURE - VOLTAGE_MID_MEASURE) + VOLTAGE_MID;
|
||||
}
|
||||
else {
|
||||
float voltage = ((value - VOLTAGE_MIN_MEASURE) * (VOLTAGE_MID - VOLTAGE_MIN)) / (VOLTAGE_MID_MEASURE - VOLTAGE_MIN_MEASURE) + VOLTAGE_MIN;
|
||||
return MAX(voltage, 0.0);
|
||||
voltage = ((value - VOLTAGE_MIN_MEASURE) * (VOLTAGE_MID - VOLTAGE_MIN)) / (VOLTAGE_MID_MEASURE - VOLTAGE_MIN_MEASURE) + VOLTAGE_MIN;
|
||||
voltage = MAX(voltage, 0.0);
|
||||
}
|
||||
return voltage;
|
||||
}
|
||||
|
||||
bool BenchPowerModule::read_power_good() {
|
||||
return 0; // TODO
|
||||
return power_good->value();
|
||||
}
|
||||
|
||||
float BenchPowerModule::read_temperature() {
|
||||
|
|
|
@ -47,12 +47,14 @@ namespace pimoroni {
|
|||
float min_temperature;
|
||||
float avg_temperature;
|
||||
float count_avg;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
private:
|
||||
PWMCluster* voltage_pwm;
|
||||
IO* power_en;
|
||||
IO* power_good;
|
||||
TCA_IO* power_good;
|
||||
uint32_t pwm_period;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
@ -18,12 +18,16 @@ namespace pimoroni {
|
|||
YukonModule(),
|
||||
frequency(frequency),
|
||||
motor(nullptr),
|
||||
encoder(nullptr) {
|
||||
encoder(nullptr),
|
||||
motor_en(nullptr),
|
||||
motor_nfault(nullptr) {
|
||||
}
|
||||
|
||||
BigMotorModule::~BigMotorModule() {
|
||||
delete(motor);
|
||||
delete(encoder);
|
||||
delete(motor_en);
|
||||
delete(motor_nfault);
|
||||
}
|
||||
|
||||
std::string BigMotorModule::name() {
|
||||
|
@ -31,6 +35,13 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void BigMotorModule::initialise(const SLOT& slot, SlotAccessor& accessor) {
|
||||
// Create motor object
|
||||
motor = new MotorCluster(pio0, 0, slot.FAST3, NUM_MOTORS);
|
||||
|
||||
// Create motor control pin objects
|
||||
motor_en = new TCA_IO(slot.SLOW3, accessor);
|
||||
motor_nfault = new TCA_IO(slot.SLOW2, accessor);
|
||||
|
||||
// Configure strip and power pins
|
||||
configure();
|
||||
|
||||
|
@ -39,23 +50,31 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void BigMotorModule::configure() {
|
||||
motor->disable_all();
|
||||
motor->decay_mode(0, SLOW_DECAY);
|
||||
|
||||
motor_nfault ->to_input();
|
||||
motor_en->to_output(false);
|
||||
}
|
||||
|
||||
void BigMotorModule::enable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
motor_en->value(true);
|
||||
}
|
||||
|
||||
void BigMotorModule::disable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
motor_en->value(true);
|
||||
}
|
||||
|
||||
bool BigMotorModule::is_enabled() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return motor_en->value();
|
||||
}
|
||||
|
||||
bool BigMotorModule::read_fault() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return !motor_nfault->value();
|
||||
}
|
||||
|
||||
bool BigMotorModule::read_current() {
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace pimoroni {
|
|||
//--------------------------------------------------
|
||||
public:
|
||||
static const std::string NAME;
|
||||
static const uint NUM_MOTORS = 2;
|
||||
static constexpr float DEFAULT_FREQUENCY = 25000.0f;
|
||||
static constexpr float TEMPERATURE_THRESHOLD = 50.0f;
|
||||
static constexpr float CURRENT_THRESHOLD = 25.0f;
|
||||
|
@ -50,8 +51,8 @@ namespace pimoroni {
|
|||
MotorCluster* motor;
|
||||
Encoder* encoder;
|
||||
private:
|
||||
TCA motor_en;
|
||||
TCA motor_nfault;
|
||||
TCA_IO* motor_en;
|
||||
TCA_IO* motor_nfault;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
#include "common.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
TCA_IO::TCA_IO(TCA pin, TCAAccessor& accessor) :
|
||||
pin(pin),
|
||||
accessor(accessor) {
|
||||
to_input();
|
||||
};
|
||||
|
||||
TCA_IO::TCA_IO(TCA pin, TCAAccessor& accessor, bool out) :
|
||||
pin(pin),
|
||||
accessor(accessor) {
|
||||
direction(out);
|
||||
};
|
||||
|
||||
//TCA_IO::~TCA_IO() {
|
||||
// to_input();
|
||||
//}
|
||||
|
||||
bool TCA_IO::direction() {
|
||||
return accessor.get_slow_config(pin);
|
||||
}
|
||||
|
||||
void TCA_IO::direction(bool out) {
|
||||
accessor.set_slow_config(pin, out);
|
||||
}
|
||||
|
||||
void TCA_IO::to_output(bool val) {
|
||||
value(val);
|
||||
direction(GPIO_OUT);
|
||||
}
|
||||
|
||||
void TCA_IO::to_input() {
|
||||
direction(GPIO_IN);
|
||||
value(false);
|
||||
}
|
||||
|
||||
bool TCA_IO::value() {
|
||||
if(direction()) {
|
||||
return accessor.get_slow_output(pin);
|
||||
}
|
||||
else {
|
||||
return accessor.get_slow_input(pin);
|
||||
}
|
||||
}
|
||||
|
||||
void TCA_IO::value(bool val) {
|
||||
accessor.set_slow_output(pin, val);
|
||||
}
|
||||
};
|
|
@ -8,6 +8,11 @@
|
|||
#include <stdexcept>
|
||||
namespace pimoroni {
|
||||
|
||||
#define CHECK_INITIALISED \
|
||||
if(!is_initialised()) { \
|
||||
throw std::runtime_error("Module not initialised\n"); \
|
||||
}
|
||||
|
||||
struct TCA {
|
||||
uint CHIP;
|
||||
uint GPIO;
|
||||
|
@ -43,7 +48,7 @@ namespace pimoroni {
|
|||
HIGH = true
|
||||
};
|
||||
|
||||
class SlotAccessor {
|
||||
class TCAAccessor {
|
||||
public:
|
||||
virtual bool get_slow_input(TCA gpio) = 0;
|
||||
virtual bool get_slow_output(TCA gpio) = 0;
|
||||
|
@ -53,11 +58,30 @@ namespace pimoroni {
|
|||
virtual void set_slow_output(TCA gpio, bool value) = 0;
|
||||
virtual void set_slow_config(TCA gpio, bool output) = 0;
|
||||
virtual void set_slow_polarity(TCA gpio, bool polarity) = 0;
|
||||
};
|
||||
|
||||
class SlotAccessor : public TCAAccessor {
|
||||
public:
|
||||
virtual float read_slot_adc1(SLOT slot) = 0;
|
||||
virtual float read_slot_adc2(SLOT slot) = 0;
|
||||
};
|
||||
|
||||
class TCA_IO {
|
||||
public:
|
||||
TCA_IO(TCA pin, TCAAccessor& accessor);
|
||||
TCA_IO(TCA pin, TCAAccessor& accessor, bool out);
|
||||
//~TCA_IO();
|
||||
bool direction();
|
||||
void direction(bool out);
|
||||
void to_output(bool val);
|
||||
void to_input();
|
||||
bool value();
|
||||
void value(bool val);
|
||||
private:
|
||||
TCA pin;
|
||||
TCAAccessor& accessor;
|
||||
};
|
||||
|
||||
class YukonModule {
|
||||
public:
|
||||
static constexpr float ROOM_TEMP = 273.15f + 25.0f;
|
||||
|
@ -102,23 +126,17 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
float __read_adc1() {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
return __accessor->read_slot_adc1(slot);
|
||||
}
|
||||
|
||||
float __read_adc2() {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
return __accessor->read_slot_adc2(slot);
|
||||
}
|
||||
|
||||
float __read_adc2_as_temp() {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
float sense = __accessor->read_slot_adc2(slot);
|
||||
float r_thermistor = sense / ((3.3f - sense) / 5100.0f);
|
||||
float t_kelvin = (BETA * ROOM_TEMP) / (BETA + (ROOM_TEMP * log(r_thermistor / RESISTOR_AT_ROOM_TEMP)));
|
||||
|
|
|
@ -18,11 +18,17 @@ namespace pimoroni {
|
|||
YukonModule(),
|
||||
motor_type(DUAL),
|
||||
frequency(frequency),
|
||||
motors(nullptr) {
|
||||
motors(nullptr),
|
||||
motors_decay(nullptr),
|
||||
motors_toff(nullptr),
|
||||
motors_en(nullptr) {
|
||||
}
|
||||
|
||||
DualMotorModule::~DualMotorModule() {
|
||||
delete(motors);
|
||||
delete(motors_decay);
|
||||
delete(motors_toff);
|
||||
delete(motors_en);
|
||||
}
|
||||
|
||||
std::string DualMotorModule::name() {
|
||||
|
@ -30,7 +36,15 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void DualMotorModule::initialise(const SLOT& slot, SlotAccessor& accessor) {
|
||||
// Configure strip and power pins
|
||||
// Create motor objects
|
||||
motors = new MotorCluster(pio0, 0, slot.FAST1, NUM_MOTORS);
|
||||
|
||||
// Create motor control pin objects
|
||||
motors_decay = new TCA_IO(slot.SLOW1, accessor);
|
||||
motors_toff = new TCA_IO(slot.SLOW2, accessor);
|
||||
motors_en = new TCA_IO(slot.SLOW3, accessor);
|
||||
|
||||
// Configure motors
|
||||
configure();
|
||||
|
||||
// Pass the slot and adc functions up to the parent now that module specific initialisation has finished
|
||||
|
@ -38,35 +52,46 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void DualMotorModule::configure() {
|
||||
motors->disable_all();
|
||||
|
||||
motors_decay->to_output(false);
|
||||
motors_toff->to_output(false);
|
||||
motors_en->to_output(false);
|
||||
}
|
||||
|
||||
void DualMotorModule::enable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
motors_en->value(true);
|
||||
}
|
||||
|
||||
void DualMotorModule::disable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
motors_en->value(false);
|
||||
}
|
||||
|
||||
bool DualMotorModule::is_enabled() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return motors_en->value();
|
||||
}
|
||||
|
||||
bool DualMotorModule::decay() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return motors_decay->value();
|
||||
}
|
||||
|
||||
void DualMotorModule::decay(bool val) {
|
||||
|
||||
CHECK_INITIALISED
|
||||
motors_decay->value(val);
|
||||
}
|
||||
|
||||
bool DualMotorModule::toff() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return motors_toff->value();
|
||||
}
|
||||
|
||||
void DualMotorModule::toff(bool val) {
|
||||
|
||||
CHECK_INITIALISED
|
||||
return motors_toff->value(val);
|
||||
}
|
||||
|
||||
bool DualMotorModule::read_fault() {
|
||||
|
|
|
@ -55,9 +55,9 @@ namespace pimoroni {
|
|||
//--------------------------------------------------
|
||||
private:
|
||||
MotorCluster* motors;
|
||||
TCA motors_decay;
|
||||
TCA motors_toff;
|
||||
TCA motors_en;
|
||||
TCA_IO* motors_decay;
|
||||
TCA_IO* motors_toff;
|
||||
TCA_IO* motors_en;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
@ -27,6 +27,8 @@ namespace pimoroni {
|
|||
delete(sw_output[1]);
|
||||
delete(sw_enable[0]);
|
||||
delete(sw_enable[1]);
|
||||
delete(power_good[0]);
|
||||
delete(power_good[1]);
|
||||
}
|
||||
|
||||
std::string DualSwitchedModule::name() {
|
||||
|
@ -39,8 +41,8 @@ namespace pimoroni {
|
|||
sw_output[1] = new IO(slot.FAST3);
|
||||
sw_enable[0] = new IO(slot.FAST1);
|
||||
sw_enable[1] = new IO(slot.FAST3);
|
||||
power_good[0] = slot.SLOW1;
|
||||
power_good[1] = slot.SLOW3;
|
||||
power_good[0] = new TCA_IO(slot.SLOW1, accessor);
|
||||
power_good[1] = new TCA_IO(slot.SLOW3, accessor);
|
||||
|
||||
// Configure switch and power pins
|
||||
configure();
|
||||
|
@ -56,14 +58,12 @@ namespace pimoroni {
|
|||
sw_enable[0]->to_output(false);
|
||||
sw_enable[1]->to_output(false);
|
||||
|
||||
__accessor->set_slow_config(power_good[0], false);
|
||||
__accessor->set_slow_config(power_good[1], false);
|
||||
power_good[0]->to_input();
|
||||
power_good[1]->to_input();
|
||||
}
|
||||
|
||||
void DualSwitchedModule::enable(uint output) {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
if(output < 1 || output > NUM_SWITCHES) {
|
||||
throw std::runtime_error("switch index out of range. Expected 1 to 2\n");
|
||||
}
|
||||
|
@ -72,9 +72,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void DualSwitchedModule::disable(uint output) {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
if(output < 1 || output > NUM_SWITCHES) {
|
||||
throw std::runtime_error("switch index out of range. Expected 1 to 2\n");
|
||||
}
|
||||
|
@ -83,9 +81,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
bool DualSwitchedModule::is_enabled(uint output) {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
if(output < 1 || output > NUM_SWITCHES) {
|
||||
throw std::runtime_error("switch index out of range. Expected 1 to 2\n");
|
||||
}
|
||||
|
@ -94,9 +90,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void DualSwitchedModule::output(uint output, bool val) {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
if(output < 1 || output > NUM_SWITCHES) {
|
||||
throw std::runtime_error("switch index out of range. Expected 1 to 2\n");
|
||||
}
|
||||
|
@ -105,9 +99,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
bool DualSwitchedModule:: read_output(uint output) {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
if(output < 1 || output > NUM_SWITCHES) {
|
||||
throw std::runtime_error("switch index out of range. Expected 1 to 2\n");
|
||||
}
|
||||
|
@ -116,14 +108,12 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
bool DualSwitchedModule::read_power_good(uint output) {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
if(output < 1 || output > NUM_SWITCHES) {
|
||||
throw std::runtime_error("switch index out of range. Expected 1 to 2\n");
|
||||
}
|
||||
|
||||
return __accessor->get_slow_input(power_good[output - 1]);
|
||||
return power_good[output - 1]->value();
|
||||
}
|
||||
|
||||
float DualSwitchedModule::read_temperature() {
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace pimoroni {
|
|||
private:
|
||||
IO* sw_output[2];
|
||||
IO* sw_enable[2];
|
||||
TCA power_good[2];
|
||||
TCA_IO* power_good[2];
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
@ -86,30 +86,22 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void LEDStripModule::enable() {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
power_en->value(true);
|
||||
}
|
||||
|
||||
void LEDStripModule::disable() {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
power_en->value(false);
|
||||
}
|
||||
|
||||
bool LEDStripModule::is_enabled() {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
return power_en->value();
|
||||
}
|
||||
|
||||
bool LEDStripModule::read_power_good() {
|
||||
if(!is_initialised()) {
|
||||
throw std::runtime_error("Module not initialised\n");
|
||||
}
|
||||
CHECK_INITIALISED
|
||||
return power_good->value();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,9 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void QuadServoDirectModule::initialise(const SLOT& slot, SlotAccessor& accessor) {
|
||||
// Create servo cluster object
|
||||
servos = new ServoCluster(pio0, 0, slot.FAST1, NUM_SERVOS);
|
||||
|
||||
// Configure strip and power pins
|
||||
configure();
|
||||
|
||||
|
@ -35,7 +38,7 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void QuadServoDirectModule::configure() {
|
||||
|
||||
servos->disable_all();
|
||||
}
|
||||
|
||||
float QuadServoDirectModule::read_adc1() {
|
||||
|
|
|
@ -16,11 +16,15 @@ namespace pimoroni {
|
|||
QuadServoRegModule::QuadServoRegModule(bool halt_on_not_pgood) :
|
||||
YukonModule(),
|
||||
halt_on_not_pgood(halt_on_not_pgood),
|
||||
servos(nullptr) {
|
||||
servos(nullptr),
|
||||
power_en(nullptr),
|
||||
power_good(nullptr) {
|
||||
}
|
||||
|
||||
QuadServoRegModule::~QuadServoRegModule() {
|
||||
delete(servos);
|
||||
delete(power_en);
|
||||
delete(power_good);
|
||||
}
|
||||
|
||||
std::string QuadServoRegModule::name() {
|
||||
|
@ -28,6 +32,13 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void QuadServoRegModule::initialise(const SLOT& slot, SlotAccessor& accessor) {
|
||||
// Create servo cluster object
|
||||
servos = new ServoCluster(pio0, 0, slot.FAST1, NUM_SERVOS);
|
||||
|
||||
// Create the power control pin objects
|
||||
power_en = new TCA_IO(slot.SLOW1, accessor);
|
||||
power_good = new TCA_IO(slot.SLOW2, accessor);
|
||||
|
||||
// Configure strip and power pins
|
||||
configure();
|
||||
|
||||
|
@ -36,23 +47,30 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void QuadServoRegModule::configure() {
|
||||
servos->disable_all();
|
||||
|
||||
power_en->to_output(false);
|
||||
power_good->to_input();
|
||||
}
|
||||
|
||||
void QuadServoRegModule::enable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
power_en->value(true);
|
||||
}
|
||||
|
||||
void QuadServoRegModule::disable() {
|
||||
|
||||
CHECK_INITIALISED
|
||||
power_en->value(false);
|
||||
}
|
||||
|
||||
bool QuadServoRegModule::is_enabled() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return power_en->value();
|
||||
}
|
||||
|
||||
bool QuadServoRegModule::read_power_good() {
|
||||
return 0; // TODO
|
||||
CHECK_INITIALISED
|
||||
return power_good->value();
|
||||
}
|
||||
|
||||
float QuadServoRegModule::read_temperature() {
|
||||
|
|
|
@ -44,8 +44,8 @@ public:
|
|||
public:
|
||||
ServoCluster* servos;
|
||||
private:
|
||||
IO* power_en;
|
||||
IO* power_good;
|
||||
TCA_IO* power_en;
|
||||
TCA_IO* power_good;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
@ -2,6 +2,7 @@ add_library(yukon INTERFACE)
|
|||
|
||||
target_sources(yukon INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/yukon.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/modules/common.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/logging.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/modules/led_strip/led_strip.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/modules/quad_servo/quad_servo_direct.cpp
|
||||
|
|
Ładowanie…
Reference in New Issue