Hot!MPU6050 (I2C) with PIC18F27K42 + MCC

Author
fabianpi
Starting Member
  • Total Posts : 49
  • Reward points : 0
  • Joined: 2017/03/26 15:30:13
  • Location: 0
  • Status: offline
2018/05/08 23:55:28 (permalink)
0

MPU6050 (I2C) with PIC18F27K42 + MCC

Hello guys.
 
Other project with PIC18F27K42 and another time that I'm looking for some help with the interface.
 
I setup a project with MPLAB X and MCC to work with the I2C from PIC18F27K42 at 64MHz Internal Oscillator to get data from MPU6050 module, what I want is to get the gyroscope data from the module.
 
I was trying to follow these project where was implemented the same module with a PIC18F4550:
http://www.electronicwings.com/pic/mpu6050-gyroscope-accelerometer-temperature-interface-with-pic18f4550

 
And unfortunately I'm not getting the data from the module. 
 
After read the datasheet and the Register Map and description, I try to read one register from the module WHO_AM_I (0x75) (which gives me the default slave address of the module: 0x68) sending a read to the MPU6050 Slave, I'm using a TFT Display to see the output from the I2C Communication.
 
The first time that goes the while(1) it can read the slave address and I saw it in the TFT as a decimal value (104) and I convert  it with the ASCII table and is 0x68! but then I only get a "0" as a response.
 
I'm not pretty sure what is going wrong, the first time I can read the slave address, then I can't read it at all... One of my thougts is that my current setup the MCC at the simplest way possible, and according to datasheet, the code seems to look for some Nacks during the I2C communication that I'm not sure that the current MCC functions generated are developing right now.
 
I will share the code and setup to show you clearly what's going on.
main.c file:
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

#include "mcc_generated_files/mcc.h"
#include "spi_pic18f.h"
#include "font.h"
#include "ili9341.h"
#include "time_delay.h"
#include "MPU6050_res_define.h"
//#include "MPU6050.h"

#define MPU6050_ADDRESS 0x69 // AD0 as high!

void main(void)
{
    char buffer[20];
 int Ax,Ay,Az,T,Gx,Gy,Gz;
 float Xa,Ya,Za,t,Xg,Yg,Zg;
    // Initialize the device
    SYSTEM_Initialize();
    SPI1_Close();
    SPI1_Init();
    TFT_Init();
    TFT_MemoryAccessControl(TFT_HORIZONTAL);
    TFT_FillScreen(BLACK);
    TFT_SetFont(Courier_New_Bold_20, 1);
    TFT_ConstText("MPU hello", 20, 10, WHITE, BLACK);
    //MPU6050_Init();
    uint8_t value = 0;
    
    while(1)
    {
       
        value = i2c2_read1ByteRegister(MPU6050_ADDRESS, GYRO_XOUT_H);
        //value = i2c2_read1ByteRegister(MPU6050_ADDRESS, WHO_AM_I);
        if(value != 0)
        {
            sprintf(buffer, "mpu Gx = %3d ", value);
            TFT_Text(buffer, 20, 104, WHITE, BLACK);
        }
            
        Delay_ms(2000);
    }
}

 
 
MPU6050_res_define.h file:
#ifndef MPU6050_RES_DEFINE_H_
#define MPU6050_RES_DEFINE_H_

#define XG_OFFS_TC 0x00
#define YG_OFFS_TC 0x01
#define ZG_OFFS_TC 0x02
#define X_FINE_GAIN 0x03
#define Y_FINE_GAIN 0x04
#define Z_FINE_GAIN 0x05
#define XA_OFFS_H 0x06
#define XA_OFFS_L_TC 0x07
#define YA_OFFS_H 0x08
#define YA_OFFS_L_TC 0x09
#define ZA_OFFS_H 0x0A
#define ZA_OFFS_L_TC 0x0B
#define XG_OFFS_USRH 0x13
#define XG_OFFS_USRL 0x14
#define YG_OFFS_USRH 0x15
#define YG_OFFS_USRL 0x16
#define ZG_OFFS_USRH 0x17
#define ZG_OFFS_USRL 0x18
#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C
#define FF_THR 0x1D
#define FF_DUR 0x1E
#define MOT_THR 0x1F
#define MOT_DUR 0x20
#define ZRMOT_THR 0x21
#define ZRMOT_DUR 0x22
#define FIFO_EN 0x23
#define I2C_MST_CTRL 0x24
#define I2C_SLV0_ADDR 0x25
#define I2C_SLV0_REG 0x26
#define I2C_SLV0_CTRL 0x27
#define I2C_SLV1_ADDR 0x28
#define I2C_SLV1_REG 0x29
#define I2C_SLV1_CTRL 0x2A
#define I2C_SLV2_ADDR 0x2B
#define I2C_SLV2_REG 0x2C
#define I2C_SLV2_CTRL 0x2D
#define I2C_SLV3_ADDR 0x2E
#define I2C_SLV3_REG 0x2F
#define I2C_SLV3_CTRL 0x30
#define I2C_SLV4_ADDR 0x31
#define I2C_SLV4_REG 0x32
#define I2C_SLV4_DO 0x33
#define I2C_SLV4_CTRL 0x34
#define I2C_SLV4_DI 0x35
#define I2C_MST_STATUS 0x36
#define INT_PIN_CFG 0x37
#define INT_ENABLE 0x38
#define DMP_INT_STATUS 0x39
#define INT_STATUS 0x3A
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define EXT_SENS_DATA_00 0x49
#define EXT_SENS_DATA_01 0x4A
#define EXT_SENS_DATA_02 0x4B
#define EXT_SENS_DATA_03 0x4C
#define EXT_SENS_DATA_04 0x4D
#define EXT_SENS_DATA_05 0x4E
#define EXT_SENS_DATA_06 0x4F
#define EXT_SENS_DATA_07 0x50
#define EXT_SENS_DATA_08 0x51
#define EXT_SENS_DATA_09 0x52
#define EXT_SENS_DATA_10 0x53
#define EXT_SENS_DATA_11 0x54
#define EXT_SENS_DATA_12 0x55
#define EXT_SENS_DATA_13 0x56
#define EXT_SENS_DATA_14 0x57
#define EXT_SENS_DATA_15 0x58
#define EXT_SENS_DATA_16 0x59
#define EXT_SENS_DATA_17 0x5A
#define EXT_SENS_DATA_18 0x5B
#define EXT_SENS_DATA_19 0x5C
#define EXT_SENS_DATA_20 0x5D
#define EXT_SENS_DATA_21 0x5E
#define EXT_SENS_DATA_22 0x5F
#define EXT_SENS_DATA_23 0x60
#define MOT_DETECT_STATUS 0x61
#define I2C_SLV0_DO 0x63
#define I2C_SLV1_DO 0x64
#define I2C_SLV2_DO 0x65
#define I2C_SLV3_DO 0x66
#define I2C_MST_DELAY_CTRL 0x67
#define SIGNAL_PATH_RESET 0x68
#define MOT_DETECT_CTRL 0x69
#define USER_CTRL 0x6A
#define PWR_MGMT_1 0x6B
#define PWR_MGMT_2 0x6C
#define BANK_SEL 0x6D
#define MEM_START_ADDR 0x6E
#define MEM_R_W 0x6F
#define DMP_CFG_1 0x70
#define DMP_CFG_2 0x71
#define FIFO_COUNTH 0x72
#define FIFO_COUNTL 0x73
#define FIFO_R_W 0x74
#define WHO_AM_I 0x75

 
 
i2c2.c file, this is generated from MCC:
#include <xc.h>
#include <stdbool.h>
#include "i2c2.h"
#include "mcc.h"
static i2c_error lastError = I2C2_GOOD;

void I2C2_Initialize(void)
{
 if(!I2C2CON0bits.EN || lastError != I2C2_GOOD)
    {
  lastError = I2C2_GOOD;
  // TXU 0; CSD Clock Stretching enabled; ACKT 0; RXO 0; ACKDT Acknowledge; ACKSTAT ACK received; ACKCNT Acknowledge;
  I2C2CON1 = 0x00;
  // ABD enabled; GCEN disabled; ACNT disabled; SDAHT 300 ns hold time; BFRET 8 I2C Clock pulses; FME disabled;
  I2C2CON2 = 0x00;
  // CLK MFINTOSC;
  I2C2CLK = 0x03;
  // CSTR Enable clocking; S Cleared by hardware after Start; MODE 7-bit address; EN enabled; RSEN disabled;
  I2C2CON0 = 0x84;
  I2C2PIR = 0;// ;Clear all the error flags
  I2C2ERR = 0;
 }
}

i2c_error i2c2_getLastError(void)
{
    return lastError;
}

static inline void sendByte(uint8_t data)
{
    uint8_t delayCounter = 255;
    if(lastError == I2C2_GOOD)
    {
        while(--delayCounter)
        {
            if(I2C2STAT1bits.TXBE)
            {
                I2C2TXB = data;
                return;
            }
            else
            {
                __delay_us(1);
            }
        }
        lastError = I2C2_FAIL_TIMEOUT;
    }
}

static inline uint8_t receiveByte(void)
{
    uint8_t delayCounter = 255;
    if(lastError == I2C2_GOOD)
    {
        while(--delayCounter)
        {
            if(I2C2STAT1bits.RXBF)
            {
                return I2C2RXB;
            }
            else
            {
                __delay_us(1);
            }
        }
        lastError = I2C2_FAIL_TIMEOUT;
    }
 return 0;
}

static inline void wait4Stop(void)
{
    uint8_t waitCount=255;
    if(lastError == I2C2_GOOD)
    {
        while(--waitCount)
        {
            if(I2C2PIRbits.PCIF)
            {
                return;
            }
            else
            {
                __delay_us(1);
            }
        }
        lastError = I2C2_FAIL_TIMEOUT;
    }
}

static inline void wait4Ack(void)
{
    uint8_t waitCount=255;
    if(lastError == I2C2_GOOD)
    {
        while(--waitCount)
        {
            if(!I2C2CON1bits.ACKSTAT)
            {
                return;
            }
            else
            {
                __delay_us(1);
            }
        }
        lastError = I2C2_FAIL_TIMEOUT;
    }
}

static inline void wait4MDRSetcount(uint8_t count)
{
    uint8_t waitCount=255;
    if(lastError == I2C2_GOOD)
    {
        while(--waitCount)
        {
            if(I2C2CON0bits.MDR)
            {
                I2C2CNT = count;
                return;
            }
            else
            {
                __delay_us(1);
            }
        }
        lastError = I2C2_FAIL_TIMEOUT;
    }
}

void i2c2_write1ByteRegister(uint8_t address, uint8_t reg, uint8_t data)
{
    I2C2_Initialize();
    I2C2ADB1= (uint8_t)(address<<1);
    I2C2CNT=2;
    I2C2CON0bits.S=1;
    sendByte(reg);
    sendByte(data);
    wait4Stop();
}

void i2c2_writeNBytes(uint8_t address, void* data, uint8_t len)
{
    uint8_t *dataPointer = data;

    I2C2_Initialize();
    I2C2ADB1= (uint8_t)(address<<1);
    I2C2CNT=len;
    I2C2CON0bits.S=1; //Start
    while(len--)
    {
        sendByte(*dataPointer++);
    }
    wait4Stop();
}

uint8_t i2c2_read1ByteRegister(uint8_t address, uint8_t reg)
{
    uint8_t result;

    I2C2_Initialize();
    I2C2ADB1= (uint8_t)(address<<1);
    I2C2CNT=1;
    I2C2CON0bits.RSEN=1;
    I2C2CON0bits.S=1; //Start
    while (I2C2CON0bits.S);
    sendByte(reg);
    wait4MDRSetcount(1);
    address = (uint8_t)(address<<1);
    I2C2ADB1= (uint8_t)(address| 0x01); //Change the R/W bit for read
    I2C2CON0bits.S=1; //Start
    I2C2CON0bits.RSEN=0;
    result = receiveByte();
    wait4Stop();
    return result;
}


uint16_t i2c2_read2ByteRegister(uint8_t address, uint8_t reg)
{
    uint16_t result;

    I2C2_Initialize();
    I2C2ADB1= (uint8_t)(address<<1);
    I2C2CNT=1;
    I2C2CON0bits.RSEN=1;
    I2C2CON0bits.S=1; //Start
    while (I2C2CON0bits.S);
    sendByte(reg);
    wait4Ack();
    wait4MDRSetcount(2);
    address=(uint8_t)(address<<1);
    I2C2ADB1= (uint8_t)(address| 0x01); //Change the R/W bit for read
    I2C2CON0bits.S=1; //Start
    while(I2C2CON0bits.S);
    I2C2CON0bits.RSEN=0;
    result = receiveByte();//read MSB of the 2byte register
    result = result<<8;
    result = result | receiveByte();//read LSB of the 2byte register
    wait4Stop();
    return result;
}

void i2c2_write2ByteRegister(uint8_t address, uint8_t reg, uint16_t data)
{
    I2C2_Initialize();
    I2C2ADB1= (uint8_t)(address<<1);
    I2C2CNT=3;
    I2C2CON0bits.S=1; //Start
    sendByte(reg);
    sendByte(data>>8);
    sendByte(data & 0x00FF);
    wait4Stop();
}

void i2c2_readDataBlock(uint8_t address, uint8_t reg, char *data, uint8_t len)
{
    I2C2_Initialize();
    I2C2ADB1= (uint8_t)(address<<1);
    I2C2CNT=1;
    I2C2CON0bits.RSEN=1;
    I2C2CON0bits.S=1; //Start
    sendByte(reg);
    wait4Ack();
    wait4MDRSetcount(len);
    address=(uint8_t)(address<<1);
    I2C2ADB1= (uint8_t)(address| 0x01); //Change the R/W bit for read
    I2C2CON0bits.S=1; //Start
    I2C2CON0bits.RSEN=0;
    while(len--)
    {
        *data++ = receiveByte();
    }
    wait4Stop();
}


 
I'm also uploading my generated project from MCC and the project model from the website that I shared before.
 
Thank you for your time and let's figure this out! 
#1

2 Replies Related Threads

    fabianpi
    Starting Member
    • Total Posts : 49
    • Reward points : 0
    • Joined: 2017/03/26 15:30:13
    • Location: 0
    • Status: offline
    Re: MPU6050 (I2C) with PIC18F27K42 + MCC 2018/05/09 00:00:31 (permalink)
    0
    Another thing that I saw interesting is obviously the i2c routine from the project model: 
     
     
    #include <pic18f4550.h>
    #include "I2C_Master_File.h"

    void I2C_Init()
    {
        TRISB0 = 1; /* Set up I2C lines by setting as input */
     TRISB1 = 1;
     SSPSTAT = 80; /* Slew rate disabled, other bits are cleared */
        SSPCON1 = 0x28; /* Enable SSP port for I2C Master mode, clock = FOSC / (4 * (SSPADD+1))*/
     SSPCON2 = 0;
        SSPADD = BITRATE; /* Set clock frequency */
        SSPIE = 1; /* Enable SSPIF interrupt */
        SSPIF = 0;
    }

    char I2C_Start(char slave_write_address)
    {
        SSPCON2bits.SEN = 1; /* Send START condition */
        while(SSPCON2bits.SEN); /* Wait for completion of START */
        SSPIF=0;
        if(!SSPSTATbits.S) /* Return 0 if START is failed */
        return 0;
        return (I2C_Write(slave_write_address)); /* Write slave device address with write to communicate */
    }

    void I2C_Start_Wait(char slave_write_address)
    {
      while(1)
      {
        SSPCON2bits.SEN = 1; /* Send START condition */
        while(SSPCON2bits.SEN); /* Wait for completion of START */
        SSPIF = 0;
        if(!SSPSTATbits.S) /* Continue if START is failed */
            continue;
        I2C_Write(slave_write_address); /* Write slave device address with write to communicate */
        if(ACKSTAT) /* Check whether Acknowledgment received or not */
        {
            I2C_Stop(); /* If not then initiate STOP and continue */
            continue;
        }
        break; /* If yes then break loop */
      }
    }

    char I2C_Repeated_Start(char slave_read_address)
    {
        RSEN = 1; /* Send REPEATED START condition */
        while(SSPCON2bits.RSEN); /* Wait for completion of REPEATED START condition */
        SSPIF = 0;
        if(!SSPSTATbits.S) /* Return 0 if REPEATED START is failed */
        return 0;
        I2C_Write(slave_read_address); /* Write slave device address with read to communicate */
        if (ACKSTAT) /* Return 2 if acknowledgment received else 1 */
         return 1;
        else
         return 2;
    }

    char I2C_Write(unsigned char data)
    {
          SSPBUF = data; /* Write data to SSPBUF */
          I2C_Ready();
          if (ACKSTAT) /* Return 2 if acknowledgment received else 1 */
            return 1;
          else
            return 2;
    }

    void I2C_Ack()
    {
        ACKDT = 0; /* Acknowledge data 1:NACK,0:ACK */
     ACKEN = 1; /* Enable ACK to send */
        while(ACKEN);
    }

    void I2C_Nack()
    {
        ACKDT = 1; /* Not Acknowledge data 1:NACK,0:ACK */
     ACKEN = 1; /* Enable ACK to send */
        while(ACKEN);
    }
    char I2C_Read(char flag) /* Read data from slave devices with 0=Ack & 1=Nack */
    {
        char buffer;
        RCEN = 1; /* Enable receive */
        while(!SSPSTATbits.BF); /* Wait for buffer full flag which set after complete byte receive */
        buffer = SSPBUF; /* Copy SSPBUF to buffer */
        if(flag==0)
            I2C_Ack(); /* Send acknowledgment */
        else
            I2C_Nack(); /* Send negative acknowledgment */
        I2C_Ready();
        return(buffer);
    }

    char I2C_Stop()
    {
        PEN = 1; /* Initiate STOP condition */
        while(PEN); /* Wait for end of STOP condition */
        SSPIF = 0;
        if(!SSPSTATbits.P); /* Return 0 if STOP failed */
        return 0;
    }

    void I2C_Ready()
    {
        while(!SSPIF); /* Wait for operation complete */
        SSPIF=0; /*clear SSPIF interrupt flag*/
    }

     
    MCC is doing all the work with a single function which, I think is good, but I was thinking to split that function to make it work like this. Is it an accurate idea? The problem would be to know how to interpret each thing in the same way.
     
    Another issue is to switch from ACK to NACK. I do not know if the code generated from MCC is dealing with NACKs in the same way as the model project that I'm looking at. But I think that I need to fix first the problem that I previously told before. 
     
    The problem that I get the slave address from the slave in the first while and the next time that will go there, only gives me a "0" answer.
     
    Thanks!
    #2
    VS89
    New Member
    • Total Posts : 23
    • Reward points : 0
    • Joined: 2012/08/06 02:50:22
    • Location: 0
    • Status: offline
    Re: MPU6050 (I2C) with PIC18F27K42 + MCC 2018/06/14 01:17:17 (permalink)
    0
    This is probably because I2C is not generating a NACK at the end of first read.
    ACKCNT bit of I2C2CON1 needs to be set(during Initialization) to generate a NACK which in turn generates the STOP condition. 
    The current MCC code is not doing this , thus not generating a STOP condition after each operation.
    #3
    Jump to:
    © 2018 APG vNext Commercial Version 4.5