CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Slave I2C code (no interrupts) showing read/respond.
Goto page 1, 2, 3, 4  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

Slave I2C code (no interrupts) showing read/respond.
PostPosted: Thu Nov 07, 2019 2:07 pm     Reply with quote

I am trying to do an I2C SLAVE (PIC24) that does not use interrupts. I've found examples of how to do simple reads from the master, and they seem to work well.

All the examples I have found that show the Slave responding back have interrupt service routines handling this.

My ultimate goal is to implement our own I2C library that we will have source code to (we've had a ton of I2C issues lately). None of us have ever had to write an I2C driver, so I'm seeing how easy or difficult it might be.

From a PC program (one in C, one in C#), we have code we wrote that uses the FTDI library to write data and read back responses, so I am now trying to do a generic version of the Slave side for our PIC24s.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.


Last edited by allenhuffman on Fri Nov 08, 2019 11:30 am; edited 1 time in total
temtronic



Joined: 01 Jul 2010
Posts: 9249
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Nov 07, 2019 3:26 pm     Reply with quote

CCS doesn't 'hide' the code for their I2C drivers. Have to ask why not use them ? If they are failing, then contact CCS and they will help !

Jay
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Thu Nov 07, 2019 3:29 pm     Reply with quote

temtronic wrote:
CCS doesn't 'hide' the code for their I2C drivers. Have to ask why not use them ? If they are failing, then contact CCS and they will help !

Jay


I was told they don't release the source to all of it (though apparently some does ship with source) -- is this not correct?
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
temtronic



Joined: 01 Jul 2010
Posts: 9249
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Thu Nov 07, 2019 4:16 pm     Reply with quote

OK... technically the 'source' or C code isn't available BUT the assembler can be seen in the listings. When you consider there's fewer PIC instructions than fuses, reading ASM is easy. Actually every bit of every byte of code you compile can be seen, though some files may need the 'nolist' option removed.

Jay
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Thu Nov 07, 2019 4:20 pm     Reply with quote

temtronic wrote:
OK... technically the 'source' or C code isn't available BUT the assembler can be seen in the listings. When you consider there's fewer PIC instructions than fuses, reading ASM is easy. Actually every bit of every byte of code you compile can be seen, though some files may need the 'nolist' option removed.

Jay


Ah, yeah, so we'd still be back to reimplementing. We wanted to take care of that global int8 that the compiler but was causing us crashes from. (Changing it to a 16-bit would have fixed that particular issue.)
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
Ttelmah



Joined: 11 Mar 2010
Posts: 19555

View user's profile Send private message

PostPosted: Fri Nov 08, 2019 1:28 am     Reply with quote

Remove the 'nolist' that is in the processor's include file, and the listing
will include the CCS functions.
Use the 'symbolic' setting for the project, and you will get a listing with
register names etc.
Result, nice and easy to see what the functions do.
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 08, 2019 8:39 am     Reply with quote

Ttelmah wrote:
Result, nice and easy to see what the functions do.


True -- one of you let me know about that in an earlier post. But it wouldn't have let us work around the compiler bug unless we wanted to start being PIC assembly programmers.

Right now I'm trying to find a bi-directional CCS I2C example that does not use interrupts. I'm trying to replicate a bit of pre-existing I2C messaging code in an IRQ-free bootloader.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
Ttelmah



Joined: 11 Mar 2010
Posts: 19555

View user's profile Send private message

PostPosted: Fri Nov 08, 2019 9:03 am     Reply with quote

Just use the same code as for interrupt driven, but leave the interrupt disabled
and test the interrupt flag bit. Exactly the same code can be used as is
inside the interrupt handler:
Instead of:

#INT_SSP //or whichever peripheral you are using, use:

if (interrupt_active(INT_SSP))
//Then have the INT_SSP code here.

Remember you will have to clear the interrupt at the end of the routine.

No other changes are needed.
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Fri Nov 08, 2019 11:28 am     Reply with quote

Ttelmah wrote:
Just use the same code as for interrupt driven, but leave the interrupt disabled
and test the interrupt flag bit. Exactly the same code can be used as is
inside the interrupt handler:


Thanks. I did not know I could use i2c_isr_state() when not using an ISR.

I took some template I2C code and modified it. I'd now like to get the P - Stop bit" status implemented so the Slave can just read whatever size message comes in.

Our existing production code parses our message format inside the ISR looking for a size field and then stops at the end and toggles a state machine to let it know there is data to read.

A reply is stuffed into a transmit buffer and then it gets sent out by the same ISR.

I'm trying to make a much more generic I2C read routine that blocks until a message of any size is received, then lets the code parse that as needed and send a response back if needed.

I took the working ISR template code and added comments from the documentation and made it poll:

Code:
unsigned int i2cPoll (void *buffer, size_t size)
{
    unsigned int state;
    unsigned int value;
    unsigned int address;
   
    while (1)
    {
        if (SI2C3IF == 1) // I2C interrupt pending.
        {
            state = i2c_isr_state(SYSTEM_BUS);
       
            value = (state & ~BIT(7)); // Mask off high bit.
       
            // High bit (X0000000) indicates READ, else WRITE
           
            if ((state & BIT(7)) == 0) // High bit CLEAR
            {
                if (value == 0x00)
                {
                    // 0 - Address match received with R/W bit clear, perform
                    // i2c_read( ) to read the I2C address.
                    address = i2c_read (SYSTEM_BUS);
                    buffer[value] = i2c_read (SYSTEM_BUS);     
                }
                else
                {
                    // 1-0x7F - Master has written data; i2c_read() will immediately
                    // return the data
                    buffer[value] = i2c_read (SYSTEM_BUS);       
                }
            }
            else // High bit SET (Slave writing to Master)
            {
                if (value == 0x00)
                {
                    // 0x80 - Address match received with R/W bit set; perform
                    // i2c_read( ) to read the I2C address, and use i2c_write( ) to
                    // pre-load the transmit buffer for the next transaction (next
                    // I2C read performed by master will read this byte).
                    //address = i2c_read (SYSTEM_BUS, 2);
                    i2c_write (SYSTEM_BUS, buffer[0]);
                }
                else
                {
                    // 0x81-0xFF - Transmission completed and acknowledged; respond
                    // with i2c_write() to pre-load the transmit buffer for the next
                    // transition (the next I2C read performed by master will read
                    // this byte).
                    i2c_write (SYSTEM_BUS, buffer[value]);
                }

                // Stop when we've written as much as user wanted to write.
                if (value > size)
                {
                    break;
                }           
            }
        }
    } // end of while (1)
   
    return value;
}


I commented out the receive "//address = i2c_read (SYSTEM_BUS);" part since it hangs there for me when running this polled code, but it was working in the ISR, so there are still bugs to squish.

NOTE: This code is one routine, where the call would block for data, then return how many bytes were received. Then if it's something we expect to reply to (Master would be waiting) we pass it a buffer which gets written out. I've been talking back and forth to a C# program to test this.

I'd like to implement the reading of the "P - Stop bit" status but that's being reset somewhere. The datasheet says "Hardware set or clear when Start, Repeated Start or Stop detected" so I'm likely doing it in the wrong place.

I'm enjoying digging into this. All the I2C stuff I've done in the past was just using existing APIs that did all this. Learning lots.

Thanks for your replies.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
Ttelmah



Joined: 11 Mar 2010
Posts: 19555

View user's profile Send private message

PostPosted: Sat Nov 09, 2019 2:03 am     Reply with quote

There is no sign of you clearing SI2C3IF. Remember _you_ have to do this
if you are polling the interrupt.
In an ISR, the compiler clears this for you.
Problem therefore is that as posted, after the first time round this code
the routine will be being used, when the interrupt has not actually
happened again. So things like reads will hang, since data is not available....
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Sat Nov 09, 2019 8:42 pm     Reply with quote

Ttelmah wrote:
There is no sign of you clearing SI2C3IF. Remember _you_ have to do this
if you are polling the interrupt.


That makes sense. I am perplexed why it was returning to the caller at all.

If I can get the P (stop) figured out, I think that will go a long way. I've only had success when I was also reading other status register bits. It reminds me my old 8-bit days with a UARTs where reading status would clear other things. I expect it's just something like that I have to learn about the PIC internals.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Tue Nov 12, 2019 3:39 pm     Reply with quote

I have been working through some messages I found on the Microchip PIC24 forum where others are trying to do the same thing -- read I2C data until the Master is done writing.

From what I've read, it is possible to miss reading the P bit if polling. But the datasheet says it is only cleared when Start, Repeated Start or Stop is detected.

Stop bit is reset when a Stop is detected???

I am trying to find more documentation than what is in the datasheet. For example, "SI2CxIF" (Slave I2C X Event Interrupt Flag Status bit). What operations trigger this, other than an incoming byte?

Thanks for any pointers to more details docs.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Wed Nov 13, 2019 4:07 am     Reply with quote

allenhuffman wrote:
I am trying to find more documentation than what is in the datasheet. For example, "SI2CxIF" (Slave I2C X Event Interrupt Flag Status bit). What operations trigger this, other than an incoming byte?

Look in the PIC24 Reference Manual on i2c. Look at page 18.
http://ww1.microchip.com/downloads/en/devicedoc/70000195f.pdf
gaugeguy



Joined: 05 Apr 2011
Posts: 303

View user's profile Send private message

PostPosted: Wed Nov 13, 2019 7:01 am     Reply with quote

It actually says "sets or clears", not "cleared"

P: Stop bit
1 = Indicates that a Stop bit has been detected last
0 = Stop bit was not detected last
Hardware sets or clears when Start, Repeated Start or Stop is detected.

Now if there are two separate messages that are extremely close to one another it may be possible to miss the stop bit when polling if it is very closely followed by a start bit for another message. A dead time between messages would prevent this.
allenhuffman



Joined: 17 Jun 2019
Posts: 580
Location: Des Moines, Iowa, USA

View user's profile Send private message Visit poster's website

PostPosted: Wed Nov 13, 2019 9:26 am     Reply with quote

PCM programmer wrote:
Look in the PIC24 Reference Manual on i2c. Look at page 18.
http://ww1.microchip.com/downloads/en/devicedoc/70000195f.pdf


Great timing! My CEO just pointed me to that document as well. It is exactly what I was looking for.
_________________
Allen C. Huffman, Sub-Etha Software (est. 1990) http://www.subethasoftware.com
Embedded C, Arduino, MSP430, ESP8266/32, BASIC Stamp and PIC24 programmer.
http://www.whywouldyouwanttodothat.com ?

Using: 24FJ256GA106, 24EP256GP202 and 24FJ64GA002.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2, 3, 4  Next
Page 1 of 4

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group