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

i2c_slaveaddr() function behavior

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kerplatz



Joined: 01 Nov 2016
Posts: 18

View user's profile Send private message

i2c_slaveaddr() function behavior
PostPosted: Thu Nov 10, 2016 9:21 am     Reply with quote

I am having a problem understanding the behavior of the i2c_slaveaddr() function. I am using the most recent compiler version - 5.064. I need to set the i2c address of a board using hardware; the system will have multiple boards hence the need to have different addresses. So to do that I am using 2 16bit rotary switches to encode the address for that board. They work fine. For example, if I set the LSB switch to 0 and the MSB switch to 2, I get the value hex 20, or 32.

When I hard code the function it works fine and I can communicate with the board via i2c.

i2c_slaveaddr(stream1, 0x20);

But this is not what I want the code to do as I would need to compile new code with the address of that board for each board. Not a good option. So if I could do this--

i2c_slaveaddr(stream1, readHexSwitch());

or

unsigned char rhs = readHexSwitch();
i2c_slaveaddr(stream1, rhs);

where readHexSwitch() just returns the value of the switch positions in hex.

This is my question, why won't the latter work. I am so perplexed as this should not cause the code to work. It does however compile. A char and an int8 should be the same thing, right? I just compiled the code using int8 instead of char and it compiles, but does not work. Any help with this would be appreciated. Before you ask if I am using the correct address in i2c, if I go back to hard coding the address, then my i2c communications with that board return. I really need a way that the hardware and software place nicely together, so I can communicate with several boards via i2c on the same wire. Thanks.
Ttelmah



Joined: 11 Mar 2010
Posts: 19541

View user's profile Send private message

PostPosted: Thu Nov 10, 2016 9:57 am     Reply with quote

First, a function won't 'return a value in hex'. All internal values are binary. Hex is just a way for us to represent these. So your function will hopefully just return a number. Smile
That having been said, problem is that the slave address is a hardware function, has to be set before the port is initialised, and there are some addresses that can't be used.
So ideally what you do, is use the 'NOiNIT' option, set the address, and then use I2C_INIT with the address selected.
To change it after initialising, close the port, and re-initalise. So:

Code:

   i2c_init(STREAM,0); //stop the port
   i2c_slaveaddr(STREAM,address);
   i2c_init(STREAM); //restart the port.

You need to ensure you function cannot return an invalid address. Must be even, and 0x1111xxx0, and 0x0000xxx0 are not allowed. So the example is silly showing address 0x8 being used....
kerplatz



Joined: 01 Nov 2016
Posts: 18

View user's profile Send private message

PostPosted: Thu Nov 10, 2016 5:03 pm     Reply with quote

This did not work.

I set #use i2c((SLAVE, I2C3, address=32, FAST=400000, FORCE_HW, stream=SYSTEM_BUS). Then in an initialization function I used this code--

i2c_init(SYSTEM_BUS, 0);
i2c_slaveaddr(SYSTEM_BUS, 34);
i2c_init(SYSTEM_BUS, 1);

and my address did not change to 34 as I can still communicate to the board via i2c. Since I changed my board address, communications via i2c should have stopped. Please advise.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Nov 10, 2016 7:52 pm     Reply with quote

You didn't give us your PIC but I believe it's a 24F series.

I don't have the PCD compiler, so I did a test with an 18F46K22.
The i2c_slaveaddr() function compiles to one line of code:
Quote:
....... i2c_slaveaddr(stream1, rhs);
0005C: MOVFF rhs, SSP1ADD


The fact that you are using I2C3 module is suspicious. Quite often,
CCS will add support for the primary module (I2C1), but for additional
ones, they may use the wrong register address. This gets corrected
after user bug reports are submitted. Look at the .LST file and the
PIC data sheet and verify that the compiler is writing to the correct
Slave address register for I2C3.
kerplatz



Joined: 01 Nov 2016
Posts: 18

View user's profile Send private message

PostPosted: Fri Nov 11, 2016 8:31 am     Reply with quote

The chip is 24FJ256GA106.h. I am using the other 2 i2c devices to do other things, they are working perfectly, hence why I said nothing about them. PS - They never leave the board. (I am doing R & D where we design and make our own boards.) So now that I have given more meaningless info to my problem, let's get back to the problem.

As I have said the code does compile, which is not the problem. It is execution. Please go back and reread what I have told you. If you need more info, ask a question and I will give you an answer. Here is a synopsis of the problem.

I can set the address in #USE I2C() and it works fine. If I use i2c_slaveaddr() it works only sometimes. I gave some examples. What I want to do is be able to set the address using hex switches so I only need to have one version of the code. Surely this is not the first time someone has done this. This is not, as far as I can tell, an initialization problem as I can make it work when I don't use i2c_slaveaddr(), I just can't change the address how and when I want to. I apologize for being somewhat snarky today, but I have been fiddling with this for a while now and I want to work towards a solution. My frustration level is high.
kerplatz



Joined: 01 Nov 2016
Posts: 18

View user's profile Send private message

PostPosted: Fri Nov 11, 2016 8:38 am     Reply with quote

Here is what the .lst file gives for those three lines of code. I will now go and figure out what it is doing.

.................... // Read the hex switches.
.................... i2c_init(SYSTEM_BUS, 0);
006EE: BCLR.B 277.7
.................... i2c_slaveaddr(SYSTEM_BUS, 34);
006F0: MOV #11,W4
006F2: MOV W4,27A
.................... i2c_init(SYSTEM_BUS, 1);
006F4: BCLR.B 2E4.7
006F6: BSET.B 277.7
006F8: BSET.B 277.5
006FA: BSET.B 276.6
006FC: BCLR.B 277.3
006FE: BSET.B 276.7
00700: BCLR.B 277.0
00702: BCLR.B 277.1
00704: BCLR.B 277.2
00706: MOV #10,W4
00708: MOV W4,27A

Yes I know the address is not 32 as I am trying to change it to a different one than what I started with. Here is the #use i2c() line.

#use i2c(SLAVE, I2C3, address=32, FAST=400000, FORCE_HW, stream=SYSTEM_BUS)
Ttelmah



Joined: 11 Mar 2010
Posts: 19541

View user's profile Send private message

PostPosted: Fri Nov 11, 2016 10:08 am     Reply with quote

On this port as shown, the compiler is behaving incorrectly, and always setting the address to the value from the #use...

So use:
Code:

#use i2c(SLAVE, I2C3, FORCE_HW, stream=SYSTEM_BUS, address=0x32)
//A 'slave' does not have a baud.

//Then use:
#byte I2C3ADD=getenv("SFR:I2C3ADD")
#byte I2C3CON=getenv("SFR:12C3CON")
#bit I2C3EN=I2C3CON.7

         iI2C3EN=FALSE; //stop the port
         I2C3ADD=address/2; //Remember PIC24 uses 7bit address mode.
         I2C3EN=TRUE;
kerplatz



Joined: 01 Nov 2016
Posts: 18

View user's profile Send private message

PostPosted: Fri Nov 11, 2016 11:40 am     Reply with quote

OK, so I removed the BAUD from my #USE_I2C setting. I get that the slave is dependent upon the master clock so this has no effect. But this is not my problem. The value contained in the I2CXADD is the address I2C will respond to when sent a message via I2C. I know all about how it works as I have written code for I2C communications many times. I am not a newbie. Can still make mistakes, but this problem was not my mistake. Read on.

As promised, I went back and studied my code using the debugger where I discovered that I could see all the registers for all the peripherals on that chip. I put my code back to where I was initializing the I2C3 like this--
Code:

#use i2c(SLAVE, I2C3, address=32, FORCE_HW, stream=SYSTEM_BUS)

The I2C3ADD register now contains XXXX XXXX 0010 0000 or 0x0020 or 32. I then tried communicating over I2C and it worked since both master and slave had the same address, 32. Then I removed the address from #USE_I2C() and added i2c_slaveaddr(SYSTEM_BUS, 32) in my init function before my while(1) loop. I then was able to communicate with the board via I2C. I checked the I2C3ADD register and it still had 0x0020 or 32. No big surprise there. Here was where everything went differently.

I then replaced the 32 in the slave address function like this

i2c_slaveaddr(SYSTEM_BUS, readHexSwitches());

That function I added just returns the value dialed on the switches. If I selected 2 for the LSB switch and 7 for the MSB switch the function would return 0x72 or 114. But that is not what the I2C3ADD register got set to. I2C3ADD register really got set to 0x39 or 57.

Half of the number I dialed into my switches. That makes sense now, but why does CCS do that differently depending upon how I choose to supply that value. It should not care. All I did was multiply that number by 2 and I was able to communicate via I2c with the board.

The same was true if I did it this way --

unsigned int8 val = 32;
i2c_slaveaddr(SYSTEM_BUS, val);

The val value was cut in half when put into the I2C3ADD register which contained 0x0010 or 16 when I compiled that code. I could then change my master address to 16 and communicate via I2C with the board.

There you go. And would someone please put this into the documentation for the CCS compiler once this has been verified. I could have saved a lot of time if I had just been able to read this somewhere. Thanks for all your help.
Ttelmah



Joined: 11 Mar 2010
Posts: 19541

View user's profile Send private message

PostPosted: Fri Nov 11, 2016 1:51 pm     Reply with quote

That's the point of this line:
"Remember PIC24 uses 7bit address mode.".

There are two different standards for I2C addresses. Technically the 'address' is the top 7bits of the byte sent on the bus. The bottom bit is the Read/Write flag. The byte being sent then, is the actual 'address' *2 plus the direction flag. On a lot of chips you then talk about the 'address' as this 8bit value.
On the PIC16/18, the register holds the 8bit address. On the PI24, the register instead wants the 7bit address....
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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