I2C write function issue requires ANSI-style prototype

Thread Starter

GoExtreme

Joined Mar 4, 2018
52
I'm trying to get SMBus transactions made for EFM8. Im not sure why Im getting errors for Write function:

'I2C_MasterWrite': requires ANSI-style prototype

Code:
void I2C_MasterWrite(unsigned char* PtrtoCmdBuffer) 
{
       while(SMB_BUSY);                    // Wait for SMBus to be free.
         SMB_BUSY = 1;                       // Claim SMBus (set to busy)
         SMB_RW = 0;                         // Mark this transfer as a WRITE
        TARGET = PtrtoCmdBuffer[0];    //copy the slave address from the transaction array to the global variable
    SMB_DATA_OUT = PtrtoCmdBuffer + 2;    //set the address of the first data byte in the transaction array
    I2C_FinalWriteAddress = SMB_DATA_OUT + (PtrtoCmdBuffer[1] - 1);    //set the final address based on the number of bytes to be transmitted
    SFRPAGE = SMB0_PAGE;
    SMB0CN0_STA = 1;    //initiate the transaction by setting the start-condition bit
}
Prototype function
void I2C_MasterWrite();

I put unsigned char* into () of prototype then it shows issues with SMB_DATA_OUT in the ISR part.

I write I2C_MasterWrite(InaConf); in the program.
 

danadak

Joined Mar 10, 2018
4,057
That error occurs if you have not -

1) Declared f() external if it is. Eg. not in main.c
2) Not declared it all. Eg. compiler is trying to find a non-existent f().
3) Typing error in the name of the f().

Regards, Dana.
 

Thread Starter

GoExtreme

Joined Mar 4, 2018
52
Hi @danadak,

Function() is under after main.c, prototype is above main. The transaction array is also above main.

unsigned char idata InaaConf[5] = {SLAVE_ADDR,3,0x00, 0x45, 0x27};
 

danadak

Joined Mar 10, 2018
4,057
Sometimes erasing the line and totally retyping it, this issue
caused by non displayable characters inadvertently inserted into
the line due to editor error, file write error.......

Is compiler reporting the correct error, comment out the line and see what
happens.

Regards, Dana.
 

Thread Starter

GoExtreme

Joined Mar 4, 2018
52
If I comment the function in main, or even change the prototype to void I2C_MasterWrite(unsigned char), it complains about 'SMB_DATA_OUT': undefined identifier.
ISR:
Code:
 switch (SMB0CN0 & 0xF0)          // Status vector
      {
         // Master Transmitter/Receiver: START condition transmitted.
         case SMB_MTSTA:
             SMB0CN0_STA = 0;           // Manually clear START bit
             SMB0CN0_STO = 0;           // Manually clear START bit
             SMB0DAT = (TARGET<<1)|SMB_RW;    // Load R/W bit

           // rec_byte_counter = 1;      // Reset the counter
           // sent_byte_counter = 1;     // Reset the counter
            break;

         // Master Transmitter: Data byte transmitted
         case SMB_MTDB:
            if (SMB0CN0_ACK)           // Slave SMB0CN0_ACK? After Address
            {
               if (SMB_RW == WRITE)    // If this transfer is a WRITE,
               {
                 // if (sent_byte_counter <= NUM_BYTES_WR)
                //  {
                     // send data byte
                     SMB0DAT = *SMB_DATA_OUT; //write first byte to SMBus data register
                     //sent_byte_counter++;
                //  }
                     if (SMB0CN0_ACK)           // Slave ACK last byte
                     {
                         if(SMB_DATA_OUT == I2C_FinalWriteAddress) // If byte is final
                                 {
                                     SMB0CN0_STO = 1;    //transmit stop condition
                                     SMB_BUSY = 0;     // And free SMBus interface
                                 }
                                 //if slave ACKed and this was not the final byte
                                 else
                                 {
                                     SMB_DATA_OUT++;    //increment pointer that points at data to be transmitted
                                     SMB0DAT = *SMB_DATA_OUT;    //write next byte to SMBus data register
                                 }

                     }

                  else // If NACK after first byte
                  {
                     SMB0CN0_STO = 1;  // Set SMB0CN0_STO to terminate transfer
                     SMB_BUSY = 0;     // And free SMBus interface
                  }
               }
 
I think that you have more than one issue. Look at this code for illustration.

Code:
#include "qm_common.h"

void myfunc(unsigned char *);

unsigned char InaaConf[5] = {10,11,12,13,14};

int main()
{
  myfunc(InaaConf);
  return 0;
}


void myfunc(unsigned char * Ar)
{
   unsigned char TARGET,SMB_DATA_OUT, I2C_FinalWriteAddress;
   unsigned char v0,v1,v2;

   v0=*Ar; /* v0 is value of element 0 of array */
   Ar++;
   v1=*Ar; /* v1 is value of element 1 of array */
   Ar++;
   v2=*Ar; /* v2 is value of element 2 of array */

   TARGET=v0;
   QM_PRINTF("TARGET= %d ",TARGET);
   SMB_DATA_OUT=v2;
   QM_PRINTF("  SMB_DATA_OUT= %d ",SMB_DATA_OUT);
   I2C_FinalWriteAddress=SMB_DATA_OUT +(v1-1);
   QM_PRINTF("  I2C_FinalWriteAddress= %d ",I2C_FinalWriteAddress);

}
Output:
TARGET= 10 SMB_DATA_OUT= 12 I2C_FinalWriteAddress= 22

ignore the #include "qm_common.h" and treat QM_PRINTF as printf - they are system specific stuff for what I was on when reading your post
 

Thread Starter

GoExtreme

Joined Mar 4, 2018
52
@MrSoftware unsigned char idata *SMB_DATA_OUT;

Code:
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <SI_EFM8UB1_Register_Enums.h>
#include "InitDevice.h"
#include "EFM8UB1_SMBus_MasterMultibyte.h"

//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
// Global holder for SMBus data
// All receive data is written here
//uint8_t SMB_DATA_IN[NUM_BYTES_RD];

// Global holder for SMBus data.
// All transmit data is read from here
//uint8_t SMB_DATA_OUT;

uint8_t TARGET;                        // Target SMBus slave address

volatile bool SMB_BUSY;                 // Software flag to indicate when the
                                       // SMB_Read() or SMB_Write() functions
                                       // have claimed the SMBus

volatile bool SMB_RW;                   // Software flag to indicate the
                                       // direction of the current transfer

uint16_t NUM_ERRORS;                   // Counter for the number of errors.

//-----------------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------------
void SMB_Write(void);
void SMB_Read(void);
void T0_Waitms(uint8_t ms);
unsigned char idata InaaConf[5] = {SLAVE_ADDR,3,0x00, 0x45, 0x27};
//unsigned char NUM_BYTES_RD;
unsigned char idata *SMB_DATA_OUT;
unsigned char I2C_FinalWriteAddress;    //ISR uses this to determine which byte is the final byte
void I2C_MasterWrite(unsigned char);
//-----------------------------------------------------------------------------
// SiLabs_Startup() Routine
// ----------------------------------------------------------------------------
// This function is called immediately after reset, before the initialization
// code is run in SILABS_STARTUP.A51 (which runs before main() ). This is a
// useful place to disable the watchdog timer, which is enable by default
// and may trigger before main() in some instances.
//-----------------------------------------------------------------------------
void SiLabs_Startup (void)
{
  // Disable the watchdog here
}
//-----------------------------------------------------------------------------
// Main Routine
//-----------------------------------------------------------------------------
//
// Main routine performs all configuration tasks, then loops forever sending
// and receiving SMBus data to the slave.
//
//-----------------------------------------------------------------------------
void main (void)
{
//  volatile uint8_t dat;               // Test counter
  // volatile uint8_t data_count;        // SMB_DATA_IN and SMB_DATA_OUT counter
   uint8_t i;                          // Dummy variable counters

   enter_BusFreeMode_from_RESET();

   DISP_EN = DISP_BC_DRIVEN;           // EFM8 does not drive display

   // If slave is holding SDA low because of an improper SMBus reset or error
   while(!SDA)
   {
      // Provide clock pulses to allow the slave to advance out
      // of its current state. This will allow it to release SDA.
      XBR2 = XBR2_XBARE__ENABLED;      // Enable Crossbar
      SCL = 0;                         // Drive the clock low
      for(i = 0; i < 255; i++);        // Hold the clock low
      SCL = 1;                         // Release the clock
      while(!SCL);                     // Wait for open-drain
                                       // clock output to rise
      for(i = 0; i < 10; i++);         // Hold the clock high
      XBR2 = XBR2_XBARE__DISABLED;     // Disable Crossbar
   }

   enter_DefaultMode_from_BusFreeMode();

   LED1 = LED_OFF;

   // TEST CODE----------------------------------------------------------------


I2C_MasterWrite(InaaConf);
}

//SMB Write

void I2C_MasterWrite(unsigned char* PtrtoCmdBuffer)    //function argument is simply the name of the transaction array
{
       while(SMB_BUSY);                    // Wait for SMBus to be free.
         SMB_BUSY = 1;                       // Claim SMBus (set to busy)
         SMB_RW = 0;                         // Mark this transfer as a WRITE
        // SMB0CN0_STA = 1;                    // Start transfer

//    I2C_State = MstW_STA_SENT;    //first state is "start condition generated"
    TARGET = PtrtoCmdBuffer[0];    //copy the slave address from the transaction array to the global variable
    SMB_DATA_OUT = PtrtoCmdBuffer + 2;    //set the address of the first data byte in the transaction array
    I2C_FinalWriteAddress = SMB_DATA_OUT + (PtrtoCmdBuffer[1] - 1);    //set the final address based on the number of bytes to be transmitted

    SFRPAGE = SMB0_PAGE;
    SMB0CN0_STA = 1;    //initiate the transaction by setting the start-condition bit
}
Header:
Code:
//-----------------------------------------------------------------------------
// EFM8UB1_SMBus_Master_Multibyte.h
//-----------------------------------------------------------------------------
// Copyright 2014 Silicon Laboratories, Inc.
// http://developer.silabs.com/legal/version/v11/Silicon_Labs_Software_License_Agreement.txt
//
// Header for main file:

#ifndef SMBUS_MASTER_MULTIBYTE_H_
#define SMBUS_MASTER_MULTIBYTE_H_

//-----------------------------------------------------------------------------
// Pin Definitions
//-----------------------------------------------------------------------------
SI_SBIT (SDA, SFR_P1, 2);              // SMBus on P1.2
SI_SBIT (SCL, SFR_P1, 3);              // and P1.3

SI_SBIT (LED1, SFR_P1, 4);             // LED green
#define LED_ON   0
#define LED_OFF  1

SI_SBIT (DISP_EN, SFR_P2, 3);          // Display Enable
#define DISP_BC_DRIVEN   0             // 0 = Board Controller drives display
#define DISP_EFM8_DRIVEN 1             // 1 = EFM8 drives display

//-----------------------------------------------------------------------------
// Global CONSTANTS
//-----------------------------------------------------------------------------

#define  SYSCLK               24500000 // System clock frequency in Hz

#define  SMB_FREQUENCY           10000 // Target SCL clock rate
                                       // This example supports between 10kHz
                                       // and 100kHz

#define  WRITE                    0x00 // SMBus WRITE command
#define  READ                     0x01 // SMBus READ command

// Device addresses (7 bits, lsb is a don't care)
#define  SLAVE_ADDR               0x40 // Device address for slave target

// Status vector - top 4 bits only
#define  SMB_MTSTA                0xE0 // (MT) start transmitted
#define  SMB_MTDB                 0xC0 // (MT) data byte transmitted
#define  SMB_MRDB                 0x80 // (MR) data byte received
// End status vector definition

//#define  NUM_BYTES_WR                3 // Number of bytes to write
                                       // Master -> Slave
//#define  NUM_BYTES_RD                2 // Number of bytes to read
                                       // Master <- Slave

//-----------------------------------------------------------------------------
// Global VARIABLES
//-----------------------------------------------------------------------------

// Global holder for SMBus data
// All receive data is written here
//extern uint8_t SMB_DATA_IN[NUM_BYTES_RD];

// Global holder for SMBus data.
// All transmit data is read from here
//extern uint8_t SMB_DATA_OUT[NUM_BYTES_WR];

extern uint8_t TARGET;                 // Target SMBus slave address

extern volatile bool SMB_BUSY;          // Software flag to indicate when the
                                       // SMB_Read() or SMB_Write() functions
                                       // have claimed the SMBus

extern volatile bool SMB_RW;            // Software flag to indicate the
                                       // direction of the current transfer

extern uint16_t NUM_ERRORS;            // Counter for the number of errors..



#endif // SMBUS_MASTER_MULTIBYTE_H_
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------
ISR
Code:
if (SMB0CN0_ARBLOST == 0)           // Check for errors
   {
      // Normal operation
      switch (SMB0CN0 & 0xF0)          // Status vector
      {
         // Master Transmitter/Receiver: START condition transmitted.
         case SMB_MTSTA:
             SMB0CN0_STA = 0;           // Manually clear START bit
             SMB0CN0_STO = 0;           // Manually clear START bit
             SMB0DAT = (TARGET<<1)|SMB_RW;    // Load R/W bit

           // rec_byte_counter = 1;      // Reset the counter
           // sent_byte_counter = 1;     // Reset the counter
            break;

         // Master Transmitter: Data byte transmitted
         case SMB_MTDB:
            if (SMB0CN0_ACK)           // Slave SMB0CN0_ACK? After Address
            {
               if (SMB_RW == WRITE)    // If this transfer is a WRITE,
               {
                 // if (sent_byte_counter <= NUM_BYTES_WR)
                //  {
                     // send data byte
                     SMB0DAT = *SMB_DATA_OUT; //write first byte to SMBus data register
                     //sent_byte_counter++;
                //  }
                     if (SMB0CN0_ACK)           // Slave ACK last byte
                     {
                         if(SMB_DATA_OUT == I2C_FinalWriteAddress) // If byte is final
                                 {
                                     SMB0CN0_STO = 1;    //transmit stop condition
                                     SMB_BUSY = 0;     // And free SMBus interface
                                 }
                                 //if slave ACKed and this was not the final byte
                                 else
                                 {
                                     SMB_DATA_OUT++;    //increment pointer that points at data to be transmitted
                                     SMB0DAT = *SMB_DATA_OUT;    //write next byte to SMBus data register
                                 }

                     }

                  else // If NACK after first byte
                  {
                     SMB0CN0_STO = 1;  // Set SMB0CN0_STO to terminate transfer
                     SMB_BUSY = 0;     // And free SMBus interface
                  }
               }
 

Ian Rogers

Joined Dec 12, 2012
1,136
SMB_DATA_OUT == I2C_FinalWriteAddress)
Is it just me... Or is SMB_DATA_OUT a pointer.. If you are using it as a count, then you don't know where in memory its pointing to.

I2C_FinalWriteAddress = SMB_DATA_OUT + (PtrtoCmdBuffer[1] - 1); <-- here you are pointing to the buffer, but the buffer may be at location 0x700 for all you know.. To find out the count it would be :-
(SMB_DATA_OUT - (PtrtoCmdBuffer[1] - 1)

But unfortunately that buffer isn't in the ISR scope. Compilers don't like you mixing up char and char* types... ( not at least without a cast!! )
 
@Raymond Genovese I was looking at All about circutis article on implementing efm8 smbus.

https://www.allaboutcircuits.com/te...ting-i2c-with-an-efm8-microcontroller-part-2/


Do I need to define each byte?
I am familiar with the article but not with that EFM8 board, @RK37 might be able to advise you better. I think, and I mean this respectfully, that you need a little better understanding about how to use pointers. That's why I posted that little program...to show you an example of using them that will compile without errors.
 
Last edited:

Thread Starter

GoExtreme

Joined Mar 4, 2018
52
Changing C file
Code:
volatile unsigned char idata InaaConf[5] = {SLAVE_ADDR,3,0x00, 0x45, 0x27};
volatile unsigned char idata *SMB_DATA_OUT;
volatile unsigned char I2C_FinalWriteAddress;    //ISR
And adding this to header:
Code:
extern volatile unsigned char idata InaaConf[5];
extern volatile unsigned char idata *SMB_DATA_OUT;
extern volatile unsigned char I2C_FinalWriteAddress;    //ISR uses this to determine which byte is the final byte
Compiled :]
 
Top