Attiny85 USI I2C
Quote from arcachofo on December 27, 2023, 3:02 pmJust one thing that catches my eye, USISIF isn't set when a start conditon was detected. Shouldn't that be the case just like USIPF for a stop condition. I also don't see where OSIOIF is set when a counter overflow occurs.
Interrupt flags are not set directly, you just raise the interrupt and it will set the flag and do anything needed.
USIPF is not an interrupt, just a flag, so we need to set it directly.And now that I think about it, USIPF is cleared by writing a one to it and this is not implemented yet.
Just one thing that catches my eye, USISIF isn't set when a start conditon was detected. Shouldn't that be the case just like USIPF for a stop condition. I also don't see where OSIOIF is set when a counter overflow occurs.
Interrupt flags are not set directly, you just raise the interrupt and it will set the flag and do anything needed.
USIPF is not an interrupt, just a flag, so we need to set it directly.
And now that I think about it, USIPF is cleared by writing a one to it and this is not implemented yet.
Quote from steinm on December 29, 2023, 9:03 pmQuote from arcachofo on December 27, 2023, 3:02 pmJust one thing that catches my eye, USISIF isn't set when a start conditon was detected. Shouldn't that be the case just like USIPF for a stop condition. I also don't see where OSIOIF is set when a counter overflow occurs.
Interrupt flags are not set directly, you just raise the interrupt and it will set the flag and do anything needed.
USIPF is not an interrupt, just a flag, so we need to set it directly.Doesn't USISIF behave for a start condition just like USIFP does for a stop condition? The interrupt is only triggered if USISIE is set, but USISIF is set when a start condition is detected and must be cleared by writing a 1 to it.
Quote from arcachofo on December 27, 2023, 3:02 pmJust one thing that catches my eye, USISIF isn't set when a start conditon was detected. Shouldn't that be the case just like USIPF for a stop condition. I also don't see where OSIOIF is set when a counter overflow occurs.
Interrupt flags are not set directly, you just raise the interrupt and it will set the flag and do anything needed.
USIPF is not an interrupt, just a flag, so we need to set it directly.
Doesn't USISIF behave for a start condition just like USIFP does for a stop condition? The interrupt is only triggered if USISIE is set, but USISIF is set when a start condition is detected and must be cleared by writing a 1 to it.
Quote from j_tofil on December 30, 2023, 1:49 amI've compiled the 2108 version and was browsing through avrusi.cpp & .h files to try to understand how it all works. I'm no USI expert (just learning how it works) and I don't understand precisely how your code works yet, but I did notice a possible discrepancy in stepCounter():
if( ++m_counter == 8 ){
m_counter = 0;
if( m_interrupt ) m_interrupt->raise();
}
From my understanding, and running some polling-mode I2C Master code through the Microchip Studio Simulator, the 4-bit counter counts from 0x0 to 0xf and then rolls-over to zero, so I believe the 'if ( ++m_counter == 8 )' should be 'if ( ++m_counter == 16 )'.
The documentation on the Counter Value doesn't seem to mention it, but the counter is incremented on both the rising *and* falling edges of SCL (when using an external clock source (USICS1=1) and writing ones to the USICLK and USITC bits), which is why it counts twice as often as one would think: 16 times then for an 8-bit byte.
Thanks for working on implementing this. I for one would like to see the interrupt capability implemented. Cheers!
I've compiled the 2108 version and was browsing through avrusi.cpp & .h files to try to understand how it all works. I'm no USI expert (just learning how it works) and I don't understand precisely how your code works yet, but I did notice a possible discrepancy in stepCounter():
if( ++m_counter == 8 ){
m_counter = 0;
if( m_interrupt ) m_interrupt->raise();
}
From my understanding, and running some polling-mode I2C Master code through the Microchip Studio Simulator, the 4-bit counter counts from 0x0 to 0xf and then rolls-over to zero, so I believe the 'if ( ++m_counter == 8 )' should be 'if ( ++m_counter == 16 )'.
The documentation on the Counter Value doesn't seem to mention it, but the counter is incremented on both the rising *and* falling edges of SCL (when using an external clock source (USICS1=1) and writing ones to the USICLK and USITC bits), which is why it counts twice as often as one would think: 16 times then for an 8-bit byte.
Thanks for working on implementing this. I for one would like to see the interrupt capability implemented. Cheers!
Quote from arcachofo on December 30, 2023, 2:09 amthe 4-bit counter counts from 0x0 to 0xf and then rolls-over to zero, so I believe the 'if ( ++m_counter == 8 )' should be 'if ( ++m_counter == 16 )'.
Yes, you are right. I will fix it.
I for one would like to see the interrupt capability implemented.
It is implemented.
USIFP clear writing a 1 was also implemented at Rev 2112.
the 4-bit counter counts from 0x0 to 0xf and then rolls-over to zero, so I believe the 'if ( ++m_counter == 8 )' should be 'if ( ++m_counter == 16 )'.
Yes, you are right. I will fix it.
I for one would like to see the interrupt capability implemented.
It is implemented.
USIFP clear writing a 1 was also implemented at Rev 2112.
Quote from Defran on January 4, 2024, 12:41 pmIn R2116, with this simple example, compiled in Arduino IDE, it is impossible to see the text on the OLED, any recommendations or ideas?. Because although the USI is still in development for testing, it is understood that the simple text presentation should work now, correct?I am waiting for any indication. Thank you very much.
Quote from j_tofil on January 5, 2024, 7:40 amDefran,
Perhaps I can help answer your question. I've been intensely studying and stepping through the avrusi.cpp functions, running some Master driver code on the Tiny85, and my opinion is that the currently released (v2124) does not work in a two-wire I2C configuration, but may work in the three-wire SPI mode.
As arcachofo stated back on 21 December 2023, "But for some reason this module was not so easy to understand." He is correct, the operation of the USI module is quite complicated and simulating it takes some care and attention.
I've been modifying/debugging the v2114 version of avrusi.cpp and avrusi.h and have it to a point where Tiny85 simulator will detect a start condition (and not detect any false start conditions); will transmit the data in the USIDR via USIWM[1:0} of b10 (two-wire mode without SCL hold) mode with a USICS{1:0} of b10 (external clock source, positive edge); and will detect a stop condition (the detection of start and stop were already implemented). Here is a screenshot of a scope trace of a start condition, 8 data bits (0xc2), a NAK, and a stop condition.
The upper line is the SDA and the lower one is the SCL. There's a glitch in the SDA (red circle) that I can't seem to get rid of between clocks 8 (addr lsbit) and 9 (NAK).
I have not gotten far enough to address and transfer data to a slave as yet, perhaps tomorrow. I've implemented the multiplexer that feeds the shifting function of the USIDR and the two multiplexers that feeds the 4-bit counter, and all appears to be working.
That being said, I haven't tried:
- an interrupt-driven driver
- the timer clock mode
- regression testing any of the SPI mode stuff (are there devices to test against?)
- and much more
Back on 21 December, arcachofo said (not to me), "If you have good knowledge of this module you could even help to finish it.". I may be beginning to learn enough about the USI device and the way the simulator code works to perhaps not finish it, but possibly nudge it a little farther along the way to completion. There are things about controlling the I/O pin levels that I just don't understand.
Thank you, Defran, for posting the pic of your circuit. I wasn't aware that there were I2C slave devices available. I assume the Ssd1306 is a functioning simulator? If so, perhaps I can use that to complete my I2C Master testing. For the application I'm working on, I want the Tiny85 to be an I2C slave and be interrupt-driven.
Best regards...
Defran,
Perhaps I can help answer your question. I've been intensely studying and stepping through the avrusi.cpp functions, running some Master driver code on the Tiny85, and my opinion is that the currently released (v2124) does not work in a two-wire I2C configuration, but may work in the three-wire SPI mode.
As arcachofo stated back on 21 December 2023, "But for some reason this module was not so easy to understand." He is correct, the operation of the USI module is quite complicated and simulating it takes some care and attention.
I've been modifying/debugging the v2114 version of avrusi.cpp and avrusi.h and have it to a point where Tiny85 simulator will detect a start condition (and not detect any false start conditions); will transmit the data in the USIDR via USIWM[1:0} of b10 (two-wire mode without SCL hold) mode with a USICS{1:0} of b10 (external clock source, positive edge); and will detect a stop condition (the detection of start and stop were already implemented). Here is a screenshot of a scope trace of a start condition, 8 data bits (0xc2), a NAK, and a stop condition.
The upper line is the SDA and the lower one is the SCL. There's a glitch in the SDA (red circle) that I can't seem to get rid of between clocks 8 (addr lsbit) and 9 (NAK).
I have not gotten far enough to address and transfer data to a slave as yet, perhaps tomorrow. I've implemented the multiplexer that feeds the shifting function of the USIDR and the two multiplexers that feeds the 4-bit counter, and all appears to be working.
That being said, I haven't tried:
- an interrupt-driven driver
- the timer clock mode
- regression testing any of the SPI mode stuff (are there devices to test against?)
- and much more
Back on 21 December, arcachofo said (not to me), "If you have good knowledge of this module you could even help to finish it.". I may be beginning to learn enough about the USI device and the way the simulator code works to perhaps not finish it, but possibly nudge it a little farther along the way to completion. There are things about controlling the I/O pin levels that I just don't understand.
Thank you, Defran, for posting the pic of your circuit. I wasn't aware that there were I2C slave devices available. I assume the Ssd1306 is a functioning simulator? If so, perhaps I can use that to complete my I2C Master testing. For the application I'm working on, I want the Tiny85 to be an I2C slave and be interrupt-driven.
Best regards...
Quote from arcachofo on January 5, 2024, 8:57 amQuote from Defran on January 4, 2024, 12:41 pmIn R2116, with this simple example, compiled in Arduino IDE, it is impossible to see the text on the OLED, any recommendations or ideas?. Because although the USI is still in development for testing, it is understood that the simple text presentation should work now, correct?I am waiting for any indication. Thank you very much.By now nothing is known to work.
I did an implementation to start testing and see what is working and what is not working.
Unfortunately an example using a library that uses another library that uses Arduino libraries is not good for testing.
@j_tofil:
Thanks for working in this.
Maybe you can share the code you have and your firmware for testing.Note that there are some things not done in my implementation, for example SCL Low at start detection.
First step is making it work in master mode.
Quote from Defran on January 4, 2024, 12:41 pmIn R2116, with this simple example, compiled in Arduino IDE, it is impossible to see the text on the OLED, any recommendations or ideas?. Because although the USI is still in development for testing, it is understood that the simple text presentation should work now, correct?I am waiting for any indication. Thank you very much.
By now nothing is known to work.
I did an implementation to start testing and see what is working and what is not working.
Unfortunately an example using a library that uses another library that uses Arduino libraries is not good for testing.
@j_tofil:
Thanks for working in this.
Maybe you can share the code you have and your firmware for testing.
Note that there are some things not done in my implementation, for example SCL Low at start detection.
First step is making it work in master mode.
Quote from j_tofil on January 5, 2024, 4:11 pmarachofo,
I can send you a copy of the code, and would love to do so to get your review of it. Once I realized I was making some significant changes to it, I began adding new code and conditionally compiling out the original code between #if 1 /* new code */ #else /* orig code */ #endif blocks, but that was not done 100%. QtCreator does a great job of muting the compiled out code, but at the moment it looks pretty messy until it's all cleaned up.
How do I get the code to you? Do I just attach it to a reply here, or is there a more private way (due to the messiness of the code)?
I'm not sure I'm manipulating the pin states in the way you intended. First off, the calls to m_CKpin->scheduleState() were not doing anything because the m_outCtrl member of the McuPin object was false. I tried calling m_CKpin->controlPin(twi,false) like you do with the m_DOpin for SPI to set m_outCtrl true, but then my driver code that also manipulates the pin states via the PORTB register stopped being able to manipulate the pin states. I tried bracketing the calls to scheduleState() between controlPin() calls, but the call to release control was setting the pin back to the prior state, so the pin state would be incorrect, then. I ended up changing the calls to m_CKpin->setOutStatFast() to manipulate the pins but I'm not certain that's the "proper" way you intended it to be done or if it breaks something somewhere else.
Anyway, let me know how you prefer me to get the code to you...
arachofo,
I can send you a copy of the code, and would love to do so to get your review of it. Once I realized I was making some significant changes to it, I began adding new code and conditionally compiling out the original code between #if 1 /* new code */ #else /* orig code */ #endif blocks, but that was not done 100%. QtCreator does a great job of muting the compiled out code, but at the moment it looks pretty messy until it's all cleaned up.
How do I get the code to you? Do I just attach it to a reply here, or is there a more private way (due to the messiness of the code)?
I'm not sure I'm manipulating the pin states in the way you intended. First off, the calls to m_CKpin->scheduleState() were not doing anything because the m_outCtrl member of the McuPin object was false. I tried calling m_CKpin->controlPin(twi,false) like you do with the m_DOpin for SPI to set m_outCtrl true, but then my driver code that also manipulates the pin states via the PORTB register stopped being able to manipulate the pin states. I tried bracketing the calls to scheduleState() between controlPin() calls, but the call to release control was setting the pin back to the prior state, so the pin state would be incorrect, then. I ended up changing the calls to m_CKpin->setOutStatFast() to manipulate the pins but I'm not certain that's the "proper" way you intended it to be done or if it breaks something somewhere else.
Anyway, let me know how you prefer me to get the code to you...
Quote from steinm on January 6, 2024, 8:29 amI did some more very basic testing of TWI as master based on release 2124. It fails early, but maybe I'm doing something wrong.
All I do is setting USICR
USICR =
(0<<USISIE)|(0<<USIOIE)| // Interrupts disabled
(1<<USIWM1)|(0<<USIWM0)| // Set USI in Two-wire mode.
(1<<USICS1)|(0<<USICS0)|(1<<USICLK)| // Software clock strobe as source.
(1<<USITC); // Toggle Clock Port.
If this is done repeatingly, then SCL should toggle. the counter should increment and USIDR should be shifted. But none is working. PortB is set as output. The monitor of USISR shows a counter value of 0xf all the time, though the counter overflow flag USIOIF toggles once in a while. I would expect USIOIF to change to 1 and remain 1 unless that bit is written to 1.
I also checked if a start condition was detected. That seems to work, but I don't see any code to reset the USISIF bit by writing a 1 to it. There is just code for USIPF.
I did some more very basic testing of TWI as master based on release 2124. It fails early, but maybe I'm doing something wrong.
All I do is setting USICR
USICR =
(0<<USISIE)|(0<<USIOIE)| // Interrupts disabled
(1<<USIWM1)|(0<<USIWM0)| // Set USI in Two-wire mode.
(1<<USICS1)|(0<<USICS0)|(1<<USICLK)| // Software clock strobe as source.
(1<<USITC); // Toggle Clock Port.
If this is done repeatingly, then SCL should toggle. the counter should increment and USIDR should be shifted. But none is working. PortB is set as output. The monitor of USISR shows a counter value of 0xf all the time, though the counter overflow flag USIOIF toggles once in a while. I would expect USIOIF to change to 1 and remain 1 unless that bit is written to 1.
I also checked if a start condition was detected. That seems to work, but I don't see any code to reset the USISIF bit by writing a 1 to it. There is just code for USIPF.