Mcf8316a motor driver programming through I2C

Hi,

I have a device that uses ESP32 mcu and mcf8316a motor driver. I need help for programming / accessing registry of the mcf8316a with ESP32 through I2C. The mcf8316a does have online GUI for parameters, but my hardware is not allowing that. We are using arduino IDE for programming. After initial settings for the driver I2C, I should be able to use just ESP32 PWM to control the motor.

I have a programmer working with this, but we are stuck. We are trying to create a test code to spin the motor attached to the driver. I can see serial monitor output but the motor does not spin. Anyone able to help?

I will link datasheet of the driver (pages starting at 70 are for writing EEPROM), and also the current code written in Arduino IDE.

DISCLAIMER: I am not a programmer, please don't go too hard on me. Cheers!

Datasheet

Test code

Serial monitor

Welcome to the forum. That is a long and hard to understand datasheet :scream:

Start at the begin. Can you run a I2C Scanner sketch ?

Is the CRC enabled or disabled by default ?

The next step is reading some kind of ID. The chip has an ID, but that is zero.
Can you try to read that ?

The chip can be busy and give a NACK. Is there a maximum time after which it is guaranteed ready ?

Please put a sketch on this forum in a post between code tags. Use the <CODE/> button for that.
If you want to show the output of the Serial Monitor, then copy-paste the text, instead of a picture of a screendump.

You don't have to add delays after a Wire.write().
The Wire.beginTransmission() does not put a start on the I2C bus. The Wire.write() does not write data to the I2C bus. The Wire.endTransmission() does not end something.

The Wire.write() writes data in a buffer (a buffer inside the Wire library) and the Wire.endTransmission() does the whole I2C session, using the data from that buffer.

Hi Koepel, thank you!

Yes, the datasheet is a monster, lots and lots of information. And sorry, here is the sketch. I had issues copy+pasting the serial monitor (new in Arduino Ide too..), but I will try that too.

#include <Wire.h>

#define BRAKE 5
#define DIR 17
#define SPEED 16

const int deviceAddress = 0x01;
#define CRC_POLYNOMIAL 0x07

void setup() {
  Wire.begin();
  Serial.begin(115200);
  Serial.println("Starting");
  pinMode(BRAKE, OUTPUT);
  pinMode(DIR, OUTPUT);
  pinMode(SPEED, OUTPUT);
  digitalWrite(BRAKE, HIGH);
  digitalWrite(DIR, HIGH);
  digitalWrite(SPEED, LOW);

  uint8_t data[] = {0x02, 0x50, 0x00, 0xA4, 0x01, 0x00, 0x00, 0x00};
  uint8_t crc = calculateCRC(data, sizeof(data));
  Wire.beginTransmission(deviceAddress);
  Wire.write((uint8_t)(0x02));  // Start Byte
  delay(100);
  Wire.write((uint8_t)(0x50));  // control Word 0
  delay(100);
  Wire.write((uint8_t)(0x00));  // Control word 1
  delay(100);
  Wire.write((uint8_t)(0xA4)); // Control word 2
  delay(100);
  Wire.write((uint8_t)(0x01));  // Data Bytes 0
  delay(100);
  Wire.write((uint8_t)(0x00)); // Data Bytes 1
  delay(100);
  Wire.write((uint8_t)(0x00)); // Data Bytes 2
  delay(100);
  Wire.write((uint8_t)(0x00)); // Data Bytes 3
  delay(100);
  Wire.write(crc); // Data Bytes 3
  delay(100);
  Wire.endTransmission();
  delay(1000);
}

void loop() {
  Serial.println("Motor should start");
  analogWrite(SPEED, 128);
  digitalWrite(BRAKE, LOW);
  delay(5000);
  Serial.println("Speed increase");
  analogWrite(SPEED, 200);
  delay(3000);
  digitalWrite(BRAKE, HIGH);
  Serial.println("Motor Stops");
  delay(2000);
  digitalWrite(DIR, LOW);
  analogWrite(SPEED, 128);
  digitalWrite(BRAKE, LOW);
  Serial.println("Motor should start in reverse direction");
  delay(5000);
  analogWrite(SPEED, 200);
  Serial.println("Speed increase");
  delay(3000);
  digitalWrite(BRAKE, HIGH);
  Serial.println("Motor Stops");
  delay(2000);
  digitalWrite(DIR, HIGH);
}

uint8_t calculateCRC(uint8_t* data, uint8_t length) {
  uint8_t crc = 0xFF; // Initial CRC value

  for (uint8_t i = 0; i < length; i++) {
    crc ^= data[i]; // XOR the CRC with the current data byte

    for (uint8_t j = 0; j < 8; j++) {
      if (crc & 0x80) { // Check if the most significant bit is set (bit 7)
        crc = (crc << 1) ^ CRC_POLYNOMIAL; // Shift left and XOR with the polynomial
      } else {
        crc <<= 1; // Just shift left
      }
    }
  }
  return crc;
}

I am not the programmer, but I will try to answer as best as I can.

-We have scanned I2C devices, and found this. 0x01 was the address shown.

-For the CRC I couldn't find the default setting

-For the NACK same, couldn't find the maximum time after it should be ready. What do you suggest, adding delay somewhere?

-Delay after write, in datasheet we found "For reliable communication, a 100-µs delay should be used between every byte transferred over the I2C bus." so maybe we misunderstood this.

-So Wire.endTransmission() will send data to the driver? Or how is it should be used?

I forwarded your reply to the programmer and asked her to join here for discussion.

Many times this type of problem is also a power supply program. Please post your annotated schematic showing exactly how it is connected including power, ground, and power sources. Also post links to technical information on your hardware devices.

The Arduino Wire library can not put delays in between the bytes.
The SCL clock can be lowered with Wire.setClock(), perhaps that will help a little.
I think that the chip is not fully according to the I2C standard and the note about the 100µs delay can be interpreted in different ways.

I suggest to add a delay after a reading or writing data over the I2C bus.

The CRC can be enabled in the 24 bit control word at the start of every I2C session. Let's keep that off for now.

Can you set the right values for the command bytes in the sketch below ?
Please add comments to tell what the bits are, so I can check it with the datasheet.

#include <Wire.h>

const int deviceAddress = 0x01;

void setup() {
  int error, n;

  Wire.begin();
  Wire.setClock(50000);      // 50kHz, half the normal speed

  Serial.begin(115200);
  Serial.println("Starting");

  // ------------------------------------------------
  // Write data to a register
  // ------------------------------------------------
  const byte control_word1[] = {0x02, 0x50, 0x00}; // <--- set the right numbers
  const byte data1[] = {0xA4, 0x01, 0x00, 0x00};   // <-- set the right numbers

  Wire.beginTransmission(deviceAddress);
  Wire.write(control_word1, 3);
  Wire.write(data1, 4);
  error = Wire.endTransmission();
  if(error == 0)
  {
    Serial.println("Data succesfully sent");
  }
  delay(1);               // the chip needs some time ?

  // ------------------------------------------------
  // Read data from a register
  // ------------------------------------------------
  const byte control_word2[] = {0x02, 0x50, 0x00};  // <--- set the right numbers

  Wire.beginTransmission(deviceAddress);
  Wire.write(control_word2, 3);
  error = Wire.endTransmission(false);   // 'false' for a repeated start
  if(error == 0)
  {
    Serial.println("Register succesfully selected");
  }
  delay(1);               // the chip needs some time ?

  n = Wire.requestFrom(deviceAddress, 4);
  if(n == 4)
  {
    Serial.println("Data received");
    for( int i=0; i<4; i++)
    {
      Serial.print("0x");
      Serial.print(Wire.read(), HEX);
      Serial.print(", ");
    }
    Serial.println();
  }
  delay(1);               // the chip needs some time ?
}

void loop() {}

I have an alternative explanation of the functions of the Wire library: Explanation of the functions of the Wire library · Koepel/How-to-use-the-Arduino-Wire-library Wiki · GitHub

Is it okay to provide schematics with imgur, to not to overfill this post?

PARTS:
Microcontroller:
ESP32-WROOM-32E

IC:s used:
Fuel gauge I2C MAX17048G+T10
Sensorless Field Oriented Control (FOC) Integrated FET BLDC Driver MCF8316A (link in first post)
3.15A USB-C Autonomous Charger for 1-Cell Li+ Batteries MAX77751
TPS61288 18-V, 15-A, Fully Integrated Synchronous Boost Converter
1A LOW DROPOUT VOLTAGE REGULATOR AMS1117 ("new user can only add 4 links to a post", so if you need datasheet of this too, I will provide it)

For now we are just testing the motor controller operation.
I have have test setup as following:

  • 12VDC lab power in VCC1
  • motor in motor drivers 3-phase output MOTOR1
  • from PC USB FTDI module -> RX TX and GND of the PCB connector J1 (from RX-TX and TX-RX, 3.3V not connected, as ESP32 is powered from VCC1)

Do you need something more?

Thanks!

We want to run the motor in standalone mode with pwm signal.
Pin Config Register is 0xA4 and it has default value of 0x00 which means it is programmed to get the analog input for motor Speed. whereas we want to run it in with pwm signal. for that we are trying to change value of the register 0xA4 and we are not able to do it succesfully. according to data sheet {pic attached} writing a register is in following method, it needs to have the 24 bit word prepared as per the guidline {pic attached} and example of how to write is also attached. but with our upper code we are having no success.

Here is the attached format of register 0xA4 we have to modify, along with its default value


image

Thank you so much! I think we have already made some progress. Amna joined the forum and added a line for your code and we tested it.

Code:

#include <Wire.h>

const int deviceAddress = 0x01;

void setup() {
  int error, n;

  Wire.begin();
  Wire.setClock(50000);      // 50kHz, half the normal speed

  Serial.begin(115200);
  Serial.println("Starting");

  // ------------------------------------------------
  // Write data to a register
  // ------------------------------------------------
  const byte control_word1[] = {0x02, 0x50, 0x00, 0xA4}; // <--- set the right numbers
  const byte data1[] = {0x01, 0x00, 0x00, 0x00};   // <-- set the right numbers

  Wire.beginTransmission(deviceAddress);
  Wire.write(control_word1, 4);
  Wire.write(data1, 4);
  error = Wire.endTransmission();
  if(error == 0)
  {
    Serial.println("Data succesfully sent");
  }
  delay(1);               // the chip needs some time ?

  // ------------------------------------------------
  // Read data from a register
  // ------------------------------------------------
  const byte control_word2[] = {0x02, 0xD0, 0x00, 0xA4};  // <--- set the right numbers

  Wire.beginTransmission(deviceAddress);
  Wire.write(control_word2, 4);
  error = Wire.endTransmission(false);   // 'false' for a repeated start
  if(error == 0)
  {
    Serial.println("Register succesfully selected");
  }
  delay(1);               // the chip needs some time ?

  n = Wire.requestFrom(deviceAddress, 4);
  Serial.println(n);
  if(n == 4)
  {
    Serial.println("Data received");
    for( int i=0; i<4; i++)
    {
      Serial.print("0x");
      Serial.print(Wire.read(), HEX);
      Serial.print(", ");
    }
    Serial.println();
  }
  delay(1);               // the chip needs some time ?
}

void loop() {}

and serial monitor output

ets Jul 29 2019 12:21:46

rst:0xc (SW_CPU_RESE\),boot:03 o 2  bF
 ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
waiting for download
: ets Jul 29 2019 12:21:46

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1344
load:0x40078000,len:13964
load:0x40080400,len:3600
entry 0x400805f0
Starting
Data succesfully sent
Register succesfully selected
0

I discussed with Amna, she wanted to know Is there something related to shadow register to read and what is it?
I also asked Amna to comment what the bits are, and she replied:

"Pin Config Register is 0xA4 and it has a default value of 0x00 which means it is programmed to get the analog input for motor Speed. whereas we want to run it in with pwm signal. here you can see in image the complete register bits are shown, secondly while sending data to be written it has to be in Least Significant Byte first"

Thanks Koepel!

Secondly I changed this line
const byte control_word2[] = {0x02, 0x50, 0x00, 0xA4};

Control word is although 3 bytes, but start byte has to be combination of Target IC (7 bits) and 8th bit as I2C write... so it makes it 0x02 next three bytes are for control word being the 3rd byte as address of register....
In this line const byte data1[] = {0x01, 0x00, 0x00, 0x00};
we are trying to send data 0x01 in 32 bits with LSB first.

Result: while we write data there is no error, but while reading the same register it gives only 0 byte of data..... whereas we expect 4 bytes of data should be given. In datasheet it is written that you can read it from a shadow register... which I don't what it is, it will be great favor if you explain that to us. Thank You for your help

If data is written to the EEPROM, it is not directly written to EEPROM.
The data is written to the shadow registers, and then a command will copy the shadow registers to EEPROM.

I made a mistake, the "ID" register is not a "identifier", but it is a "Measured d-axis Current".
Is there a register that is safe to read and write ? Or is it only the EEPROM that can be written ?

I have scrolled a few times through the datasheet, and I'm about at the limit what I understand about it :brain:
You did the right thing to ask at Reddit as well, but always be clear what you do. You can give a link here to Reddit and a link there to this topic.

We can read and write through only shadow registers, in datasheet they have given the range of addresses for shadow registers, but we don't know that which shadow register address will correspond to our target address 0xA4. Thank you

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.