Quantcast
Viewing all articles
Browse latest Browse all 21930

DRV8244-Q1: Issues Communicating with DRV8244-Q1 via SPI - Only 'Clear Fault' and 'Read Device ID' Work

Part Number: DRV8244-Q1

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 receive 0x0, which indicates no active communication or fault status.

Specific Questions:

  1. SPI Timing: Are there any specific timing nuances that are commonly overlooked when dealing with DRV8244 that could cause the chip to be unresponsive?

  2. 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.

  3. Control Mode Settings: I have attempted to set CONFIG4_REGISTER to 0b00000000 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?

  4. EN/IN Pins for PWM: According to the datasheet, both EN/IN1 and PH/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);
}


Viewing all articles
Browse latest Browse all 21930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>