Page 1 of 1

SBL2e XA I2C interface

Posted: Tue Dec 23, 2014 1:12 pm
by nsclfrib
I'm trying to use a SBL2e XA to communicate between some I2C interfaced equipment, and Ethernet.

So far, the NetBurner is just sitting there like a little black blob as far as the I2C interface is concerned.

I can't get it to wake up any of the I2C equipment or even to acknowledge their existence.

I know the addresses of all the components, and a remote display unit for the equipment works correctly.

The equipment is interface at a 5v level, but I believe there should be no problem interfacing with the NetBurner.

Does the NetBurner require pull-up resistors on the bus? The previous equipment had 4.7k pull-ups to +5, but if I put any value of resistor (I've tried anything from 1.2k to 10k, and both the +5 from the remote equipment, and the +3.3 on pin 5 of the connector.

In any case, if I leave the resistors off, there is an enormous amount of noise on the signal lines, and if I put any pull-ups on the lines, they just go high, and I can't get them to transmit any data.

So far, I am not impressed, but it's probably something I've done.

Anyone had any luck interfacing I2C to an SBL2e?

Re: SBL2e XA I2C interface

Posted: Tue Dec 23, 2014 2:42 pm
by rnixon
Can't tell from your post if you have the dev kit or not, but it kind of sounds like you don't. From the data sheet

Optional
The following features are available with the optional development kit:
• Customize any aspect of operation including web pages, data filtering, or custom network applications
• I2C support

Are you having a code development problem?

Re: SBL2e XA I2C interface

Posted: Wed Dec 24, 2014 4:58 am
by nsclfrib
Yes, I'm using the development kit (in fact, 2 of them, they both have the same problems).

I can't even get any of the sample code to work properly.

What I'm trying to do is provide a computer interface to a rack of Mean Well RCP-1000 power supplies. Each unit has a PCF8574 8 bit digital input, a PCF8591 8 bit A/D, and an AT24C02 parameter eprom.
The units came with a remote display panel, which has LEDS and displays on it, which works properly over I2C, but provides no capability of computer monitoring. We want to get rid of that, and replace it with an interface to our controls system.

To this point, neither of the SBL2e units provide any indication that they are capable of performing this function, and after almost a week of working on them, I'm starting to think I'm wasting my time.

Later-

Re: SBL2e XA I2C interface

Posted: Wed Dec 24, 2014 9:19 am
by mbrown
Hm, there's a couple things that could possibly be going wrong. For certain, I can tell you that the I2C bus works on the SBL2exa you mentioned you have (Forrest put a couple together with some sensors to test our cloud connectivity stuff. I think Dan may still even have one at his house that we have a webpage for somewhere...)

In answer to your hardware questions. Yes, you do need pull-up resistors. Your range sounds fine. However, I'm not 100% that the SBL2E is 5V tolerant. You could be right and I'm just being forgetful, but I'll have to look at the voltage levels again to make sure everything checks out. If it doesn't, check out: http://www.ti.com/lit/ds/symlink/pca9306.pdf . We've been using these on some of the mcf5441x and mcf5270 boards that require different voltage levels on the i2c bus.

Questions come as follows: What are you doing to determine the i2c bus isn't communicating. Obviously the overall communication scheme isn't working, but are you saying this purely based on software or are you say using a scope to see the lines move? If you're saying that purely based on software, I would recommend taking a look at the following code.

Code: Select all

   I2CInit();

   iprintf("Scanning I2C \r\n");

	for (int x = 1; x < 0x80; x++)
	{
		int result = I2CStart(x, I2C_START_WRITE, 1);
		if (result < I2C_TIMEOUT)
		{
			iprintf("Found device at  0x%X, Result: %d\r\n", x, result);
			I2CStop();
		}
		else
		{
			I2CStop();
			I2CResetPeripheral();
		}
	}

	iprintf("Scan complete\r\n");
Being sure to include i2cmaster.h, this code will run a scan of all the available i2c addresses looking for one to respond. One of the most common things people get wrong on a software level is having the wrong address. If all your hardware is indeed working and it's just a software problem, running that code above should get your device to at least respond if it can run at 100kHz, which most things can.

If you are looking at a scope and you can't see any transmissions/fluctionations going across the wires, I would more seriously look into the IC I mentioned above. If you're just not seeing any acks, but the first byte is going across, it would hint again that your address isn't right.

Try out the code and let me know a little more about how you've been debugging if you're still having some problems.

Re: SBL2e XA I2C interface

Posted: Wed Dec 24, 2014 10:59 am
by nsclfrib
I've got some of the stuff working (OK, a fair bit working) now, I broke the first rule of taking over a project from someone else "... don't assume the previous developer had any idea what was going on...". Turns out, he had the cable wired wrong.

Now to move into what I'm having a problem with.

My first component is a PCF8574 digital input port, being used for machine status. It is at address 0x23 in this case.
Here is the code I'm trying to use to access it:
----------------------------

Code: Select all

			// try doing start
			for(ii = 0; ii < 4; ii++)
			{
				status = I2CStart(addr, I2C_START_READ, I2C_START_TIMEOUT);
				if(status < I2C_TIMEOUT)
					break;
				OUR_iprintf(to_tcp, "(%d) addr 0x%02X -> %-20s  CR=0x%02X SR=0x%02X\r\n", count, addr, I2CStatusText[status], I2C_CR, I2C_SR);
				OUR_iprintf(to_tcp,"(%d) Having to try start again #%d\r\n",count,ii);
				I2CStop();
				//I2CResetPeripherial();
				DumpI2C(to_tcp);
				//SetupI2C again
			}
			if(status < I2C_TIMEOUT)
			{ }
			else
				OUR_iprintf(to_tcp, "(%d) addr 0x%02X -> %-20s  CR=0x%02X SR=0x%02X\r\n", count, addr, I2CStatusText[status], I2C_CR, I2C_SR);
			// if read okay, try to read bytes
			if (status < I2C_TIMEOUT) {
				rc = 0;
				status = I2CRead(&newPsStat,I2C_RX_TX_TIMEOUT);
				if (status < I2C_TIMEOUT) {
					if(newPsStat != psStat)
					{
						psStat = newPsStat;
						OUR_iprintf(to_tcp, "New Status = 0x%02x\r\n", psStat);
					}
				}
				else
				{
					OUR_iprintf(to_tcp, "unable to read any bytes!\r\n");
				}
			}
			// then do stop
			I2CStop();

----------------------------
This code works the first time I try to execute it, but any subsequent calls cause nothing but I2C_TIMEOUT errors, which I don't seem to get recovered from. It shows that the bus lost arbitration, and can't get it back. Also the data that it does read the first time, is completely wrong.

I think I should probably be using I2CReadBuf to read this, but it states "...to be read ... in master mode ... without the need of a start or stop bit." Does this routine itself create the start sequence? I see in the parameters I can tell it not to generate a stop bit.
When I get to the PCF8591 A/D I need to write a byte (select channel), and read a response (reading). Are those both a single transaction, or do I need to generate a stop bit in between? For some reason, I thought the only time to generate a stop bit was when I was going to move to a new address.

Re: SBL2e XA I2C interface

Posted: Wed Dec 24, 2014 3:43 pm
by mbrown
Right, so perhaps the comments in the i2c documentation are a little confusing. I'm not the original author of the original driver, but I've made the most recent contributions and probably have the best off hand knowledge of how it works. I'll make a note to go through the documentation another time when I get back to the office and update it to be clearer. For most applications using the I2C bus, you're going to want to use the readbuf and sendbuf commands. All of the other functions are utilized by these two to basically physically manhandle the bus into getting it to work. I'll explain.

Start for instance sends a start sequence followed by a send command that sends the address you want to talk to. Send following a write or start bit physically sends one byte across the bus. Read follows a read bit and reads a singular byte on the bus. Stop sends a stop bit. Restart sends a restart after these commands and then acts like the start function. That being said, all of these are base functions utilized by the i2csendbuf and i2creadbuf commands except for restart. If you simply want to read one byte across the bus, the cleanest and easiest way to do this is I2CReadBuf(address, &read_var, 1); This appropriate sends the start sequence, the address, a read bit, then a byte of read data, followed by a stop bit. This would be roughly equivalent to:

I2CStart(address, read); //(This further simplifies to sending a start bit on the line followed by I2CSend(address);)
I2CRead(&read_var);
I2CStop();

I'm generalizing because I don't have the driver sitting in front of me and I'm assuming you'll be clever enough to figure out all the other variables based on what you've already sent me.

If your I2C bus was non-standard, it might be necessary to use the other commands, but really it's usually more efficient and cleaner to just use SendBuf and ReadBuf. If you want to use restarts, this is pretty simple as well. Usually this just involves adding false as the last parameter to SendBuf or ReadBuf followed by I2CRestart, followed by whatever you want to follow the restart.

For instance I've used the following code to read or write to a single register with restarts. I would be willing to bet, you're simply trying to implement something that just does exactly this.

Code: Select all

/* Use I2C to read a byte from the specified register on address I2C_TEMP_SENSOR_ADDRESS */
uint8_t read8(uint8_t reg) {
    uint8_t rx = 0;
    int status = I2CSendBuf(I2C_TEMP_SENSOR_ADDRESS, &reg, 1, false);
    if ( status != I2C_MASTER_OK )
    	iprintf("Error %d calling I2CSendBuf()\r\n", status);

    status = I2CRestart(I2C_TEMP_SENSOR_ADDRESS, I2C_START_READ);
    if (( status != I2C_OK ) | (status != I2C_NEXT_READ_OK))
        iprintf("Error %d calling I2CRestart()\r\n", status);

    status = I2CReadBuf(I2C_TEMP_SENSOR_ADDRESS, &rx, 1);
    if ( (status != I2C_OK) && (status != I2C_NEXT_READ_OK) )
    	iprintf("Error %d calling I2CReadBuf()\r\n", status );
    return rx;
}

/* Use I2C to write a byte to the specified register on address I2C_TEMP_SENSOR_ADDRESS */
uint8_t write8(uint8_t reg, uint8_t value) {

    int status = I2CSendBuf(I2C_TEMP_SENSOR_ADDRESS, &reg, 1, false);
    if ( status != I2C_OK )
    	iprintf("Error calling I2CSendBuf()\r\n");

    status = I2CRestart(I2C_TEMP_SENSOR_ADDRESS, I2C_START_WRITE);
    if (( status != I2C_OK ) | (status != I2C_NEXT_WRITE_OK))
        iprintf("Error %d calling I2CRestart()\r\n", status);

    status = I2CSendBuf(I2C_TEMP_SENSOR_ADDRESS, &value, 1);
    if ( status != I2C_OK )
    	iprintf("Error calling I2CSendBuf()\r\n");

    return status;
}
If you don't mind me asking, what does your iprintf function do? Does this send data out your tcp port to a given address?

Re: SBL2e XA I2C interface

Posted: Thu Dec 25, 2014 7:27 am
by pbreed
iprintf is just printf without the floating point part.
So this send things out the serial port...
The floating point code for printf is many times larger than the rest of the printf code...


First rule of i2C if the data sheet lists 2 addresses , ie different for read and write, the data sheet is in error,
The I2C standard does not list two addresses, it lists one address with an appended bit for R/W.

So when having I2C problems either run the scanner to see what addresses are out there, or try using
(2*data sheet write address ) as the i2c address...