USI / clock speed settings / USI as I2C Slave

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

Hi all I'm sorry in advance again for these basic question, I have searched the archives here and have learned much regarding my question as posted above but nothing that addresses some of the nuances of my misunderstanding or ignorance at this stage of learning.

 

Table 15-2. Relationship between the USICS[1:0] and USICLK Setting

USICS1 USICS0 USICLK Clock Source 4-bit Counter Clock Source
0 0 0 No Clock No Clock
0 0 1 Software clock strobe (USICLK) Software clock strobe (USICLK)
0 1 X Timer/Counter0 Compare Match Timer/Counter0 Compare Match
1 0 0 External, positive edge External, both edges
1 1 0 External, negative edge External, both edges
1 0 1 External, positive edge Software clock strobe (USITC)
1 1 1 External, negative edge Software clock strobe (USITC)

 

The above table taken from the Atmel datasheet for a ATTiny. What I would appreciate understanding with clarity is how I go about deciding when using an external clock what setting do I use? Do I use positive edge, negative edge, etc. I know I could push buttons and eventually make it work but that never satisfies me. What references do I need to refer to make these decisions?

 

Secondly referring to Atmel AVR312 (Using the USI Module as a slave) I have a 328 sending out a start condition, and I successfully enter
ISR(USI_START_vect) on the ATTiny I want to act as a slave.

 

I can step through the code and see that it recognizes the ID I have assigned, and then this following code I'm sure many of you are very familiar with;

    

//Set USI to send ACK

            USIDR = 0;

            USI_SET_SDA_OUTPUT(); 

            USISR = USI_SLAVE_COUNT_ACK_USISR;

        }

        else

        {
            //Set USI to Start Condition Mode

            USICR = USI_SLAVE_SET_START_COND_USICR;

            USISR = USI_SLAVE_SET_START_COND_USISR;
        }

        break;

 

The code is executed to set the register to count one clock cycle, pull the SDA line low, etc. Now it looks to me like the USI hardware is supposed to look after all this for me after I set the register. The USI hardware should be holding the SCL line low as well simplifying timing between master and slave.

 

Am I correct in my understanding thus far?

 

I never see this on the Logic Analyzer.

 

All I ever see on the analyzer is the Start Condition and then a NACK - Never the ACK I want to see... 

 

I have the main routine continuously looping issuing a Start to said device. Would this Start be causing the USI to reset? I was and I guess still am making the assumption that this shouldn't matter as the USI has control of the SDA line for this time? Is this understanding flawed? I will of course try this morning not sending repeated starts from the master to test my understanding of this.

 

Edit: I'm currently reading AVR310 Using the USI Module as a I2C Slave. While this is not what I want to do the code here is amazingly helpful. I'm not sure why its not mentioned more when the AVR312 is cited? They are helpful to be looked at together? no?

 

I'm sorry I just bought my first scope and I'm learning how to set triggers - I'm finding this tricky for a newbie.

 

I'm also going to try "manually" setting the SDA line low for one cycle this morning to see what happens, I'm feeling like I'm hacking at it now though - with a club. 

 

One last question and this is really quite a newbie question. It is my assumption that the idea of the i2C bus being set at a specific speed 100, 400, etc. that of course the speed difference between the components isn't a factor as a slave will essentially hold up the bus until it is completed its work. So in this it doesn't matter if my Master is a 328P running at 16Mhz and my ATTiny is running at 1Mhz.

 

Maybe this is far too much for one post. I'm just learning my away around this amazing resource of people and knowledge. I'm not even sure if I posted this in the right forum.

 

Thanks all.. 

 

Last Edited: Wed. Dec 19, 2018 - 01:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I never went into detail on how the USI works, I just used the code provided by Atmel in the ap note and it just worked. But this may explain some of what your seeing as explained in the ap note.

 

A logic analyzer is a better tool for this then a scope, as it will interpret what it sees, while a scope you must interpret (correctly) what you see.  

Since you talk about using an M328 as the master, I hope your using proven, known good code for the master and not trying to develop both ends at the same time.

 

Rediron wrote:
I'm also going to try "manually" setting the SDA line low for one cycle this morning to see what happens, I'm feeling like I'm hacking at it now though - with a club.

No need for this, as the USI will "ACK" when it receives an address match, if your seeing a "NAK" then the address does not match!

 

The best part of I2C is it will tell you what is wrong by looking at the status returned by the functions, what we see a LOT here is beginners using VOID functions when they should be returning the status and using code that should be checking for and acting on that status as needed.

 

So, post a small complete code that demos the problem your seeing, state the address of the slave and your scope pictures of the issue and we may be able to help.

 

Jim

edit spelling

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Wed. Dec 19, 2018 - 01:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just noticed there are two app notes on using the USI as a I2C slave,

AVR311 and AVR312

 

Not sure what is different but I was quoting from AVR312 above.

 

Jim

Edit:  AVR312 is using the TWI as a slave where

AVR311 is using the USI as a slave.

 

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Wed. Dec 19, 2018 - 02:14 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Okay I will clean all the embarrassing // DEBUG-FIX out of the code sometime this morning and post it. 

 

You mention above that the address does not match. I'm going to check it further this morning...

 

Here is some of the code as per your mention of address match before I waste more of anybody's time...

 

Here again I apologize for my ignorance as this is much to learn all at once. In the following code the USIDR is accessed. Now for debugging purposes I buffered it with a variable I marked as volatile. The reason I point out this obvious addition is it is through this I learned, of course, that there is a USIBR as well. 

 

In the datasheet it says, "Instead of reading data from the USI Data Register the USI Buffer Register can be used. This makes controlling
the USI less time critical and gives the CPU more time to handle other program tasks."

 

So when should I use this register rather than the USIDR register directly? 

 

I noticed the value of USIDR changing while I was stopped in the ISR - it was all over the place. So my newbieness wants to ask you. Doesn't this imply that the data in the USIDR register has to be read as quickly as possible?

 

I got code I got from the web from some gentlemen, Adam Honse website, looks like he mostly followed the AVR312 except for buffering scheme.

 

In this routine the USIDR register is obviously read many, many clock cycles after it is read the first time. How can this code reasonably expect the contents of the register to be the same? Is this again an artifact of debugging inside the ISR? So I guess you can see I'm a little confused as per the timing of this...and it lead to me using a volatile to buffer the value so I could at least see if I was getting something from the master to the slave - which I am. Or it appears to me.

 

Nontheless in the following code I can trace the code to //Set USI to send ACK. Wouldn't this imply that it is recognizing the address I sent it. I thought again, perhaps my debugging was causing timing problems - obviously I shouldn't be setting breakpoints in an ISR an expecting normal behaviour. 

 

So I have of course let the exact same code run unhindered sans my double buffering with the volatile and it still always shows a NACK.

 

I'm a bit intimidated with all of the intricate timing 

 

ISR(USI_OVF_vect)

{

    volatile uint8_t temp=(USIDR >>1);
    

    switch (USI_I2C_Slave_State)

    {
        /////////////////////////////////////////////////////////////////////////
        // Case USI_SLAVE_CHECK_ADDRESS                                        //
        //                                                                     //
        //  The first state after the start condition, this state checks the   //
        //  received byte against the stored slave address as well as the      //
        //  global transmission address of 0x00.  If there is a match, the R/W //
        //  bit is checked to branch either to sending or receiving modes.     //
        //  If the address was not for this device, the USI system is          //
        //  re-initialized for start condition.                                //
        /////////////////////////////////////////////////////////////////////////

        

        case USI_SLAVE_CHECK_ADDRESS:

        if((temp == 0) || ((temp) == usi_i2c_slave_address)) // DEBUG_FIX was (USIDR >> 1) now (USDIR) testing only

        {
            if (temp & 0x01)

            {
                USI_I2C_Slave_State = USI_SLAVE_SEND_DATA;

            }

            else

            {
                USI_Slave_internal_address_set = 0;
                USI_I2C_Slave_State = USI_SLAVE_RECV_DATA_WAIT;

            }

            //Set USI to send ACK

            USIDR = 0;

            // USI_SET_SDA_OUTPUT(); Trying opposite to see on scope. DEBUG

            USI_SET_SDA_INPUT();
            USISR = USI_SLAVE_COUNT_ACK_USISR;

            /*
            PORTD &= ~(1 << n); // Pin n goes low  --  add to notes
            PORTD |= (1 << n); // Pin n goes high
            */

        }
 

 

Thanks so much for taking your time in answering me. I'm very happy to go off on my own and learn what I need to learn but would sure appreciate some pushing in the right direction for some of these things if my understandings or ignorance needs to be rectified - lol. Thanks so much..

 

I think you would have to be some kind of electronics genius to successfully do any of this stuff without a logic analyzer. I have learned so much with this tool that its upfront cost is woithout a doubt negligible again. I don't work for Saleae or anything but again I do thank those guys for being willing to give me a "Garage Hacker" price on the Logic 16. Great folks!

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

Rediron wrote:
Nontheless in the following code I can trace the code to //Set USI to send ACK. Wouldn't this imply that it is recognizing the address I sent it.

Yes, trying to trace program flow will foul things up, to see if the address matches, you can do one of two things.

Place a break point after the return function call and look at the status returned, or look at the scope trace and see if the ack bit is sent!

 

One of the confusing things about I2C is how addresses are used by different programs.

I2C uses a 7 bit address, but it is left shifted one bit for the r/w bit to be added, some programs expect this as a 7 bit address (and does the shifting and adding of the r/w bit)

while others expect an 8 bit address already shifted and with the r/w bit already added.  To add to this confusion, some I2C device sheets will state the address as 7 bit, while others will state it as 8 bit.

So you need to know how your software is expecting the address and pass it the way its expected.

 

Hope that helps.

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Wed. Dec 19, 2018 - 03:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry as per your question about developing Master/Slave at the same time. I am using code that I have been communicating with may different i2C devices I have here. So it is this code that I'm using to try and issue a Start to the Tiny I have acting as a slave. Is this what you mean? I/e I have been using the dedicated TWI hardware and some simple code to control that on the 328P.

 

I hope I may ask a design question here. I'm an artist (used to be a software programmer) making some work that require a massive amount of embedded work - hence my new hobby. I think I find it more fun than the art. I truly wish I would have discovered this fascinating world earlier when I was coding.

 

I had asked sometime ago about CAN and was corrected to use RS-485. Wow that was a good correction - much simpler. I'm testing these Tiny's as slaves right now on the i2C bus but eventually will want to communicate with them over RS485. I have bought all the chips from Maxim and after a few weeks of learning them I'll likely ask more questions. 

 

Nonetheless I want to be able to send intermittent PWM signals to two servos that will be controlled by each Tiny slave.  So my plan is to eventually wrap the i2c in some simple protocol over the RS-485. I haven't got that far yet as my mind has been exploding with the amount of things to learn. I have found after being away many years that just learning GIT was a bit maddening - though a thousand times better than CVS software I used 20 years ago.

 

Anyways does this sound like a sound approach? Something you pros would use?

 

edit: That was you who corrected me on the RS485 I see now. Wish I could send you a case of beer...

 

 

Last Edited: Wed. Dec 19, 2018 - 03:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ki0bk wrote:
or look at the scope trace and see if the ack bit is sent!

 

What is the best way to set this up. I have tried setting all kinds of triggers and I'm reading some online tutorials about scopes but it seems to me that even using a scope well can be an artful endeavour... If you don't have time to answer such a basic question I'm sure its something I will joyfully discover over the next few days...

 

Thanks again,

Rod

 

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

Rediron wrote:
Anyways does this sound like a sound approach? Something you pros would use?

Well most tiny's do not have a USART or TWI interfaces, so would not be my first choice but the Attiny1634 has both, so take a look at it.

I've heard it may have some issues with external xtal and USART interaction, so if you go that route, search for those threads here.

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

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

ki0bk wrote:
One of the confusing things about I2C is how addresses are used by different programs. I2C uses a 7 bit address, but it is left shifted one bit for the r/w bit to be added, some programs expect this as a 7 bit address (and does the shifting and adding of the r/w bit) while others expect an 8 bit address already shifted and with the r/w bit already added. To add to this confusion, some I2C device sheets will state the address as 7 bit, while others will state it as 8 bit.

 

This I have absolutely discovered and I'm amazed there is such an inconsistency. Being involved in this field how would you design your driver? In this code Mr. Honse decided to shift in the ISR. Is this the correct design methodology? It seems the actual i2c specs indicate this is the behaviour to be expected but then as I have been learning it seems everyone approaches it in a different way. Often times it would seem just making the code dependent specifically on that use case is what happens.  Is this just a fact of this inconsistency? Or is this inconsistency there because to many noobs like me haven't taken the time to read the Phillips i2C spec? I did but again when your learning this much information in this short of time its hard to be sure your understanding is correct. 

 

Cheers

 

Last Edited: Wed. Dec 19, 2018 - 03:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rediron wrote:
What is the best way to set this up.

To begin, I would trigger on the first falling edge of an I2C start, use normal triggering, and adjust horizontal sweep to display one I2C frame. 

Hopefully you have a 2 ch scope so place the other channel on the SCK line, you can then see where the bits are located and look for the ones and zeros.

 

Jim

 

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

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

Jim,

 

First I'm deeply indebted to you for answering my questions. I don't know if its allowed here but I'm more than happy to send some $$ to your paypal account for your time in helping me with these newbie questions. I setup as you suggested, not sure if I got the falling edge setting correct on this Hantek. I hope I don't regret buying this or its a case of a bad tool for a newbie. 

 

These are the images from the Saleae and the Hantek.

 

Edit: I should say again you have had me ordering from microchip direct. I ordered a few of those ATtiny you suggested. I still though hope I can get this working enough to have learned from it... Thanks again..

 

Cheers,

Rod

 

P.S

I say this as I know the skills you folks have earned have not come easily... So appreciate immensely your help...

Attachment(s): 

Last Edited: Wed. Dec 19, 2018 - 08:02 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the offer, but we are all volunteers here, I sat where you are now a few years ago, but thanks to others who have shared their wisdom, I get to pass it on now! (Pay it forward)

 

I like the LA display, is 0x58 the correct I2C address? Is that what you expected?

 

 

Jim

See signature below

 

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Wed. Dec 19, 2018 - 09:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes I was expecting  0x58. In the earlier post I mentioned that while I knew setting a break would mess up the timing of the ISR routine I did grab the value of the register on entry into a volatile. The source trace shows it making it to the point where it sets the hardware to send an ACK i/e setting it to pull SDA low for one cycle. I have never actually seen the ACK generated. This is with or without me setting breaks in the ISR routine.

 

BTW I did get your point about using a different ATtiny, and I ordered a few as you suggested from MicrochipDirect today. They are only a few dollars each with shipping. If I was making a million of my sculptures then sure shaving a few pennies off of every unit would add up - I'm not doing that.  Nonetheless I would like to understand the best I can about what is going on here as it is proving to be an excellent learning experience so far.

 

Thanks again,

Rod

 

PS. My wave forms are very rounded. Is this because of line capacitance, etc. or I just don't know how to setup the scope?

Last Edited: Wed. Dec 19, 2018 - 10:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rediron wrote:
PS. My wave forms are very rounded. Is this because of line capacitance, etc. or I just don't know how to setup the scope?

 

That is normal for I2C data, as the driver forces the line low, but lets it float high with the pull up resistor and line capacitance.

 

We will need to see the code, preferably without your added debug mods, how does it compare to the app note code?

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

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

Rediron wrote:
Edit: I'm currently reading AVR310 Using the USI Module as a I2C Slave.

rereading OP, found the above,

AVR310 - USI as I2C master

AVR311 - USI as I2C slave

 

Hopefully you are using the code from AVR311 ???

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

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

Jim,

Yes the code looks very much like that abstract except with the authors, not mine, changes to how data is passed from the ISR into the main execution thread. I ran GIT diff on the code and lets say I can categorically state that I know who the Father is....

 

Before you posted back lastnight I went and played with resistor sizes to see how it changed the wave shapes. Interesting... 

 

I'm going to clean up the code this evening, I've been out all day today, and post or the next day. I would like to make sure that I have reread everything you have said here, one for sure is the "convenient" multiple Starts may very well be what is causing the driver code to not issue an ACK - exactly as you stated when we first started this conversation. So I indeed want to thoroughly explore everything we have talked about and try suggestions before I ask you, I was going to say everyone, smile, but it has been just you... So I want to ensure I have done everything we have spoken about before I go further. 

 

I also stumbled onto this article again, had forgotten about it, 

https://hackaday.com/2016/07/19/...

 

While the article is absolutely excellent for someone such as myself learning all this stuff I'd have to say the true gems are in the comments.

 

Have you have tried putting different sized pull down resistors on individual i2c devices so that they exhibit their own electrical signature on the scope? Remember I know nothing of this wonderful world of electronics - I am the noob of noobs!  Nonetheless I found this fascinating and put it in my notes to try sometime and verify if it really is a useful diagnostic tool.

 

This was interesting to me as well; 

http://www.i2cchip.com/constant_current_pullup.html

 

I think the author is talking about LTC4311 chips as well for people that need really fast i2c busses. I burst out laughing at the comment of, "many peoples troubles begin with back alley bit banging routines.

 

I also became interested in these NXP PCA9600 bus buffers. He is doing I2C bus on a model railway, with get this, over 100 i2C devices. I believe him he's umm one of those model railroader types, incessant, fixated on details, etc.. lol

 

The last thing I might ask here is. Is this idea of using MOSFETS to do level shifting is that a garage engineer thing or is it common industrial practice?

 

Anyways I'm now safely home in my Studio\Lab feeling like the luckiest guy in the world and I'm going to take a look at what we have discussed and will be back in a day or so to post code.

 

Whether it works or not ;-) Its nice knowing if I run into a problem I might be able to drop a note in here and if you have time you might give me some insight. Thanks for that.

 

Cheers,

Rod

 

 

 

 

 

 

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

Rediron wrote:
The last thing I might ask here is. Is this idea of using MOSFETS to do level shifting is that a garage engineer thing or is it common industrial practice?

That's how it is done.....  

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274

 

 

 

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

Jim, 

 

I have been busy with a medical emergency with my aging mother but I was eventually able to get it to recognize the start sequence, etc. The odd thing is I had it working for a few hours, and then it quit lastnight and for the life of me I couldn't figure out why it isn't working again.

 

Continuing my learning I searched here, google for people timing I2c, USI, etc. and learned much about using the oscope as a software diagnostic tool, I've never had an oscope before so it never occurred to me I could toggle a pin in the ISR, doh!  Looking at a German fellows most erudite write up here about how the USI start condition is fired at the wrong time has allowed me to a) see the difference between the USI abstracts and others code available out on the internet and b) his sharing of Saleae images and taking the time to clearly pointing out the timing issues taught me how to see and test for these kinds of issues - so that was great learning experience even if it didn't directly solve my problem.

 

Frustrating thing is now I am truly baffled as to why it just quit working. This is obviously an electrical issue and I'll leave this bread board and keep going back to it as my diagnostic skills (hopefully) improve over the coming months. After it quit working I put the LA on the SCL and SDA lines by it and they where so corrupted that the protocol analyzer in Saleae gave up. I thought ok I've found it! I Don't understand why it worked for hours lastnight and now nothing, but this has to be it. I cleaned up some wires around there and noticed I inadvertently ran the SDA line from another junction point and so had done it twice - not a short just duplication. Is the right term ringing? Could this introduce noise through subtle timing issues from line capacitance etc. I don't even know the right questions to ask yet - I'm in trouble lol. 

 

I'm new to electronics so not sure why this made such a mess of things but indeed after I removed the extra connections the Saleae could see the entire protocol sequence correctly by the chip again. I figured, damn, I have it and now it will toggle that pin in the ISR and I'll see it pulled low again. That's all I did is set the output high in main and had the ISR set it low. Easy to see even on an LED that the ISR had been entered at least once. For the life of me I couldn't get it working again lastnight- I changed all the chips etc. This will be for another day as it is surely an electrical problem and I'm simply not experienced enough yet to know what to look for. Seemed to me if I had the I2C signals going to the pins of the chip with the scope and Saleae both confirming it that it should work again. I didn't think I would have to learn all the maths to go with bus capacitance for this simple project but maybe its something like that which is changing timing etc. I'm far to much of a noob at this point to know what to look for.

 

Today the Attiny1616 came as you suggested. Amazing little chip for a $1.00. Takes a bit longer as I'd never soldered onto a surf\breakout board with such tiny space and was pretty intimidated. Not as hard as I thought - the first one worked. 

 

The code is a little different for port access, etc. but fairly intuitive. After 5 days of trying to get the USI to act as a I2c slave on the Attiny25 I had this chip working as a slave in about an hour after it arrived from microchip direct - that's including learning to solder it on a surfboard and add header pins etc. That's also including looking at the Device menu in Atmel Studio and going, "Great! What the hell is UPDI?."  After digging out the octopus connector for the ICE I realized its pretty darn nice this UPDI. Though if I'm using debugwire\ISP and this at the same time I may shell out and but another ICE. I think changing the cables from chip to chip 20 times a day will have me spending more money on replacement cables and wasting time than the cost of another ICE. I made a little jig with perfboard to move my original one around to different ISP connectors but of course won't work with UPDI.

 

Pretty relieved and very, very thankful for you willing to take the time to point me to the attiny1616. It may not have occurred to many as I do sound pretty ignorant about this subject area. It really is a powerful chip. Already pushing my servo control code to it. It is a very compliant I2C slave.

 

Sorry for the long winded thanks but I write it I suppose mostly for other noobs like me. If I can do this stuff even at a mediocre level I think anyone can if they stick to it until they get it. Its a lot to learn indeed.

 

With the seemingly hundreds of choices for this line of microcontrollers is there some sheet where everything is consolidated in a spreadsheet etc. If I enter a project knowing I want these services on a chip, in this form factor, at this speed, etc. Where can I go to quickly see all of these products indexed against each other?  

 

Cheers,

Rod

 

Last Edited: Sat. Dec 29, 2018 - 03:12 AM