dsPIC33CH I2C code syntax problem (SOLVED)

Thread Starter

GettinBetter

Joined Jun 22, 2018
42
I've added the code for the three functions used for the transmission as copied from I2C1.c.
Appreciate your time and thoughts.

MasterWrite Function:
void I2C1_MasterWrite(
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address,
                                I2C1_MESSAGE_STATUS *pstatus)
{
    static I2C1_TRANSACTION_REQUEST_BLOCK   trBlock;

    // check if there is space in the queue
    if (i2c1_object.trStatus.s.full != true)
    {
        I2C1_MasterWriteTRBBuild(&trBlock, pdata, length, address);
        I2C1_MasterTRBInsert(1, &trBlock, pstatus);
    }
    else
    {
        *pstatus = I2C1_MESSAGE_FAIL;
    }

 }
MasterWriteTRBBuild Function:
void I2C1_MasterWriteTRBBuild(
                                I2C1_TRANSACTION_REQUEST_BLOCK *ptrb,
                                uint8_t *pdata,
                                uint8_t length,
                                uint16_t address)
{
    ptrb->address = address << 1;
    ptrb->length  = length;
    ptrb->pbuffer = pdata;
}

bool I2C1_MasterQueueIsEmpty(void)
{
    return((bool)i2c1_object.trStatus.s.empty);
}
MasterTRBInsert Function:
void I2C1_MasterTRBInsert(
                                uint8_t count,
                                I2C1_TRANSACTION_REQUEST_BLOCK *ptrb_list,
                                I2C1_MESSAGE_STATUS *pflag)
{

    // check if there is space in the queue
    if (i2c1_object.trStatus.s.full != true)
    {
        *pflag = I2C1_MESSAGE_PENDING;

        i2c1_object.pTrTail->ptrb_list = ptrb_list;
        i2c1_object.pTrTail->count     = count;
        i2c1_object.pTrTail->pTrFlag   = pflag;
        i2c1_object.pTrTail++;

        // check if the end of the array is reached
        if (i2c1_object.pTrTail == (i2c1_tr_queue + I2C1_CONFIG_TR_QUEUE_LENGTH))
        {
            // adjust to restart at the beginning of the array
            i2c1_object.pTrTail = i2c1_tr_queue;
        }

        // since we added one item to be processed, we know
        // it is not empty, so set the empty status to false
        i2c1_object.trStatus.s.empty = false;

        // check if full
        if (i2c1_object.pTrHead == i2c1_object.pTrTail)
        {
            // it is full, set the full status to true
            i2c1_object.trStatus.s.full = true;
        }

        // for interrupt based
        if(i2c1_state == S_MASTER_IDLE)
        {   
            // force the task to run since we know that the queue has
            // something that needs to be sent
            IFS1bits.MI2C1IF = 1;
        }           
        
    }
    else
    {
        *pflag = I2C1_MESSAGE_FAIL;
    }
 

Thread Starter

GettinBetter

Joined Jun 22, 2018
42
Ok, well this works.. it's taken me all day, and most of that was digging around in the I2C1.c file with the TRBBuild, and TRB Insert functions, but hey I can move on now.. :D

Working Code:
/**
 PROJECT NAME: X1632-8Mhz_BNO055_Comms3

    
  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
#define ACCGYRO_CON 0b00000101        //Register Value 0x05
#define BNO55_I2C_ADDR 0b00101000        //Slave Device Address 0x28
    
#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);

          //  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
  */
      
uint8_t counter;    // Loop counter
uint8_t *pdata;     // Pointer declaration to the 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 data array.
uint16_t address;   // Slave device address.
I2C1_MESSAGE_STATUS *pstatus;   //I2C returned status message.
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.
 
for (counter = 0; counter < length ;counter++)   //counter to loop increment 'operation mode' Register & value index.
{
 I2C1_MasterWrite(pdata, length, address, &pstatus);   //value stored at the address pdata points to
__delay32(5000);
               // wait for the message to be sent or status has changed.
                while(pstatus == I2C1_MESSAGE_PENDING)
                {
                   __delay32(5000);


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

printf("\n\n\r I2C Message status = %X \n\n\r",pstatus);     //debug
__delay32(5000);
printf("Device Address = %08x \n\n\r",address);         //debug
__delay32(5000);
printf("Data  = %08x \n\n\r",*pdata);                    //debug
__delay32(5000);

pdata++;

}
if (retryTimeOut == RETRY_MAX)
                    break;
                else
                    retryTimeOut++;
if (pstatus == I2C1_MESSAGE_COMPLETE)
    break;
 
}
  while(1)
    {
      
    }
 return 1;
}
Removed the Asterisk from pdata in the I2C1_MasterWrite function on line 83.

Code:
 I2C1_MasterWrite(pdata, length, address, &pstatus);
Terminal_20-12-20.png

Salea_Plot_Address_And_Data_20-12-20.png


I appreciate your help guys, nothing like a bit of brainstorming to solve a problem, it was a great learning curve for me too.

Regards
GB
 

Thread Starter

GettinBetter

Joined Jun 22, 2018
42
Just a quick update for anyone who might be playing with this code example...
ric from 'PICforum' suggested that I didn't need to loop the I2C1_MasterWrite function twice.

He was indeed correct, as I found out later that the pdata pointer is automatically incremented within the I2C1_MasterWrite function. So that can go, along with the pdata++ as it's also not needed.
Another thing is that when you remove the 'for' loop, the printf statement for pdata only prints the second element in the array, as the first is incremented within the I2C1_MasterWrite function.

Just thought I'd mention it for completeness

Regards
GB
 
Last edited:

MrChips

Joined Oct 2, 2009
34,817
@ MrChips
I know the difference between Binary, Decimal, & Hex, I'm just confused as to which one to use and when. In this case I used the binary version because the example did.

Regards
GB
That is the point I am trying to get you to understand.

If you enter 01010 into text code, how should the compiler interpret this?
The answer is one thousand and ten. It does not know that you intended this to be 10 in decimal.

The computer does not care how you enter the value. It will see binary every time. It is the role of the compiler to convert what you wrote into binary based on the syntax rules of the computer language.

It does not matter if you enter 0b1010, 0x0A, or 10.
The computer is going to see 00001010 in 8-bit binary or 0000000000001010 in 16-bit binary etc. depending on the size of the data type.

It is up to you the human programmer to choose how best to input a value into your text code.

Which of the following is best readable and makes most sense to you?

#define TEN 0b01010
#define TEN 0x0A
#define TEN 10

You want to use the number representation that makes most sense.
Examples:

#define BIT3_MASK 0b11110111

#define RAM_ADDRESS 0xC000

#define YEAR 2020
 

Thread Starter

GettinBetter

Joined Jun 22, 2018
42
As suggested in post #12.
Hi Albert, well at the time, I didn't agree, with you (or ric), but when looking at the logic output there was another transmission with 0x05 and some random value, which kept changing, although the 0x05 was consistent. It was then that I realised you guys were correct, I removed the loop and the second unwanted transmission was gone, and the first transmission still had both values that I wanted.

In my defence, I didn't agree because I didn't fully understand how the I2CMasterWrite function worked. I wouldn't say I do now, but I am at least getting better (pun intended) :D


That is the point I am trying to get you to understand......
Thank you, Understood. More use will drive this home I'm sure.

Regards
GB
 
Top