cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Explorer
Explorer
4,134 Views
Registered: ‎04-18-2017

Zynq I2C only outputs address

Hello,

 

I am trying to use the I2C embedded in the ARM. I used the master polled example to reproduce this code:

 

#include <stdio.h>
#include "xiicps.h"
#include "xparameters.h"

#define TAS5706_0_I2C_ID 		XPAR_PS7_I2C_0_DEVICE_ID
#define TAS5706_ADDRESS			0x36
#define TAS5706_I2C_SCL_RATE	20000

static XIicPs Iic;

int main(void)
{
	int Status;
	XIicPs_Config *Config;
	unsigned char u8TxData[2], buff[1024];

	int32_t ByteCount;

	u8TxData[0] = 0x00;
	u8TxData[1] = 0x01;

	/*
	 * Initialize the IIC driver so that it's ready to use
	 * Look up the configuration in the config table,
	 * then initialize it.
	 */
	Config = XIicPs_LookupConfig(TAS5706_0_I2C_ID);
	if (NULL == Config) {
		return XST_FAILURE;
	}

	Status = XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	/* Set the IIC serial clock rate. */
	XIicPs_SetSClk(&Iic, TAS5706_I2C_SCL_RATE);

	while(1)
	{
		XIicPs_MasterSendPolled(&Iic, u8TxData, 2, TAS5706_ADDRESS);
		while(XIicPs_BusIsBusy(&Iic));
		usleep(50000);
		//XIicPs_MasterRecvPolled(&Iic, buff, 2, TAS5706_ADDRESS);
	}

	return 0;
}

I am only seeing the address on the osciloscope on the SDA pin. Have I missed something in the code?

Thanks for the help.

0 Kudos
29 Replies
Highlighted
Adventurer
Adventurer
4,111 Views
Registered: ‎01-28-2013

Could you post the status of the Interrupt Mask Register after each I2C operation?

0 Kudos
Highlighted
Explorer
Explorer
4,095 Views
Registered: ‎04-18-2017

Newbie questions. How do I check the Interrupt Mask Register?
0 Kudos
Highlighted
Scholar
Scholar
4,013 Views
Registered: ‎04-13-2015

Seeing the address on the bus is a very good start.

Not moving past the address may not necessary be an issue with your program but it could be the slave device not responding.

After the address is sent on the bus by the master, it is followed by the R/W bit (also sent by the master) and then the slave will acknowledge.

The acknowledge is the SDA (the data line) being held low.for at one clock cycle (there could and will most likely be many many more cycles of SDA held low).

Have a look with your scope to see if the SDA is being held low after the R/W cycle.

If is not then the slave hasn't recognized the address and this will provoke an abort of the transfer.

 

For your convenience, the I2C standard can be retrieved from:

http://www.nxp.com/docs/en/user-guide/UM10204.pdf

 

Regards.

0 Kudos
Highlighted
Moderator
Moderator
3,992 Views
Registered: ‎07-31-2012

Nice explanation.

Later you need to see if data transaction followed by address.

I see that you have two data to send.

 

regards

Praveen


-------------------------------------------------------------------------
Don’t forget to reply, kudo, and accept as solution.
-------------------------------------------------------------------------
0 Kudos
Highlighted
Scholar
Scholar
3,982 Views
Registered: ‎04-13-2015

To make sure I didn't add some confusion, when the slave holds the SDA line low for many many clock, the SCL (clock) line is also held low by the slave.

That's how a slave can temprary freeze the bus transaction until it's ready to send or read the data.

 

Regards

0 Kudos
Highlighted
Explorer
Explorer
3,968 Views
Registered: ‎04-18-2017

I have to check again at the lab (I will do it in about 15 hours), but if I recall correctly, I see the address, then the next bit is low (I believe it is then the acknowledge from the slave) and the SDA goes back to 1 and stays like that. I will post a picture and also try with another slave.

0 Kudos
Highlighted
Scholar
Scholar
3,963 Views
Registered: ‎04-13-2015

The bit after the address is the R/W bit.

If it is low, therefore it means a write transfer on the bus.

As you are doing a write of 2 bytes, so far so good.

If the line doesn't also remain low for the following bit, it means the slave device didn't respond.

 

Looking forward the scope capture

 

Regards

 

0 Kudos
Highlighted
Explorer
Explorer
3,941 Views
Registered: ‎04-18-2017

You can see here the screenshot.

 

Thanks again for the help.

0 Kudos
Highlighted
Explorer
Explorer
3,938 Views
Registered: ‎04-18-2017

Please correct me if I'm wrong. In my case, the address is 0x36. The way I2C works is it outputs the LSB first, then the MSB. And they are also inverted. Therefore, my address is 0011 0110 (0x36), my output is 0110 1100, which is what I have in the screenshot, right? And that is followed by a 1 which is the R/W bit I asume.
0 Kudos
Highlighted
Explorer
Explorer
3,765 Views
Registered: ‎04-18-2017

I have been looking a bit....could this all be due to the XIICPS_CR_ACKEN_MASK, refering to the ACK bit that it might not be activated?
https://www.xilinx.com/support/answers/58323.html
0 Kudos
Highlighted
Scholar
Scholar
3,761 Views
Registered: ‎04-13-2015

It looks like you're getting very close to nail down the problem

Have a look at sections 3.1.2 & 3.1.6 in the standard.

 

Regards

0 Kudos
Highlighted
Scholar
Scholar
3,760 Views
Registered: ‎04-13-2015

A reminder: there are 7 address bits, not 8

Regards

0 Kudos
Highlighted
Explorer
Explorer
3,754 Views
Registered: ‎04-18-2017

I did a 1 bit shift for the address. Instead of ADDRESS, now I have (ADDRESS>>1).

Regarding the standard, I'll take a look at the sections you mentioned....but it seems to be more of an issue of configuring the I2C on the ZYNQ, doesn't it?
0 Kudos
Highlighted
Explorer
Explorer
3,751 Views
Registered: ‎04-18-2017

I see two options to configure the ZYNQ (rather the arm). One would be to enable it to acknowledge the acknowledge from the slave and the second option would be not to wait for the ack from the slave and send the data....but still I have to figure out exactly how to do this.
0 Kudos
Highlighted
Scholar
Scholar
3,751 Views
Registered: ‎04-13-2015

You're correct.

The scope shows 0110110,0,0,11111

0110110 is the address

0 is R/W indicating a write transfer

0 is the slave acknowledging

Then the clock stops.

So the Zynq does not see/process the acknowledge from the slave.

As tn45eng mentioned, you'll have to check the interrupt mask register.

You can get all the information about the I2C controller registers in Appendix B of the Zynq TRM

Also check section 20.2.2 in the TRM.

 

Regards

 

 

 

 

0 Kudos
Highlighted
Explorer
Explorer
3,749 Views
Registered: ‎04-18-2017

How do I check the interrupt mask register?
0 Kudos
Highlighted
Scholar
Scholar
3,742 Views
Registered: ‎04-13-2015

To read the register:

MASK_VALUE  = *((volatile unsigned int *)REGISTER_ADDRESS);

 

You'll find the address of the register in Appendix B of the TRM

 

0 Kudos
Highlighted
Explorer
Explorer
3,728 Views
Registered: ‎04-18-2017

I have seen that the XIicPs_MasterSendPolled function configures the control register and it sets the ACK bit. After it is called, I read the control register with `RegVal = XIicPs_ReadReg(Config->BaseAddress, XIICPS_CR_OFFSET);` which returns 0x0e. This means that ACK_EN is enabled (Page 1385 from the Zynq TRM). If I read the interrupt status register, it reads 0x04, NACK set to 1 (Transfer not acknowledged. slave responds with a NACK or master terminates the transfer before all data is supplied). Shouldn't it be one or the other, or complementary?

0 Kudos
Highlighted
Scholar
Scholar
3,702 Views
Registered: ‎04-13-2015

In the control register, no choice as the ACK bit must be set (see the description text for that bit).

For the status register #2, you now know the 2 possible causes for not seeing the 2 bytes being sent after the address on the bus.

You should read and understand the standard otherwise you are trying to debug this a bit on the blind side.

You have a scope,which is great because you can see what is going on the bus.

Carefully read and reread TRM's chapter #20 and correlate / double check with your code (and Xilinx's BSP) & the registers.

 

 

 

 

0 Kudos
Highlighted
Explorer
Explorer
3,786 Views
Registered: ‎04-18-2017

Well, as far as setting the register, accordingly to the TRM:

 

1. Write to the control register to set up SCL speed and addressing mode. This is done by `XIicPs_SetSClk(&Iic, TAS5706_I2C_SCL_RATE);` in my main and XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); called from XIicPs_MasterSendPolled, if I am not mistaken.

2. Set the MS, ACKEN, and CLR_FIFO bits and clear the RW bit in the Control register. This is again done by XIicPs_SetupMaster.

 

Therefore, the procedure from the TRM (Page 606) is being followed by the functions generated in the BSP, and when I read the registers, I believe I read them as the should be so I am lost on how to proceed.

 

0 Kudos
Highlighted
Scholar
Scholar
3,783 Views
Registered: ‎04-13-2015

We don't use Xilinx's BSP as we prefer to create and provide drivers with simple APIs limited to init / recv / send using compile time configuration for polling / ISR / DMA transfers.

So I can't provide meaningful feedback on the internal of the BSP functions, but it looks like the registers values are OK.

 

If you want to try something different, all our drivers are free supplied with working demos

The I2C demos supports 5 or 6 different devices.

You can fill a request on our website.

www.code-time.com

 

Regards

 

 

 

0 Kudos
Highlighted
Explorer
Explorer
3,755 Views
Registered: ‎04-18-2017

I prefer to use the BSP functions. I hope tn45eng sees the message where I posted the interrupt and control masks.
0 Kudos
Highlighted
Explorer
Explorer
3,731 Views
Registered: ‎04-18-2017

Ok, I am back at the lab with the scope.

 

I have changed in the XIicPs_SetupMaster function, called within the XIicPs_MasterSendPolled that I call from my main (in the infitive loop), where it configures the ACK bit:

 

	/*
	 * Set up master, AckEn, nea and also clear fifo.
	 */
	ControlReg |= (u32)XIICPS_CR_ACKEN_MASK | (u32)XIICPS_CR_CLR_FIFO_MASK |
			(u32)XIICPS_CR_NEA_MASK | (u32)XIICPS_CR_MS_MASK;

	if (Role == RECVING_ROLE) {
		ControlReg |= (u32)XIICPS_CR_RD_WR_MASK;
	}else {
		ControlReg &= (u32)(~XIICPS_CR_RD_WR_MASK);
	}

	XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, ControlReg);

I changed it so it looks like this: ControlReg |= (u32)XIICPS_CR_CLR_FIFO_MASK | (u32)XIICPS_CR_NEA_MASK | (u32)XIICPS_CR_MS_MASK;

 

So I am not setting the ACK bit, but when I see the SDA on the scope, it still only outputs the address.

 

My address is #define TAS5706_ADDRESS            0x36    // 0011 0110. It is correct to do XIicPs_MasterSendPolled(&Iic, u8TxData, 2, (TAS5706_ADDRESS>>1));, as it is a 7-bit address. Right?

 

Thanks for the help.

0 Kudos
Highlighted
Explorer
Explorer
3,728 Views
Registered: ‎04-18-2017

I forgot to say that I read the control register in the while loop after I call XIicp_MasterSendPolled with ControlReg = XIicPs_ReadReg(Config->BaseAddress, XIICPS_CR_OFFSET); and I get ControlReg=0x0000fe06, InterruptReg=0x00000004 when I set ACK=1 and ControlReg=0x0000fe0e, InterruptReg=0x00000004 when I set ACK=0.
When I set ACK0=0, I expected the address and the two bytes to be on SDA, but they aren't.
0 Kudos
Highlighted
Adventurer
Adventurer
3,715 Views
Registered: ‎01-28-2013

@aripod

 

So from the IMR values you reported here (0x04), it is clear that the slave doesn't acknowledge the transfer (NACK bit is set). The goal is to get the COMP bit set in the IMR.

 

You are seeing some value in the clock and data so the pin mapping is right.  So its either you are missing some setting in the processor or the hardware interface is not OK or the chip itself is not OK.

 

Your hardware is new so there are a couple some basic questions like does the hardware work at all and what is the address?

Since this is a new hardware will first verify if the hardware is OK and get back to settings later.

 

 

As for address, one lazy and easy thing to do with I2C is to run a while loop with all possible address 0 to 128(normal addressing) to find out all the slaves connected to it. So you don't have to wonder if you have the address right.

 

 

Voltage levels, clock speed, reset and pull up resistor values are the next thing you would want to look into.

 

Did you check if the chip supports the clock speed you are running?

The voltage level of the I2C pins in ZynQ matches up with that of the chip?

Apply a hard reset to the chip and make sure it is out of reset?

What is the pull up resistor value you are using?

 

 

0 Kudos
Highlighted
Explorer
Explorer
3,670 Views
Registered: ‎04-18-2017

I have tested the hardware with an image that was created two years ago and everything worked (it is an audio amplifier and I made the speakers reproduce audio).
I also doublé checked and the IC was reseted...my bad. Now, when I send 2 bytes on the I2C, I can see the address, the ACK and the two bytes with their respective ack. After I send them, I read the interrupt status and it is 0x01.
Now, when I want to send 4 bytes, I can see on the scope the address with its ack, and the 4 bytes with their ack but the interrupt status read 0x03 (incomplete transfer). How is that possible?
0 Kudos
Highlighted
Scholar
Scholar
3,658 Views
Registered: ‎04-13-2015

The interrupt status register bits are sticky

Sec 20.2.8 in the TRM.

So once a bit has been set, it will remain set until manually cleared.

Bit #1 was likely set before the end of the transfer.

0 Kudos
Highlighted
Explorer
Explorer
3,644 Views
Registered: ‎04-18-2017

Ok, I see...so nothing to worry about then.

I can close the thread now. Thank you both for your big help.
0 Kudos
Highlighted
Adventurer
Adventurer
3,598 Views
Registered: ‎01-28-2013

@aripod The register is Write to clear type. Always clear the interrupt before initiating a new transaction. 

0 Kudos