Hello,
I've been trying to no avail to make use of both the I2C buses available on the Zedboard. I only have 2 devices, but they're connected to different external pins and given I have 2 busses I see no reason to make them share the lines.I've been working on a design and successfully implemented the first device. When I went to add the second Bus on the Zedboard output; however, when I enable the second bus the first device stops working and gets hung not receiving interrupts. This is kind of annoying and I can't find a solution so I'm moving on for now and setting them both up on the same bus, but I'm hoping someone can direct me towards a tutorial on how to make use of both the busses,
This was my initial I2C code from when I only had one bus enabled (It's based heavily on the example https://github.com/Xilinx/embeddedsw/blob/master/XilinxProcessorIPLib/drivers/iicps/examples/xiicps_intr_master_example.… )
int SetupIIC(){
XIicPs_Config *Config;
int Status;
print("DAC IIC TEST\n\r");
Config = XIicPs_LookupConfig(XPAR_XIICPS_0_DEVICE_ID);
if (NULL == Config) {
return XST_FAILURE;
}
print("IIC Lookup Config Done \n\r");
Status = XIicPs_CfgInitialize(&Iic, Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
print("IIC Cfg Initialize Done\n\r");
/*
* Perform a self-test to ensure that the hardware was built correctly.
*/
Status = XIicPs_SelfTest(&Iic);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
print("IIC Self Test Done\n\r");
Status = SetupInterruptSystem(&Iic);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
print("IIC Interrupts Setup\n\r");
XIicPs_SetStatusHandler(&Iic, (void *) &Iic, Handler);
print("IIC Status Handler Setup\n\r");
XIicPs_SetSClk(&Iic, IIC_SCLK_RATE);
Status = XIicPs_SetOptions(&Iic, XIICPS_7_BIT_ADDR_OPTION || XIICPS_REP_START_OPTION);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
print("IIC 7 BIT Address Mode, repeated start\n\r");
print("IIC Setup Complete\n\r");
return XST_SUCCESS;
}
void Handler(void *CallBackRef, u32 Event)
{
/*
* All of the data transfer has been finished.
*/
if (0 != (Event & XIICPS_EVENT_COMPLETE_RECV)){
RecvComplete = TRUE;
} else if (0 != (Event & XIICPS_EVENT_COMPLETE_SEND)) {
SendComplete = TRUE;
} else if (0 != (Event & XIICPS_EVENT_NACK)) {
TotalNack++;
} else if (0 == (Event & XIICPS_EVENT_SLAVE_RDY)){
/*
* If it is other interrupt but not slave ready interrupt, it is
* an error.
* Data was received with an error.
*/
TotalErrorCount++;
}
}
static int SetupInterruptSystem(XIicPs *IicPsPtr)
{
int Status;
XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */
Xil_ExceptionInit();
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(&InterruptController, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&InterruptController);
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(&InterruptController, IIC_INT_VEC_ID,
(Xil_InterruptHandler)XIicPs_MasterInterruptHandler,
(void *)IicPsPtr);
if (Status != XST_SUCCESS) {
return Status;
}
/*
* Enable the interrupt for the Iic device.
*/
XScuGic_Enable(&InterruptController, IIC_INT_VEC_ID);
/*
* Enable interrupts in the Processor.
*/
Xil_ExceptionEnable();
return XST_SUCCESS;
}
This is what I ended at when trying to use multiple buses
/*****************************************************************************/
/**
*
* This function is the handler which performs processing to handle data events
* from the IIC. It is called from an interrupt context such that the amount
* of processing performed should be minimized.
*
* This handler provides an example of how to handle data for the IIC and
* is application specific.
*
* @param CallBackRef contains a callback reference from the driver, in
* this case it is the instance pointer for the IIC driver.
* @param Event contains the specific kind of event that has occurred.
*
* @return None.
*
* @note None.
*
*******************************************************************************/
void AD5391_Handler(void *CallBackRef, u32 Event)
{
/*
* All of the data transfer has been finished.
*/
if (0 != (Event & XIICPS_EVENT_COMPLETE_RECV)){
AD5391_RecvComplete = TRUE;
} else if (0 != (Event & XIICPS_EVENT_COMPLETE_SEND)) {
AD5391_SendComplete = TRUE;
} else if (0 != (Event & XIICPS_EVENT_NACK)) {
AD5391_TotalNack++;
} else if (0 == (Event & XIICPS_EVENT_SLAVE_RDY)){
/*
* If it is other interrupt but not slave ready interrupt, it is
* an error.
* Data was received with an error.
*/
AD5391_TotalErrorCount++;
}
}
void HDMI_Handler(void *CallBackRef, u32 Event)
{
/*
* All of the data transfer has been finished.
*/
if (0 != (Event & XIICPS_EVENT_COMPLETE_RECV)){
HDMI_RecvComplete = TRUE;
} else if (0 != (Event & XIICPS_EVENT_COMPLETE_SEND)) {
HDMI_SendComplete = TRUE;
} else if (0 != (Event & XIICPS_EVENT_NACK)) {
HDMI_TotalNack++;
} else if (0 == (Event & XIICPS_EVENT_SLAVE_RDY)){
/*
* If it is other interrupt but not slave ready interrupt, it is
* an error.
* Data was received with an error.
*/
HDMI_TotalErrorCount++;
}
}
/******************************************************************************/
/**
*
* This function setups the interrupt system such that interrupts can occur
* for the IIC. This function is application specific since the actual
* system may or may not have an interrupt controller. The IIC could be
* directly connected to a processor without an interrupt controller. The
* user should modify this function to fit the application.
*
* @param IicPsPtr contains a pointer to the instance of the Iic
* which is going to be connected to the interrupt controller.
*
* @return XST_SUCCESS if successful, otherwise XST_FAILURE.
*
* @note None.
*
*******************************************************************************/
static int SetupInterruptSystem(XIicPs *IicPsPtr, XIicPs *IicPsPtr1)
{
int Status;
XScuGic_Config *IntcConfig; /* Instance of the interrupt controller */
/*
* Initialize the interrupt controller driver so that it is ready to
* use.
*/
IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
if (NULL == IntcConfig) {
return XST_FAILURE;
}
Status = XScuGic_CfgInitialize(&InterruptController, IntcConfig,
IntcConfig->CpuBaseAddress);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
Status = XScuGic_SelfTest(&InterruptController);
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
/*
* Connect the interrupt controller interrupt handler to the hardware
* interrupt handling logic in the processor.
*/
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
(Xil_ExceptionHandler)XScuGic_InterruptHandler,
&InterruptController);
/*
* Enable non-critical exceptions.
*/
Xil_ExceptionEnable();
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
Status = XScuGic_Connect(&InterruptController, IIC_INT_VEC_ID_AD5391,
(Xil_InterruptHandler)XIicPs_MasterInterruptHandler,
(void *)IicPsPtr);
if (Status != XST_SUCCESS) {
return Status;
}
XScuGic_Enable(&InterruptController, IIC_INT_VEC_ID_AD5391);
//XScuGic_SetPriorityTriggerType(&InterruptController, IIC_INT_VEC_ID_AD5391, 0XA0 , 0x3) ;
Status = XScuGic_Connect(&InterruptController, IIC_INT_VEC_ID_HDMI,
(Xil_InterruptHandler)XIicPs_MasterInterruptHandler,
(void *)IicPsPtr1);
if (Status != XST_SUCCESS) {
return Status;
}
XScuGic_Enable(&InterruptController, IIC_INT_VEC_ID_HDMI);
//XScuGic_SetPriorityTriggerType(&InterruptController, IIC_INT_VEC_ID_HDMI, 0XA8 , 0x3) ;
return XST_SUCCESS;
}
Any advice or directions to an appropriate tutorial would be much appreciated.