Settings meaning for TWI device

Go To Last Post
72 posts / 0 new

Pages

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

GermanFranz wrote:

Moe123 wrote:

 How can he use that code ????!! that code does a completly different task.

 

 

Sure? It's same TWI Mr.Moe123 wink

 

Diefferent "task", its not just about how to initialize TWI and thats it....

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

Moe123 wrote:
Diefferent "task", its not just about how to initialize TWI and thats it....

 

Well Mr. Moe123,

first, this helpful instructive code does not just show the initialization and second, it would be nice if you could offer specific help on the subject here.

Your objections, however, do not make much hope , or?

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

Herr Franz,

 

Please read again what I wrote.

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

Nahhh... It's not working.

 

I0ve changed a few things but I can't see on scope what I was expecting.

 

I haven't seen that code yet. But to go through it I need also to take a look at that chip.

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

PsySc0rpi0n wrote:
I haven't seen that code yet. But to go through it I need also to take a look at that chip.

Once again: TWI its the same! Completely. If this C-Code is working on ATTiny402 and an ATTiny416 you can use same techniques, same code for read/write access using Mega4808.

Moe123 wrote:
Please read again what I wrote

Please read again what is "task" of this thread.

Last Edited: Sat. Apr 20, 2019 - 03:33 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

GermanFranz wrote:
PsySc0rpi0n wrote:
I haven't seen that code yet. But to go through it I need also to take a look at that chip.
Once again: TWI its the same! Completely. If this C-Code is working on ATTiny402 and an ATTiny416 you can use same techniques, same code for read/write access using Mega4808.

 

Ok, I guess I'll have to give it a try!

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

Hello.

 

Finally back to my TWI thing.

 

I've been looking to the code in those 2 files.

I have some questions because I'm not sure if things are the way I'm thinking they are!

 

I'll go through each code regarding each question.

 

In the following code:

char TWI_Start(char addr){
	if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) != TWI_BUSSTATE_BUSY_gc){
		TWI0.MCTRLB &= ~(1<<TWI_ACKACT_bp);
		TWI0.MADDR = addr;

		if (addr & 1){
			while (!(TWI0_MSTATUS & TWI_RIF_bm))
				/*wait*/;
		}
		else{
			while (!(TWI0_MSTATUS & TWI_WIF_bm))
				/*wait*/;
		}
		return TWI0.MSTATUS;
	}
	else
		return TWI0.MSTATUS;
}

First question is why there is this TWI_Start() function and then one other for the Read operation and another for the write operation? I had created only the TWI_Init() and then the TWI_Read() functions. Is this "Start" function mandatory?

Then, I don't understand why there is an ACK signal being sent if the BUSSTATE is different from BUSY... Can you please explain me why?

Then, I don't understand why there is this IF with "addr & 1 ". What is the purpose of this? If this is to set a READ/WRITE operation, then, why are there specific functions for the same Read/Write operations?

Also, RIF and WIF, according to the User Manual, says that these bits are set when a Read or Write operations are successfully completed. But this function has no code to read or write anything from/for the BUS. So why is this code inside this function? Or am I getting all wrong?

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

PsySc0rpi0n wrote:
First question is why there is this TWI_Start() function and then one other for the Read operation and another for the write operation? I had created only the TWI_Init() and then the TWI_Read() functions. Is this "Start" function mandatory?
I may have suggested this before but have you looked at Fleury? Not necessarily the nitty gritty details of the implementation but simply the highlevel API he provides - he has a complete/minimal implementation of everything a normal use of TWI will require:

 

http://homepage.hispeed.ch/peterfleury/doxygen/avr-gcc-libraries/group__pfleury__ic2master.html#func-members

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

clawson wrote:

PsySc0rpi0n wrote:
First question is why there is this TWI_Start() function and then one other for the Read operation and another for the write operation? I had created only the TWI_Init() and then the TWI_Read() functions. Is this "Start" function mandatory?
I may have suggested this before but have you looked at Fleury? Not necessarily the nitty gritty details of the implementation but simply the highlevel API he provides - he has a complete/minimal implementation of everything a normal use of TWI will require:

 

http://homepage.hispeed.ch/peterfleury/doxygen/avr-gcc-libraries/group__pfleury__ic2master.html#func-members

 

Yes, you have already suggested to study Fleury's code and try to start from there, but at this point, I want to try the other suggested code! I was just trying to understand how that code works so that I can use it properly!

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

I kind of took some parts of that code and I can now see e few more things on my scope but I still think it's not correct what scope is showing!

 

My actual code:

https://ideone.com/4GVVf4

 

This is what my scope shows now:

 

Looks like the only correct thing is the address which is 0x18. In this code I was trying to read 5 times and average the value. But I'm not even sure if what I see here represents 5 reads and even if it does (I think there are 6 reads instead), why the sensor is telling 01, FF, FF, FF, FF? This doesn't looks correct at all. The 0x1D could be eventually correct but not all the others!

Last Edited: Fri. Apr 26, 2019 - 10:05 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Seems to me you have too many unknowns.

 

You probably want to start out with well known, totally understood I2C device - perhaps an RTC from the DS13xx range? Maybe an EEPROM? Use that to get your I2C stack to the point where it's fully implemented, tested and understood and does what you want. Then when you connect to this new "unknown device" any problems you hit must be with that device, not with the I2C implementation.

 

Otherwise you just don't know.

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

PsySc0rpi0n wrote:
why the sensor is telling 01, FF, FF, FF, FF? This doesn't looks correct at all

What should the sensor provide with these data?

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

GermanFranz wrote:
PsySc0rpi0n wrote:
why the sensor is telling 01, FF, FF, FF, FF? This doesn't looks correct at all
What should the sensor provide with these data?

 

Just temperature values. The first byte that is read, should not be 0 either!

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

Where do you set the address to read from? For that matter, what is the slave device? There is no mention of it in your code.

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

Kartman wrote:
Where do you set the address to read from? For that matter, what is the slave device? There is no mention of it in your code.

 

Line 108 of the code. It's in TWI_Read() function! Address is 0x18!

The Slave device is a temperature sensor MCP9808.

Last Edited: Mon. Apr 29, 2019 - 08:41 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I made this work with the other guy code and a couple of changes!

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

Hi, would you be able to post the working code? Thanks

Pete

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

Hello, sir.

 

I am on the totally same kind of project now.

 

If you don't mind, please let me refer to your full code.

 

I don't want you to think I'm rude because of my short english.

 

Thank you.

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

There is another thread, which I can't easily find at the moment, about TWI on Mega-0 and Tiny-0/1 chips. It describes a TWI "library" that I ported from the Arduino world. The original was written by Microchip and the only changes I made were to eliminate those bogus (e.g. Arduino style) pin setting functions. It is somewhat clumsy in that it relies on interrupts. And, it is surprisingly large. It is written as C, not C++. BUT, IT WORKS.

 

I want to do a bit more sanitizing to make it interrupt independent. Until I get to that point, I'd be happy to provide a copy of what I have.  

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Fri. May 22, 2020 - 04:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you. I thought I had something wrong in the code and thought it best to just delete the post, but I verified it was correct so I will post again.

 

The code below is just a starting point and is also minimal, but it does work (should work for any avr0/1). It is a master-only/polled/simplified version rewritten in C from what I have in C++. In this case tested on a tiny3217 with an lcd and a temp sensor, but any avr0/1 will do. It may or may not be easier to decipher than an atmel start version, but I would like to think it is.

 

Not complete, but a good start for simple reading/writing.  Contrary to what the datasheet describes (smart mode simplifies code and minimizes user interaction), I think smart mode can be left unused as these mcu's have no dma. In smart mode you have to set the NACK before the last read, in normal mode you just ACKread after each read (and NACKstop after done reading), so it amounts to just doing one thing (check if last byte, set to NACK) or the other (ACKread) in the read loop and there seems to be no advantage to smart mode that I can see. I suspect they are thinking of a dma capable mcu where a dma read would then do the ack when the dma transfer/read takes place. If there is something good about smart mode, anyone can correct me.

 

The reads/writes below can be 'chained' by specifying 'false' for the doStop argument, and the next read/write will end up being a repeated start. For both the read and write, the first buffer byte has to be the (unshifted) slave address. Check for the return value, if less than you planned then an error or nack occurred.

 

There are things missing (like slave, irq's), but should be good enough to talk to relatively simple/small data things that do not need irq's to move data or respond to other masters.

 

//Twi.h header avr0/1

#include <stdint.h>

#include <stdbool.h>

#define U8 uint8_t

 

void Twi_baudReg    (U8 v);

void Twi_on         ();

U8   Twi_readBytes  (U8* buf, const U8 len, bool doStop);

U8   Twi_writeBytes (const U8* buf, const U8 len, bool doStop);

 

#undef U8

 

 

//Twi.c avr0/1

#include <avr/io.h>

#include <stdint.h>

#include <stdbool.h>

#include "Twi.h"

#define U8 uint8_t

 

bool isAnyFlag      ()      { return TWI0.MSTATUS & 0b11101100; } //rif,wif,hold,arblost,buserr
bool isAnyErrFlag   ()      { return TWI0.MSTATUS & 0b00001100; } //arblost,buserr
void clearErrFlags  ()      { TWI0.MSTATUS = 0b00001100; } //arblost,buserr
void addressRead    (U8 v)  { TWI0.MADDR = (v<<1) | 1; }
void addressWrite   (U8 v)  { TWI0.MADDR = v<<1; }
void dataWR         (U8 v)  { TWI0.MDATA = v; }
U8   dataRD         ()      { return TWI0.MDATA; }
void
Twi_baudReg    (U8 v)  { TWI0.MBAUD = v; }
void toStateIdle    ()      { TWI0.MSTATUS = 0b11101101; } //clear all flags, IDLE
void NACKstop       ()      { TWI0.MCTRLB = 0b0111; } //NACK,stop
void stop           ()      { TWI0.MCTRLB = 0b0011; } //ACK,stop
void ackActionACK   ()      { TWI0.MCTRLB = 0b0000; } //ACk,no cmd
void ACKread        ()      { TWI0.MCTRLB = 0b0010; } //ACK,read
bool isWriteOK      ()      { return TWI0.MSTATUS == 0b01100010; } //wif,hold,rxack=0,owner = ok
bool isReadOK       ()      { return TWI0.MSTATUS == 0b10100010; } //rif,hold,rxack=0(from a previous write ack),owner = ok
void
Twi_on         ()      { toStateIdle(); TWI0.MCTRLA = 1; }

 

//can make timeout whatever value you want, is 256 clks in this case

bool waitTimeout () {
    U8 t = 0;
    while( ++t && !isAnyFlag() );
    return t != 0; //if t==0, is timeout, t!=0 is any flag set
}

//if any error flags, just clear error flags, else send stop
void anyFail () {
    if( isAnyErrFlag() ) clearErrFlags(); //or toStateIdle() if want to force state
    else stop();
}

bool waitWriteOK () {
    if( waitTimeout() && isWriteOK() ) return true;
    anyFail();
    return false;
}

bool waitReadOK () {
    if( waitTimeout() && isReadOK() ) return true;
    anyFail();
    return false;
}

 

// buf[0] = address, len = bytes to read into buf, doStop = true = stop when done
// return bytes read
U8
Twi_readBytes (U8* buf, const U8 len, bool doStop) {
    U8 readLen = 0;
    ackActionACK();                            //we ack reads
    addressRead(*buf);                         //start, ack, read 1 byte

    //if was ok, we already have 1 byte
    while( true ){
        if( ! waitReadOK() ) return readLen;   //error?
        *buf++ = dataRD();                     //store data
        if( ++readLen >= len ) break;          //done?
        ACKread();                             //allow read next byte
    }
    if( doStop ) NACKstop();                   //send stop? (also NACK last read)
    return readLen;
}

// buf[0] = address, len = bytes to write from buf, doStop = true = stop when done
// return bytes written (including address)
U8
Twi_writeBytes (const U8* buf, const U8 len, bool doStop) {
    U8 writeLen = 0;
    addressWrite(*buf++);                        //start
    while( true ){
        if( ! waitWriteOK() ) return writeLen;   //error? (or NACK)
        if( ++writeLen >= len ) break;           //more?
        dataWR(*buf++);                          //send next byte
    }
    if( doStop ) stop();                         //send stop?
    return writeLen;
}

#undef U8

//end Twi.c

 

 

/*

twi baud - too fast is not ok, too slow is ok
the typical maximum value for baud register will be 95 - (20MHz cpu clk, 100kHz scl)
so use 95 if you don't want to do any thinking (will be slower than 100kHz)
you can also eliminate rise time in calculations (probably unknown), 
  will just end up being a little slower than ideal

 

pins- use portmux if want to use the alternate pins

pins- the twi takes over the pins completely so nothing to do to set them up (even overrides inputdisable)

 

EXAMPLE

 

read ID register (2 bytes) of TMP117
write 15 to set pointer to ID register
then read 2 bytes

remember readBytes needs an address in the first byte of the buffer

in this case we are reusing the write buffer so address is already in place

*/

 

#include "Twi.h"

#include <stdint.h>

int main(){

 

Twi_baudReg( 95 );                         //100kHz@20MHz, 50kHz@10Mhz, etc.
Twi_on();                                  //to IDLE, enable

const uint8_t addr = 0x48;                 //TMP117 address
uint16_t id = 0;
uint8_t buf[2] = { addr, 15 };             //use same buffer for write and read in this case
if( 2 == Twi_writeBytes(buf, 2, false) &&  //no stop, so read will
    2 == Twi_readBytes(buf, 2, true) ) {   //be a repeat start
    id = (buf[0]<<8) | buf[1];             //big endian to little endian

    //id was read ok
}

 

}

 

edit- changed a couple C++ things found, like 'not' to !

 

In an online compiler (for mega4809, as that is the only avr0/1 io.h info they have it seems, but is the same code)

https://godbolt.org/z/k-BP66

 

a little simpler, where readBytes/writeBytes just returns true/false (not really going to make use of bytes read/written if not what we wanted, so true/false is fine)

https://godbolt.org/z/7jDe4i

Last Edited: Sat. May 23, 2020 - 01:05 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This lib is said to work: See attached zip file.

Jim

 

Attachment(s): 

 

 

 

 

Pages