Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I2C issue with M5Stack STEPPER MOTOR module #192

Open
zBuffer opened this issue May 15, 2019 · 5 comments
Open

I2C issue with M5Stack STEPPER MOTOR module #192

zBuffer opened this issue May 15, 2019 · 5 comments

Comments

@zBuffer
Copy link

zBuffer commented May 15, 2019

I've tried to communicate with the STEPPER MOTOR module using the following code, it kept getting 0xFF response from the device. I've tried changing the bus speed slower/faster, but no avail. For sending, it doesn't work as well, with exceptions thrown (except for i2c.write() without parameters).

I've compared the MicroPython driver and this, they don't look that different to me.

Then I looked at their GRBL firmware and schematics - which the only curiosity I could spot is the GPIO16, GPIO17 connection, possible for the alternative UART firmware.

import I2C from "pins/i2c";
import Poco from "commodetto/Poco";
import Resource from "Resource";
import Timer from "timer";

const render = new Poco(screen);
const font = new Resource("8x8font.dat");
const i2c = new I2C({ address: 0x70 });
const black = render.makeColor(0, 0, 0);
const white = render.makeColor(255, 255, 255);

let lines = [""];
let renderedLines = 0;
let blink = true;
let question = false;

render.begin();
render.fillRectangle(black, 0, 0, render.width, render.height);
render.end();

Timer.repeat(() => {
    while (1) {
        let arr = i2c.read(1);
        if (arr === undefined) {
            question = false;
            break;
        }
        if (arr[0] == 0xFF) {
            question = true;
            blink = !blink;
            break;
        } else if (arr[0] == 0x00) {
            question = false;
            blink = !blink;
            break;
        } else {
            lines[lines.length - 1] += String.fromCharCode(arr[0]);
            if (String.fromCharCode(arr[0]) == "\n") {
                lines.push("");
                break;
            }
        }
    }


    for (let i = renderedLines, y = renderedLines * 9; i < lines.length; i++ , y += 9) {
        render.begin(0, y, render.width, 8);
        render.fillRectangle(black, 0, 0, render.width, render.height);
        render.drawText(lines[i], font, white, 0, y, render.width);
        render.end();
    }

    let s = lines[lines.length - 1];
    let c = question ? "?" : "_";
    if (s[s.length - 1] == "\n") {
        renderedLines = lines.length;
        let y = renderedLines * 9;
        render.begin(0, y, 8, 8);
        render.fillRectangle(black, 0, 0, render.width, render.height);
        render.drawText(blink ? c : "", font, white, 0, y, render.width);
        render.end();
    } else {
        renderedLines = lines.length - 1;
        let y = renderedLines * 9;
        let x = lines[renderedLines].length * 9;
        render.begin(x, y, 8, 8);
        render.fillRectangle(black, 0, 0, render.width, render.height);
        render.drawText(blink ? c : "", font, white, x, y, render.width);
        render.end();
    }


}, 500);

It's supposed to grab the GRBL header when the (Arduino) module boots up. The same hardware has been tested on the MicroPython firmware with the following (similar) code, which they worked fine:

from m5stack import *
from m5ui import *
import i2c_bus

clear_bg(0x222222)



btnA = M5Button(name="ButtonA", text="ButtonA", visibility=False)
btnB = M5Button(name="ButtonB", text="ButtonB", visibility=False)
btnC = M5Button(name="ButtonC", text="ButtonC", visibility=False)
label1 = M5TextBox(15, 16, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)

i2c = i2c_bus.get(i2c_bus.PORTA)
s = ""
blink = True

while True:
  while True:
    c = i2c.readfrom(0x70, 1)
    if c[0] == 0x00:
      blink = not blink
      break
    else:
      s = s + c.decode()
  
  label1.setText(s + ("_" if blink else ""))
  wait(1)
@zBuffer
Copy link
Author

zBuffer commented May 15, 2019

Update:
Things start to work if I select m5stack as build target, not m5stack_fire, plus I need to disconnect the USB and do a power cycle. I'm guessing SMBHold and something in the debugging circuit is freezing up the module. Will continue to investigate.

@phoddie
Copy link
Collaborator

phoddie commented May 15, 2019

Ouch. Good luck tracking that down. Looking forward to hearing what you learn.

@zBuffer
Copy link
Author

zBuffer commented May 15, 2019

Update:
I think I'm able to isolate the issue. It's not an issue with SMBHold, but a specific MPU6500/MPU9250 command: this.writeByte(REGISTERS.INT_BYPASS, 0b00000010); which somehow screws up the bus.

Investigating it.

@zBuffer
Copy link
Author

zBuffer commented May 15, 2019

Update:
Turning off INT_BYPASS in the driver fixed the issue. The attached AK8963 magnetometer can be accessed indirectly by controlling MPU9250's master I2C bus.

e.g.

const REGISTERS = {
    I2C_MST_CNTRL: 0x24,
    I2C_SLV0_ADDR: 0x25,
    I2C_SLV0_REG: 0x26,
    I2C_SLV0_DO: 0x63,
    I2C_SLV0_CTRL: 0x27,
    INT_BYPASS: 0x37,
    ACCEL_XOUT: 0x3B, //big endian
    ACCEL_YOUT: 0x3D,
    ACCEL_ZOUT: 0x3F,
    TEMP_OUT: 0x41,
    GYRO_XOUT: 0x43,
    GYRO_YOUT: 0x45,
    GYRO_ZOUT: 0x47,
    EXT_SENS_DATA_00: 0x49,
    USER_CNTRL: 0x6A,
    PWR_MGMT_1: 0x6B,
    PWR_MGMT_2: 0x6C,
    WHO_AM_I: 0x75
};

const I2C_MST_EN = 0x20;
const I2C_MST_CLK = 0x0D;
const I2C_SLV0_EN = 0x80;
...
    enable() {
        this.writeByte(REGISTERS.PWR_MGMT_1, 0);
        this.writeByte(REGISTERS.INT_BYPASS, 0);
        // Indirect peripheral access
        this.writeByte(REGISTERS.USER_CNTRL, I2C_MST_EN);
        this.writeByte(REGISTERS.I2C_MST_CNTRL, I2C_MST_CLK);
        Timer.delay(150);
    }
...
   get MasterBus() {
        let that = this;
        return class {
            constructor(dictionary) {
                this.config = dictionary;
            }

            readBlock(register, count, buffer) {
                that.writeByte(REGISTERS.I2C_SLV0_ADDR, this.config.address | 0x80);
                that.writeByte(REGISTERS.I2C_SLV0_REG, register);
                that.writeByte(REGISTERS.I2C_SLV0_CTRL, I2C_SLV0_EN | count);
                Timer.delay(1);
                return that.readBlock(REGISTERS.EXT_SENS_DATA_00, count, buffer);
            }

            writeBlock(register, ...value) {
                that.writeByte(REGISTERS.I2C_SLV0_ADDR, this.config.address);
                that.writeByte(REGISTERS.I2C_SLV0_REG, register);
                that.writeBlock(REGISTERS.I2C_SLV0_DO, ...value);
                return that.writeByte(REGISTERS.I2C_SLV0_CTRL, I2C_SLV0_EN | value.length);
            }

            writeByte(register, value) {
                return this.writeBlock(register, value & 0xFF);
            }

            writeWord(register, value, endian) {
                if (endian)
                    return this.write(register, (value >> 8) & 255, value & 255);
                else
                    return this.write(register, value & 255, (value >> 8) & 255);
            }

            readByte(register) {
                return this.readBlock(register, 1)[0];
            }

            readWord(register, endian) {
                let value = this.readBlock(register, 2);
                return endian ? (value[1] | (value[0] << 8)) : (value[0] | (value[1] << 8));
            }
        };
    }

@phoddie
Copy link
Collaborator

phoddie commented May 16, 2019

Glad to hear you were able to resolve it from your script. Would a pull request make sense so others can use this too?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants