diff --git a/tasmota/xdrv_34_wemos_motor_v1.ino b/tasmota/xdrv_34_wemos_motor_v1.ino index cfd9de2d2..b38a863e1 100644 --- a/tasmota/xdrv_34_wemos_motor_v1.ino +++ b/tasmota/xdrv_34_wemos_motor_v1.ino @@ -1,7 +1,7 @@ /* xdrv_34_wemos_motor_v1.ino - Support for I2C WEMOS motor shield (6612FNG) - Copyright (C) 2021 Denis Sborets and Theo Arends + Copyright (C) 2021 Denis Sborets, Theo Arends, Peter Franck This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,6 +21,7 @@ #ifdef USE_WEMOS_MOTOR_V1 /*********************************************************************************************\ * WEMOS_MOTOR_V1 - DC motor driver shield (6612FNG) v 1.0.0 + * WEMOS_MOTOR_V2 - DC motor driver shield (6612FNG) v 2.0.0 (#define WEMOS_MOTOR_V2) * * I2C Address: 0x30 * @@ -28,10 +29,11 @@ * driver44 ,,{,} * command: * RESET - reset a motor shield - * SETMOTOR - seter motor state + * SETMOTOR - set motor state * motor: * 0 - motor A * 1 - motor B + * 2 - both motors (V2 only) * direction: * 0 - short break * 1 - CCW @@ -61,6 +63,38 @@ #define STOP 3 #define STANDBY 4 +#ifdef WEMOS_MOTOR_V2 // Support latest Lolin board +// #define DEBUG_WEMOS_MOTOR // be more verbose +#define WEMOS_MOTOR_PID_V2 0x02 // Product ID of V2.0.0 +#define WMTR_V2_BUFFSZ 5 // I2C command buffer size +enum WEMOS_MOTOR_V2_CMD +{ + WV2_GET_SLAVE_STATUS = 0x01, + WV2_RESET_SLAVE, + WV2_CHANGE_I2C_ADDRESS, + WV2_CHANGE_STATUS, + WV2_CHANGE_FREQ, + WV2_CHANGE_DUTY +}; +enum WEMOS_MOTOR_V2_STATUS +{ + WV2_MOTOR_STATUS_STOP = 0x00, + WV2_MOTOR_STATUS_CCW, + WV2_MOTOR_STATUS_CW, + WV2_MOTOR_STATUS_SHORT_BRAKE, + WV2_MOTOR_STATUS_STANDBY +}; +enum WEMOS_MOTOR_V2_CHANNEL +{ + WV2_MOTOR_CH_A=0x00, + WV2_MOTOR_CH_B, + WV2_MOTOR_CH_BOTH +}; +const char WemosMotorDriver[] = "WEMOS_MOTOR_V2"; +#else // WEMOS_MOTOR_V2 +const char WemosMotorDriver[] = "WEMOS_MOTOR_V1"; +#endif // WEMOS_MOTOR_V2 + struct WMOTORV1 { bool detected = false; uint8_t motor; @@ -69,31 +103,75 @@ struct WMOTORV1 { void WMotorV1Detect(void) { if (I2cSetDevice(WEMOS_MOTOR_V1_ADDR)) { +#ifdef WEMOS_MOTOR_V2 + uint8_t i2c_data[WMTR_V2_BUFFSZ]; + // Check product ID & version + i2c_data[0] = WV2_GET_SLAVE_STATUS; + WMotorV2command(i2c_data, 1); + if (i2c_data[0] == WEMOS_MOTOR_PID_V2) { + #ifdef DEBUG_WEMOS_MOTOR + AddLog(LOG_LEVEL_INFO, PSTR("WEM: %s Rev. %u found"), WemosMotorDriver, i2c_data[1]); + #endif // DEBUG_WEMOS_MOTOR + } else { return; } +#endif // WEMOS_MOTOR_V2 WMotorV1.detected = true; - I2cSetActiveFound(WEMOS_MOTOR_V1_ADDR, "WEMOS_MOTOR_V1"); + I2cSetActiveFound(WEMOS_MOTOR_V1_ADDR, WemosMotorDriver); WMotorV1Reset(); } } void WMotorV1Reset(void) { -// Wire.begin(); WMotorV1SetFrequency(WEMOS_MOTOR_V1_FREQ); } void WMotorV1SetFrequency(uint32_t freq) { +#ifdef WEMOS_MOTOR_V2 + uint8_t i2c_data[WMTR_V2_BUFFSZ]; + i2c_data[0] = WV2_CHANGE_FREQ; + i2c_data[1] = WV2_MOTOR_CH_BOTH; + i2c_data[2] = (uint8_t)(freq & 0xff); + i2c_data[3] = (uint8_t)((freq >> 8) & 0xff); + i2c_data[4] = (uint8_t)((freq >> 16) & 0xff); + WMotorV2command(i2c_data, 5); +#else // WEMOS_MOTOR_V2 Wire.beginTransmission(WEMOS_MOTOR_V1_ADDR); Wire.write(((byte)(freq >> 16)) & (byte)0x0f); Wire.write((byte)(freq >> 16)); Wire.write((byte)(freq >> 8)); Wire.write((byte)freq); - Wire.endTransmission(); // stop transmitting -// delay(100); + Wire.endTransmission(); +#endif // WEMOS_MOTOR_V2 } void WMotorV1SetMotor(uint8_t motor, uint8_t dir, float pwm_val) { +#ifdef WEMOS_MOTOR_V2 + uint8_t i2c_data[WMTR_V2_BUFFSZ]; + // send command + uint8_t cmd = dir; + if (cmd == 0 || cmd == 3) { + cmd ^= 3; // short brake and stop swapped + } + i2c_data[0] = WV2_CHANGE_STATUS; + i2c_data[1] = (uint8_t)motor; + i2c_data[2] = (uint8_t)cmd; + WMotorV2command(i2c_data, 3); + #ifdef DEBUG_WEMOS_MOTOR + AddLog(LOG_LEVEL_INFO, PSTR("WEM: Ch: %u Cmd: %u"), motor, cmd); + #endif // DEBUG_WEMOS_MOTOR + // set duty cycle + uint16_t duty = (pwm_val > 100.0) ? 10000 : (uint16_t)(pwm_val * 100); + #ifdef DEBUG_WEMOS_MOTOR + AddLog(LOG_LEVEL_INFO, PSTR("WEM: Duty: %u"), duty); + #endif // DEBUG_WEMOS_MOTOR + i2c_data[0] = WV2_CHANGE_DUTY; + i2c_data[1] = (uint8_t)motor; + i2c_data[2] = (uint8_t)(duty & 0xff); + i2c_data[3] = (uint8_t)((duty >> 8) & 0xff); + WMotorV2command(i2c_data,4); +#else // WEMOS_MOTOR_V2 Wire.beginTransmission(WEMOS_MOTOR_V1_ADDR); Wire.write(motor | (byte)0x10); Wire.write(dir); @@ -106,7 +184,7 @@ void WMotorV1SetMotor(uint8_t motor, uint8_t dir, float pwm_val) Wire.write((byte)(_pwm_val >> 8)); Wire.write((byte)_pwm_val); Wire.endTransmission(); -// delay(100); +#endif // WEMOS_MOTOR_V2 } bool WMotorV1Command(void) @@ -132,8 +210,13 @@ bool WMotorV1Command(void) char *command = strtok(XdrvMailbox.data, ","); if (strcmp(command, "RESET") == 0) { +#ifdef WEMOS_MOTOR_V2 // do a 'real' reset + uint8_t i2c_data[WMTR_V2_BUFFSZ]; + i2c_data[0] = WV2_RESET_SLAVE; + WMotorV2command(i2c_data, 1); +#endif // WEMOS_MOTOR_V2 WMotorV1Reset(); - Response_P(PSTR("{\"WEMOS_MOTOR_V1\":{\"RESET\":\"OK\"}}")); + Response_P(PSTR("{\"%s\":{\"RESET\":\"OK\"}}"), WemosMotorDriver); return true; } @@ -148,13 +231,39 @@ bool WMotorV1Command(void) } WMotorV1SetMotor(motor, dir, duty); - Response_P(PSTR("{\"WEMOS_MOTOR_V1\":{\"SETMOTOR\":\"OK\"}}")); + Response_P(PSTR("{\"%s\":{\"SETMOTOR\":\"OK\"}}"), WemosMotorDriver); return true; } } return false; } +#ifdef WEMOS_MOTOR_V2 +void WMotorV2command(uint8_t *data, uint8_t len) // process V2 request +{ + int i; + Wire.beginTransmission(WEMOS_MOTOR_V1_ADDR); + for (i = 0; i < len; i++) { + Wire.write(data[i]); + } + Wire.endTransmission(); + + if (data[0] == WV2_GET_SLAVE_STATUS) { + Wire.requestFrom(WEMOS_MOTOR_V1_ADDR, 2); + } else { + Wire.requestFrom(WEMOS_MOTOR_V1_ADDR, 1); + } + i = 0; + bzero(data, WMTR_V2_BUFFSZ); + while (Wire.available()) + { + data[i] = Wire.read(); + i++; + } +} +#endif // WEMOS_MOTOR_V2 + + /*********************************************************************************************\ * Interface \*********************************************************************************************/