/** * This function disables slave monitor mode. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_DisableSlaveMonitor(XIicPs *InstancePtr) { u32 BaseAddr; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* * Clear slave monitor control bit. */ XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_SLVMON_MASK)); /* * wait for slv monitor control bit to be clear */ while (XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & XIICPS_CR_SLVMON_MASK); /* * Clear interrupt flag for slave monitor interrupt. */ XIicPs_DisableInterrupts(BaseAddr, XIICPS_IXR_SLV_RDY_MASK); return; }
/** * This function perform the reset sequence to the given I2c interface by * configuring the appropriate control bits in the I2c specifc registers * the i2cps reset squence involves the following steps * Disable all the interuupts * Clear the status * Clear FIFO's and disable hold bit * Clear the line status * Update relevant config registers with reset values * * @param BaseAddress of the interface * * @return N/A * * @note * This function will not modify the slcr registers that are relavant for * I2c controller ******************************************************************************/ void XIicPs_ResetHw(u32 BaseAddress) { u32 RegVal; /* Disable all the interrupts */ XIicPs_WriteReg(BaseAddress, XIICPS_IDR_OFFSET, XIICPS_IXR_ALL_INTR_MASK); /* Clear the interrupt status */ RegVal = XIicPs_ReadReg(BaseAddress,XIICPS_ISR_OFFSET); XIicPs_WriteReg(BaseAddress, XIICPS_ISR_OFFSET, RegVal); /* Clear the hold bit,master enable bit and ack bit */ RegVal = XIicPs_ReadReg(BaseAddress,XIICPS_CR_OFFSET); RegVal &= ~(XIICPS_CR_HOLD_MASK|XIICPS_CR_MS_MASK|XIICPS_CR_ACKEN_MASK); /* Clear the fifos */ RegVal |= XIICPS_CR_CLR_FIFO_MASK; XIicPs_WriteReg(BaseAddress, XIICPS_CR_OFFSET, RegVal); /* Clear the timeout register */ XIicPs_WriteReg(BaseAddress, XIICPS_TIME_OUT_OFFSET, 0x0); /* Clear the transfer size register */ XIicPs_WriteReg(BaseAddress, XIICPS_TRANS_SIZE_OFFSET, 0x0); /* Clear the status register */ RegVal = XIicPs_ReadReg(BaseAddress,XIICPS_SR_OFFSET); XIicPs_WriteReg(BaseAddress, XIICPS_SR_OFFSET, RegVal); /* Update the configuraqtion register with reset value */ XIicPs_WriteReg(BaseAddress, XIICPS_CR_OFFSET, 0x0); }
/** * This function initiates an interrupt-driven send in master mode. * * It tries to send the first FIFO-full of data, then lets the interrupt * handler to handle the rest of the data if there is any. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the send buffer. * @param ByteCount is the number of bytes to be sent. * @param SlaveAddr is the address of the slave we are sending to. * * @return None. * * @note This send routine is for interrupt-driven transfer only. * ****************************************************************************/ void XIicPs_MasterSend(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount, u16 SlaveAddr) { u32 BaseAddr; u32 Platform = XGetPlatform_Info(); /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; InstancePtr->RecvBufferPtr = NULL; InstancePtr->IsSend = 1; /* * Set repeated start if sending more than FIFO of data. */ if (((InstancePtr->IsRepeatedStart) != 0)|| ((ByteCount > XIICPS_FIFO_DEPTH) != 0U)) { XIicPs_WriteReg(BaseAddr, (u32)XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) | (u32)XIICPS_CR_HOLD_MASK); } /* * Setup as a master sending role. */ (void)XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); (void)TransmitFifoFill(InstancePtr); XIicPs_EnableInterrupts(BaseAddr, (u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_COMP_MASK | (u32)XIICPS_IXR_ARB_LOST_MASK); /* * Do the address transfer to notify the slave. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr); /* Clear the Hold bit in ZYNQ if receive byte count is less than * the FIFO depth to get the completion interrupt properly. */ if ((ByteCount < XIICPS_FIFO_DEPTH) && (Platform == (u32)XPLAT_ZYNQ)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) & (u32)(~XIICPS_CR_HOLD_MASK)); } }
/** * * This function gets the options for the IIC device. The options control how * the device behaves relative to the IIC bus. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return 32 bit mask of the options, where a 1 means the option is on, * and a 0 means to the option is off. One or more bit values may * be contained in the mask. See the bit definitions named * XIICPS_*_OPTION in the file xiicps.h. * * @note None. * ******************************************************************************/ u32 XIicPs_GetOptions(XIicPs *InstancePtr) { u32 OptionsFlag = 0; u32 ControlReg; unsigned int Index; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Read control register to find which options are currently set. */ ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET); /* * Loop through the options table to determine which options are set. */ for (Index = 0; Index < XIICPS_NUM_OPTIONS; Index++) { if (ControlReg & OptionsTable[Index].Mask) { OptionsFlag |= OptionsTable[Index].Option; } if ((ControlReg & XIICPS_CR_NEA_MASK) == 0) { OptionsFlag |= XIICPS_10_BIT_ADDR_OPTION; } } return OptionsFlag; }
/** * Put more data into the transmit FIFO, number of bytes is ether expected * number of bytes for this transfer or available space in FIFO, which ever * is less. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return Number of bytes left for this instance. * * @note This is function is shared by master and slave. * ******************************************************************************/ int TransmitFifoFill(XIicPs *InstancePtr) { u8 AvailBytes; int LoopCnt; int NumBytesToSend; /* * Determine number of bytes to write to FIFO. */ AvailBytes = XIICPS_FIFO_DEPTH - XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_TRANS_SIZE_OFFSET); if (InstancePtr->SendByteCount > AvailBytes) { NumBytesToSend = AvailBytes; } else { NumBytesToSend = InstancePtr->SendByteCount; } /* * Fill FIFO with amount determined above. */ for (LoopCnt = 0; LoopCnt < NumBytesToSend; LoopCnt++) { XIicPs_SendByte(InstancePtr); } return InstancePtr->SendByteCount; }
/** * This function enables the slave monitor mode. * * It enables slave monitor in the control register and enables * slave ready interrupt. It then does an address transfer to slave. * Interrupt handler will signal the caller if slave responds to * the address transfer. * * @param InstancePtr is a pointer to the XIicPs instance. * @param SlaveAddr is the address of the slave we want to contact. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_EnableSlaveMonitor(XIicPs *InstancePtr, u16 SlaveAddr) { u32 BaseAddr; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* * Enable slave monitor mode in control register. */ XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_MS_MASK | XIICPS_CR_NEA_MASK | XIICPS_CR_SLVMON_MASK ); /* * Set up interrupt flag for slave monitor interrupt. */ XIicPs_EnableInterrupts(BaseAddr, XIICPS_IXR_NACK_MASK | XIICPS_IXR_SLV_RDY_MASK); /* * Initialize the slave monitor register. */ XIicPs_WriteReg(BaseAddr, XIICPS_SLV_PAUSE_OFFSET, 0xF); /* * Set the slave address to start the slave address transmission. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); return; }
/* * * This function handles continuation of receiving data. It is invoked * from interrupt handler. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return Number of bytes still expected by the instance. * * @note None. * ****************************************************************************/ static int SlaveRecvData(XIicPs *InstancePtr) { volatile u32 StatusReg; u32 BaseAddr; BaseAddr = InstancePtr->Config.BaseAddress; StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); while (StatusReg & XIICPS_SR_RXDV_MASK) { XIicPs_RecvByte(InstancePtr); StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); } return InstancePtr->RecvByteCount; }
/** * * This function clears the options for the IIC device driver. The options * control how the device behaves relative to the IIC bus. The device must be * idle rather than busy transferring data before setting these device options. * * @param InstancePtr is a pointer to the XIicPs instance. * @param Options contains the specified options to be cleared. This is a * bit mask where a 1 means to turn the option off. One or more bit * values may be contained in the mask. See the bit definitions * named XIICPS_*_OPTION in xiicps.h. * * @return * - XST_SUCCESS if options are successfully set. * - XST_DEVICE_IS_STARTED if the device is currently transferring * data. The transfer must complete or be aborted before setting * options. * * @note None * ******************************************************************************/ int XIicPs_ClearOptions(XIicPs *InstancePtr, u32 Options) { u32 ControlReg; unsigned int Index; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET); /* * If repeated start option is cleared, set the flag. * The hold bit in CR will be cleared by driver when the * following transfer ends. */ if (Options & XIICPS_REP_START_OPTION) { InstancePtr->IsRepeatedStart = 0; Options = Options & (~XIICPS_REP_START_OPTION); } /* * Loop through the options table and clear the specified options. */ for (Index = 0; Index < XIICPS_NUM_OPTIONS; Index++) { if (Options & OptionsTable[Index].Option) { /* * 10-bit option is specially treated, because it is * using the 7-bit option, so clearing it means turning * 7-bit option on. */ if (OptionsTable[Index].Option & XIICPS_10_BIT_ADDR_OPTION) { /* Turn 7-bit on */ ControlReg |= OptionsTable[Index].Mask; } else { /* Turn 7-bit off */ ControlReg &= ~OptionsTable[Index].Mask; } } } /* * Now write the control register. Leave it to the upper layers * to restart the device. */ XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, ControlReg); /* * Keep a copy of what options this instance has. */ InstancePtr->Options = XIicPs_GetOptions(InstancePtr); return XST_SUCCESS; }
/* * * This function handles continuation of receiving data. It is invoked * from interrupt handler. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return Number of bytes still expected by the instance. * * @note None. * ****************************************************************************/ static s32 SlaveRecvData(XIicPs *InstancePtr) { u32 StatusReg; u32 BaseAddr; BaseAddr = InstancePtr->Config.BaseAddress; StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); while (((StatusReg & XIICPS_SR_RXDV_MASK)!=0x0U) && ((InstancePtr->RecvByteCount > 0) != 0x0U)) { XIicPs_RecvByte(InstancePtr); StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); } return InstancePtr->RecvByteCount; }
/** * This function initiates an interrupt-driven receive in master mode. * * It sets the transfer size register so the slave can send data to us. * The rest of the work is managed by interrupt handler. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the receive buffer. * @param ByteCount is the number of bytes to be received. * @param SlaveAddr is the address of the slave we are receiving from. * * @return None. * * @note This receive routine is for interrupt-driven transfer only. * ****************************************************************************/ void XIicPs_MasterRecv(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount, u16 SlaveAddr) { u32 BaseAddr; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->RecvBufferPtr = MsgPtr; InstancePtr->RecvByteCount = ByteCount; InstancePtr->CurrByteCount = ByteCount; InstancePtr->SendBufferPtr = NULL; InstancePtr->IsSend = 0; InstancePtr->UpdateTxSize = 0; if ((ByteCount > XIICPS_DATA_INTR_DEPTH) || (InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_HOLD_MASK); } /* * Initialize for a master receiving role. */ XIicPs_SetupMaster(InstancePtr, RECVING_ROLE); /* * Do the address transfer to signal the slave. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); /* * Setup the transfer size register so the slave knows how much * to send to us. */ if (ByteCount > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); InstancePtr->CurrByteCount = XIICPS_MAX_TRANSFER_SIZE; InstancePtr->UpdateTxSize = 1; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, ByteCount); } XIicPs_EnableInterrupts(BaseAddr, XIICPS_IXR_NACK_MASK | XIICPS_IXR_DATA_MASK | XIICPS_IXR_RX_OVR_MASK | XIICPS_IXR_COMP_MASK | XIICPS_IXR_ARB_LOST_MASK); }
/** * * This function sets the options for the IIC device driver. The options control * how the device behaves relative to the IIC bus. The device must be idle * rather than busy transferring data before setting these device options. * * @param InstancePtr is a pointer to the XIicPs instance. * @param Options contains the specified options to be set. This is a bit * mask where a 1 means to turn the option on. One or more bit * values may be contained in the mask. See the bit definitions * named XIICPS_*_OPTION in xiicps.h. * * @return * - XST_SUCCESS if options are successfully set. * - XST_DEVICE_IS_STARTED if the device is currently transferring * data. The transfer must complete or be aborted before setting * options. * * @note None. * ******************************************************************************/ s32 XIicPs_SetOptions(XIicPs *InstancePtr, u32 Options) { u32 ControlReg; u32 Index; u32 OptionsVar = Options; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET); /* * If repeated start option is requested, set the flag. * The hold bit in CR will be written by driver when the next transfer * is initiated. */ if ((OptionsVar & (u32)XIICPS_REP_START_OPTION) != (u32)0 ) { InstancePtr->IsRepeatedStart = 1; OptionsVar = OptionsVar & (~XIICPS_REP_START_OPTION); } /* * Loop through the options table, turning the option on. */ for (Index = 0U; Index < XIICPS_NUM_OPTIONS; Index++) { if ((OptionsVar & OptionsTable[Index].Option) != (u32)0x0U) { /* * 10-bit option is specially treated, because it is * using the 7-bit option, so turning it on means * turning 7-bit option off. */ if ((OptionsTable[Index].Option & XIICPS_10_BIT_ADDR_OPTION) != (u32)0x0U) { /* Turn 7-bit off */ ControlReg &= ~OptionsTable[Index].Mask; } else { /* Turn 7-bit on */ ControlReg |= OptionsTable[Index].Mask; } } } /* * Now write to the control register. Leave it to the upper layers * to restart the device. */ XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, ControlReg); /* * Keep a copy of what options this instance has. */ InstancePtr->Options = XIicPs_GetOptions(InstancePtr); return (s32)XST_SUCCESS; }
/* * IIC Busy? */ int isIicBusBusy(XIicPs* IicPs) { u32 StatusReg = 0; StatusReg = XIicPs_ReadReg(IicPs->Config.BaseAddress, XIICPS_SR_OFFSET); if (StatusReg & XIICPS_SR_BA_MASK) { return TRUE; } else { return FALSE; } }
/** * * Runs a self-test on the driver/device. The self-test is destructive in that * a reset of the device is performed in order to check the reset values of * the registers and to get the device into a known state. * * Upon successful return from the self-test, the device is reset. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return * - XST_SUCCESS if successful. * - XST_REGISTER_ERROR indicates a register did not read or write * correctly * * @note None. * ******************************************************************************/ int XIicPs_SelfTest(XIicPs *InstancePtr) { Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * All the IIC registers should be in their default state right now. */ if ((XIICPS_CR_RESET_VALUE != XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET)) || (XIICPS_TO_RESET_VALUE != XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_TIME_OUT_OFFSET)) || (XIICPS_IXR_ALL_INTR_MASK != XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_IMR_OFFSET))) { return XST_FAILURE; } XIicPs_Reset(InstancePtr); /* * Write, Read then write a register */ XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_SLV_PAUSE_OFFSET, REG_TEST_VALUE); if (REG_TEST_VALUE != XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_SLV_PAUSE_OFFSET)) { return XST_FAILURE; } XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_SLV_PAUSE_OFFSET, 0); XIicPs_Reset(InstancePtr); return XST_SUCCESS; }
/** * Check whether the I2C bus is busy * * @param InstancePtr is a pointer to the XIicPs instance. * * @return * - TRUE if the bus is busy. * - FALSE if the bus is not busy. * * @note None. * ******************************************************************************/ int XIicPs_BusIsBusy(XIicPs *InstancePtr) { u32 StatusReg; StatusReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_SR_OFFSET); if (StatusReg & XIICPS_SR_BA_MASK) { return TRUE; }else { return FALSE; } }
/** * * Aborts a transfer in progress by resetting the FIFOs. The byte counts are * cleared. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ******************************************************************************/ void XIicPs_Abort(XIicPs *InstancePtr) { u32 IntrMaskReg; u32 IntrStatusReg; Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Enter a critical section, so disable the interrupts while we clear * the FIFO and the status register. */ IntrMaskReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_IMR_OFFSET); XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_IDR_OFFSET, XIICPS_IXR_ALL_INTR_MASK); /* * Clear the FIFOs. */ XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, XIICPS_CR_CLR_FIFO_MASK); /* * Read, then write the interrupt status to make sure there are no * pending interrupts. */ IntrStatusReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_ISR_OFFSET); XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Restore the interrupt state. */ IntrMaskReg = XIICPS_IXR_ALL_INTR_MASK & (~IntrMaskReg); XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_IER_OFFSET, IntrMaskReg); }
/** * Check whether the I2C bus is busy * * @param InstancePtr is a pointer to the XIicPs instance. * * @return * - TRUE if the bus is busy. * - FALSE if the bus is not busy. * * @note None. * ******************************************************************************/ s32 XIicPs_BusIsBusy(XIicPs *InstancePtr) { u32 StatusReg; s32 Status; StatusReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_SR_OFFSET); if ((StatusReg & XIICPS_SR_BA_MASK) != 0x0U) { Status = (s32)TRUE; }else { Status = (s32)FALSE; } return Status; }
/** * This function initiates an interrupt-driven send in master mode. * * It tries to send the first FIFO-full of data, then lets the interrupt * handler to handle the rest of the data if there is any. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the send buffer. * @param ByteCount is the number of bytes to be sent. * @param SlaveAddr is the address of the slave we are sending to. * * @return None. * * @note This send routine is for interrupt-driven transfer only. * ****************************************************************************/ void XIicPs_MasterSend(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount, u16 SlaveAddr) { u32 BaseAddr; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(MsgPtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertVoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; InstancePtr->RecvBufferPtr = NULL; InstancePtr->IsSend = 1; /* * Set repeated start if sending more than FIFO of data. */ if ((InstancePtr->IsRepeatedStart) || (ByteCount > XIICPS_FIFO_DEPTH)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_HOLD_MASK); } /* * Setup as a master sending role. */ XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); /* * Do the address transfer to notify the slave. */ XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); TransmitFifoFill(InstancePtr); XIicPs_EnableInterrupts(BaseAddr, XIICPS_IXR_NACK_MASK | XIICPS_IXR_COMP_MASK | XIICPS_IXR_ARB_LOST_MASK); }
/** * * This function sets the options for the IIC device driver. The options control * how the device behaves relative to the IIC bus. The device must be idle * rather than busy transferring data before setting these device options. * * @param InstancePtr is a pointer to the XIicPs instance. * @param Options contains the specified options to be set. This is a bit * mask where a 1 means to turn the option on. One or more bit * values may be contained in the mask. See the bit definitions * named XIICPS_*_OPTION in xiicps.h. * * @return * - XST_SUCCESS if options are successfully set. * - XST_DEVICE_IS_STARTED if the device is currently transferring * data. The transfer must complete or be aborted before setting * options. * * @note None. * ******************************************************************************/ int XIicPs_SetOptions(XIicPs *InstancePtr, u32 Options) { u32 ControlReg; unsigned int Index; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET); /* * Loop through the options table, turning the option on. */ for (Index = 0; Index < XIICPS_NUM_OPTIONS; Index++) { if (Options & OptionsTable[Index].Option) { /* * 10-bit option is specially treated, because it is * using the 7-bit option, so turning it on means * turning 7-bit option off. */ if (OptionsTable[Index].Option & XIICPS_10_BIT_ADDR_OPTION) { /* Turn 7-bit off */ ControlReg &= ~OptionsTable[Index].Mask; } else { /* Turn 7-bit on */ ControlReg |= OptionsTable[Index].Mask; } } } /* * Now write to the control register. Leave it to the upper layers * to restart the device. */ XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, ControlReg); /* * Keep a copy of what options this instance has. */ InstancePtr->Options = XIicPs_GetOptions(InstancePtr); return XST_SUCCESS; }
/* * This function prepares a device to transfers as a master. * * @param InstancePtr is a pointer to the XIicPs instance. * * @param Role specifies whether the device is sending or receiving. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if bus is busy. * * @note Interrupts are always disabled, device which needs to use * interrupts needs to setup interrupts after this call. * ****************************************************************************/ static int XIicPs_SetupMaster(XIicPs *InstancePtr, int Role) { u32 ControlReg; u32 BaseAddr; u32 EnabledIntr = 0x0; Xil_AssertNonvoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; ControlReg = XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET); /* * Only check if bus is busy when repeated start option is not set. */ if ((ControlReg & XIICPS_CR_HOLD_MASK) == 0) { if (XIicPs_BusIsBusy(InstancePtr)) { return XST_FAILURE; } } /* * Set up master, AckEn, nea and also clear fifo. */ ControlReg |= XIICPS_CR_ACKEN_MASK | XIICPS_CR_CLR_FIFO_MASK | XIICPS_CR_NEA_MASK | XIICPS_CR_MS_MASK; if (Role == RECVING_ROLE) { ControlReg |= XIICPS_CR_RD_WR_MASK; EnabledIntr = XIICPS_IXR_DATA_MASK |XIICPS_IXR_RX_OVR_MASK; }else { ControlReg &= ~XIICPS_CR_RD_WR_MASK; } EnabledIntr |= XIICPS_IXR_COMP_MASK | XIICPS_IXR_ARB_LOST_MASK; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, ControlReg); XIicPs_DisableAllInterrupts(BaseAddr); return XST_SUCCESS; }
/** * * This function gets the serial clock rate for the IIC device. The device * must be idle rather than busy transferring data before setting these device * options. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return The value of the IIC clock to the nearest Hz based on the * control register settings. The actual value may not be exact to * to integer math rounding errors. * * @note None. * ******************************************************************************/ u32 XIicPs_GetSClk(XIicPs *InstancePtr) { u32 ControlReg; u32 ActualFscl; u32 Div_a; u32 Div_b; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET); Div_a = (ControlReg & XIICPS_CR_DIV_A_MASK) >> XIICPS_CR_DIV_A_SHIFT; Div_b = (ControlReg & XIICPS_CR_DIV_B_MASK) >> XIICPS_CR_DIV_B_SHIFT; ActualFscl = (InstancePtr->Config.InputClockHz) / (22 * (Div_a + 1) * (Div_b + 1)); return ActualFscl; }
/** * This function enables the slave monitor mode. * * It enables slave monitor in the control register and enables * slave ready interrupt. It then does an address transfer to slave. * Interrupt handler will signal the caller if slave responds to * the address transfer. * * @param InstancePtr is a pointer to the XIicPs instance. * @param SlaveAddr is the address of the slave we want to contact. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_EnableSlaveMonitor(XIicPs *InstancePtr, u16 SlaveAddr) { u32 BaseAddr; u32 ConfigReg; Xil_AssertVoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; /* Clear transfer size register */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_TRANS_SIZE_OFFSET, 0x0U); /* * Enable slave monitor mode in control register. */ ConfigReg = XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET); ConfigReg |= (u32)XIICPS_CR_MS_MASK | (u32)XIICPS_CR_NEA_MASK | (u32)XIICPS_CR_CLR_FIFO_MASK | (u32)XIICPS_CR_SLVMON_MASK; ConfigReg &= (u32)(~XIICPS_CR_RD_WR_MASK); XIicPs_WriteReg(BaseAddr, (u32)XIICPS_CR_OFFSET, ConfigReg); /* * Set up interrupt flag for slave monitor interrupt. * Dont enable NACK. */ XIicPs_EnableInterrupts(BaseAddr, (u32)XIICPS_IXR_SLV_RDY_MASK); /* * Initialize the slave monitor register. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_SLV_PAUSE_OFFSET, 0xFU); /* * Set the slave address to start the slave address transmission. */ XIicPs_WriteReg(BaseAddr, (u32)XIICPS_ADDR_OFFSET, (u32)SlaveAddr); return; }
/* * This function prepares a device to transfers as a master. * * @param InstancePtr is a pointer to the XIicPs instance. * * @param Role specifies whether the device is sending or receiving. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if bus is busy. * * @note Interrupts are always disabled, device which needs to use * interrupts needs to setup interrupts after this call. * ****************************************************************************/ static s32 XIicPs_SetupMaster(XIicPs *InstancePtr, s32 Role) { u32 ControlReg; u32 BaseAddr; Xil_AssertNonvoid(InstancePtr != NULL); BaseAddr = InstancePtr->Config.BaseAddress; ControlReg = XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET); /* * Only check if bus is busy when repeated start option is not set. */ if ((ControlReg & XIICPS_CR_HOLD_MASK) == 0U) { if (XIicPs_BusIsBusy(InstancePtr) == (s32)1) { return (s32)XST_FAILURE; } } /* * 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); XIicPs_DisableAllInterrupts(BaseAddr); return (s32)XST_SUCCESS; }
/* * This function handles continuation of sending data. It is invoked * from interrupt handler. * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ static void MasterSendData(XIicPs *InstancePtr) { TransmitFifoFill(InstancePtr); /* * Clear hold bit if done, so stop can be sent out. */ if (InstancePtr->SendByteCount == 0) { /* * If user has enabled repeated start as an option, * do not disable it. */ if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET) & ~ XIICPS_CR_HOLD_MASK); } } return; }
/** * The interrupt handler for the master mode. It does the protocol handling for * the interrupt-driven transfers. * * Completion events and errors are signaled to upper layer for proper handling. * * <pre> * The interrupts that are handled are: * - DATA * This case is handled only for master receive data. * The master has to request for more data (if there is more data to * receive) and read the data from the FIFO . * * - COMP * If the Master is transmitting data and there is more data to be * sent then the data is written to the FIFO. If there is no more data to * be transmitted then a completion event is signalled to the upper layer * by calling the callback handler. * * If the Master is receiving data then the data is read from the FIFO and * the Master has to request for more data (if there is more data to * receive). If all the data has been received then a completion event * is signalled to the upper layer by calling the callback handler. * It is an error if the amount of received data is more than expected. * * - NAK and SLAVE_RDY * This is signalled to the upper layer by calling the callback handler. * * - All Other interrupts * These interrupts are marked as error. This is signalled to the upper * layer by calling the callback handler. * * </pre> * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_MasterInterruptHandler(XIicPs *InstancePtr) { u32 IntrStatusReg; u32 StatusEvent = 0; u32 BaseAddr; int ByteCnt; int IsHold; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; /* * Read the Interrupt status register. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * Write the status back to clear the interrupts so no events are * missed while processing this interrupt. */ XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Use the Mask register AND with the Interrupt Status register so * disabled interrupts are not processed. */ IntrStatusReg &= ~(XIicPs_ReadReg(BaseAddr, XIICPS_IMR_OFFSET)); ByteCnt = InstancePtr->CurrByteCount; IsHold = 0; if (XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & XIICPS_CR_HOLD_MASK) { IsHold = 1; } /* * Send */ if ((InstancePtr->IsSend) && (0 != (IntrStatusReg & XIICPS_IXR_COMP_MASK))) { if (InstancePtr->SendByteCount > 0) { MasterSendData(InstancePtr); } else { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } /* * Receive */ if ((!(InstancePtr->IsSend)) && ((0 != (IntrStatusReg & XIICPS_IXR_DATA_MASK)) || (0 != (IntrStatusReg & XIICPS_IXR_COMP_MASK)))){ while (XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET) & XIICPS_SR_RXDV_MASK) { if ((InstancePtr->RecvByteCount < XIICPS_DATA_INTR_DEPTH) && IsHold && (!(InstancePtr->IsRepeatedStart))) { IsHold = 0; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } XIicPs_RecvByte(InstancePtr); ByteCnt--; if (InstancePtr->UpdateTxSize && (ByteCnt == XIICPS_FIFO_DEPTH + 1)) break; } if (InstancePtr->UpdateTxSize && (ByteCnt == XIICPS_FIFO_DEPTH + 1)) { /* * wait while fifo is full */ while(XIicPs_ReadReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET) != (ByteCnt - XIICPS_FIFO_DEPTH)); if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCnt = XIICPS_MAX_TRANSFER_SIZE + XIICPS_FIFO_DEPTH; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH); InstancePtr->UpdateTxSize = 0; ByteCnt = InstancePtr->RecvByteCount; } } InstancePtr->CurrByteCount = ByteCnt; } if ((!(InstancePtr->IsSend)) && (0 != (IntrStatusReg & XIICPS_IXR_COMP_MASK))) { /* * If all done, tell the application. */ if (InstancePtr->RecvByteCount == 0){ if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } } /* * Slave ready interrupt, it is only meaningful for master mode. */ if (0 != (IntrStatusReg & XIICPS_IXR_SLV_RDY_MASK)) { StatusEvent |= XIICPS_EVENT_SLAVE_RDY; } if (0 != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) { if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_NACK; } /* * All other interrupts are treated as error. */ if (0 != (IntrStatusReg & (XIICPS_IXR_NACK_MASK | XIICPS_IXR_ARB_LOST_MASK | XIICPS_IXR_RX_UNF_MASK | XIICPS_IXR_TX_OVR_MASK | XIICPS_IXR_RX_OVR_MASK))) { if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } StatusEvent |= XIICPS_EVENT_ERROR; } /* * Signal application if there are any events. */ if (0 != StatusEvent) { InstancePtr->StatusHandler(InstancePtr->CallBackRef, StatusEvent); } }
/** * This function initiates a polled mode receive in master mode. * * It repeatedly sets the transfer size register so the slave can * send data to us. It polls the data register for data to come in. * If slave fails to send us data, it fails with time out. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the receive buffer. * @param ByteCount is the number of bytes to be received. * @param SlaveAddr is the address of the slave we are receiving from. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if timed out. * * @note This receive routine is for polled mode transfer only. * ****************************************************************************/ int XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount, u16 SlaveAddr) { u32 IntrStatusReg; u32 Intrs; u32 StatusReg; u32 BaseAddr; int IsHold = 0; int UpdateTxSize = 0; /* * Assert validates the input arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->RecvBufferPtr = MsgPtr; InstancePtr->RecvByteCount = ByteCount; if((ByteCount > XIICPS_DATA_INTR_DEPTH) || (InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_HOLD_MASK); IsHold = 1; } XIicPs_SetupMaster(InstancePtr, RECVING_ROLE); /* * Clear the interrupt status register before use it to monitor. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); /* * Set up the transfer size register so the slave knows how much * to send to us. */ if (ByteCount > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCount = XIICPS_MAX_TRANSFER_SIZE; UpdateTxSize = 1; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, ByteCount); } /* * Intrs keeps all the error-related interrupts. */ Intrs = XIICPS_IXR_ARB_LOST_MASK | XIICPS_IXR_RX_OVR_MASK | XIICPS_IXR_RX_UNF_MASK | XIICPS_IXR_NACK_MASK; /* * Poll the interrupt status register to find the errors. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); while ((InstancePtr->RecvByteCount > 0) && ((IntrStatusReg & Intrs) == 0)) { StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); while (StatusReg & XIICPS_SR_RXDV_MASK) { if ((InstancePtr->RecvByteCount < XIICPS_DATA_INTR_DEPTH) && IsHold && (!(InstancePtr->IsRepeatedStart))) { IsHold = 0; XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } XIicPs_RecvByte(InstancePtr); ByteCount --; if (UpdateTxSize && (ByteCount == XIICPS_FIFO_DEPTH + 1)) break; StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); } if (UpdateTxSize && (ByteCount == XIICPS_FIFO_DEPTH + 1)) { /* * wait while fifo is full */ while(XIicPs_ReadReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET) != (ByteCount - XIICPS_FIFO_DEPTH)); if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) > XIICPS_MAX_TRANSFER_SIZE) { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, XIICPS_MAX_TRANSFER_SIZE); ByteCount = XIICPS_MAX_TRANSFER_SIZE + XIICPS_FIFO_DEPTH; }else { XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET, InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH); UpdateTxSize = 0; ByteCount = InstancePtr->RecvByteCount; } } IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); } if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } if (IntrStatusReg & Intrs) { return XST_FAILURE; } return XST_SUCCESS; }
/** * This function initiates a polled mode send in master mode. * * It sends data to the FIFO and waits for the slave to pick them up. * If slave fails to remove data from FIFO, the send fails with * time out. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the send buffer. * @param ByteCount is the number of bytes to be sent. * @param SlaveAddr is the address of the slave we are sending to. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if timed out. * * @note This send routine is for polled mode transfer only. * ****************************************************************************/ int XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, int ByteCount, u16 SlaveAddr) { u32 IntrStatusReg; u32 StatusReg; u32 BaseAddr; u32 Intrs; /* * Assert validates the input arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(XIICPS_ADDR_MASK >= SlaveAddr); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; if ((InstancePtr->IsRepeatedStart) || (ByteCount > XIICPS_FIFO_DEPTH)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr, XIICPS_CR_OFFSET) | XIICPS_CR_HOLD_MASK); } XIicPs_SetupMaster(InstancePtr, SENDING_ROLE); XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr); /* * Intrs keeps all the error-related interrupts. */ Intrs = XIICPS_IXR_ARB_LOST_MASK | XIICPS_IXR_TX_OVR_MASK | XIICPS_IXR_NACK_MASK; /* * Clear the interrupt status register before use it to monitor. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Transmit first FIFO full of data. */ TransmitFifoFill(InstancePtr); IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * Continue sending as long as there is more data and * there are no errors. */ while ((InstancePtr->SendByteCount > 0) && ((IntrStatusReg & Intrs) == 0)) { StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); /* * Wait until transmit FIFO is empty. */ if ((StatusReg & XIICPS_SR_TXDV_MASK) != 0) { IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); continue; } /* * Send more data out through transmit FIFO. */ TransmitFifoFill(InstancePtr); } /* * Check for completion of transfer. */ while ((IntrStatusReg & XIICPS_IXR_COMP_MASK) != XIICPS_IXR_COMP_MASK){ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * If there is an error, tell the caller. */ if ((IntrStatusReg & Intrs) != 0) { return XST_FAILURE; } } if (!(InstancePtr->IsRepeatedStart)) { XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET, XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) & (~XIICPS_CR_HOLD_MASK)); } return XST_SUCCESS; }
/** * The interrupt handler for slave mode. It does the protocol handling for * the interrupt-driven transfers. * * Completion events and errors are signaled to upper layer for proper * handling. * * <pre> * * The interrupts that are handled are: * - DATA * If the instance is sending, it means that the master wants to read more * data from us. Send more data, and check whether we are done with this * send. * * If the instance is receiving, it means that the master has writen * more data to us. Receive more data, and check whether we are done with * with this receive. * * - COMP * This marks that stop sequence has been sent from the master, transfer * is about to terminate. However, for receiving, the master may have * written us some data, so receive that first. * * It is an error if the amount of transfered data is less than expected. * * - NAK * This marks that master does not want our data. It is for send only. * * - Other interrupts * These interrupts are marked as error. * * </pre> * * @param InstancePtr is a pointer to the XIicPs instance. * * @return None. * * @note None. * ****************************************************************************/ void XIicPs_SlaveInterruptHandler(XIicPs *InstancePtr) { u32 IntrStatusReg; u32 IsSend = 0U; u32 StatusEvent = 0U; s32 LeftOver; u32 BaseAddr; /* * Assert validates the input arguments. */ Xil_AssertVoid(InstancePtr != NULL); Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; /* * Read the Interrupt status register. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); /* * Write the status back to clear the interrupts so no events are missed * while processing this interrupt. */ XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Use the Mask register AND with the Interrupt Status register so * disabled interrupts are not processed. */ IntrStatusReg &= ~(XIicPs_ReadReg(BaseAddr, XIICPS_IMR_OFFSET)); /* * Determine whether the device is sending. */ if (InstancePtr->RecvBufferPtr == NULL) { IsSend = 1U; } /* Data interrupt * * This means master wants to do more data transfers. * Also check for completion of transfer, signal upper layer if done. */ if ((u32)0U != (IntrStatusReg & XIICPS_IXR_DATA_MASK)) { if (IsSend != 0x0U) { LeftOver = TransmitFifoFill(InstancePtr); /* * We may finish send here */ if (LeftOver == 0) { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } else { LeftOver = SlaveRecvData(InstancePtr); /* We may finish the receive here */ if (LeftOver == 0) { StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } } } /* * Complete interrupt. * * In slave mode, it means the master has done with this transfer, so * we signal the application using completion event. */ if (0U != (IntrStatusReg & XIICPS_IXR_COMP_MASK)) { if (IsSend != 0x0U) { if (InstancePtr->SendByteCount > 0) { StatusEvent |= XIICPS_EVENT_ERROR; }else { StatusEvent |= XIICPS_EVENT_COMPLETE_SEND; } } else { LeftOver = SlaveRecvData(InstancePtr); if (LeftOver > 0) { StatusEvent |= XIICPS_EVENT_ERROR; } else { StatusEvent |= XIICPS_EVENT_COMPLETE_RECV; } } } /* * Nack interrupt, pass this information to application. */ if (0U != (IntrStatusReg & XIICPS_IXR_NACK_MASK)) { StatusEvent |= XIICPS_EVENT_NACK; } /* * All other interrupts are treated as error. */ if (0U != (IntrStatusReg & (XIICPS_IXR_TO_MASK | XIICPS_IXR_RX_UNF_MASK | XIICPS_IXR_TX_OVR_MASK | XIICPS_IXR_RX_OVR_MASK))){ StatusEvent |= XIICPS_EVENT_ERROR; } /* * Signal application if there are any events. */ if (0U != StatusEvent) { InstancePtr->StatusHandler(InstancePtr->CallBackRef, StatusEvent); } }
/** * This function receives a buffer in polled mode as a slave. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the receive buffer. * @param ByteCount is the number of bytes to be received. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if timed out. * * @note This receive routine is for polled mode transfer only. * ****************************************************************************/ s32 XIicPs_SlaveRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount) { u32 IntrStatusReg; u32 StatusReg; u32 BaseAddr; s32 Count; /* * Assert validates the input arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->RecvBufferPtr = MsgPtr; InstancePtr->RecvByteCount = ByteCount; StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); /* * Clear the interrupt status register. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Clear the status register. */ StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_SR_OFFSET, StatusReg); StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); Count = InstancePtr->RecvByteCount; while (Count > (s32)0) { /* Wait for master to put data */ while ((StatusReg & XIICPS_SR_RXDV_MASK) == 0U) { StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); /* * If master terminates the transfer before we get all * the data or the master tries to read from us, * it is an error. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); if (((IntrStatusReg & (XIICPS_IXR_DATA_MASK | XIICPS_IXR_COMP_MASK))!=0x0U) && ((StatusReg & XIICPS_SR_RXDV_MASK) == 0U) && ((InstancePtr->RecvByteCount > 0) != 0x0U)) { return (s32)XST_FAILURE; } /* * Clear the interrupt status register. */ XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); } /* * Read all data from FIFO. */ while (((StatusReg & XIICPS_SR_RXDV_MASK)!=0x0U) && ((InstancePtr->RecvByteCount > 0) != 0x0U)){ XIicPs_RecvByte(InstancePtr); StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); } Count = InstancePtr->RecvByteCount; } return (s32)XST_SUCCESS; }
/** * This function sends a buffer in polled mode as a slave. * * @param InstancePtr is a pointer to the XIicPs instance. * @param MsgPtr is the pointer to the send buffer. * @param ByteCount is the number of bytes to be sent. * * @return * - XST_SUCCESS if everything went well. * - XST_FAILURE if master sends us data or master terminates the * transfer before all data has sent out. * * @note This send routine is for polled mode transfer only. * ****************************************************************************/ s32 XIicPs_SlaveSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount) { u32 IntrStatusReg; u32 StatusReg; u32 BaseAddr; s32 Tmp; s32 BytesToSend; s32 Error = 0; s32 Status = (s32)XST_SUCCESS; u32 Value; /* * Assert validates the input arguments. */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(MsgPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY); BaseAddr = InstancePtr->Config.BaseAddress; InstancePtr->SendBufferPtr = MsgPtr; InstancePtr->SendByteCount = ByteCount; /* * Use RXRW bit in status register to wait master to start a read. */ StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); while (((StatusReg & XIICPS_SR_RXRW_MASK) == 0U) && ((!Error) != 0)) { /* * If master tries to send us data, it is an error. */ if ((StatusReg & XIICPS_SR_RXDV_MASK) != 0x0U) { Error = 1; } StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); } if (Error != 0) { Status = (s32)XST_FAILURE; } else { /* * Clear the interrupt status register. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); /* * Send data as long as there is more data to send and * there are no errors. */ Value = (InstancePtr->SendByteCount > (s32)0) && ((!Error) != 0); while (Value != (u32)0x00U) { /* * Find out how many can be sent. */ BytesToSend = InstancePtr->SendByteCount; if (BytesToSend > (s32)(XIICPS_FIFO_DEPTH)) { BytesToSend = (s32)(XIICPS_FIFO_DEPTH); } for(Tmp = 0; Tmp < BytesToSend; Tmp ++) { XIicPs_SendByte(InstancePtr); } StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); /* * Wait for master to read the data out of fifo. */ while (((StatusReg & XIICPS_SR_TXDV_MASK) != (u32)0x00U) && ((!Error) != 0)) { /* * If master terminates the transfer before all data is * sent, it is an error. */ IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET); if ((IntrStatusReg & XIICPS_IXR_NACK_MASK) != 0x0U) { Error = 1; } /* Clear ISR. */ XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg); StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET); } Value = (InstancePtr->SendByteCount > (s32)0U) && ((!Error) != 0); } } if (Error != 0) { Status = (s32)XST_FAILURE; } return Status; }
/** * * This function sets the serial clock rate for the IIC device. The device * must be idle rather than busy transferring data before setting these device * options. * * The data rate is set by values in the control register. The formula for * determining the correct register values is: * Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1)) * See the hardware data sheet for a full explanation of setting the serial * clock rate. * * @param InstancePtr is a pointer to the XIicPs instance. * @param FsclHz is the clock frequency in Hz. The two most common clock * rates are 100KHz and 400KHz. * * @return * - XST_SUCCESS if options are successfully set. * - XST_DEVICE_IS_STARTED if the device is currently transferring * data. The transfer must complete or be aborted before setting * options. * - XST_FAILURE if the Fscl frequency can not be set. * * @note The clock can not be faster than the input clock divide by 22. * ******************************************************************************/ int XIicPs_SetSClk(XIicPs *InstancePtr, u32 FsclHz) { u32 Div_a; u32 Div_b; u32 ActualFscl; u32 Temp; u32 LastError; u32 CurrentError; u32 ControlReg; u32 BestDivA; u32 BestDivB; Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); Xil_AssertNonvoid(FsclHz > 0); if (0 != XIicPs_In32((InstancePtr->Config.BaseAddress) + XIICPS_TRANS_SIZE_OFFSET)) { return XST_DEVICE_IS_STARTED; } /* * Assume Div_a is 0 and calculate (divisor_a+1) x (divisor_b+1). */ Temp = (InstancePtr->Config.InputClockHz) / (22 * FsclHz); /* * If the answer is negative or 0, the Fscl input is out of range. */ if (0 == Temp) { return XST_FAILURE; } LastError = FsclHz; BestDivA = 0; BestDivB = 0; for (Div_a = 0; Div_a < 4; Div_a++) { Div_b = (Temp / (Div_a + 1)) - 1; ActualFscl = (InstancePtr->Config.InputClockHz) / (22 * (Div_a + 1) * (Div_b + 1)); CurrentError = ((ActualFscl > FsclHz) ? (ActualFscl - FsclHz) : (FsclHz - ActualFscl)); if (LastError > CurrentError) { BestDivA = Div_a; BestDivB = Div_b; LastError = CurrentError; } } /* * Read the control register and mask the Divisors. */ ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET); ControlReg &= ~(XIICPS_CR_DIV_A_MASK | XIICPS_CR_DIV_B_MASK); ControlReg |= (BestDivA << XIICPS_CR_DIV_A_SHIFT) | (BestDivB << XIICPS_CR_DIV_B_SHIFT); XIicPs_WriteReg(InstancePtr->Config.BaseAddress, XIICPS_CR_OFFSET, ControlReg); return XST_SUCCESS; }