DRV8311: Application issues.

Expert 1550 points
Part Number: DRV8311

Tool/software:

Hi Team,

Using DRV8311P.

Using the tSPI protocol for register reading and writing, it was found that the written data is inconsistent with the read data
1) NSLEEP pull down ->pull up
2) PWM_SYNC ->Pull up
3) Register writing and reading
Can you help me see what the reason is?

The schematic diagram and communication program are as follows:

drv8311_p.c
#include <stdio.h>
#include <stdint.h>
#include <linux/spi/spidev.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

#define SPI_DEVICE "/dev/spidev3.1"
#define SPI_SPEED 10000000 // 10MHz

#define REG_DEV_STS1 0x00
#define REG_OT_STS 0x04
#define REG_SUP_STS 0x05
#define REG_DEV_STS 0x06
#define REG_SYS_STS 0x07
#define REG_PWM_SYNC_PRD 0x0C
#define REG_FLT_MODE 0x10
#define REG_SYSF_CTRL 0x12
#define REG_DRVF_CTRL 0x13
#define REG_FLT_TCTRL 0x16
#define REG_FLT_CLR 0x17
#define REG_PWMG_PERIOD 0x18
#define REG_PWMG_A_DUTY 0x19
#define REG_PWMG_B_DUTY 0x1A
#define REG_PWMG_C_DUTY 0x1B
#define REG_PWM_STATE 0x1C
#define REG_PWMG_CTRL 0x1D
#define REG_PWM_CTRL1 0x20
#define REG_DRV_CTRL 0x22
#define REG_CSA_CTRL 0x23
#define REG_SYS_CTRL 0x3F

#define DEVICE_ID 0x03
#define TSPI_WRITE_FLAG 0x00
#define TSPI_READ_FLAG 0x80

#define SPI_BIT_PER_WORD 8

static int s_spi_dev_fd;

int drv8311_spi_init(void)
{
    s_spi_dev_fd = open(SPI_DEVICE, O_RDWR);
    if (s_spi_dev_fd < 0) {
        perror("Failed to open SPI device");
        return -1;
    }
    printf("open SPI_DEVICE = %s ok\n", SPI_DEVICE);

    uint8_t mode = SPI_MODE_1;
    if (ioctl(s_spi_dev_fd, SPI_IOC_WR_MODE, &mode) < 0) {
        perror("Failed to set SPI mode");
        close(s_spi_dev_fd);
        return -1;
    }

    uint32_t speed = SPI_SPEED;
    if (ioctl(s_spi_dev_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) {
        perror("Failed to set SPI_IOC_WR_MAX_SPEED_HZ");
        close(s_spi_dev_fd);
        return -1;
    }
    if (ioctl(s_spi_dev_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
        perror("Failed to set SPI SPI_IOC_RD_MAX_SPEED_HZ");
        close(s_spi_dev_fd);
        return -1;
    }
    int bit = SPI_BIT_PER_WORD;
    if (ioctl(s_spi_dev_fd, SPI_IOC_WR_BITS_PER_WORD, &bit)) {
        perror("Failed to set SPI SPI_IOC_WR_BITS_PER_WORD");
        close(s_spi_dev_fd);
        return -1;
    }
    if (ioctl(s_spi_dev_fd, SPI_IOC_RD_BITS_PER_WORD, &bit)) {
        perror("Failed to set SPI SPI_IOC_WR_BITS_PER_WORD");
        close(s_spi_dev_fd);
        return -1;
    }

    return 0;
}

int drv8311_tspi_read(int spi_fd, uint8_t reg_addr, uint16_t *data, uint32_t data_len) {
    
    uint8_t tx_buf[4] = {0};
    uint8_t rx_buf[4] = {0};

    tx_buf[0] = TSPI_READ_FLAG | (DEVICE_ID << 3) | ((reg_addr >> 5) & 0x07);
    tx_buf[1] = ((reg_addr & 0x1F) << 3);
    tx_buf[2] = 0x00;
    tx_buf[3] = 0x00;

    struct spi_ioc_transfer msg;
    memset(&msg, 0, sizeof(msg));
    msg.tx_buf = (unsigned long)tx_buf;
    msg.rx_buf = (unsigned long)rx_buf;
    msg.len = 4;
    msg.speed_hz = SPI_SPEED;
    msg.bits_per_word = SPI_BIT_PER_WORD;
    msg.cs_change = 0;

    if (ioctl(spi_fd, SPI_IOC_MESSAGE(1), &msg) < 0) {
        perror("SPI Read Error");
        return -1;
    }

    *data = (rx_buf[1] << 8) | rx_buf[2];
    *data &= 0x7FFF;
    printf("\r\n");
    printf("=============================read==============================\n");
    printf("tspi read reg_addr = 0x%x, status = 0x%x, data = 0x%x\n", reg_addr, rx_buf[0], *data);
    printf("drv8311_tspi_read tx_buf[0] = 0x%x, tx_buf[1] = 0x%x, tx_buf[2] = 0x%x\n", tx_buf[0], tx_buf[1], tx_buf[2]);
    printf("===========================================================\n");
    printf("\r\n");
    return 0;
}

int drv8311_tspi_write(int spi_fd, uint8_t reg_addr, uint16_t data) {
    uint8_t tx_buf[4] = {0};
    tx_buf[0] = TSPI_WRITE_FLAG | (DEVICE_ID << 3) | ((reg_addr >> 5) & 0x07);
    tx_buf[1] = ((reg_addr & 0x1F) << 3);
    tx_buf[2] = (data >> 8) & 0xFF;
    tx_buf[3] = data & 0xFF;

    struct spi_ioc_transfer msg;
    memset(&msg, 0, sizeof(msg));
    msg.tx_buf = (unsigned long)tx_buf;
    msg.rx_buf = 0;
    msg.len = 4;
    msg.speed_hz = SPI_SPEED;
    msg.bits_per_word = SPI_BIT_PER_WORD;
    msg.cs_change = 0;

    if (ioctl(spi_fd, SPI_IOC_MESSAGE(1), &msg) < 0) {
        perror("SPI Write Error");
        return -1;
    }

    printf("\r\n");
    printf("===========================write================================\n");
    printf("tspi write reg_addr = 0x%x data = 0x%x\n", reg_addr, data);
    printf("drv8311_tspi_write tx_buf[0] = 0x%x, tx_buf[1] = 0x%x, tx_buf[2] = 0x%x, tx_buf[3] = 0x%x\n", tx_buf[0], tx_buf[1], tx_buf[2], tx_buf[3]);
    printf("===========================================================\n");
    printf("\r\n");

    uint16_t reg_status = 0;
    drv8311_tspi_read(spi_fd, reg_addr, &reg_status, 2);
    return 0;
}

int drv8311_exit(void)
{
    if (s_spi_dev_fd > 0 ) {
        if (drv8311_tspi_write(s_spi_dev_fd, REG_PWMG_CTRL, 0) < 0) {
            close(s_spi_dev_fd);
            return -1;
        }
        close(s_spi_dev_fd);
        printf("drv8311_exit done\n");
        return 0;
    }

    printf("invalid s_spi_dev_fd \n");
    return -1;
}

static int drv8311_check_status(void)
{
    printf("drv8311_check_status \n");
    uint16_t reg_status = 0;
    if (drv8311_tspi_read(s_spi_dev_fd, REG_DEV_STS1, &reg_status, 2) < 0) { // 0x80 default
        printf("read REG_DEV_STS1 faied \n");
    }

    if (drv8311_tspi_read(s_spi_dev_fd, REG_OT_STS, &reg_status, 2) < 0) {
        printf("read REG_OT_STS faied \n");
    }

    if (drv8311_tspi_read(s_spi_dev_fd, REG_SUP_STS, &reg_status, 2) < 0) {
        printf("read REG_SUP_STS faied \n");
    }

    if (drv8311_tspi_read(s_spi_dev_fd, REG_SYS_STS, &reg_status, 2) < 0) {
        printf("read REG_SYS_STS faied \n");
    }

    return 0;
}

static int drv8311_set_param(void)
{
    printf("drv8311_set_param \n");

    // clean 
    if (drv8311_tspi_write(s_spi_dev_fd, REG_FLT_CLR, 0x0001) < 0) {
        printf("write REG_PWMG_A_DUTY faied \n");
    }

    // set mode
    if (drv8311_tspi_write(s_spi_dev_fd, REG_PWM_CTRL1, 0x0003) < 0) {
        printf("write REG_PWM_CTRL1 faied \n");
    }

    // set TDEAD_CTRL and SLEW_RATE
    if (drv8311_tspi_write(s_spi_dev_fd, REG_DRV_CTRL, 0x0013) < 0) {
        printf("write REG_PWM_CTRL1 faied \n");
    }

    // set duty
    if (drv8311_tspi_write(s_spi_dev_fd, REG_PWMG_A_DUTY, 0x0800) < 0) {
        printf("write REG_PWMG_A_DUTY faied \n");
    }
    if (drv8311_tspi_write(s_spi_dev_fd, REG_PWMG_B_DUTY, 0x0800) < 0) {
        printf("write REG_PWMG_B_DUTY faied \n");
    }
    if (drv8311_tspi_write(s_spi_dev_fd, REG_PWMG_C_DUTY, 0x0800) < 0) {
        printf("write REG_PWMG_C_DUTY faied \n");
    }

    // set period
    if (drv8311_tspi_write(s_spi_dev_fd, REG_PWMG_PERIOD, 0x0032) < 0) {
        printf("write REG_PWM_CTRL1 faied \n");
    }

    // set pwm state
    if (drv8311_tspi_write(s_spi_dev_fd, REG_PWM_STATE, 0x0777) < 0) {
        printf("write REG_PWM_CTRL1 faied \n");
    }

    // enable gen pwm and PWM_OSC_SYNC
    if (drv8311_tspi_write(s_spi_dev_fd, REG_PWMG_CTRL, 0x0420) < 0) {
        printf("write REG_PWM_CTRL1 faied \n");
    }

    return 0;
}

int main() {
    
    if (drv8311_spi_init()) {
        printf("drv8311_spi_init failed\n");
        return -1;
    }

    drv8311_set_param();
    int loop_cnt = 0;
    while (0) {
        loop_cnt++;
        drv8311_check_status();
        sleep(1);
        if (loop_cnt >= 15) {
            loop_cnt = 0;
            break;
        }
    }
    drv8311_exit();
    return 0;
}

  • Hi Reed,

    When you say SPI written data and read data are inconsistent, can you elaborate? Are you using a logic analyzer? Do you have screen shots of some of you read and writes?

    What MCU and IDE are you using? I may not be much help with actually looking at your code but here is a snippet of how tSPI works for DRV8311 using a LAUNCHXL - 280049C and CCS

    Uint16 tspi_read_block(Uint16 id, Uint16 addr, Uint16 data_size)
    {
        Uint16 p_addr;
        Uint16 p_data;
        Uint16 commandword;
    
        Uint16 dummy = 0;
    
        p_addr = spi_parity_calc(addr);
        commandword = (0x8000) | (id << 11) | (addr << 3) | (p_addr << 0);
        SpiaRegs.SPITXBUF=commandword;
    
        int data_ptr;
        for (data_ptr = 0; data_ptr < data_size; data_ptr++)
        {
            p_data = spi_parity_calc(dummy);
            commandword = (p_data << 15) | dummy;
            SpiaRegs.SPITXBUF=commandword;
            spi_data_tx[data_ptr] = SpiaRegs.SPIRXBUF;
        }
    
        while(SpiaRegs.SPIFFRX.bit.RXFFST != data_size);
    
        return SpiaRegs.SPIRXBUF;
    }
    
    Uint16 tspi_write_block(Uint16 id, Uint16 addr, Uint16 data_size, Uint16 data[])
    {
    
        Uint16 p_addr;
        Uint16 p_data;
        Uint16 commandword;
    
        p_addr = spi_parity_calc(addr);
        commandword = (id << 11) | (addr << 3) | (p_addr << 0);
        SpiaRegs.SPITXBUF=commandword;
    
        int data_ptr;
        for (data_ptr = 0; data_ptr < data_size; data_ptr++)
        {
            p_data = spi_parity_calc(data[data_ptr]);
            commandword = (p_data << 15) | data[data_ptr];
            SpiaRegs.SPITXBUF=commandword;
        }
    
        while(SpiaRegs.SPIFFRX.bit.RXFFST != data_size);
    
        return SpiaRegs.SPIRXBUF;
    }

    Regards,

    Yara

  • Thank you very much for your reply. If the parity check is disabled, does the parity bit still need to be calculated? By the way, could you provide the source code for the spi_parity_calc function?

  • Hi Zhu,

    Yes, if parity check is disabled you should still make sure your SPI frame has the correct parity, otherwise it will be an invalid SPI transaction.

    bool spi_parity_calc(Uint16 word)
    {
        uint16_t p = 0;
        while(word)
        {
           p ^= (word & 1);
           word >>= 1;
        }
        return(p);
    }
    

    Regards,

    Yara

  • Hi Yara, 

    Thank you for your prompt reply,
    Following your suggestion, I filled the correct parity bits, but still have the problem.
    For example, I wrote data to the PWM_CTRL1 register, but when I read the data of PWM_CTRL1 again, the data read out was not the data I wrote.

    There is another question,we are using the HiSilicon 3519 main chipset. After composing the tSPI frame data, we use the Linux SPI bus communication protocol to perform data read and write operations,
    is this approach feasible?
     
  • Hi Zhu,

    After composing the tSPI frame data, we use the Linux SPI bus communication protocol to perform data read and write operations,

    I don't see an issue with this as long as you keep in mind the SPI requirements of this device 

    Do you have a logic analyzer? Any waveforms you can show me of the SPI communication?

    A good start would be to read all the registers and see if you are getting the default values. If you're not getting the default values then there could be something wrong with your SPI frame. Keep in mind that you should use the tSPI frame and NOT the SPI frame found in the datasheet.

    Regards,

    Yara

  • Hi Yara, 

    I used a logic analyzer to analyze the waveform, and here are the waveform results and my log output

    Yes, I am using tSPI frame, but it seems to have no effect, I checked my data, and I couldn’t find any issues. The data I composed can be seen in the log output of the image above. Can you see any issues?

    Regards,

    Zhu

  • Hi Yara, Thank you for your help.

    I know the cause of the issues,In the data sheet it is described that the data output is 24 bits, but in fact the output is 32 bits, and the last 16 bits are the data content,So I read the last 16 bits of the 4-byte output data, which is the data I wrote earlier.

    Regards

  • Hi Zhu,

    Your issue has been resolved? Please hit the the "this resolved my issue" button so the thread can be closed.

    If you have any additional questions feel free to post another E2E question.

    Regards,

    Yara

  • Hi Yara, 

    Thanks, I will close this thread. If I have any additional questions, I will ask your team for help.

    Regards,

    Zhu