I2c master code

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

void i2cinit(void)
 {
     
    TWSR=0x00;   //set prescaler bits to zero
    TWBR=0x128;   // SCL frequency is 60lhz for Xtal= 16M
    
 }

 

uint8_t i2cstart( uint8_t address)
 {   TWSR=0x00;
     //transmission start condition
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    //wait for end of transmission
    while (!(TWCR & (1<<TWINT))==0);          
    //check if the start condition was successfully transmitted
    bit1(TWCR);
    if ((TWSR & 0xF8)!= 0x08)
    return 1;

    //load slave address into data register
    TWDR=address;         
    //start transmission of address           
    TWCR= (1<<TWINT)|(1<<TWEN);     
    //wait for end of transmission 
    while(!(TWCR&(1<<TWINT))) ;   
    // check if the device has acknowledged the READ / WRITE mode
    uint8_t twst = TWCR & 0xF8;
    if ( (twst != 0x18) && (twst != 0x40) ) return 2;
    
    return 0;    
}

 

 

 

this is my start function for the i2c master configuration.

Now this function is returning 1 and when i check the TWSR value it is printing 11111000.

and i am not getting what is wrong in this??? 

 

 

 

also one dout I am confused on one part

To start I2C transmission i have to SET(1) TWINT bit of TWCR register to CLEAR the flag .

And  after completion of the event - TWINT flag is SET that is TWINT bit is cleared(0) by the application hardware  and TWSR register is updated with the suitable value 

So we monitor the TWINT bit to see whether event is completed or not and TWSR register to see which event is done.

 

Now confusion is on this statement -  

while (!(TWCR & (1<<TWINT)));      - Now when TWINT (this is 7th bit in TWCR register) bit is cleared by hardware on completion of event my TWCR  register will be - 0*******

So -TWCR & (1<<TWINT) = 00000000  ........  and  therefore ( !(TWCR & (1<<TWINT)))  - gives 1. So in this case my while loop becomes true                                                                                                                        and it will be inside the while loop for all the time . Which should not be the case because as on completion of event TWINT bit is cleared indicates event                                                                                                                    has occoured  so it should come out from while loop. So rather then this statement should it be not 

while ((TWCR & (1<<TWINT))); ... now it  will come out of the loop only when my TWINT becomes 0 ...for rest of the time till it is TWINT i s 1 ( not ceared by hardware ) it will remain                                                                                                                             inside the loop  waiting for hardware response.

 

This topic has a solution.

Kunal Gupta

github.com/gkunalupta

Last Edited: Mon. Jun 22, 2020 - 10:00 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Which MCU, please!

 

I do not think that a prescale value of zero is allowed with most standard Mega/Tiny devices. Please check your spec sheet!

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

Last Edited: Fri. Apr 10, 2020 - 09:22 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Mcu atmega 2560 .... I didn't find any such thing about prescalors

Kunal Gupta

github.com/gkunalupta

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

OK, the prescale value is still 16 (e.g. F_CPU/16) when TWBR = 0, or 1MHz.

 

That does NOT give: SCL frequency is 60lhz  what ever that is. Maybe you mean 60khz? It won't give that either. Many peripherals are limited to 400khz, and will probably fail at 1MHz.

 

Also, do you have the external pull-up resistors on SDA and SCL?

 

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kunalgupta wrote:
    while (!(TWCR & (1<<TWINT))==0);          

For one thing, that's wrong, you have reversed the logic so you aren't waiting until TWINT is set.

You have it right further down

Kunalgupta wrote:

    while(!(TWCR&(1<<TWINT))) ;   

You need to wait until after TWINT is set before reading TWSR.

And I don't know what this is

Kunalgupta wrote:

    bit1(TWCR);

 

EDIT:

your confusion might be with the behaviour of TWINT bit. This behaves like other interrupt flag bits, where it does different thing for read vs write.

Writing 1 to the bit clears the underlying hardware flag. Reading the bit returns the state of the underlying hardware flag.

So write bit to 1, this clears hardware flag, then start reading, hardware flag will initially be clear so bit reads as 0, when hardware has finished the flag will be set and bit will then read as 1.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well when I write
while(!(TWCR&(1<<TWINT)))
Then it gets struck inside the loop and don't comes out of it and when i read TWCR for TWINT bit it always read 0.
That is what i wrote in #1 that we have to wait till TWINT becomes 0 and it should come out if the loop when it is 0 and stays in loop when it is 1 . But on writing this statement it is happening opposite .

Kunal Gupta

github.com/gkunalupta

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Buy a keyboard with a <SPACE> key.   It will make your code readable by human beings.  

 

It will help you to understand what you have written.

And probably enable you to solve problems by yourself.

 

If your code is neatly formatted members will read it.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

[/

Just a minute ....by this u mean that when i read TWINT bit in TWCR it shows me the status of TWINT flag and not TWINT bit ... That is when i it shows 0 it means that it is showing me the status of flag ( which is cleared that is why showing 0) and not of the TWINT bit ( which is in actually 1 as flag is cleared) . Similar when it shows 1 it means that my TWINT flag is set and showing the status of the flag and not of the TWINT bit ( which is in actually 0 as flag is set) .
?????

Kunal Gupta

github.com/gkunalupta

Last Edited: Sat. Apr 11, 2020 - 07:58 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

Buy a keyboard with a <SPACE> key.   It will make your code readable by human beings.  

 

It will help you to understand what you have written.

And probably enable you to solve problems by yourself.

 

If your code is neatly formatted members will read it.

 

David.

Sry but i didn't get your point

Kunal Gupta

github.com/gkunalupta

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No human being is going to treat your posts seriously when you produce messages like #8.   It is disrespect.

 

Regarding code formatting.  It is quite simple.  Neat layout,  indentation of blocks,  separation of operators with whitespace, ...

 

The compiler does not care if you write ugly code.

But human readers do.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Regarding code formatting.  It is quite simple.  Neat layout,  indentation of blocks,  separation of operators with whitespace, ...

Indeed.

 

And to preserve that neat layout when posted on a forum - any forum - you to have to use the proper method for posting it

 

See: https://www.avrfreaks.net/commen...

 

For instructions on how to do that properly on this forum, see Tip #1 in my signature, below (may not be visible on mobile)

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kunalgupta wrote:
Just a minute ....by this u mean that when i read TWINT bit in TWCR it shows me the status of TWINT flag

If you stop there, then yes.

As a software person rather than hardware, the way I picture it is, within the TWI hardware block there is a flag.

When you read TWCR, the state of that flag is reported in the TWINT bit.

When you write to TWCR, if you write TWINT bit as 1 it causes the flag to be cleared.

This is sometimes referred to as being wite sensitive.

 

Kunalgupta wrote:
Well when I write
while(!(TWCR&(1<<TWINT)))
Then it gets struck inside the loop and don't comes out of it and when i read TWCR for TWINT bit it always read 0.

So you need to figure out why TWINT bit never gets to reading as 1.

Check your wiring.

As ka7ehk said, do you have pullups?

What is the master connected to?

If you remove any connection to a slave deice, what happens then?  Your start function should get as far as returning 2 in that case.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

No human being is going to treat your posts seriously when you produce messages like #8.   It is disrespect.

David.

Well sry but i still didn't get that what i have written thing which seems to be disrespecting to you .my intention was not so ...

MrKendo wrote:

[ do you have pullups?

What is the master connected to?

If you remove any connection to a slave deice, what happens then?  Your start function should get as far as returning 2 in that case.

 

Well i am using arduino mega for master and Arduino uno for slave ...and i found on internet that with mega their is no need to connect external pull up resistor its internal pull up resistor are enough .

Well but my Arduino uno 12c pins are like this show in figure( the pins which Don't have header) . Will it add any difference???

Attachment(s): 

Kunal Gupta

github.com/gkunalupta

Last Edited: Sat. Apr 11, 2020 - 11:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

Kunalgupta wrote:
Well i am using arduino mega for master and Arduino uno for slave

In that case there must be existing arduino code for i2c that is known to work.

Start with that for both master and slave, get that working first.

You can then start substituting your own code for master.

When you do start testing your own code for master, like i said, what does it do when the slave is disconnected?

It should at least get as far as start then sla+w which will not be acked so your function should return 2.

 

Kunalgupta wrote:
...and i found on internet that with mega their is no need to connect external pull up resistor its internal pull up resistor are enough

That may be true if the clock speed isn't too high.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kunalgupta wrote:
and i found on internet that with mega their is no need to connect external pull up resistor its internal pull up resistor are enough .

Where is there fact in that statement? There's a lot of mis-information on the interwebs. Internal pullups are around 50k, i2c requires 4k7 or less depending on voltage, speed and load. Anything higher and it *may* work. How many problems do you want to solve at once?

 

If you refer to the Arduino mega schematics, they show 10k pullups on the I2C bus. This is better than the AVR's internal pullups but still not to spec.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:

 

It should at least get as far as start then sla+w which will not be acked so your function should return 2.

well yes and i found one interesting thing 

my function is now returning 2  

 

in the given code 

bit1()- prints the binary value of the register mentioned in its bracket

printstring1() - prints the string written in its bracket on the screen

/*
uint8_t I2C_start(uint8_t address)
This function needs to be called any time a connection to a new slave device should be established. 
The function returns 1 if an error has occurred, otherwise it returns 0.

The syntax to start a operation write to a device is either: I2C_start(SLAVE_ADDRESS+I2C_WRITE); or 
I2C_start(SLAVE_WRITE_ADDRESS);

The syntax to start a read operation from a device is either: I2C_start(SLAVE_ADDRESS+I2C_READ); or
 I2C_start(SLAVE_READ_ADDRESS);
 */

 

 uint8_t i2cstart( uint8_t address)
 {   
     //transmission start condition
    TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    //wait for end of transmission
    while ((TWCR & (1<<TWINT))==0);          
    
    //check if the start condition was successfully transmitted
  
    if ((TWSR & 0xF8)!= 0x08)
    {
        //bit1(TWSR);
        return 1;
    }
  
    //load slave address into data register
    TWDR=address;         
    //start transmission of address           
    TWCR= (1<<TWINT)|(1<<TWEN);     
    //wait for end of transmission 
    
    while(!(TWCR&(1<<TWINT))) ;   
   
    // check if the device has acknowledged the READ / WRITE mode
    uint8_t twst = TWSR & 0xF8;
    if ( (twst != 0x18) || (twst != 0x40) ) 
    {
        
        return 2;
        }
    
    return 0;    
}

 

/*

function for debugging start function 

*/

  void teststart(uint8_t address)
  {      a=i2cstart(address);
             switch(a)
      {
           case 1 : printString1(" start condition fail  \n");
                   
            
                    break;
           case 0:  printString1(" succefull \n");
                    break;
           case 2:  printString1("device has not acknowledged the READ / WRITE mode \n");
                    break;
      }
      
      
  }
  /*
  void I2C_stop(void)
  This function disables the TWI peripheral completely and therefore disconnects
  the device from the bus.
   */
  void i2cstop()
  { 
     
      TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
    
 bit0(TWCR);
      printString0("\n");
      while(!(TWCR &(1<<TWINT))==0); //checks whether stop is send or not.

      //bit1(TWCR);
      //printString1("\n");
  }

// for master receiver- data send with the address is SLA+R(1)
 //for master transmitter - data send with address is SLA+W(0)
 /*
 uint8_t I2C_write(uint8_t data)
 This function is used to write data to the currently active device. The only parameter
 this function takes is the 8 bit unsigned integer to be sent. 
 The function returns 1 if an error has occurred, otherwise it returns 0.
 */
 uint8_t i2cwrite(char  data)
 {   
     // load data into data register
     TWDR = data;
     // start transmission of data
     TWCR = (1<<TWINT) | (1<<TWEN);
    // printString1("nkjk \n ");
    // bit1(TWCR);
     // wait for end of transmission
     while( (TWCR & (1<<TWINT))==0);
    // printString1("kol \n");
     // check if the device has transmitted the data byte
     if( (TWSR & 0xF8) != 0x28 ){ return 1; }
     
     return 0;
     
}
void testwrite( char data )
{     b=i2cwrite( data);
    switch(b)
    {
        
        case 0:  printString1(" write ack received \n");
        break;
        case 1:  printString1(" write ack not received \n ");
        break;
        
    }
    
}

int main(void)
{   UART_Init1(); 
    printString1("*******************Welcome to i2c ********************* \n");
    char array[10]="kunal";
    i2cinit();
  
    while (1) 
    {
        teststart(11110010);
        _delay_ms(1000);
        //testwrite(11111111);
        i2cstop();
    }
}

 

 

 

Now interesting thing is that  my stop function gets struck inside the while loop when i write  while(!(TWCR &(1<<TWINT))) and it gets struck inside the stop function only  and doesnt come out of it.

 

 

and When i write while(!(TWCR &(1<<TWINT))==0);  my function is now returning 2 as u can see in image attached () on returning 2 it is showing device has not acknowledged the READ / WRITE mode    AND value which is shown in figure is the status of the TWSR register which is -0x20. though my function comes out of the while loop and from stop function but on printing the status of  TWINT it always shows 0 which means that my flag is cleared and not setting .

So their is problem in my stop event of the i2c . So any suggestions why so happening , is their any mistake in the choronolgy of the code or functions are wrong defined?????? 

 

Attachment(s): 

Kunal Gupta

github.com/gkunalupta

Last Edited: Sat. Apr 11, 2020 - 07:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And just one  more thing my setup is working fine with arduino inbuilt library  , i have tested it and that is working perfectly fine .So their is no problem in my setup or wiring of the circuit.

Kunal Gupta

github.com/gkunalupta

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Kunalgupta wrote:
Now interesting thing is that  my stop function gets struck inside the while loop when i write  while(!(TWCR &(1<<TWINT)))

TWINT does not get set after a STOP.

If you look at what other code does for a stop eg. Fleury i2c (and I imagine similar if you dig around inside the arduino code) :-

 

TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
 while (TWCR & (1<<TWSTO));

 

Note that in this case, unlike with TWINT, you are waiting until TWSTO goes back low.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If it working with the Arduino library, why don’t you look at how Arduino does it? The code is already sitting on your computer for you to look at! You can compare it with your code and see where you go wrong.