Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

dsPIC33CH128MP508 PIM I2C BNO055 Comms Issue (SOLVED)

Status
Not open for further replies.

GettinBetter

New Member
HW: Explorer 16/32 ver3, 8MHz, PIC33CH128MP508 PIM
SW: MPLABX v5.3, MCC, XC16, terminal via UART1/mini USB
Slave: BNO055 Absolute Orientation Sensor
Aims: Output BNO055 data to terminal via UART.

PIN Config:
Debug (PGEC2 dp 45, PGED2 dp 43).
I2C (SCL dp 60, SDA dp 61).
UART (Tx dp 50 - pp 49, Rx dp 49, pp 51).
In order to get the UART to USB (hence out to terminal) requires that the Explorer16/32 board j48 block pin49 be linked to pin 52 & J48 block pin 50 to pin 51.
[dp = device(chip)pin]
[pp = PIM pin]

Hi Guys,
I'm a bit of a noob with 'C' programming, but (as my name suggests) I'm getting better...
I'm using the MCC in the above named software to generate the code but, there are sections that require customisation/additional code etc.

The code in the i2c.h file shows a MasterRead & MasterWrite examples, but the read from EEPROM example requires a TRB to be setup. now I'm thinking that as the read & write functions are only single byte action, that they could be passed directly to the function.
Below I have removed all the timeout & retry counts for clarity (I can add maybe them later)

C:
/**
    @Summary
        Handles one i2c master read transaction with the
        supplied parameters.

    @Description
        This function prepares a TRB, then inserts it on the i2c queue.
        Finally, it waits for the transaction to complete and returns
        the result.

    @Preconditions
        None

    @Param
        address - The address of the i2c peripheral to be accessed
    
    @Param
        length - The length of the data block to be sent
    
    @Param
        *pdata - A pointer to the memory location where received data will
                 be stored

    @Param
        *pstatus - A pointer to the status variable that the i2c driver
            updates during the execution of the message.

    @Returns
        I2C1_MESSAGE_STATUS

    @Example
        <code>

/* address -The address of the i2c peripheral to be accessed.
*  length - The length of the data block to be sent.
*  *pdata - A pointer to the memory location where received data will be stored.
*  *pstatus - A pointer to the status variable that the i2c driver updates during the execution of the message.
*/
            uint8_t BNO055_Read(uint16_t address, uint8_t *pData, uint16_t nCount)
            {
            I2C1_MESSAGE_STATUS status;
            uint8_t     *pD;
            uint16_t address = 0x29;         // slave device address
            uint8_t length = 1;
            uint8_t *pData;

                pD = pData;

                    while(status != I2C1_MESSAGE_FAIL)
                    {
                    void I2C1_MasterWrite(uint8_t *pdata, uint8_t length, uint16_t address, I2C1_MESSAGE_STATUS *pstatus);
                        while(status == I2C1_MESSAGE_PENDING)
                        {
                             __delay32(5000);
                            
                        }

                        if (status == I2C1_MESSAGE_COMPLETE)
                            break;
                    }

                    if (status == I2C1_MESSAGE_COMPLETE)
                    {

                        // this portion will read the byte from the BNO Temperature register location.

                        while(status != I2C1_MESSAGE_FAIL)
                        {
                            I2C1_MasterRead( pD, 1, BNO055_ADDRESS, &status);

                            while(status == I2C1_MESSAGE_PENDING)
                            {
                                __delay32(5000);       
                            }

                            if (status == I2C1_MESSAGE_COMPLETE)
                                break;
                        }
                    }

                    // exit if the last transaction failed
                    if (status == I2C1_MESSAGE_FAIL)
                    {
                        return(0);
                        break;
                    }
                }
                return(1);
            }
 
//        </code>

I've attached the original MCC generated file for your perusal.
Am I on the right path, or am I approaching this from the wrong angle? Any feedback would be appreciated.
Regards
GB
 

Attachments

  • i2c1.h
    24.5 KB · Views: 274
The MCC module produces incomprehensible code. Start with a simple pic16 chip, work out how to program that and then move on to more advanced chips. Why do you want to jump in at the deep end?

Mike.
 
The MCC module produces incomprehensible code...

Mike.

That's becoming clearer, as I dig deeper the irregularities are becoming obvious.
I started with 8bit, then 16, each time realising they wouldn't be able to fulfill my projects requirements. A learning curve is a learning curve ..
 
The MCC code is a nightmare..

If you plan to do any serious work in C with PIC MCUs, I'd strongly recommend you get the CCS compiler.
That still works with MPLab for editing, compiling and debugging - but all functions are far easier to use.

eg. Reading a block of data from an I2C device, in the simplest form, can be done with a single function i2c_transfer(), though It does have many more discrete configuration and transfer functions as well.

C:
unsigned int8 rData[16];

int1 ack;
// rData is a pointer to the location the data read in will be stored

ack=i2c_transfer_in(0xA0,rData,16);

if(ack==0)
     printf("Data read successfully");
else
     printf("data not read");

You can download the compiler manual here, to have a look through it.

In general the functions and C code for any feature are the same for any type/size PIC, as long as the relevant peripheral is present in the device being used.
 
I can't believe it took this long to get this solved, although having to build a new PC absorbed some of that time ...anyway, here is a version of the code that works for me, or at least got me started. I hope this helps anyone trying to use the MCC as a means to get into PIC using 'C'.

The first write changes the BNO default status of 'configuration mode' to any of the other mode to allow the data to be read. In my case it was 'ACCGYR'
The second write sends the device address and a read bit, then transfers all data that it reads from the registers into a buffer that in turn tranfers it to a variable array that you choose (in my case it was pD). The transmission block builder created by the MCC increments sequentially, and starts at the memory address you give it, for the numer of time you want it to loop/ or increment, so if your register addresses aren't sequential you'd need to write this code differently.


C:
/**
PROJECT NAME: X1632-8Mhz_BNO055_Comms3
*
* THE WRITE OF 0x£D & 0x05 WORKS WITH EXPECTED OUTPUT
* THE READ IS WORK IN PROGRESS 24.12.20
*
  Section: Included Files
*/
#include "xc.h"
#include "mcc_generated_files/system.h"
#include "mcc_generated_files/uart1.h"
#include "mcc_generated_files/i2c1.h"
#include <libpic30.h> //Defines __delay32();
#include <stdio.h> // Defines printf("");



#define CONFIGMODE 0b00000000 // default value = config mode
#define OPR_MODE 0b00111101 //Register 0x3D = 'NDOF'
#define ACCGYRO_CON 0b00001100 //Register Value 0x0C
#define BNO55_I2C_ADDR 0b00101000 //Slave Device Address 0x28

#define BNO055_ACC_DATA_X_LSB   0x08
#define BNO055_ACC_DATA_X_MSB   0x09
#define BNO055_ACC_DATA_Y_LSB   0x0A
#define BNO055_ACC_DATA_Y_MSB   0x0B
#define BNO055_ACC_DATA_Z_LSB   0x0C
#define BNO055_ACC_DATA_Z_MSB   0x0D
#define BNO055_MAG_DATA_X_LSB   0x0E
#define BNO055_MAG_DATA_X_MSB   0x0F
#define BNO055_MAG_DATA_Y_LSB   0x10
#define BNO055_MAG_DATA_Y_MSB   0x11
#define BNO055_MAG_DATA_Z_LSB   0x12
#define BNO055_MAG_DATA_Z_MSB   0x13
#define BNO055_GYR_DATA_X_LSB   0x14
#define BNO055_GYR_DATA_X_MSB   0x15
#define BNO055_GYR_DATA_Y_LSB   0x16
#define BNO055_GYR_DATA_Y_MSB   0x17
#define BNO055_GYR_DATA_Z_LSB   0x18
#define BNO055_GYR_DATA_Z_MSB   0x19

#define DEVICE_TIMEOUT 50
#define RETRY_MAX 100

int main(void)
{
    // initialise the device
    SYSTEM_Initialize();

/* INITIALISES THE FOLLOWING
    PIN_MANAGER_Initialize();
    CLOCK_Initialize();
    INTERRUPT_Initialize();
    I2C1_Initialize();
    UART1_Initialize();
    INTERRUPT_GlobalEnable();
    SYSTEM_CORCONModeOperatingSet(CORCON_MODE_PORVALUES);
*/


__delay32(5000);

// Commented out to clear terminal clutter

//          // SYSTEMS USED & PROJECT AIMS
//    printf("\n\n\r Explorer 16/32 v3 DM240001-3, ICD4, dsPIC33CH128MP508 PIM\n\r");
//    __delay32(5000);
//    printf("MPLABX v5.4, MCC v4.0.2, XC16 v1.60\n\r");
//    __delay32(5000);
//    printf("Project Name: X1632-8Mhz_BNO055_Comms3\n\r");
//    __delay32(5000);
//    printf("Simple write to BNO055 Comms via I2C \n\n\r");
//    __delay32(5000);
//    __delay32(5000);


/*
  * From To Switching time
  * CONFIGMODE Any operation mode 7ms
  * Any operation mode CONFIGMODE 19ms
  */

/* DELAY FUNCTION */

void Cust_Delay(uint8_t CDCount)
{
    uint8_t i;
    for(i=0; i<CDCount+1;i++)
    {
        __delay32(5000);
    }
};


uint8_t *pdata; // block to be sent, in this case it's the address of the register to write to, and the value to write.
uint8_t length; // number of elements in pdata.
uint16_t address; // Slave device address.
I2C1_MESSAGE_STATUS *pstatus; // Internal status register to gauge I2C_MasterRead/Write function progress.
uint16_t retryTimeOut, slaveTimeOut;

length = 2;        // number of bytes to transfer in the for loop.

address = (BNO55_I2C_ADDR); // Shifted (in the I2C1 TRB function) to the LSB as only writing 7 bit address.
retryTimeOut = 0;
slaveTimeOut = 0;

     //   SET OP_MODE(0x3D) TO ACCGYRO(0x05)
uint8_t data[]= {OPR_MODE, ACCGYRO_CON};      //address of the OP_MODE register to write to, and the value to write.

while(pstatus != I2C1_MESSAGE_FAIL)     // After I2C1_MasterWrite is called this status is returned. The default is ENUMERATING  and so satisfys the test.
{

  pdata = data;     // Initialise the source of the data.

I2C1_MasterWrite(pdata, length, address, &pstatus);   //value stored at the address pdata points to

                Cust_Delay(2);

               // wait for the message to be sent or status has changed.
                while(pstatus == I2C1_MESSAGE_PENDING)
                {
                   Cust_Delay(2);


                    // timeout checking
                    // check for max retry and skip this byte
                    if (slaveTimeOut == DEVICE_TIMEOUT)
                        break;
                    else
                        slaveTimeOut++;
                }

if (pstatus == I2C1_MESSAGE_COMPLETE)
      break;
if (retryTimeOut == RETRY_MAX)
    break;
else
    retryTimeOut++;
if (pstatus == I2C1_MESSAGE_COMPLETE)
    break;

}
// Commented out to clear terminal clutter
//printf("\FIRST WRITE HAS FINISHED, OP_CODE CHANGED TO ACCGYR\n\n\r");                    //debug
//__delay32(1000);


  while(1)
    {

// START OF READ SECTION
int16_t Concantenated[18];  // Variable to get the result the LSB & MSB register values
uint16_t nCount;
uint8_t start_address[] = {0x08}; // Starting address of the BNO registers that I want to read
uint8_t *Data2;                    // Pointer to use for the I2C1_MasterWrite to use
uint8_t Data3[18];                 // Array that
uint16_t timeOut;
uint8_t *pD;
Data2 = start_address;

                    I2C1_MESSAGE_STATUS *pstatus = I2C1_MESSAGE_PENDING;
                    timeOut = 0;
                    while(pstatus != I2C1_MESSAGE_FAIL)
                    {
                        // write one byte
                        I2C1_MasterWrite(                 Data2,         // register address to start reading from
                                                        1,            // one byte register address
                                                        address,    // slave device address
                                                        &pstatus); // return status
                        Cust_Delay(2);
                        while(pstatus == I2C1_MESSAGE_PENDING);
                        {
                        Cust_Delay(2);
                    
                            if (pstatus == I2C1_MESSAGE_COMPLETE)
                                break;
                        
                            // check for max retry and skip this byte
                            if (timeOut == RETRY_MAX)
                                break;
                        else
                            timeOut++;
                        }
                    }

                    if (pstatus == I2C1_MESSAGE_COMPLETE)
                    {
                  
                        // this portion should read the 18 bytes from the 18 memory locations.
                        // ACC, MAG & GYR just happen are consecutive. 6 each, LSB X, MSB X ,LSB Y, MSB Y, LSB Z, MSB Z, etc.
                        timeOut = 0;
                        nCount = 18; // Number of bytes the I2C1_MasterRead function will read.
                        pD = Data3;     // Variable pointer that is passed to the I2C1 Master Read function
                                        // all data read will be sent to the Data3 array.
                    
                       I2C1_MESSAGE_STATUS *pstatus = I2C1_MESSAGE_PENDING;  // Set status to satisfy the 'while' and allow it to start.
                        while(pstatus != I2C1_MESSAGE_FAIL)
                        {
                            //READ 18 bytes starting at the previously sent register address.
                            I2C1_MasterRead(         pD,     // Data3 array that the read data is sent to.
                                                    nCount, // Number of cycles the I2C1_MasterRead function will do.
                                                    address,    // slave device address.
                                                    &pstatus);    // Internal status register to gauge function progress.

                            Cust_Delay(2);

                            // wait for the message to be sent or status has changed.
                            while(pstatus == I2C1_MESSAGE_PENDING);
                            {
                            Cust_Delay(2);
                            if (pstatus == I2C1_MESSAGE_COMPLETE)
                                break;
                        
                            // check for max retry and skip this byte
                            if (timeOut == RETRY_MAX)
                                break;
                            else
                                timeOut++;
                            }
                    // exit if the last transaction failed
                    if (pstatus == I2C1_MESSAGE_FAIL)
                        break;
                    }
                }
                    // All data3 elements must be read before the next I2C1_MasterRead cycle, else it will be over written.
                    int16_t temp1;
                
                        temp1 = (pD[1]<<8);
                        Concantenated[0]= (temp1 + pD[0]);
                       printf("ACC_DATA_X = %d \n\r", Concantenated[0]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[3]<<8);
                       Concantenated[1]= (temp1 + pD[2]);
                       printf("ACC_DATA_Y = %d \n\r", Concantenated[1]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[5]<<8);
                        Concantenated[2]= (temp1 + pD[4]);
                       printf("ACC_DATA_Z = %d \n\r", Concantenated[2]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[7]<<8);
                        Concantenated[3]= (temp1 + pD[6]);
                       printf("MAG_DATA_X = %d \n\r", Concantenated[3]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[9]<<8);
                        Concantenated[4]= (temp1 + pD[8]);
                       printf("MAG_DATA_Y = %d \n\r", Concantenated[4]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[11]<<8);
                        Concantenated[5]= (temp1 + pD[10]);
                       printf("MAG_DATA_Z = %d \n\r", Concantenated[5]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[13]<<8);
                        Concantenated[6]= (temp1 + pD[12]);
                       printf("GYR_DATA_X = %d \n\r", Concantenated[6]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[15]<<8);
                        Concantenated[7]= (temp1 + pD[14]);
                       printf("GYR_DATA_Y = %d \n\r", Concantenated[7]);
                       Cust_Delay(2);
                  
                       temp1 = (pD[17]<<8);
                        Concantenated[8]= (temp1 + pD[16]);
                       printf("GYR_DATA_Z = %d \n\r",Concantenated[8]);
                       Cust_Delay(2);
                  
                       printf("\033[0;0H");
                       Cust_Delay(2);
      
  }
return(1);

}
/**
End of File
*
*/
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top