This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

DRV8316REVM: Issue with SPI

Part Number: DRV8316REVM
Other Parts Discussed in Thread: DRV8316

Tool/software:

Having an issue with SPI on the DRV8316EVM board communicating with an ESP32-s3 board. Trying to talk to it over SPI. Seem to never read anything other than zero. Probed signals - seems to be ok on send side (SCK, MOSI, and CS) but never see response on SDO. I thought it might be issue with pull up, but see SDO pin at 3.3V always. Below is my code and wiring:

Wiring:

Drvoff (J4 pin )-> GND

SCK -> J3 pin 13

CS -> J4 pin 4

MOSI -> J4 pin 12

MISO -> J4 pin 14

ESP GND -> J3 pin 4

ESP GPIO 4-> J3 pin 17 (nSleep)

Code:

/**
 * @file drv8316_demo.ino
 * @author Your Name
 * @brief Demo for controlling a TI DRV8316R motor driver with a Seeed XIAO ESP32-S3.
 * @version 0.4
 * @date 2025-08-05
 *
 * @details
 * This code demonstrates basic SPI communication with the DRV8316R. It performs:
 * 1. A pre-flight check to verify that SPI communication is working.
 * 2. Dumps the contents of all status and control registers.
 * 3. Unlocks the control registers.
 * 4. Writes to a control register (CR2) to change the SDO pin from open-drain to push-pull.
 * 5. Verifies that the write was successful.
 *
 * @note
 * Key hardware consideration: The DRV8316's SDO (MISO) pin defaults to open-drain mode.
 * This requires a pull-up resistor. This code enables the ESP32's internal pull-up
 * on the MISO pin to satisfy this requirement.
 *
 * SPI Settings:
 * - Clock Speed: 1 MHz
 * - Bit Order: MSBFIRST
 * - SPI Mode: MODE1 (CPOL=0, CPHA=1)
 */

#include <SPI.h>

//================================================================================
// Pin Assignments & Constants
//================================================================================

// --- Pinout for Seeed XIAO ESP32-S3 ---
constexpr uint8_t PIN_SCK    = 7;  // Default SCK (D6 on XIAO)
constexpr uint8_t PIN_MISO   = 8;  // Default MISO (D7 on XIAO)
constexpr uint8_t PIN_MOSI   = 9;  // Default MOSI (D8 on XIAO)
constexpr uint8_t PIN_CS     = 3;  // CORRECTED: Using D5 (GPIO5) for Chip Select
constexpr uint8_t PIN_NSLEEP = 4;  // Using D4 (GPIO4) for nSLEEP

// --- DRV8316R Register Addresses ---
namespace DRV8316R
{
    // Status Registers
    constexpr uint8_t ADDR_IC_STATUS   = 0x00;
    constexpr uint8_t ADDR_STATUS_1    = 0x01;
    constexpr uint8_t ADDR_STATUS_2    = 0x02;

    // Control Registers
    constexpr uint8_t ADDR_CONTROL_1   = 0x03;
    constexpr uint8_t ADDR_CONTROL_2   = 0x04;
    constexpr uint8_t ADDR_CONTROL_3   = 0x05;
    constexpr uint8_t ADDR_CONTROL_4   = 0x06;
    constexpr uint8_t ADDR_CONTROL_5   = 0x07;
    constexpr uint8_t ADDR_CONTROL_6   = 0x08;
    constexpr uint8_t ADDR_CONTROL_10  = 0x0C;

    // --- Important Register Values & Masks ---
    constexpr uint8_t UNLOCK_KEY       = 0x03; // Value to write to REG_LOCK field
    constexpr uint8_t REG_LOCK_MASK    = 0x07; // Bits 2:0 for REG_LOCK
    constexpr uint8_t SDO_PUSH_PULL_BIT= 0x20; // Bit 5 in CR2 for SDO_MODE
    constexpr uint8_t CR2_DEFAULT_VAL  = 0x60; // Default value of Control Register 2
}

// --- SPI Configuration ---
SPISettings drvSpiSettings(1'000'000, MSBFIRST, SPI_MODE1);


//================================================================================
// SPI Frame Construction
//================================================================================

/**
 * @brief Calculates the even parity bit for the other 15 bits of a 16-bit word.
 * The parity bit itself (bit 8) is ignored in the calculation.
 * @param frame The 16-bit frame.
 * @return 1 if parity is odd (to make the total even), 0 if parity is already even.
 */
uint8_t calculateParity(uint16_t frame) {
    frame &= ~(1 << 8); // Ignore the parity bit itself
    // Efficiently calculate parity using XOR folding
    frame ^= frame >> 8;
    frame ^= frame >> 4;
    frame ^= frame >> 2;
    frame ^= frame >> 1;
    return frame & 1;
}

/**
 * @brief Builds a complete 16-bit SPI frame with the correct parity.
 * @param isRead True for a read command, false for a write.
 * @param addr The 6-bit register address.
 * @param data The 8-bit data to write (ignored for read operations).
 * @return The fully constructed 16-bit SPI frame.
 */
uint16_t buildFrame(bool isRead, uint8_t addr, uint8_t data = 0x00) {
    uint16_t frame = (uint16_t(isRead) << 15) | ((uint16_t(addr) & 0x3F) << 9) | data;
    frame |= (uint16_t(calculateParity(frame)) << 8);
    return frame;
}

/**
 * @brief Creates a "no operation" frame, typically used to clock out data from the driver.
 * @return A 16-bit NOP frame.
 */
uint16_t nopFrame() {
    return buildFrame(true, 0x00, 0x00);
}


//================================================================================
// Core SPI Communication Functions
//================================================================================

/**
 * @brief Performs a 16-bit SPI transfer to the DRV8316R.
 * @param txData The 16-bit data to transmit.
 * @return The 16-bit data received from the driver.
 */
uint16_t drvTransfer16(uint16_t txData) {
    SPI.beginTransaction(drvSpiSettings);
    digitalWrite(PIN_CS, LOW);
    uint16_t rxData = SPI.transfer16(txData);
    digitalWrite(PIN_CS, HIGH);
    SPI.endTransaction();
    delayMicroseconds(1); // Ensure CS stays high for the minimum required time (tHI_nSCS)
    return rxData;
}

/**
 * @brief Reads an 8-bit register from the DRV8316R.
 * @note The DRV8316R uses a pipelined response. A read command must be followed
 * by a second transaction (e.g., a NOP) to clock out the requested data.
 * @param addr The address of the register to read.
 * @return The 8-bit value of the register.
 */
uint8_t drvRead8(uint8_t addr) {
    drvTransfer16(buildFrame(true, addr));
    uint16_t response = drvTransfer16(nopFrame());
    return (response & 0xFF);
}

/**
 * @brief Writes an 8-bit value to a register on the DRV8316R.
 * @note A second transaction is sent to ensure the write command is fully processed.
 * @param addr The address of the register to write to.
 * @param data The 8-bit value to write.
 */
void drvWrite8(uint8_t addr, uint8_t data) {
    drvTransfer16(buildFrame(false, addr, data));
    drvTransfer16(nopFrame()); // Ensure write completes
}


//================================================================================
// High-Level Driver Functions
//================================================================================

/**
 * @brief Unlocks the control registers for writing.
 * @return True if unlock was successful, false otherwise.
 */
bool unlockRegisters() {
    Serial.println(F("\n--- Unlocking Registers ---"));
    drvWrite8(DRV8316R::ADDR_CONTROL_1, DRV8316R::UNLOCK_KEY);

    uint8_t readVal = drvRead8(DRV8316R::ADDR_CONTROL_1);
    Serial.printf("Attempted to write 0x%02X to CR1. Read back: 0x%02X\n", DRV8316R::UNLOCK_KEY, readVal);

    if ((readVal & DRV8316R::REG_LOCK_MASK) == DRV8316R::UNLOCK_KEY) {
        Serial.println(F("White check mark Registers appear to be unlocked."));
        return true;
    } else {
        Serial.println(F("X Register unlock failed."));
        return false;
    }
}

/**
 * @brief Prints all status registers to the Serial monitor.
 */
void printStatusRegisters() {
    Serial.println(F("\n--- DRV8316 STATUS REGISTERS ---"));
    for (uint8_t addr = DRV8316R::ADDR_IC_STATUS; addr <= DRV8316R::ADDR_STATUS_2; ++addr) {
        uint8_t val = drvRead8(addr);
        Serial.printf("  Reg 0x%02X: 0x%02X\n", addr, val);
    }
}

/**
 * @brief Prints all control registers to the Serial monitor.
 */
void printControlRegisters() {
    Serial.println(F("\n--- DRV8316 CONTROL REGISTERS ---"));
    const uint8_t control_reg_addrs[] = {0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x0C};
    for (uint8_t addr : control_reg_addrs) {
        uint8_t val = drvRead8(addr);
        Serial.printf("  Reg 0x%02X: 0x%02X\n", addr, val);
    }
}

/**
 * @brief Demo function to change SDO mode to push-pull and verify the write.
 */
void demoChangeSdoMode() {
    Serial.println(F("\n--- Demo: Set SDO to Push-Pull Mode ---"));
    if (!unlockRegisters()) {
        return;
    }

    uint8_t before = drvRead8(DRV8316R::ADDR_CONTROL_2);
    uint8_t after = before | DRV8316R::SDO_PUSH_PULL_BIT;
    drvWrite8(DRV8316R::ADDR_CONTROL_2, after);
    uint8_t verify = drvRead8(DRV8316R::ADDR_CONTROL_2);

    Serial.printf("CR2 before : 0x%02X\n", before);
    Serial.printf("Writing    : 0x%02X\n", after);
    Serial.printf("CR2 after  : 0x%02X\n", verify);

    if (verify == after) {
        Serial.println(F("White check mark Write successful!"));
    } else {
        Serial.println(F("X Mismatch – write failed!"));
    }
}


//================================================================================
// Arduino Setup & Loop
//================================================================================

void setup() {
    // --- Initialize Serial Communication ---
    Serial.begin(115200);
    while (!Serial) {
        delay(10); // Wait for USB-CDC connection
    }
    Serial.println(F("\nDRV8316R SPI Demo - Refactored"));

    // --- Initialize Hardware Pins ---
    pinMode(PIN_CS, OUTPUT);
    digitalWrite(PIN_CS, HIGH);

    pinMode(PIN_NSLEEP, OUTPUT);
    digitalWrite(PIN_NSLEEP, LOW); // Ensure device is in sleep initially
    delay(2);
    digitalWrite(PIN_NSLEEP, HIGH); // Wake up device
    delay(3); // Wait for tWAKE

    // CORRECTED & RE-ENABLED: This is essential for communication.
    pinMode(PIN_MISO, INPUT_PULLUP);

    // --- Initialize SPI Bus ---
    SPI.begin(PIN_SCK, PIN_MISO, PIN_MOSI, -1);

    // --- Pre-flight Check ---
    Serial.println(F("\n--- Pre-flight Check ---"));
    Serial.printf("Reading CR2 (0x%02X), which defaults to 0x%02X...\n", DRV8316R::ADDR_CONTROL_2, DRV8316R::CR2_DEFAULT_VAL);
   
    uint8_t cr2_val = drvRead8(DRV8316R::ADDR_CONTROL_2);
    Serial.printf("Value read from CR2: 0x%02X\n", cr2_val);

    if (cr2_val == DRV8316R::CR2_DEFAULT_VAL) {
        Serial.println(F("White check mark SUCCESS! Valid response received. SPI communication is working."));
    } else {
        Serial.println(F("X FATAL: No valid response from DRV8316. Halting."));
        Serial.println(F("This indicates a hardware or wiring problem. Please check:"));
        Serial.println(F("  1. All SPI wires (MISO, MOSI, SCK, CS) and GND connections."));
        Serial.println(F("  2. Is the EVM powered on correctly?"));
        Serial.println(F("  3. Is the red nFAULT LED on the EVM lit?"));
        while (true); // Halt execution
    }

    Serial.println(F("\nPre-flight check complete. Press any key in Serial Monitor to run main demo..."));
}

void loop() {
    if (Serial.available() > 0) {
        while(Serial.available() > 0) Serial.read(); // Clear buffer
       
        printStatusRegisters();
        printControlRegisters();
        demoChangeSdoMode();

        Serial.println(F("\nDemo finished. Press any key to run again..."));
    }
}