mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 10:46:31 +00:00
Refactor BL09xx driver
This commit is contained in:
parent
20038aac18
commit
388b3d5f54
@ -51,20 +51,6 @@
|
||||
#define BL0942_UREF 15187
|
||||
#define BL0942_IREF 251213
|
||||
|
||||
#define BL09XX_PULSES_NOT_INITIALIZED -1
|
||||
|
||||
#define BL0939_BUFFER_SIZE 35
|
||||
#define BL0940_BUFFER_SIZE 35
|
||||
#define BL0942_BUFFER_SIZE 23
|
||||
|
||||
#define BL0939_MODEL 39
|
||||
#define BL0940_MODEL 40
|
||||
#define BL0942_MODEL 42
|
||||
|
||||
#define BL0939_ADDRESS 0x05
|
||||
#define BL0940_ADDRESS 0x00
|
||||
#define BL0942_ADDRESS 0x08
|
||||
|
||||
#define BL09XX_WRITE_COMMAND 0xA0 // 0xA8 according to documentation
|
||||
#define BL09XX_REG_I_FAST_RMS_CTRL 0x10
|
||||
#define BL09XX_REG_MODE 0x18
|
||||
@ -81,13 +67,26 @@
|
||||
|
||||
TasmotaSerial *Bl09XXSerial = nullptr;
|
||||
|
||||
enum Bl09xxModel { BL0939_MODEL, BL0940_MODEL, BL0942_MODEL, BL09XX_MODEL }; // Model index number starting from 0
|
||||
const uint32_t bl09xx_pref[] = { BL0939_PREF, BL0940_PREF, BL0942_PREF }; // Power reference constant
|
||||
const uint32_t bl09xx_uref[] = { BL0939_UREF, BL0940_UREF, BL0942_UREF }; // Voltage reference constant
|
||||
const uint32_t bl09xx_iref[] = { BL0939_IREF, BL0940_IREF, BL0942_IREF }; // Current reference constant
|
||||
const uint8_t bl09xx_type[] = { 39, 40, 42 }; // Device name BL09xx
|
||||
const uint8_t bl09xx_phase_count[] = { 2, 1, 1 }; // Supported phase/channel count
|
||||
const uint8_t bl09xx_address[] = { 0x05, 0x00, 0x08 }; // Device address
|
||||
const uint8_t bl09xx_buffer_size[] = { 35, 35, 23 }; // Serial receive buffer size
|
||||
const uint8_t bl09xx_init[5][4] = {
|
||||
{ BL09XX_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A }, // Reset to default
|
||||
{ BL09XX_REG_USR_WRPROT, 0x55, 0x00, 0x00 }, // Enable User Operation Write
|
||||
{ BL09XX_REG_MODE, 0x00, 0x10, 0x00 }, // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS
|
||||
{ BL09XX_REG_TPS_CTRL, 0xFF, 0x47, 0x00 }, // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS
|
||||
{ BL09XX_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00 } // 0x181C = Half cycle, Fast RMS threshold 6172
|
||||
};
|
||||
|
||||
struct BL09XX {
|
||||
long voltage = 0;
|
||||
long current[2] = { 0, };
|
||||
long power[2] = { 0, };
|
||||
long power_cycle_first = 0;
|
||||
long cf_pulses[2] = { 0, };
|
||||
long cf_pulses_last_time[2] = { BL09XX_PULSES_NOT_INITIALIZED, BL09XX_PULSES_NOT_INITIALIZED};
|
||||
uint32_t voltage = 0;
|
||||
uint32_t current[2] = { 0, };
|
||||
uint32_t power[2] = { 0, };
|
||||
float temperature;
|
||||
uint16_t tps1 = 0;
|
||||
uint8_t *rx_buffer = nullptr;
|
||||
@ -99,15 +98,6 @@ struct BL09XX {
|
||||
bool received = false;
|
||||
} Bl09XX;
|
||||
|
||||
const uint8_t bl09xx_init[5][4] = {
|
||||
{ BL09XX_REG_SOFT_RESET, 0x5A, 0x5A, 0x5A }, // Reset to default
|
||||
{ BL09XX_REG_USR_WRPROT, 0x55, 0x00, 0x00 }, // Enable User Operation Write
|
||||
{ BL09XX_REG_MODE, 0x00, 0x10, 0x00 }, // 0x0100 = CF_UNABLE energy pulse, AC_FREQ_SEL 50Hz, RMS_UPDATE_SEL 800mS
|
||||
{ BL09XX_REG_TPS_CTRL, 0xFF, 0x47, 0x00 }, // 0x47FF = Over-current and leakage alarm on, Automatic temperature measurement, Interval 100mS
|
||||
{ BL09XX_REG_I_FAST_RMS_CTRL, 0x1C, 0x18, 0x00 } // 0x181C = Half cycle, Fast RMS threshold 6172
|
||||
};
|
||||
|
||||
|
||||
bool Bl09XXDecode3940(void) {
|
||||
// 0 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
|
||||
// Sample from BL0940 (single channel)
|
||||
@ -136,26 +126,20 @@ bool Bl09XXDecode3940(void) {
|
||||
float t = ((170.0f/448.0f)*(((float)Bl09XX.tps1/2.0f)-32.0f))-45.0f;
|
||||
Bl09XX.temperature = ConvertTemp(t);
|
||||
|
||||
Bl09XX.voltage = Bl09XX.rx_buffer[12] << 16 | Bl09XX.rx_buffer[11] << 8 | Bl09XX.rx_buffer[10]; // V_RMS unsigned
|
||||
|
||||
int32_t tmp;
|
||||
Bl09XX.current[0] = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // IA_RMS unsigned
|
||||
tmp = Bl09XX.rx_buffer[18] << 24 | Bl09XX.rx_buffer[17] << 16 | Bl09XX.rx_buffer[16] << 8; // WATT_A signed
|
||||
Bl09XX.power[0] = abs(tmp >> 8); // WATT_A unsigned
|
||||
tmp = Bl09XX.rx_buffer[24] << 24 | Bl09XX.rx_buffer[23] << 16 | Bl09XX.rx_buffer[22] << 8; // CFA_CNT signed
|
||||
Bl09XX.cf_pulses[0] = abs(tmp >> 8); // CFA_CNT unsigned
|
||||
Bl09XX.voltage = Bl09XX.rx_buffer[12] << 16 | Bl09XX.rx_buffer[11] << 8 | Bl09XX.rx_buffer[10]; // V_RMS unsigned
|
||||
Bl09XX.current[0] = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // IA_RMS unsigned
|
||||
int32_t tmp = Bl09XX.rx_buffer[18] << 24 | Bl09XX.rx_buffer[17] << 16 | Bl09XX.rx_buffer[16] << 8; // WATT_A signed
|
||||
Bl09XX.power[0] = abs(tmp >> 8); // WATT_A unsigned
|
||||
|
||||
if (Energy.phase_count > 1) {
|
||||
Bl09XX.current[1] = Bl09XX.rx_buffer[9] << 16 | Bl09XX.rx_buffer[8] << 8 | Bl09XX.rx_buffer[7]; // IB_RMS unsigned
|
||||
tmp = Bl09XX.rx_buffer[21] << 24 | Bl09XX.rx_buffer[20] << 16 | Bl09XX.rx_buffer[19] << 8; // WATT_B signed
|
||||
Bl09XX.power[1] = abs(tmp >> 8); // WATT_B unsigned
|
||||
tmp = Bl09XX.rx_buffer[27] << 24 | Bl09XX.rx_buffer[26] << 16 | Bl09XX.rx_buffer[25] << 8; // CFB_CNT signed
|
||||
Bl09XX.cf_pulses[1] = abs(tmp >> 8); // CFB_CNT unsigned
|
||||
Bl09XX.current[1] = Bl09XX.rx_buffer[9] << 16 | Bl09XX.rx_buffer[8] << 8 | Bl09XX.rx_buffer[7]; // IB_RMS unsigned
|
||||
tmp = Bl09XX.rx_buffer[21] << 24 | Bl09XX.rx_buffer[20] << 16 | Bl09XX.rx_buffer[19] << 8; // WATT_B signed
|
||||
Bl09XX.power[1] = abs(tmp >> 8); // WATT_B unsigned
|
||||
}
|
||||
|
||||
#ifdef DEBUG_BL09XX
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d/%d, P %d/%d, C %d/%d, T %d"),
|
||||
Bl09XX.voltage, Bl09XX.current[0], Bl09XX.current[1], Bl09XX.power[0], Bl09XX.power[1], Bl09XX.cf_pulses[0], Bl09XX.cf_pulses[1], Bl09XX.tps1);
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d/%d, P %d/%d, T %d"),
|
||||
Bl09XX.voltage, Bl09XX.current[0], Bl09XX.current[1], Bl09XX.power[0], Bl09XX.power[1], Bl09XX.tps1);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -185,18 +169,14 @@ bool Bl09XXDecode42(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Bl09XX.voltage = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // V_RMS unsigned
|
||||
|
||||
int32_t tmp;
|
||||
Bl09XX.current[0] = Bl09XX.rx_buffer[3] << 16 | Bl09XX.rx_buffer[2] << 8 | Bl09XX.rx_buffer[1]; // IA_RMS unsigned
|
||||
tmp = Bl09XX.rx_buffer[12] << 24 | Bl09XX.rx_buffer[11] << 16 | Bl09XX.rx_buffer[10] << 8; // WATT_A signed
|
||||
Bl09XX.power[0] = abs(tmp >> 8); // WATT_A unsigned
|
||||
tmp = Bl09XX.rx_buffer[15] << 24 | Bl09XX.rx_buffer[14] << 16 | Bl09XX.rx_buffer[13] << 8; // CFA_CNT signed
|
||||
Bl09XX.cf_pulses[0] = abs(tmp >> 8); // CFA_CNT unsigned
|
||||
Bl09XX.voltage = Bl09XX.rx_buffer[6] << 16 | Bl09XX.rx_buffer[5] << 8 | Bl09XX.rx_buffer[4]; // V_RMS unsigned
|
||||
Bl09XX.current[0] = Bl09XX.rx_buffer[3] << 16 | Bl09XX.rx_buffer[2] << 8 | Bl09XX.rx_buffer[1]; // IA_RMS unsigned
|
||||
int32_t tmp = Bl09XX.rx_buffer[12] << 24 | Bl09XX.rx_buffer[11] << 16 | Bl09XX.rx_buffer[10] << 8; // WATT_A signed
|
||||
Bl09XX.power[0] = abs(tmp >> 8); // WATT_A unsigned
|
||||
|
||||
#ifdef DEBUG_BL09XX
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d, P %d, C %d"),
|
||||
Bl09XX.voltage, Bl09XX.current[0], Bl09XX.power[0], Bl09XX.cf_pulses[0]);
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: U %d, I %d, P %d"),
|
||||
Bl09XX.voltage, Bl09XX.current[0], Bl09XX.power[0]);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
@ -207,7 +187,7 @@ void Bl09XXUpdateEnergy() {
|
||||
Energy.voltage[0] = (float)Bl09XX.voltage / Settings->energy_voltage_calibration;
|
||||
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("BL9: Voltage %f, Temp %f"), Energy.voltage[0], Bl09XX.temperature);
|
||||
for (uint32_t chan = 0; chan < Energy.phase_count; chan++) {
|
||||
if (Bl09XX.power[chan] > Settings->energy_power_calibration) { // We need at least 1W
|
||||
if (Bl09XX.power[chan] > Settings->energy_power_calibration) { // We need at least 1W
|
||||
Energy.active_power[chan] = (float)Bl09XX.power[chan] / Settings->energy_power_calibration;
|
||||
Energy.current[chan] = (float)Bl09XX.current[chan] / Settings->energy_current_calibration;
|
||||
#ifdef DEBUG_BL09XX
|
||||
@ -222,12 +202,12 @@ void Bl09XXUpdateEnergy() {
|
||||
}
|
||||
}
|
||||
} else { // Powered off
|
||||
// Bl09XX.power_cycle_first = 0;
|
||||
Energy.voltage[0] = 0;
|
||||
Energy.active_power[0] = Energy.active_power[1] = 0;
|
||||
Energy.current[0] = Energy.current[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Bl09XXSerialInput(void) {
|
||||
while (Bl09XXSerial->available()) {
|
||||
yield();
|
||||
@ -249,12 +229,12 @@ void Bl09XXSerialInput(void) {
|
||||
if (checksum == Bl09XX.rx_buffer[Bl09XX.buffer_size -1]) {
|
||||
Energy.data_valid[0] = 0;
|
||||
bool ok;
|
||||
if (BL0942_MODEL == Bl09XX.model)
|
||||
if (BL0942_MODEL == Bl09XX.model) {
|
||||
ok = Bl09XXDecode42();
|
||||
else
|
||||
} else {
|
||||
ok = Bl09XXDecode3940();
|
||||
if (ok)
|
||||
Bl09XXUpdateEnergy();
|
||||
}
|
||||
if (ok) { Bl09XXUpdateEnergy(); }
|
||||
Bl09XX.received = false;
|
||||
return;
|
||||
} else {
|
||||
@ -304,24 +284,9 @@ void Bl09XXInit(void) {
|
||||
ClaimSerial();
|
||||
}
|
||||
if (HLW_UREF_PULSE == Settings->energy_voltage_calibration) {
|
||||
switch (Bl09XX.model) {
|
||||
case BL0939_MODEL:
|
||||
Settings->energy_voltage_calibration = BL0939_UREF;
|
||||
Settings->energy_current_calibration = BL0939_IREF;
|
||||
Settings->energy_power_calibration = BL0939_PREF;
|
||||
break;
|
||||
case BL0940_MODEL:
|
||||
Settings->energy_voltage_calibration = BL0940_UREF;
|
||||
Settings->energy_current_calibration = BL0940_IREF;
|
||||
Settings->energy_power_calibration = BL0940_PREF;
|
||||
break;
|
||||
case BL0942_MODEL:
|
||||
default:
|
||||
Settings->energy_voltage_calibration = BL0942_UREF;
|
||||
Settings->energy_current_calibration = BL0942_IREF;
|
||||
Settings->energy_power_calibration = BL0942_PREF;
|
||||
break;
|
||||
}
|
||||
Settings->energy_voltage_calibration = bl09xx_uref[Bl09XX.model];
|
||||
Settings->energy_current_calibration = bl09xx_iref[Bl09XX.model];
|
||||
Settings->energy_power_calibration = bl09xx_pref[Bl09XX.model];
|
||||
}
|
||||
if ((BL0940_MODEL == Bl09XX.model) && (Settings->energy_current_calibration < (BL0940_IREF / 20))) {
|
||||
Settings->energy_current_calibration *= 100;
|
||||
@ -329,7 +294,7 @@ void Bl09XXInit(void) {
|
||||
|
||||
if (BL0942_MODEL != Bl09XX.model) {
|
||||
#ifdef DEBUG_BL09XX
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Send Init string for model BL09%02d"), Bl09XX.model);
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("BL9: Send Init string"));
|
||||
#endif
|
||||
Energy.use_overtemp = true; // Use global temperature for overtemp detection
|
||||
for (uint32_t i = 0; i < 5; i++) {
|
||||
@ -352,32 +317,32 @@ void Bl09XXInit(void) {
|
||||
}
|
||||
|
||||
void Bl09XXPreInit(void) {
|
||||
if (PinUsed(GPIO_BL0939_RX) && PinUsed(GPIO_TXD)) {
|
||||
Bl09XX.model = BL0939_MODEL;
|
||||
Bl09XX.address = BL0939_ADDRESS;
|
||||
Bl09XX.buffer_size = BL0939_BUFFER_SIZE;
|
||||
Bl09XX.rx_pin = Pin(GPIO_BL0939_RX);
|
||||
} else if (PinUsed(GPIO_BL0940_RX) && PinUsed(GPIO_TXD)) {
|
||||
Bl09XX.model = BL0940_MODEL;
|
||||
Bl09XX.address = BL0940_ADDRESS;
|
||||
Bl09XX.buffer_size = BL0940_BUFFER_SIZE;
|
||||
Bl09XX.rx_pin = Pin(GPIO_BL0940_RX);
|
||||
}
|
||||
else if (PinUsed(GPIO_BL0942_RX) && PinUsed(GPIO_TXD)) {
|
||||
Bl09XX.model = BL0942_MODEL;
|
||||
Bl09XX.address = BL0942_ADDRESS;
|
||||
Bl09XX.buffer_size = BL0942_BUFFER_SIZE;
|
||||
Bl09XX.rx_pin = Pin(GPIO_BL0942_RX);
|
||||
}
|
||||
if (Bl09XX.model) {
|
||||
Bl09XX.rx_buffer = (uint8_t*)(malloc(Bl09XX.buffer_size));
|
||||
if (Bl09XX.rx_buffer != nullptr) {
|
||||
Energy.voltage_common = true; // Use common voltage
|
||||
Energy.frequency_common = true; // Use common frequency
|
||||
Energy.use_overtemp = true; // Use global temperature for overtemp detection
|
||||
Energy.phase_count = (BL0939_MODEL == Bl09XX.model) ? 2 : 1; // Handle two channels as two phases
|
||||
TasmotaGlobal.energy_driver = XNRG_14;
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("BL9: Enabling BL09%02d"), Bl09XX.model);
|
||||
if (PinUsed(GPIO_TXD)) {
|
||||
Bl09XX.model = BL09XX_MODEL;
|
||||
if (PinUsed(GPIO_BL0939_RX)) {
|
||||
Bl09XX.model = BL0939_MODEL;
|
||||
Bl09XX.rx_pin = Pin(GPIO_BL0939_RX);
|
||||
}
|
||||
else if (PinUsed(GPIO_BL0940_RX)) {
|
||||
Bl09XX.model = BL0940_MODEL;
|
||||
Bl09XX.rx_pin = Pin(GPIO_BL0940_RX);
|
||||
}
|
||||
else if (PinUsed(GPIO_BL0942_RX)) {
|
||||
Bl09XX.model = BL0942_MODEL;
|
||||
Bl09XX.rx_pin = Pin(GPIO_BL0942_RX);
|
||||
}
|
||||
if (Bl09XX.model != BL09XX_MODEL) {
|
||||
Bl09XX.address = bl09xx_address[Bl09XX.model];
|
||||
Bl09XX.buffer_size = bl09xx_buffer_size[Bl09XX.model];
|
||||
Bl09XX.rx_buffer = (uint8_t*)(malloc(Bl09XX.buffer_size));
|
||||
if (Bl09XX.rx_buffer != nullptr) {
|
||||
Energy.voltage_common = true; // Use common voltage
|
||||
Energy.frequency_common = true; // Use common frequency
|
||||
Energy.use_overtemp = true; // Use global temperature for overtemp detection
|
||||
Energy.phase_count = bl09xx_phase_count[Bl09XX.model]; // Handle two channels as two phases
|
||||
TasmotaGlobal.energy_driver = XNRG_14;
|
||||
AddLog(LOG_LEVEL_DEBUG,PSTR("BL9: Enabling BL09%02d"), bl09xx_type[Bl09XX.model]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user