Tool/software:
Hello TI Community,
I'm currently working on a project involving the DRV8244-Q1 motor driver, interfacing it with an ESP32 via SPI. I'm having trouble getting the driver to respond to any SPI commands other than 'clear fault' and 'read device ID'. After issuing the 'clear fault' command, I can successfully read the device ID, but any subsequent attempt to write configuration registers or control commands results in the chip not responding as expected.
Here is an overview of the setup and the key issues:
System Overview:
Microcontroller: ESP32
Motor Driver: DRV8244-Q1
SPI Clock Frequency: 1 MHz
SPI Settings: MSBFIRST, SPI Mode 1
Wiring: I have confirmed all connections to be correct, and the nSCS pin is controlled properly during transactions.
No Response to Other Commands: If I attempt to send any other command apart from 'clear fault' and 'read device ID', the chip only responds with 0x0
when reading from FAULT_SUMMARY_REGISTER
or STATUS1_REGISTER
. This seems to indicate that the chip is either not processing these commands correctly or is locked in an unknown state. 2. DRV8244 Output Control: The chip seems to be unresponsive when attempting to control the motor outputs. I have ensured that the nSLEEP
and DRVOFF
pins are properly set to enable the active state, but I still cannot get the motor driver to actively respond to control signals.
What I've Tried:
SPI Timing Compliance: I have reviewed the SPI timing requirements from the datasheet and made sure my delays for
nSCS
and clock timing are compliant.Unlocking Registers: I have added explicit commands to unlock the configuration registers before making any changes, as per the datasheet recommendations.
Status and Fault Checks: After attempting a configuration write, I read back the
FAULT_SUMMARY_REGISTER
and always receive0x0
, which indicates no active communication or fault status.
Specific Questions:
SPI Timing: Are there any specific timing nuances that are commonly overlooked when dealing with DRV8244 that could cause the chip to be unresponsive?
Configuration Locking Mechanism: Am I missing a step related to the locking and unlocking mechanism of the configuration registers? I explicitly unlock with the
COMMAND_REGISTER
but it seems the device still doesn't respond to configuration changes.Control Mode Settings: I have attempted to set
CONFIG4_REGISTER
to0b00000000
to configure the device for PWM control, but it doesn't seem to enable the output. Could there be an issue with the values I am using to configure the registers for active PWM control?EN/IN Pins for PWM: According to the datasheet, both
EN/IN1
andPH/IN2
must be set high for active operation. I have tried doing this, but the output remains inactive. Is there something else I should be configuring in the registers to properly drive the motor outputs in PWM mode?
I've attached my code below for reference. Any insights or suggestions would be greatly appreciated. I'm really stuck at this point and could use some expert guidance.
Thank you for your help!
Image may be NSFW.
Clik here to view.
/* * Register Settings Translation * ---------------------------- * COMMAND_REGISTER (0x08): Used to send commands to the device, such as clearing faults. * CONFIG1_REGISTER (0x0A): Configuration register for basic device settings (e.g., open load detection, mode selection). * - `0x80`: Enable open load detection * - `0x40`: Set mode to standby * CONFIG4_REGISTER (0x0D): Configuration register for setting over-current protection thresholds, filter time, and other settings. * - `0x00`: TOCP_SEL = 6 µsec, OCP_SEL = 100%, DRVOFF_SEL = OR, EN_IN1_SEL = OR, PH_IN2_SEL = OR * - `0x10`: TOCP_SEL = 6 µsec, OCP_SEL = 75%, DRVOFF_SEL = OR, EN_IN1_SEL = OR, PH_IN2_SEL = OR * - `0x20`: TOCP_SEL = 6 µsec, OCP_SEL = 50%, DRVOFF_SEL = OR, EN_IN1_SEL = OR, PH_IN2_SEL = OR * - `0x50`: TOCP_SEL = 3 µsec, OCP_SEL = 75%, DRVOFF_SEL = AND, EN_IN1_SEL = OR, PH_IN2_SEL = OR * FAULT_SUMMARY_REGISTER (0x01): Reports fault conditions in the system, such as over-current or thermal shutdown. * - `0x80`: SPI communication fault detected * - `0x40`: Power-On Reset detected * - `0x20`: General fault present * - `0x10`: VM Over Voltage detected * - `0x08`: VM Under Voltage detected * - `0x04`: Over Current Protection triggered * - `0x02`: Thermal Shutdown detected * - `0x01`: Open Load Active detected * STATUS1_REGISTER (0x02): Reports status conditions like open load detection, device active state, etc. * - `0x80`: Open Load Active detected on OUT1 * - `0x40`: Open Load Active detected on OUT2 * - `0x20`: ITRIP comparator triggered * - `0x10`: Device in ACTIVE state */ #include <Wire.h> // For HUSB238 I2C communication #include "Adafruit_HUSB238.h" // HUSB238 library #include <SPI.h> // For DRV8244 SPI communication // SPI macros for bit manipulation #define SPI_ADDRESS_MASK 0x3F00 #define SPI_ADDRESS_POS 8 #define SPI_DATA_MASK 0x00FF #define SPI_DATA_POS 0 #define SPI_RW_BIT_MASK 0x8000 // Pin definitions #define SDA_PIN 10 #define SCL_PIN 8 #define SCLK_PIN 2 #define SDI_PIN 3 #define SDO_PIN 4 #define NSCS_PIN 5 #define IN1_PIN 0 // PH/IN1 pin for motor direction control #define IN2_PIN 1 // PH/IN2 pin for motor direction control #define PWM_CHANNEL 0 #define PWM_FREQ 3000 // Set PWM frequency to 20 kHz #define PWM_RESOLUTION 8 // 8-bit resolution (0-255) Adafruit_HUSB238 husb238; // SPI settings for DRV8244 with SPI Mode 1 SPISettings spiSettings(1000000, MSBFIRST, SPI_MODE1); // Register addresses (configurable variables) const uint8_t COMMAND_REGISTER = 0x08; const uint8_t CONFIG1_REGISTER = 0x0A; const uint8_t CONFIG4_REGISTER = 0x0D; const uint8_t FAULT_SUMMARY_REGISTER = 0x01; const uint8_t STATUS1_REGISTER = 0x02; // Function to send a 16-bit frame to the DRV8244 uint16_t drv8244SPITransaction(uint8_t command, uint8_t data) { uint16_t sdi = ((command << SPI_ADDRESS_POS) & SPI_ADDRESS_MASK) | ((data << SPI_DATA_POS) & SPI_DATA_MASK); // Combine command and data uint16_t sdo = 0; digitalWrite(NSCS_PIN, HIGH); // Ensure nSCS is high before starting a new transaction delayMicroseconds(1); // Ensure nSCS is high for at least 300 ns (delayMicroseconds(1) = 1000 ns) digitalWrite(NSCS_PIN, LOW); // Select the device delayMicroseconds(1); // Small delay to ensure proper setup time (tSU_nSCS = 25 ns) SPI.beginTransaction(spiSettings); // Send the 16-bit SDI word and receive the SDO word sdo = SPI.transfer16(sdi); SPI.endTransaction(); digitalWrite(NSCS_PIN, HIGH); // Deselect the device delayMicroseconds(1); // Ensure nSCS remains high for stability (tHI_nSCS >= 300 ns) return sdo; } // Function to write to a register void drv8244WriteRegister(uint8_t address, uint8_t value) { // Construct the command using address and set write bit (B15=0 for write) uint16_t command = ((address << SPI_ADDRESS_POS) & SPI_ADDRESS_MASK) | (value & SPI_DATA_MASK); // Properly mask address and data // Send the command and value in a 16-bit frame drv8244SPITransaction(command >> SPI_ADDRESS_POS, value); delay(50); // Allow some time after writing register to ensure proper handling } // Function to read from a register uint8_t drv8244ReadRegister(uint8_t address) { // Construct the command using address and set read bit (B15=1 for read) uint16_t command = SPI_RW_BIT_MASK | ((address << SPI_ADDRESS_POS) & SPI_ADDRESS_MASK); // Set read bit and mask address uint16_t response = drv8244SPITransaction(command >> SPI_ADDRESS_POS, 0x00); // Extract the report byte from the response return (uint8_t)(response & SPI_DATA_MASK); } // Function to read the Device ID void readDeviceID() { uint8_t deviceID = drv8244ReadRegister(0x00); // Assuming Device ID is at register 0x00 Serial.print("Device ID: 0x"); Serial.println(deviceID, HEX); if (deviceID == 0x00) { Serial.println("Warning: Device ID read as 0x00. SPI communication may be failing."); } else { Serial.println("Device ID read successfully."); } } // Initialization function for DRV8244 void setupDRV8244() { SPI.begin(SCLK_PIN, SDO_PIN, SDI_PIN, NSCS_PIN); pinMode(NSCS_PIN, OUTPUT); digitalWrite(NSCS_PIN, HIGH); // Set CS high initially // Clear faults drv8244WriteRegister(COMMAND_REGISTER, 0b10000000); // Clear faults command delay(100); // Allow more time for fault clearance Serial.println("Cleared faults using COMMAND register."); delay(100); // Allow more time for fault clearance // Explicitly unlock configuration and SPI_IN registers drv8244WriteRegister(COMMAND_REGISTER, 0b10010000); // Unlock configuration and SPI_IN registers delay(100); // Small delay to ensure unlock takes effect // Verify unlock status uint8_t unlockStatus = drv8244ReadRegister(STATUS1_REGISTER); Serial.print("STATUS1 Register after unlock attempt: 0x"); Serial.println(unlockStatus, HEX); Serial.println("Unlocked configuration and SPI_IN registers for modification."); delay(100); // Small delay to ensure unlock takes effect // Verify if configuration is unlocked by reading back a register uint8_t statusAfterUnlock = drv8244ReadRegister(STATUS1_REGISTER); Serial.print("STATUS1 Register after unlock: 0x"); Serial.println(statusAfterUnlock, HEX); // Write CONFIG4 register to configure for PWM control of IN1 and IN2 drv8244WriteRegister(CONFIG4_REGISTER, 0b00000000); // Set DRVOFF_SEL = OR, EN_IN1_SEL = OR, PH_IN2_SEL = OR for PWM control, configure OCP Serial.println("CONFIG4 register written for PWM control of EN_IN1 and PH_IN2 and OCP settings."); delay(100); // Allow more time for the settings to take effect // Set DRVOFF to 0 to enable device output drv8244WriteRegister(COMMAND_REGISTER, 0b00000001); // Set DRVOFF to 0 Serial.println("DRVOFF set to 0 to enable outputs."); delay(100); // Allow more time for the settings to take effect // Read FAULT_SUMMARY register after attempting to write CONFIG4 uint8_t faultSummaryAfterConfig = drv8244ReadRegister(FAULT_SUMMARY_REGISTER); Serial.print("FAULT_SUMMARY Register after CONFIG4 write: 0x"); Serial.println(faultSummaryAfterConfig, HEX); // Lock the configuration registers after modification drv8244WriteRegister(COMMAND_REGISTER, 0b10000000); // Lock configuration registers delay(100); // Ensure lock takes effect Serial.println("Locked configuration registers after modification."); delay(100); // Ensure lock takes effect before proceeding // Read Device ID to verify communication readDeviceID(); delay(100); // Allow time for device ID readout } // Function to initialize PWM for motor control void setupPWM() { // Set nSLEEP to HIGH to enable active state pinMode(NSCS_PIN, OUTPUT); digitalWrite(NSCS_PIN, HIGH); // Ensure nSLEEP is HIGH delay(10); // Delay to ensure device comes out of sleep state pinMode(IN1_PIN, OUTPUT); pinMode(IN2_PIN, OUTPUT); // Attach IN1 to PWM and set initial state for IN2 ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION); ledcAttachPin(IN1_PIN, PWM_CHANNEL); digitalWrite(IN2_PIN, LOW); // Set IN2 to LOW for forward direction // Start with PWM off ledcWrite(PWM_CHANNEL, 0); } // Function for ramp-up motor start void startMotorWithRampUp(uint8_t targetDutyCycle, uint16_t rampDurationMs = 2000) { Serial.println("Starting motor with ramp-up..."); // Calculate the step size and delay between increments uint8_t currentDutyCycle = 0; uint16_t stepDelayMs = rampDurationMs / targetDutyCycle; // Gradually increase the PWM duty cycle for (currentDutyCycle = 0; currentDutyCycle <= targetDutyCycle; currentDutyCycle++) { ledcWrite(PWM_CHANNEL, currentDutyCycle); delay(stepDelayMs); // Small delay for ramp-up } Serial.print("Motor reached target duty cycle: "); Serial.print(targetDutyCycle); Serial.println("%."); } void setup() { Serial.begin(115200); // Initialize Serial while (!Serial) delay(10); Serial.println("Starting HUSB238 with DRV8244 Integration..."); // Initialize I2C for HUSB238 Serial.println("Initializing HUSB238..."); Wire.begin(SDA_PIN, SCL_PIN); if (!husb238.begin(HUSB238_I2CADDR_DEFAULT, &Wire)) { Serial.println("Failed to initialize HUSB238. Check wiring!"); while (1) { delay(1000); // Stay in a loop if initialization fails } } Serial.println("HUSB238 initialized successfully."); // Request 20V from HUSB238 Serial.println("Requesting 20V..."); husb238.selectPD(PD_SRC_20V); // Select 20V profile husb238.requestPD(); // Request selected profile delay(100); // Allow time for request if (husb238.getPDResponse() == SUCCESS) { Serial.println("20V successfully requested and applied."); } else { Serial.println("Failed to apply 20V."); while (1); // Halt on failure } // Initialize DRV8244 setupDRV8244(); // Initialize PWM for motor control setupPWM(); } void loop() { static bool motorStarted = false; // Periodic status check delay(1000); Serial.println("Checking HUSB238 status..."); if (!husb238.isAttached()) { Serial.println("HUSB238 is not attached to power!"); return; } if (husb238.getPDResponse() != SUCCESS) { Serial.println("Voltage not maintained. Re-requesting..."); husb238.selectPD(PD_SRC_12V); // Re-select 12V husb238.requestPD(); // Re-request PD if (husb238.getPDResponse() == SUCCESS) { Serial.println("12V successfully reapplied."); } else { Serial.println("Failed to reapply 12V."); } } else { Serial.println("12V is maintained."); } if (!motorStarted) { // Start motor with ramp-up to 50% duty cycle startMotorWithRampUp(200, 8000); // Ramp up to 50% duty cycle over 3 seconds motorStarted = true; } // Read FAULT_SUMMARY register uint8_t faultSummary = drv8244ReadRegister(FAULT_SUMMARY_REGISTER); Serial.print("FAULT_SUMMARY Register: 0x"); Serial.println(faultSummary, HEX); // Read STATUS1 register uint8_t status1 = drv8244ReadRegister(STATUS1_REGISTER); Serial.print("STATUS1 Register: 0x"); Serial.println(status1, HEX); }