cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Nasir_124
Newbie
Newbie
314 Views
Registered: ‎08-26-2020

ZYNQ I2C Slave Receive throttling SDA

Hi, I am new to this forum and as well to Vivado embedded development so please bear with my naive query. I have an external Master device that sends 4 byte in total to AXI_IIC SLAVE to PL(1 byte device address, 2 byte register address, 1 byte data). As shown below in hardware definition: 

1.png

The problem is: My slave only receives 1 byte of address to the buffer and then throttled the SDA line. as shown below:

4e10dc1c-ec4a-4e04-a2c2-fed16263b450.jpg3.jpg

Device address is 0x18 and then register address of 2 byte 0x39A, however receive buffer stores only '3' and then stops the data bus from sending further.

 

In vivado SDK i have used Interrupt mode xiic_slave_example.c and modified it to my usage as follow:

72.	#include "xparameters.h"
73.	#include "xiic.h"
74.	#include "xintc.h"
75.	#include "xil_exception.h"
76.	#include "xscugic.h"
77.	 
78.	/************************** Constant Definitions *****************************/
79.	 
80.	/*
81.	 * The following constants map to the XPAR parameters created in the
82.	 * xparameters.h file. They are defined here such that a user can easily
83.	 * change all the needed parameters in one place.
84.	 */
85.	#define IIC_DEVICE_ID		XPAR_IIC_0_DEVICE_ID
86.	//#define INTC_DEVICE_ID		XPAR_INTC_0_DEVICE_ID
87.	//#define IIC_INTR_ID		XPAR_INTC_0_IIC_0_VEC_ID
88.	 
89.	#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
90.	#define IIC_INT_VEC_ID		XPS_FPGA0_INT_ID
91.	 
92.	/*
93.	 * The following constant defines the address of the IIC device on the IIC bus.
94.	 * Since the address is only 7 bits, this constant is the address divided by 2.
95.	 */
96.	#define SLAVE_ADDRESS		0x18	/* 0xE0 as an 8 bit number. */
97.	 
98.	#define RECEIVE_COUNT		4
99.	#define SEND_COUNT		4

101.	 
102.	/**************************** Type Definitions *******************************/
103.	 
104.	/***************** Macros (Inline Functions) Definitions *********************/
105.	 
106.	/************************** Function Prototypes ******************************/
107.	 
108.	int IicSlaveExample();
109.	int SlaveWriteData(u16 ByteCount);
110.	int SlaveReadData(u8 *BufferPtr, u16 ByteCount);
111.	static int SetupInterruptSystem(XIic * IicInstPtr);
112.	static void StatusHandler(XIic *InstancePtr, int Event);
113.	static void SendHandler(XIic *InstancePtr);
114.	static void ReceiveHandler(XIic *InstancePtr);
115.	 
116.	/************************** Variable Definitions *****************************/
117.	 
118.	XIic IicInstance;		/* The instance of the IIC device. */
119.	XScuGic InterruptController;	/* The instance of the Interrupt Controller */
120.	 
121.	 
122.	u8 WriteBuffer[SEND_COUNT];	/* Write buffer for writing a page. */
123.	u8 ReadBuffer[RECEIVE_COUNT];	/* Read buffer for reading a page. */
124.	 
125.	volatile u8 TransmitComplete;
126.	volatile u8 ReceiveComplete;
127.	 
128.	volatile u8 SlaveRead;
129.	volatile u8 SlaveWrite;
130.	 
131.	/************************** Function Definitions *****************************/
132.	 
133.	/*****************************************************************************/
134.	/**
135.	* Main function to call the IIC Slave example.
136.	*
137.	* @param	None.
138.	*
139.	* @return	XST_SUCCESS if successful else XST_FAILURE.
140.	*
141.	* @note		None.
142.	*
143.	******************************************************************************/
144.	int main(void)
145.	{
146.		int Status;
147.	 
148.		/*
149.		 * Run the IIC Slave example.
150.		 */
151.		xil_printf("i2c slave example begin\n");
152.		Status = IicSlaveExample();
153.		if (Status != XST_SUCCESS) {
154.			return XST_FAILURE;
155.		}
156.	 
157.		return XST_SUCCESS;
158.	}
159.	 
160.	void delay_SL(u32 delayCount) {
161.		do {
162.			__asm__("nop");
163.			delayCount--;
164.		} while (delayCount > 0);
165.	}
166.	/*****************************************************************************/
167.	/**
168.	* This function writes and reads the data as a slave. The IIC master on the bus
169.	* initiates the transfers.
170.	*
171.	* @param	None.
172.	*
173.	* @return	XST_SUCCESS if successful else XST_FAILURE.
174.	*
175.	* @note		None.
176.	*
177.	******************************************************************************/
178.	int IicSlaveExample()
179.	{
180.		int Status;
181.		u8 Index;
182.		XIic_Config *ConfigPtr;	/* Pointer to configuration data */
183.	 
184.	 
185.		/*
186.		 * Initialize the IIC driver so that it is ready to use.
187.		 */
188.		ConfigPtr = XIic_LookupConfig(IIC_DEVICE_ID);
189.		if (ConfigPtr == NULL) {
190.			return XST_FAILURE;
191.		}
192.	 
193.		Status = XIic_CfgInitialize(&IicInstance, ConfigPtr,
194.						ConfigPtr->BaseAddress);
195.		if (Status != XST_SUCCESS) {
196.			return XST_FAILURE;
197.		}
198.	 
199.		/*
200.		 * Setup the Interrupt System.
201.		 */
202.		Status = SetupInterruptSystem(&IicInstance);
203.		if (Status != XST_SUCCESS) {
204.			return XST_FAILURE;
205.		}
206.	 
207.		xil_printf("i2c slave example begin test1\r\n");
208.		/*
209.		 * Include the Slave functions.
210.		 */
211.		XIic_SlaveInclude();
212.	 
213.		/*
214.		 * Set the Transmit, Receive and Status Handlers.
215.		 */
216.		XIic_SetStatusHandler(&IicInstance, &IicInstance,
217.					  (XIic_StatusHandler) StatusHandler);
218.		XIic_SetSendHandler(&IicInstance, &IicInstance,
219.					(XIic_Handler) SendHandler);
220.		XIic_SetRecvHandler(&IicInstance, &IicInstance,
221.					(XIic_Handler) ReceiveHandler);
222.	 
223.	//	xil_printf("i2c slave example begin test2\r\n");
224.		/*
225.		 * Set the Address as a RESPOND type.
226.		 */
227.		Status = XIic_SetAddress(&IicInstance, XII_ADDR_TO_RESPOND_TYPE,
228.					 SLAVE_ADDRESS);
229.		if (Status != XST_SUCCESS) {
230.			return XST_FAILURE;
231.		}
232.	 
233.	//	xil_printf("i2c slave example begin test3\r\n");
234.		/*
235.		 * The IIC Master on this bus should initiate the transfer
236.		 * and write data to the slave at this instance.
237.		 */
238.		while(1)
239.		{
240.			xil_printf("i2c slave example recv data\r\n");
241.			SlaveReadData(ReadBuffer, RECEIVE_COUNT);
242.	 
243.	 
244.			delay_SL(0x1fffff);
245.	 
246.		}
247.			for (Index = 0; Index < SEND_COUNT; Index++) {
248.				WriteBuffer[Index] = Index;
249.			}
250.	 
251.			xil_printf("i2c slave example write data to master\r\n");
252.			/*
253.			 * The IIC Master on this bus should initiate the transfer
254.			 * and read data from the slave.
255.			 */
256.			SlaveWriteData(SEND_COUNT);
257.	 
258.	 
259.		return XST_SUCCESS;
260.	}
261.	 

My Slave Read function looks like this:

275.	int SlaveReadData(u8 *BufferPtr, u16 ByteCount)
276.	{
277.		int Status;
278.		int i=0;
279.	 
280.		/*
281.		 * Set the defaults.
282.		 */
283.		ReceiveComplete = 1;
284.	 
285.		/*
286.		 * Start the IIC device.
287.		 */
288.		//xil_printf("i2c slave example begin test4\r\n");
289.		Status = XIic_Start(&IicInstance);
290.		if (Status != XST_SUCCESS) {
291.			return XST_FAILURE;
292.		}
293.	 
294.		/*
295.		 * Set the Global Interrupt Enable.
296.		 */
297.		XIic_IntrGlobalEnable(IicInstance.BaseAddress);
298.	 
299.		//xil_printf("i2c slave example begin test5\r\n");
300.	 
301.	
302.	
303.	
304.	 
305.		
306.	 
307.
308.		/*
309.		 * Wait for AAS interrupt and completion of data reception.
310.		 */
311.		while ((ReceiveComplete) || (XIic_IsIicBusy(&IicInstance) == TRUE)) {
312.			if (SlaveRead) {
313.				XIic_SlaveRecv(&IicInstance, ReadBuffer, RECEIVE_COUNT);
314.				SlaveRead = 0;
315.			}
316.		}
317.		xil_printf("\r\n slave readbuffer is \r\n");
318.		for(i=0;i<25;i+=6)
319.		{
320.			xil_printf("[%d] 0x%x [%d] 0x%x [%d] 0x%x [%d] 0x%x [%d] 0x%x [%d] 0x%x\r\n",i,ReadBuffer[i],i+1,ReadBuffer[i+1],i+2,ReadBuffer[i+2],i+3,ReadBuffer[i+3],i+4,ReadBuffer[i+4],i+5,ReadBuffer[i+5]);
321.		}
322.	//	xil_printf("i2c slave example begin test6\r\n");
323.		/*
324.		 * Disable the Global Interrupt Enable.
325.		 */
326.		XIic_IntrGlobalDisable(IicInstance.BaseAddress);
327.	 
328.	//	xil_printf("i2c slave example begin test7\r\n");
329.		/*
330.		 * Stop the IIC device.
331.		 */
332.		Status = XIic_Stop(&IicInstance);
333.		if (Status != XST_SUCCESS) {
334.			return XST_FAILURE;
335.		}
336.	 
337.		return XST_SUCCESS;
338.	}

The interrupt setup looks like this:

 

 

489.	static int SetupInterruptSystem(XIic * IicInstPtr)
490.	{
491.	#if 0
492.		int Status;
493.	 
494.		if (InterruptController.IsStarted == XIL_COMPONENT_IS_STARTED) {
495.			return XST_SUCCESS;
496.		}
497.	 
498.		/*
499.		 * Initialize the interrupt controller driver so that it's ready to use.
500.		 */
501.		Status = XIntc_Initialize(&InterruptController, INTC_DEVICE_ID);
502.		if (Status != XST_SUCCESS) {
503.			return XST_FAILURE;
504.		}
505.	 
506.		/*
507.		 * Connect the device driver handler that will be called when an
508.		 * interrupt for the device occurs, the handler defined above
509.		 * performs the specific interrupt processing for the device.
510.		 */
511.		Status = XIntc_Connect(&InterruptController, IIC_INTR_ID,
512.					   (XInterruptHandler) XIic_InterruptHandler,
513.					   IicInstPtr);
514.		if (Status != XST_SUCCESS) {
515.			return XST_FAILURE;
516.		}
517.	 
518.		/*
519.		 * Start the interrupt controller so interrupts are enabled for all
520.		 * devices that cause interrupts.
521.		 */
522.		Status = XIntc_Start(&InterruptController, XIN_REAL_MODE);
523.		if (Status != XST_SUCCESS) {
524.			return XST_FAILURE;
525.		}
526.	 
527.		/*
528.		 * Enable the interrupts for the IIC device.
529.		 */
530.		XIntc_Enable(&InterruptController, IIC_INTR_ID);
531.	 
532.		/*
533.		 * Initialize the exception table.
534.		 */
535.		Xil_ExceptionInit();
536.	 
537.		/*
538.		 * Register the interrupt controller handler with the exception table.
539.		 */
540.		Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
541.					 (Xil_ExceptionHandler) XIntc_InterruptHandler,
542.					 &InterruptController);
543.	 
544.		/*
545.		 * Enable non-critical exceptions.
546.		 */
547.		Xil_ExceptionEnable();
548.	 
549.	 
550.		return XST_SUCCESS;
551.	#endif
552.	 
553.		int Status;
554.		XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */
555.	 
556.		Xil_ExceptionInit();
557.	 
558.		/*
559.		 * Initialize the interrupt controller driver so that it is ready to
560.		 * use.
561.		 */
562.		IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
563.		if (NULL == IntcConfig) {
564.			return XST_FAILURE;
565.		}
566.	 
567.		Status = XScuGic_CfgInitialize(&InterruptController, IntcConfig,
568.						IntcConfig->CpuBaseAddress);
569.		if (Status != XST_SUCCESS) {
570.			return XST_FAILURE;
571.		}
572.	 
573.	 
574.		/*
575.		 * Connect the interrupt controller interrupt handler to the hardware
576.		 * interrupt handling logic in the processor.
577.		 */
578.		Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
579.					(Xil_ExceptionHandler)XScuGic_InterruptHandler,
580.					&InterruptController);
581.	 
582.		/*
583.		 * Connect the device driver handler that will be called when an
584.		 * interrupt for the device occurs, the handler defined above performs
585.		 * the specific interrupt processing for the device.
586.		 */
587.		Status = XScuGic_Connect(&InterruptController, IIC_INT_VEC_ID,
588.				(Xil_InterruptHandler)XIic_InterruptHandler,
589.				(void *)IicInstPtr);
590.		if (Status != XST_SUCCESS) {
591.			return Status;
592.		}
593.	 
594.		/*
595.		 * Enable the interrupt for the Iic device.
596.		 */
597.		XScuGic_Enable(&InterruptController, IIC_INT_VEC_ID);
598.	 
599.	 
600.		/*
601.		 * Enable interrupts in the Processor.
602.		 */
603.		Xil_ExceptionEnable();
604.	 
605.		return XST_SUCCESS;
606.	}

The rest of the code is same as in xiic_slave_example. 

There is no error while building and interrupt works well each time master send data. However, the receiving is only 1 byte and then throttle. Furthermore, Master is not using repeated start mode. 

In xiic_slave.c its mentioned to XIic_SlaveRecv fucntion:
* The slave will always receive 1 byte before the bus is throttled causing a
* receive pending interrupt before this routine is executed. After one byte
* the bus will throttle. The depth is set to the proper amount immediatelly
* allowing the master to send more bytes and then to again throttle, but at the
* proper fifo depth. The interrupt is a level. Clearing and enabling will cause
* the Rx interrupt to pend at the correct level.

But I can't understand this clearly, any insight will be much appreciated. 

Thank you so much,

 

0 Kudos
0 Replies