/***************************************************************************** * * This function checks to see if the IIC bus is busy. If so, it will enable * the bus not busy interrupt such that the driver is notified when the bus * is no longer busy. * * @param InstancePtr points to the Iic instance to be worked on. * * @return * * - FALSE indicates the IIC bus is not busy. * - TRUE indicates the bus was in use and that the BusNotBusy * interrupt is enabled which will update the EventStatus when the bus is no * longer busy. * * @note * * None * ******************************************************************************/ static u32 IsBusBusy(XIic * InstancePtr) { u8 ControlReg; u8 StatusReg; ControlReg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); StatusReg = XIo_In8(InstancePtr->BaseAddress + XIIC_SR_REG_OFFSET); /* If this device is already master of the bus as when using the repeated * start and the bus is busy setup to wait for it to not be busy */ if (((ControlReg & XIIC_CR_MSMS_MASK) == 0) && /* not master */ (StatusReg & XIIC_SR_BUS_BUSY_MASK)) { /* is busy */ /* The bus is busy, clear pending BNB interrupt incase previously set * and then enable BusNotBusy interrupt */ InstancePtr->BNBOnly = TRUE; XIic_mClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_BNB_MASK); InstancePtr->Stats.BusBusy++; return TRUE; } return FALSE; }
/** * Receive the specified data from the device that has been previously addressed * on the IIC bus. This function assumes the following: * - The Rx Fifo occupancy depth has been set to its max. * - Upon entry, the Rx Fifo is empty. * - The 7 bit address has been sent. * - The dynamic stop and number of bytes to receive has been written to Tx * Fifo. * * @param BaseAddress contains the base address of the IIC Device. * @param BufferPtr points to the buffer to hold the data that is received. * @param ByteCount is the number of bytes to be received. The range of this * value is greater than 0 and not higher than 255. * * @return The number of bytes remaining to be received. * * @note This function contains loops that could cause the function not * to return if the hardware is not working. * ******************************************************************************/ static unsigned DynRecvData(u32 BaseAddress, u8 *BufferPtr, u8 ByteCount) { u8 StatusReg; u32 IntrStatus; u32 IntrStatusMask; while (ByteCount > 0) { /* Setup the mask to use for checking errors because when * receiving one byte OR the last byte of a multibyte message * an error naturally occurs when the no ack is done to tell * the slave the last byte. */ if (ByteCount == 1) { IntrStatusMask = XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK; } else { IntrStatusMask = XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_BNB_MASK; } /* * Wait for a byte to show up in the Rx Fifo. */ while (1) { IntrStatus = XIIC_READ_IISR(BaseAddress); StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); if ((StatusReg & XIIC_SR_RX_FIFO_EMPTY_MASK) != XIIC_SR_RX_FIFO_EMPTY_MASK) { break; } /* Check the transmit error after the receive full * because when sending only one byte transmit error * will occur because of the no ack to indicate the end * of the data. */ if (IntrStatus & IntrStatusMask) { return ByteCount; } } /* * Read in byte from the Rx Fifo. If the Fifo reached the * programmed occupancy depth as programmed in the Rx occupancy * reg, this read access will un throttle the bus such that * the next byte is read from the IIC bus. */ *BufferPtr++ = XIo_In8(BaseAddress + XIIC_DRR_REG_OFFSET); ByteCount--; } return ByteCount; }
/** * Receive data as a master on the IIC bus. This function receives the data * using polled I/O and blocks until the data has been received. It only * supports 7 bit addressing. The user is responsible for ensuring the bus is * not busy if multiple masters are present on the bus. * * @param BaseAddress contains the base address of the IIC Device. * @param Address contains the 7 bit IIC Device address of the device to send * the specified data to. * @param BufferPtr points to the data to be sent. * @param ByteCount is the number of bytes to be sent. This value can't be * greater than 255 and needs to be greater than 0. * * @return The number of bytes received. * * @note Upon entry to this function, the IIC interface needs to be already * enabled in the CR register. * ******************************************************************************/ unsigned XIic_DynRecv(u32 BaseAddress, u8 Address, u8 *BufferPtr, u8 ByteCount) { unsigned RemainingByteCount; u32 StatusRegister; /* * Clear the latched interrupt status so that it will be updated with * the new state when it changes. */ XIic_mClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); /* * Send the 7 bit slave address for a read operation and set the state * to indicate the address has been sent. Upon writing the address, a * start condition is initiated. MSMS is automatically set to master * when the address is written to the Fifo. If MSMS was already set, * then a re-start is sent prior to the address. */ XIic_mDynSend7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION); /* * Wait for the bus to go busy. */ StatusRegister = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK) != XIIC_SR_BUS_BUSY_MASK) { StatusRegister = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); } /* * Clear the latched interrupt status for the bus not busy bit which * must be done while the bus is busy. */ XIic_mClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); /* * Write to the Tx Fifo the dynamic stop control bit with the number of * bytes that are to be read over the IIC interface from the presently * addressed device. */ XIic_mDynSendStop(BaseAddress, ByteCount); /* * Receive the data from the IIC bus. */ RemainingByteCount = DynRecvData(BaseAddress, BufferPtr, ByteCount); /* * The receive is complete. Return the number of bytes that were * received. */ return ByteCount - RemainingByteCount; }
/****************************************************************************** * * This function fills the FIFO using the occupancy register to determine the * available space to be filled. When the repeated start option is on, the last * byte is withheld to allow the control register to be properly set on the last * byte. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @param Role indicates the role of this IIC device, a slave or a master, on * the IIC bus (XIIC_SLAVE_ROLE or XIIC_MASTER_ROLE) * * @return * * None. * * @note * * None. * ******************************************************************************/ void XIic_TransmitFifoFill(XIic * InstancePtr, int Role) { u8 AvailBytes; int LoopCnt; int NumBytesToSend; /* Determine number of bytes to write to FIFO. Number of bytes that can be * put into the FIFO is (FIFO depth) - (current occupancy + 1) * When more room in FIFO than msg bytes put all of message in the FIFO. */ AvailBytes = IIC_TX_FIFO_DEPTH - (XIo_In8(InstancePtr->BaseAddress + XIIC_TFO_REG_OFFSET) + 1); if (InstancePtr->SendByteCount > AvailBytes) { NumBytesToSend = AvailBytes; } else { /* More space in FIFO than bytes in message */ if ((InstancePtr->Options & XII_REPEATED_START_OPTION) || (Role == XIIC_SLAVE_ROLE)) { NumBytesToSend = InstancePtr->SendByteCount; } else { NumBytesToSend = InstancePtr->SendByteCount - 1; } } /* fill FIFO with amount determined above */ for (LoopCnt = 0; LoopCnt < NumBytesToSend; LoopCnt++) { XIic_mWriteSendByte(InstancePtr); } }
/** * * This function sets the options for the IIC device driver. The options control * how the device behaves relative to the IIC bus. If an option applies to * how messages are sent or received on the IIC bus, it must be set prior to * calling functions which send or receive data. * * To set multiple options, the values must be ORed together. To not change * existing options, read/modify/write with the current options using * XIic_GetOptions(). * * <b>USAGE EXAMPLE:</b> * * Read/modify/write to enable repeated start: * <pre> * u8 Options; * Options = XIic_GetOptions(&Iic); * XIic_SetOptions(&Iic, Options | XII_REPEATED_START_OPTION); * </pre> * * Disabling General Call: * <pre> * Options = XIic_GetOptions(&Iic); * XIic_SetOptions(&Iic, Options &= ~XII_GENERAL_CALL_OPTION); * </pre> * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @param NewOptions are the options to be set. See xiic.h for a list of * the available options. * * @return * * None. * * @note * * Sending or receiving messages with repeated start enabled, and then * disabling repeated start, will not take effect until another master * transaction is completed. i.e. After using repeated start, the bus will * continue to be throttled after repeated start is disabled until a master * transaction occurs allowing the IIC to release the bus. * <br><br> * Options enabled will have a 1 in its appropriate bit position. * ****************************************************************************/ void XIic_SetOptions(XIic * InstancePtr, u32 NewOptions) { u8 CntlReg; XASSERT_VOID(InstancePtr != NULL); XIic_mEnterCriticalRegion(InstancePtr->BaseAddress); /* Update the options in the instance and get the contents of the control * register such that the general call option can be modified */ InstancePtr->Options = NewOptions; CntlReg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); /* The general call option is the only option that maps directly to * a hardware register feature */ if (NewOptions & XII_GENERAL_CALL_OPTION) { CntlReg |= XIIC_CR_GENERAL_CALL_MASK; } else { CntlReg &= ~XIIC_CR_GENERAL_CALL_MASK; } /* Write the new control register value to the register */ XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CntlReg); XIic_mExitCriticalRegion(InstancePtr->BaseAddress); }
Xuint32 Read_Bitmap_Header_Bytes(Xuint32 FLASH_ADDR, Xuint32 offset) { Xuint32 Bitmap_Header_Data; Xuint8 Flash_Data; XIo_Out16 (FLASH_ADDR, 0xFF); Flash_Data = XIo_In8(FLASH_ADDR + offset); Bitmap_Header_Data = 0x00000000 | Flash_Data; Flash_Data = XIo_In8(FLASH_ADDR + offset + 1); Bitmap_Header_Data = Bitmap_Header_Data | (Flash_Data << 8); Flash_Data = XIo_In8(FLASH_ADDR + offset + 2); Bitmap_Header_Data = Bitmap_Header_Data | (Flash_Data << 16); Flash_Data = XIo_In8(FLASH_ADDR + offset + 3); Bitmap_Header_Data = Bitmap_Header_Data | (Flash_Data << 24); }
/** * * This function receives a byte from PS/2. It operates in the polling mode * and blocks until a byte of data is received. * * @param BaseAddress contains the base address of the PS/2 port. * * @return The data byte received by PS/2. * * @note None. * *****************************************************************************/ u8 XPs2_RecvByte(u32 BaseAddress) { while (XPs2_mIsReceiveEmpty(BaseAddress)) { } return (u8) XIo_In8(BaseAddress + XPS2_RX_REG_OFFSET); }
void BMP_buildImageData(struct bitmap* bitm) { Xuint32 rows = bitm->dibHeader.height; Xuint32 columns = bitm->dibHeader.width; Xint32 i, j; bitm->addr += 2; /*bitm->imageData = (Xuint32**)malloc(rows * sizeof(Xuint32*)); for (i = 0; i < rows; i++) { bitm->imageData[i] = (Xuint32*)malloc(columns * sizeof(Xuint32)); }*/ //Xuint32 addr = XPAR_FLASH_MEM0_BASEADDR + 40 + 14 + 256*4; Xuint32 padding = 4 - (columns*(bitm->dibHeader.bpp/8))%4; if (padding == 4) { padding = 0; } //xil_printf("%d\n",padding); //xil_printf("%d %d\n",rows,columns); for (i = 0; i < rows; ++i) { for (j = 0; j < columns; ++j) { if(bitm->dibHeader.bpp == 8) { bitm->imageData[i][j] = XIo_In8(bitm->addr); bitm->addr += 1; //addr += 1; } else if (bitm->dibHeader.bpp == 16) { bitm->imageData[i][j] = rgb16_to_rgb32(Xil_EndianSwap16(XIo_In16 (bitm->addr))); bitm->addr += 2; } else if (bitm->dibHeader.bpp == 24) { bitm->imageData[i][j] = (XIo_In8(bitm->addr)) | (XIo_In8(bitm->addr + 1) << 8) | (XIo_In8(bitm->addr + 2) << 16); bitm->addr += 3; } } bitm->addr += padding; } }
/****************************************************************************** * This function reads a number of bytes from an IIC chip into a * specified buffer. * * @param CoreAddress contains the address of the IIC core. * @param ChipAddress contains the address of the IIC core. * @param RegAddress contains the address of the register to write to. * @param BufferPtr contains the address of the data buffer to be filled. * @param ByteCount contains the number of bytes in the buffer to be read. * This value is constrained by the page size of the device such * that up to 64K may be read in one call. * * @return The number of bytes read. A value less than the specified input * value indicates an error. * * @note None. * ******************************************************************************/ int fmc_ipmi_iic_read(Xuint32 CoreAddress, Xuint8 ChipAddress, Xuint8 RegAddress, Xuint8 *BufferPtr, Xuint8 ByteCount) { Xuint8 ReceivedByteCount = 0; Xuint8 SentByteCount = 0; Xuint8 StatusReg; XStatus TestStatus=XST_FAILURE; int cnt = 0; // Make sure all the Fifo's are cleared and Bus is Not busy. do { StatusReg = XIo_In8(CoreAddress + XIIC_SR_REG_OFFSET); //xil_printf("[fmc_imageov_iic_read] XIo_In8(CoreAddress + XIIC_SR_REG_OFFSET) => 0x%02X\n\r", StatusReg ); StatusReg = StatusReg & (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK | XIIC_SR_BUS_BUSY_MASK); } while (StatusReg != (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK)); // Position the Read pointer to specific location. do { StatusReg = XIo_In8(CoreAddress + XIIC_SR_REG_OFFSET); //xil_printf("[fmc_imageov_iic_read] XIo_In8(CoreAddress + XIIC_SR_REG_OFFSET) => 0x%02X\n\r", StatusReg ); if(!(StatusReg & XIIC_SR_BUS_BUSY_MASK)) { SentByteCount = XIic_DynSend(CoreAddress, ChipAddress, (Xuint8 *)&RegAddress, 1, XIIC_REPEATED_START); } cnt++; }while(SentByteCount != 1 && (cnt < 100000)); // Error writing chip address so return SentByteCount if (SentByteCount < 1) { return SentByteCount; } // Receive the data. ReceivedByteCount = XIic_DynRecv(CoreAddress, ChipAddress, BufferPtr, ByteCount); // Return the number of bytes received. return ReceivedByteCount; }
/** * * Sets the options for the specified driver instance. The options are * implemented as bit masks such that multiple options may be enabled or * disabled simultaneously. * * The GetOptions function may be called to retrieve the currently enabled * options. The result is ORed in the desired new settings to be enabled and * ANDed with the inverse to clear the settings to be disabled. The resulting * value is then used as the options for the SetOption function call. * * @param InstancePtr is a pointer to the XUartNs550 instance. * @param Options contains the options to be set which are bit masks * contained in the file xuartns550.h and named XUN_OPTION_*. * * @return * - XST_SUCCESS if the options were set successfully. * - XST_UART_CONFIG_ERROR if the options could not be set because * the hardware does not support FIFOs * * @note None. * *****************************************************************************/ int XUartNs550_SetOptions(XUartNs550 *InstancePtr, u16 Options) { u32 Index; u8 Register; /* * Assert validates the input arguments */ XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* * Loop thru the options table to map the logical options to the * physical options in the registers of the UART. */ for (Index = 0; Index < XUN_NUM_OPTIONS; Index++) { /* * If the FIFO control register is being read, this is a * special case that requires special register processing */ if (OptionsTable[Index].RegisterOffset == XUN_FCR_OFFSET) { Register = ReadFcrRegister(InstancePtr->BaseAddress); } else { /* * Read the register which contains option so that the * register can be changed without destoying any other * bits of the register */ Register = XIo_In8(InstancePtr->BaseAddress + OptionsTable[Index].RegisterOffset); } /* * If the option is set in the input, then set the * corresponding bit in the specified register, otherwise * clear the bit in the register */ if (Options & OptionsTable[Index].Option) { Register |= OptionsTable[Index].Mask; } else { Register &= ~OptionsTable[Index].Mask; } /* * Write the new value to the register to set the option */ XIo_Out8(InstancePtr->BaseAddress + OptionsTable[Index].RegisterOffset, Register); } /* To be done, add error checks for enabling/resetting FIFOs */ return XST_SUCCESS; }
/** * * This functions reads the FIFO control register. It's primary purpose is to * isolate the special processing for reading this register. It is necessary * to write to the line control register, then read the FIFO control register, * and then restore the line control register. * * @param BaseAddress contains the base address of the registers in the * device. * * @return The contents of the FIFO control register. * * @note None. * *****************************************************************************/ static u8 ReadFcrRegister(u32 BaseAddress) { u8 LcrRegister; u8 FcrRegister; u8 IerRegister; /* * Enter a critical section here by disabling Uart interrupts. We do * not want to receive an interrupt while we have the FCR latched since * the interrupt handler may want to read the IIR. */ IerRegister = XIo_In8(BaseAddress + XUN_IER_OFFSET); XIo_Out8(BaseAddress + XUN_IER_OFFSET, 0); /* * Get the line control register contents and set the divisor latch * access bit so the FIFO control register can be read, this can't * be done with a true 16550, but is a feature in the Xilinx device */ LcrRegister = XIo_In8(BaseAddress + XUN_LCR_OFFSET); XIo_Out8(BaseAddress + XUN_LCR_OFFSET, LcrRegister | XUN_LCR_DLAB); /* * Read the FIFO control register so it can be returned */ FcrRegister = XIo_In8(BaseAddress + XUN_FCR_OFFSET); /* * Restore the line control register to it's original contents such * that the DLAB bit is no longer set and return the register */ XIo_Out8(BaseAddress + XUN_LCR_OFFSET, LcrRegister); /* * Exit the critical section by restoring the IER */ XIo_Out8(BaseAddress + XUN_IER_OFFSET, IerRegister); return FcrRegister; }
/** * * The IIC bus busy signals when a master has control of the bus. Until the bus * is released, i.e. not busy, other devices must wait to use it. * * When this interrupt occurs, it signals that the previous master has released * the bus for another user. * * This interrupt is only enabled when the master Tx is waiting for the bus. * * This interrupt causes the following tasks: * - Disable Bus not busy interrupt * - Enable bus Ack * Should the slave receive have disabled acknowledgement, enable to allow * acknowledgment of the sending of our address to again be addresed as slave * - Flush Rx FIFO * Should the slave receive have disabled acknowledgement, a few bytes may * be in FIFO if Rx full did not occur because of not enough byte in FIFO * to have caused an interrupt. * - Send status to user via status callback with the value: * XII_BUS_NOT_BUSY_EVENT * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return * * None. * * @note * * None. * ******************************************************************************/ static void BusNotBusyHandler(XIic * InstancePtr) { u32 Status; u8 CntlReg; /* Should the slave receive have disabled acknowledgement, * enable to allow acknowledgment of the sending of our address to * again be addresed as slave */ CntlReg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, (CntlReg & ~XIIC_CR_NO_ACK_MASK)); /* Flush Tx FIFO by toggling TxFIFOResetBit. FIFO runs normally at 0 * Do this incase needed to Tx FIFO with more than expected if what * was set to Tx was less than what the Master expected - read more * from this slave so FIFO had junk in it */ XIic_mFlushTxFifo(InstancePtr); /* Flush Rx FIFO should slave rx had a problem, sent No ack but * still received a few bytes. Should the slave receive have disabled * acknowledgement, clear rx FIFO */ XIic_mFlushRxFifo(InstancePtr); /* Send Application messaging status via callbacks. Disable either Tx or * Receive interrupt. Which callback depends on messaging direction. */ Status = XIIC_READ_IIER(InstancePtr->BaseAddress); if (InstancePtr->RecvBufferPtr == NULL) { /* Slave was sending data (master was reading), disable * all the transmit interrupts */ XIIC_WRITE_IIER(InstancePtr->BaseAddress, (Status & ~XIIC_TX_INTERRUPTS)); } else { /* Slave was receiving data (master was writing) disable receive * interrupts */ XIIC_WRITE_IIER(InstancePtr->BaseAddress, (Status & ~XIIC_INTR_RX_FULL_MASK)); } /* Send Status in StatusHandler callback */ InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, XII_BUS_NOT_BUSY_EVENT); }
/** * * This function gets the modem status from the specified UART. The modem * status indicates any changes of the modem signals. This function allows * the modem status to be read in a polled mode. The modem status is updated * whenever it is read such that reading it twice may not yield the same * results. * * @param InstancePtr is a pointer to the XUartNs550 instance . * * @return The modem status which are bit masks that are contained in * the file xuartns550.h and named XUN_MODEM_*. * * @note * * The bit masks used for the modem status are the exact bits of the modem * status register with no abstraction. * *****************************************************************************/ u8 XUartNs550_GetModemStatus(XUartNs550 *InstancePtr) { u8 ModemStatusRegister; /* * Assert validates the input arguments */ XASSERT_NONVOID(InstancePtr != NULL); /* Read the modem status register to return */ ModemStatusRegister = XIo_In8(InstancePtr->BaseAddress + XUN_MSR_OFFSET); return ModemStatusRegister; }
static Xuint8 SlaveRecvData(Xuint32 BaseAddress, Xuint8 *BufferPtr) { Xuint8 IntrStatus; while(1) { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); if( IntrStatus & XIIC_INTR_NAAS_MASK ) { //xil_printf("Recv complete: %02x\r\n", IntrStatus); break; } if( IntrStatus & XIIC_INTR_RX_FULL_MASK ) { *(BufferPtr++) = XIo_In8(BaseAddress + XIIC_DRR_REG_OFFSET); //xil_printf("Data received: %d\r\n", *(BufferPtr-1)); XI2c_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK); } } } // end SlaveRecvData()
/****************************************************************************** * This function writes a buffer of bytes to the IIC chip. * * @param CoreAddress contains the address of the IIC core. * @param ChipAddress contains the address of the chip. * @param RegAddress contains the address of the register to write to. * @param BufferPtr contains the address of the data to write. * @param ByteCount contains the number of bytes in the buffer to be written. * Note that this should not exceed the page size as noted by the * constant PAGE_SIZE. * * @return The number of bytes written, a value less than that which was * specified as an input indicates an error. * * @note None. * ******************************************************************************/ int fmc_ipmi_iic_write(Xuint32 CoreAddress, Xuint8 ChipAddress, Xuint8 RegAddress, Xuint8 *BufferPtr, Xuint8 ByteCount) { Xuint8 SentByteCount; Xuint8 WriteBuffer[PAGE_SIZE + 1]; Xuint8 Index; Xuint8 StatusReg; // Make sure all the Fifo's are cleared and Bus is Not busy. do { StatusReg = XIo_In8(CoreAddress + XIIC_SR_REG_OFFSET); //xil_printf("[fmc_imageov_iic_write] XIo_In8(CoreAddress + XIIC_SR_REG_OFFSET) => 0x%02X\n\r", StatusReg ); StatusReg = StatusReg & (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK | XIIC_SR_BUS_BUSY_MASK); } while (StatusReg != (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK)); /* * A temporary write buffer must be used which contains both the address * and the data to be written, put the address in first */ WriteBuffer[0] = RegAddress; /* * Put the data in the write buffer following the address. */ for (Index = 0; Index < ByteCount; Index++) { WriteBuffer[Index + 1] = BufferPtr[Index]; } /* * Write data at the specified address. */ SentByteCount = XIic_DynSend(CoreAddress, ChipAddress, WriteBuffer, ByteCount + 1, XIIC_STOP); if (SentByteCount < 1) { SentByteCount = 1; } // Return the number of bytes written. return SentByteCount - 1; }
Xuint8 XI2c_SlaveAccess(Xuint32 BaseAddress, Xuint8 SlaveAddress, Xuint8 *BufferPtr) { Xuint8 CtrlReg, StatusReg, SlaveSendFlag, DeviceAddress; Xuint8 IntrStatus, count = 0; XI2c_mClearTXFifo(BaseAddress); /** Set the device slave address **/ DeviceAddress = SlaveAddress << 1; XIo_Out8(BaseAddress + XIIC_ADR_REG_OFFSET, DeviceAddress); /** Wait until the device is addressed as slave **/ do { IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); } while(!(IntrStatus & XIIC_INTR_AAS_MASK)); XIo_Out8(BaseAddress + XIIC_RFD_REG_OFFSET, 0); /** Clear the recieve-fifo interrupt register **/ XI2c_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK); /** Read the status register to see if we need to receive or send data **/ StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); XI2c_mClearIisr(BaseAddress, XIIC_INTR_NAAS_MASK | XIIC_INTR_BNB_MASK); SlaveSendFlag = StatusReg & XIIC_SR_MSTR_RDING_SLAVE_MASK; if( SlaveSendFlag ) { SlaveSendData(BaseAddress, BufferPtr); } else { SlaveRecvData(BaseAddress, BufferPtr); } XI2c_mClearIisr(BaseAddress, XIIC_INTR_AAS_MASK); return 1; } // XI2c_SlaveAccess()
/** * * Gets the options for the specified driver instance. The options are * implemented as bit masks such that multiple options may be enabled or * disabled simulataneously. * * @param InstancePtr is a pointer to the XUartNs550 instance. * * @return The current options for the UART. The optionss are bit masks * that are contained in the file xuartns550.h and * named XUN_OPTION_*. * * @note None. * *****************************************************************************/ u16 XUartNs550_GetOptions(XUartNs550 *InstancePtr) { u16 Options = 0; u8 Register; u32 Index; /* * Assert validates the input arguments */ XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* * Loop thru the options table to map the physical options in the * registers of the UART to the logical options to be returned */ for (Index = 0; Index < XUN_NUM_OPTIONS; Index++) { /* * If the FIFO control register is being read, the make sure to * setup the line control register so it can be read */ if (OptionsTable[Index].RegisterOffset == XUN_FCR_OFFSET) { Register = ReadFcrRegister(InstancePtr->BaseAddress); } else { Register = XIo_In8(InstancePtr->BaseAddress + OptionsTable[Index].RegisterOffset); } /* * If the bit in the register which correlates to the option * is set, then set the corresponding bit in the options, * ignoring any bits which are zero since the options variable * is initialized to zero */ if (Register & OptionsTable[Index].Mask) { Options |= OptionsTable[Index].Option; } } return Options; }
/** * * This function determines if the specified UART is sending data. If the * transmitter register is not empty, it is sending data. * * @param InstancePtr is a pointer to the XUartNs550 instance. * * @return A value of TRUE if the UART is sending data, otherwise FALSE. * * @note None. * *****************************************************************************/ int XUartNs550_IsSending(XUartNs550 *InstancePtr) { u8 LsrRegister; /* * Assert validates the input arguments */ XASSERT_NONVOID(InstancePtr != NULL); /* * Read the line status register to determine if the transmitter is * empty */ LsrRegister = XIo_In8(InstancePtr->BaseAddress + XUN_LSR_OFFSET); /* * If the transmitter is not empty then indicate that the UART is still * sending some data */ return ((LsrRegister & XUN_LSR_TX_EMPTY) == 0); }
/****************************************************************************** * * Initialize the IIC core for Dynamic Functionality. * * @param BaseAddress contains the base address of the IIC Device. * * @return XST_SUCCESS if Successful else XST_FAILURE. * * @note None. * ******************************************************************************/ int XIic_DynInit(u32 BaseAddress) { u8 Status; /* * Reset IIC Core. */ XIIC_RESET(BaseAddress); /* * Set receive Fifo depth to maximum (zero based). */ XIo_Out8(BaseAddress + XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1); /* * Reset Tx Fifo. */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, XIIC_CR_TX_FIFO_RESET_MASK); /* * Enable IIC Device, remove Tx Fifo reset & disable general call. */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK); /* * Read status register and verify IIC Device is in initial state. Only the * Tx Fifo and Rx Fifo empty bits should be set. */ Status = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); if(Status == (XIIC_SR_RX_FIFO_EMPTY_MASK | XIIC_SR_TX_FIFO_EMPTY_MASK)) { return XST_SUCCESS; } return XST_FAILURE; }
/****************************************************************************** * * This function sends the proper byte of the address as well as generate the * proper address bit fields depending on the address byte required and the * direction of the data (write or read). * * A master receiving has the restriction that the direction must be switched * from write to read when the third address byte is transmitted. * For the last byte of the 10 bit address, repeated start must be set prior * to writing the address. If repeated start options is enabled, the * control register is written before the address is written to the tx reg. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return * * None. * * @note * * This function does read/modify/write to the device control register. Calling * functions must ensure critical sections are used. * ******************************************************************************/ static void SendSlaveAddr(XIic * InstancePtr) { u8 CRreg; /* Set the control register for Master Receive, repeated start must be set * before writing the address, MSMS should be already set, don't set here * so if arbitration is lost or some other reason we don't want MSMS set * incase of error */ CRreg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); CRreg |= XIIC_CR_REPEATED_START_MASK; CRreg &= ~XIIC_CR_DIR_IS_TX_MASK; XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CRreg); /* Send the 1st byte of the 10 bit address as a read operation, enable the * receive interrupt to know when data is received, assuming that the * receive FIFO threshold has been previously set */ XIic_mSend10BitAddrByte1(InstancePtr->AddrOfSlave, XIIC_READ_OPERATION); XIic_mClearEnableIntr(InstancePtr->BaseAddress, XIIC_INTR_RX_FULL_MASK); }
static void PrintStatus(Xuint32 BaseAddress) { Xuint8 CtrlReg, StatusReg, IntrStatus, DevAddress; Xuint8 RxFifoOcy, TxFifoOcy, RxFifoDepth; CtrlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET); StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); DevAddress = XIo_In8(BaseAddress + XIIC_ADR_REG_OFFSET); RxFifoOcy = XIo_In8(BaseAddress + XIIC_RFO_REG_OFFSET); TxFifoOcy = XIo_In8(BaseAddress + XIIC_TFO_REG_OFFSET); RxFifoDepth = XIo_In8(BaseAddress + XIIC_RFD_REG_OFFSET); xil_printf("\r\nControl Reg:\t\t 0x%02x\r\n", CtrlReg); xil_printf("Status Reg:\t\t 0x%02x\r\n", StatusReg); xil_printf("Interrupts:\t\t 0x%02x\r\n", IntrStatus); //xil_printf("Device Address:\t\t 0x%02x\r\n", DevAddress); //xil_printf("Rx Fifo Occupancy:\t 0x%02x\r\n", RxFifoOcy); //xil_printf("Tx Fifo Occupancy:\t 0x%02x\r\n", TxFifoOcy); //xil_printf("Rx Fifo Depth:\t\t 0x%02x\r\n", RxFifoDepth); } // end PrintStatus()
/** * * Sets the data format for the specified UART. The data format includes the * baud rate, number of data bits, number of stop bits, and parity. It is the * caller's responsibility to ensure that the UART is not sending or receiving * data when this function is called. * * @param InstancePtr is a pointer to the XUartNs550 instance . * @param FormatPtr is a pointer to a format structure containing the data * format to be set. * * @return * * - XST_SUCCESS if the data format was successfully set. * - XST_UART_BAUD_ERROR indicates the baud rate could not be set * because of the amount of error with the baud rate and the input * clock frequency. * - XST_INVALID_PARAM if one of the parameters was not valid. * * @note * * The data types in the format type, data bits and parity, are 32 bit fields * to prevent a compiler warning that is a bug with the GNU PowerPC compiler. * The asserts in this function will cause a warning if these fields are * bytes. * <br><br> * The baud rates tested include: 1200, 2400, 4800, 9600, 19200, 38400, 57600 * and 115200. * *****************************************************************************/ int XUartNs550_SetDataFormat(XUartNs550 *InstancePtr, XUartNs550Format *FormatPtr) { int Status; u8 LcrRegister; XASSERT_NONVOID(InstancePtr != NULL); XASSERT_NONVOID(FormatPtr != NULL); /* * Verify the inputs specified are valid and return an error if any * are not, without setting the data format */ if ((FormatPtr->DataBits > XUN_FORMAT_8_BITS) || (FormatPtr->Parity > XUN_FORMAT_EVEN_PARITY) || ((FormatPtr->StopBits != XUN_FORMAT_2_STOP_BIT) && (FormatPtr->StopBits != XUN_FORMAT_1_STOP_BIT))) { return XST_INVALID_PARAM; } /* * Try to set the baud rate and if it's not successful then don't * continue altering the data format, this is done first to avoid the * format from being altered when an error occurs */ Status = XUartNs550_SetBaudRate(InstancePtr, FormatPtr->BaudRate); if (Status != XST_SUCCESS) { return Status; } /* * Read the line control register which contains the parity, length and * stop bits so they can be updated without affecting any other bits */ LcrRegister = XIo_In8(InstancePtr->BaseAddress + XUN_LCR_OFFSET); /* * Set the length of data (8,7,6,5) by first clearing out the bits * that control it in the register, then set the length in the register */ LcrRegister &= ~XUN_LCR_LENGTH_MASK; LcrRegister |= FormatPtr->DataBits; /* * Set the number of stop bits in the line control register, if the * number of stop bits is not 2, then it must be one which is the bit * in the register cleared */ if (FormatPtr->StopBits == XUN_FORMAT_2_STOP_BIT) { LcrRegister |= XUN_LCR_2_STOP_BITS; } else { LcrRegister &= ~XUN_LCR_2_STOP_BITS; } /* * Set the parity by first clearing out the bits that control it in the * register, then set the bits in the register, the default is no parity * after clearing the register bits */ LcrRegister &= ~XUN_LCR_PARITY_MASK; if (FormatPtr->Parity != XUN_FORMAT_NO_PARITY) { /* Some form of parity is specified, set the bit indicating that * parity is enabled, then setup even or odd, the default is odd * after clearing the register bits */ LcrRegister |= XUN_LCR_ENABLE_PARITY; if (FormatPtr->Parity == XUN_FORMAT_EVEN_PARITY) { LcrRegister |= XUN_LCR_EVEN_PARITY; } } /* * Write the line control register out to save the new data format * that has been created */ XIo_Out8(InstancePtr->BaseAddress + XUN_LCR_OFFSET, LcrRegister); return XST_SUCCESS; }
/** * Send data as a master on the IIC bus. This function sends the data using * polled I/O and blocks until the data has been sent. It only supports 7 bit * addressing. The user is responsible for ensuring the bus is not busy if * multiple masters are present on the bus. * * @param BaseAddress contains the base address of the IIC Device. * @param Address contains the 7 bit IIC address of the device to send the * specified data to. * @param BufferPtr points to the data to be sent. * @param ByteCount is the number of bytes to be sent. * @param Option: XIIC_STOP = end with STOP condition, XIIC_REPEATED_START * = don't end with STOP condition. * * @return The number of bytes sent. * * @note None. * ******************************************************************************/ unsigned XIic_DynSend(u32 BaseAddress, u16 Address, u8 *BufferPtr, u8 ByteCount, u8 Option) { unsigned RemainingByteCount; u32 StatusRegister; /* * Clear the latched interrupt status so that it will be updated with * the new state when it changes, this must be done after the address * is put in the FIFO */ XIic_mClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); /* * Put the address into the Fifo to be sent and indicate that the * operation to be performed on the bus is a write operation. Upon * writing the address, a start condition is initiated. MSMS is * automatically set to master when the address is written to the Fifo. * If MSMS was already set, then a re-start is sent prior to the * address. */ if(!(Address & XIIC_TX_DYN_STOP_MASK)) { XIic_mDynSend7BitAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); } else { XIic_mDynSendStartStopAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); } /* * Wait for the bus to go busy. */ StatusRegister = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); while (( StatusRegister & XIIC_SR_BUS_BUSY_MASK) != XIIC_SR_BUS_BUSY_MASK) { StatusRegister = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); } /* * Clear the latched interrupt status for the bus not busy bit which * must be done while the bus is busy. */ XIic_mClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); /* * Send the specified data to the device on the IIC bus specified by the * the address. */ RemainingByteCount = DynSendData(BaseAddress, BufferPtr, ByteCount, Option); /* * The send is complete return the number of bytes that was sent. */ return ByteCount - RemainingByteCount; }
/****************************************************************************** * * Receive the specified data from the device that has been previously addressed * on the IIC bus. This function assumes that the 7 bit address has been sent * and it should wait for the transmit of the address to complete. * * @param BaseAddress contains the base address of the IIC device. * @param BufferPtr points to the buffer to hold the data that is received. * @param ByteCount is the number of bytes to be received. * @param Option indicates whether to hold or free the bus after reception * of data, XIIC_STOP = end with STOP condition, XIIC_REPEATED_START * = don't end with STOP condition. * * @return * * The number of bytes remaining to be received. * * @note * * This function does not take advantage of the receive FIFO because it is * designed for minimal code space and complexity. It contains loops that * that could cause the function not to return if the hardware is not working. * * This function assumes that the calling function will disable the IIC device * after this function returns. * ******************************************************************************/ static unsigned RecvData(u32 BaseAddress, u8 *BufferPtr, unsigned ByteCount, u8 Option) { u8 CntlReg; u32 IntrStatusMask; u32 IntrStatus; /* Attempt to receive the specified number of bytes on the IIC bus */ while (ByteCount > 0) { /* Setup the mask to use for checking errors because when receiving one * byte OR the last byte of a multibyte message an error naturally * occurs when the no ack is done to tell the slave the last byte */ if (ByteCount == 1) { IntrStatusMask = XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_BNB_MASK; } else { IntrStatusMask = XIIC_INTR_ARB_LOST_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_BNB_MASK; } /* Wait for the previous transmit and the 1st receive to complete * by checking the interrupt status register of the IPIF */ while (1) { IntrStatus = XIIC_READ_IISR(BaseAddress); if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { break; } /* Check the transmit error after the receive full because when * sending only one byte transmit error will occur because of the * no ack to indicate the end of the data */ if (IntrStatus & IntrStatusMask) { return ByteCount; } } CntlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET); /* Special conditions exist for the last two bytes so check for them * Note that the control register must be setup for these conditions * before the data byte which was already received is read from the * receive FIFO (while the bus is throttled */ if (ByteCount == 1) { if (Option == XIIC_STOP) { /* If the Option is to release the bus after the last data * byte, it has already been read and no ack has been done, so * clear MSMS while leaving the device enabled so it can get off * the IIC bus appropriately with a stop. */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK); } } /* Before the last byte is received, set NOACK to tell the slave IIC * device that it is the end, this must be done before reading the byte * from the FIFO */ if (ByteCount == 2) { /* Write control reg with NO ACK allowing last byte to * have the No ack set to indicate to slave last byte read. */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, CntlReg | XIIC_CR_NO_ACK_MASK); } /* Read in data from the FIFO and unthrottle the bus such that the * next byte is read from the IIC bus */ *BufferPtr++ = XIo_In8(BaseAddress + XIIC_DRR_REG_OFFSET); if ((ByteCount == 1) && (Option == XIIC_REPEATED_START)) { /* RSTA bit should be set only when the FIFO is completely Empty. */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, XIIC_CR_ENABLE_DEVICE_MASK | XIIC_CR_MSMS_MASK | XIIC_CR_REPEATED_START_MASK); } /* Clear the latched interrupt status so that it will be updated with * the new state when it changes, this must be done after the receive * register is read */ XIic_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); ByteCount--; } if (Option == XIIC_STOP) { /* If the Option is to release the bus after Reception of data, wait * for the bus to transition to not busy before returning, the IIC * device cannot be disabled until this occurs. It should transition as * the MSMS bit of the control register was cleared before the last byte * was read from the FIFO. */ while (1) { if (XIIC_READ_IISR(BaseAddress) & XIIC_INTR_BNB_MASK) { break; } } } return ByteCount; }
/** * Send data as a master on the IIC bus. This function sends the data * using polled I/O and blocks until the data has been sent. It only supports * 7 bit addressing mode of operation. The user is responsible for ensuring * the bus is not busy if multiple masters are present on the bus. * * @param BaseAddress contains the base address of the IIC device. * @param Address contains the 7 bit IIC address of the device to send the * specified data to. * @param BufferPtr points to the data to be sent. * @param ByteCount is the number of bytes to be sent. * @param Option indicates whether to hold or free the bus after * transmitting the data. * * @return * * The number of bytes sent. * * @note * * None * ******************************************************************************/ unsigned XIic_Send(u32 BaseAddress, u8 Address, u8 *BufferPtr, unsigned ByteCount, u8 Option) { unsigned RemainingByteCount; u8 ControlReg; volatile u8 StatusReg; /* Check to see if already Master on the Bus. * If Repeated Start bit is not set send Start bit by setting MSMS bit else * Send the address. */ ControlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET); if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* Put the address into the FIFO to be sent and indicate that the operation * to be performed on the bus is a write operation */ XIic_mSend7BitAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); /* Clear the latched interrupt status so that it will be updated with the * new state when it changes, this must be done after the address is put * in the FIFO */ XIic_mClearIisr(BaseAddress, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); /* MSMS must be set after putting data into transmit FIFO, indicate the * direction is transmit, this device is master and enable the IIC device */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, XIIC_CR_MSMS_MASK | XIIC_CR_DIR_IS_TX_MASK | XIIC_CR_ENABLE_DEVICE_MASK); /* Clear the latched interrupt * status for the bus not busy bit which must be done while the bus is busy */ StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) { StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); } XIic_mClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); } else { /* Already owns the Bus indicating that its a Repeated Start call. * 7 bit slave address, send the address for a write operation * and set the state to indicate the address has been sent */ XIic_mSend7BitAddress(BaseAddress, Address, XIIC_WRITE_OPERATION); } /* Send the specified data to the device on the IIC bus specified by the * the address */ RemainingByteCount = SendData(BaseAddress, BufferPtr, ByteCount, Option); ControlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET); if ((ControlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* The Transmission is completed, disable the IIC device if the Option * is to release the Bus after transmission of data and return the number * of bytes that was received. Only wait if master, if addressed as slave * just reset to release the bus. */ if ((ControlReg & XIIC_CR_MSMS_MASK) != 0) { XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, (ControlReg & ~XIIC_CR_MSMS_MASK)); StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) != 0) { StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); } } XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, 0); } return ByteCount - RemainingByteCount; }
/** * Receive data as a master on the IIC bus. This function receives the data * using polled I/O and blocks until the data has been received. It only * supports 7 bit addressing mode of operation. The user is responsible for * ensuring the bus is not busy if multiple masters are present on the bus. * * @param BaseAddress contains the base address of the IIC device. * @param Address contains the 7 bit IIC address of the device to send the * specified data to. * @param BufferPtr points to the data to be sent. * @param ByteCount is the number of bytes to be sent. * @param Option indicates whether to hold or free the bus after reception * of data, XIIC_STOP = end with STOP condition, XIIC_REPEATED_START * = don't end with STOP condition. * * @return * * The number of bytes received. * * @note * * None * ******************************************************************************/ unsigned XIic_Recv(u32 BaseAddress, u8 Address, u8 *BufferPtr, unsigned ByteCount, u8 Option) { u8 CntlReg; unsigned RemainingByteCount; volatile u8 StatusReg; /* Tx error is enabled incase the address (7 or 10) has no device to answer * with Ack. When only one byte of data, must set NO ACK before address goes * out therefore Tx error must not be enabled as it will go off immediately * and the Rx full interrupt will be checked. If full, then the one byte * was received and the Tx error will be disabled without sending an error * callback msg. */ XIic_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK | XIIC_INTR_ARB_LOST_MASK); /* Set receive FIFO occupancy depth for 1 byte (zero based) */ XIo_Out8(BaseAddress + XIIC_RFD_REG_OFFSET, 0); /* Check to see if already Master on the Bus. * If Repeated Start bit is not set send Start bit by setting MSMS bit else * Send the address. */ CntlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET); if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* 7 bit slave address, send the address for a read operation * and set the state to indicate the address has been sent */ XIic_mSend7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION); /* MSMS gets set after putting data in FIFO. Start the master receive * operation by setting CR Bits MSMS to Master, if the buffer is only one * byte, then it should not be acknowledged to indicate the end of data */ CntlReg = XIIC_CR_MSMS_MASK | XIIC_CR_ENABLE_DEVICE_MASK; if (ByteCount == 1) { CntlReg |= XIIC_CR_NO_ACK_MASK; } /* Write out the control register to start receiving data and call the * function to receive each byte into the buffer */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, CntlReg); /* Clear the latched interrupt status for the bus not busy bit which must * be done while the bus is busy */ StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); while ((StatusReg & XIIC_SR_BUS_BUSY_MASK) == 0) { StatusReg = XIo_In8(BaseAddress + XIIC_SR_REG_OFFSET); } XIic_mClearIisr(BaseAddress, XIIC_INTR_BNB_MASK); } else { /* Already owns the Bus indicating that its a Repeated Start call. * 7 bit slave address, send the address for a read operation * and set the state to indicate the address has been sent */ XIic_mSend7BitAddress(BaseAddress, Address, XIIC_READ_OPERATION); } /* Try to receive the data from the IIC bus */ RemainingByteCount = RecvData(BaseAddress, BufferPtr, ByteCount, Option); CntlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET); if ((CntlReg & XIIC_CR_REPEATED_START_MASK) == 0) { /* The receive is complete, disable the IIC device if the Option is * to release the Bus after Reception of data and return the number of * bytes that was received */ XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, 0); } /* Return the number of bytes that was received */ return ByteCount - RemainingByteCount; }
/** * * This interrupt occurs four different ways: Two as master and two as slave. * Master: * <pre> * (1) Transmitter (IMPLIES AN ERROR) * The slave receiver did not acknowledge properly. * (2) Receiver (Implies tx complete) * Interrupt caused by setting TxAck high in the IIC to indicate to the * the last byte has been transmitted. * </pre> * * Slave: * <pre> * (3) Transmitter (Implies tx complete) * Interrupt caused by master device indicating last byte of the message * has been transmitted. * (4) Receiver (IMPLIES AN ERROR) * Interrupt caused by setting TxAck high in the IIC to indicate Rx * IIC had a problem - set by this device and condition already known * and interrupt is not enabled. * </pre> * * This interrupt is enabled during Master send and receive and disabled * when this device knows it is going to send a negative acknowledge (Ack = No). * * Signals user of Tx error via status callback sending: XII_TX_ERROR_EVENT * * When MasterRecv has no message to send and only receives one byte of data * from the salve device, the TxError must be enabled to catch addressing * errors, yet there is not opportunity to disable TxError when there is no * data to send allowing disabling on last byte. When the slave sends the * only byte the NOAck causes a Tx Error. To disregard this as no real error, * when there is data in the Receive FIFO/register then the error was not * a device address write error, but a NOACK read error - to be ignored. * To work with or without FIFO's, the Rx Data interrupt is used to indicate * data is in the rx register. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return * * None. * * @note * * No action is required to clear this interrupt in the device as it is a * pulse. The interrupt need only be cleared in the IpIf interface. * ******************************************************************************/ static void TxErrorHandler(XIic * InstancePtr) { u32 IntrStatus; u8 CntlReg; /* When Sending as a slave, Tx error signals end of msg. Not Addressed As * Slave will handle the callbacks. this is used to only flush the Tx fifo. * The addressed as slave bit is gone as soon as the bus has been released * such that the buffer pointers are used to determine the direction of * transfer (send or receive). */ if (InstancePtr->RecvBufferPtr == NULL) { /* Master Receiver finished reading message. Flush Tx fifo to remove an * 0xFF that was written to prevent bus throttling, and disable all * transmit and receive interrupts */ XIic_mFlushTxFifo(InstancePtr); XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); /* If operating in Master mode, call status handler to indicate * NOACK occured */ CntlReg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); if ((CntlReg & XIIC_CR_MSMS_MASK) != 0) { InstancePtr->StatusHandler(InstancePtr-> StatusCallBackRef, XII_SLAVE_NO_ACK_EVENT); } return; } /* Data in the receive register from either master or slave receive * When:slave, indicates master sent last byte, message completed. * When:master, indicates a master Receive with one byte received. When a * byte is in Rx reg then the Tx error indicates the Rx data was recovered * normally Tx errors are not enabled such that this should not occur. */ IntrStatus = XIIC_READ_IISR(InstancePtr->BaseAddress); if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { /* Rx Reg/FIFO has data, Disable tx error interrupts */ XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_INTR_TX_ERROR_MASK); return; } XIic_mFlushTxFifo(InstancePtr); /* Disable and clear tx empty, ½ empty, Rx Full or tx error interrupts */ XIic_mDisableIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); XIic_mClearIntr(InstancePtr->BaseAddress, XIIC_TX_RX_INTERRUPTS); /* Clear MSMS as on TX error when Rxing, the bus will be * stopped but MSMS bit is still set. Reset to proper state */ CntlReg = XIo_In8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET); CntlReg &= ~XIIC_CR_MSMS_MASK; XIo_Out8(InstancePtr->BaseAddress + XIIC_CR_REG_OFFSET, CntlReg); /* set FIFO occupancy depth = 1 so that the first byte will throttle * next recieve msg */ XIo_Out8(InstancePtr->BaseAddress + XIIC_RFD_REG_OFFSET, 0); /* make event callback */ InstancePtr->StatusHandler(InstancePtr->StatusCallBackRef, XII_SLAVE_NO_ACK_EVENT); }
/** * * Gets the data format for the specified UART. The data format includes the * baud rate, number of data bits, number of stop bits, and parity. * * @param InstancePtr is a pointer to the XUartNs550 instance . * @param FormatPtr is a pointer to a format structure that will contain * the data format after this call completes. * * @return None. * * @note None. * * @internal * * This function gets the state of the hardware rather than returning a state * that has been stored to ensure that the hardware is correct. * *****************************************************************************/ void XUartNs550_GetDataFormat(XUartNs550 *InstancePtr, XUartNs550Format *FormatPtr) { u8 LcrRegister; XASSERT_VOID(InstancePtr != NULL); XASSERT_VOID(FormatPtr != NULL); /* * Assert validates the input arguments */ XASSERT_VOID(InstancePtr != NULL); XASSERT_VOID(InstancePtr->IsReady == XCOMPONENT_IS_READY); /* * Get the baud rate from the instance, this is not retrieved from the * hardware because it is only kept as a divisor such that it is more * difficult to get back to the divisor */ FormatPtr->BaudRate = InstancePtr->BaudRate; /* * Read the line control register which contains the parity, length and * stop bits so they can be updated without affecting any other bits */ LcrRegister = XIo_In8(InstancePtr->BaseAddress + XUN_LCR_OFFSET); /* * Set the length of data (8,7,6,5) by first clearing out the bits * that control it in the register, then set the length in the register */ FormatPtr->DataBits = LcrRegister & XUN_LCR_LENGTH_MASK; /* * Set the number of stop bits by first clearing out the bits in that * control it in the register, then set the bits in the register, the * default is one stop bit after clearing the register bits */ if (LcrRegister & XUN_LCR_2_STOP_BITS) { FormatPtr->StopBits = XUN_FORMAT_2_STOP_BIT; } else { FormatPtr->StopBits = XUN_FORMAT_1_STOP_BIT; } /* * Determine what parity is set from the register and setup the format * to correspond */ if ((LcrRegister & XUN_LCR_ENABLE_PARITY) == 0) { FormatPtr->Parity = XUN_FORMAT_NO_PARITY; } else { /* * Parity is enables, so determine if it's even or odd and set the * format to correspond */ if (LcrRegister & XUN_LCR_EVEN_PARITY) { FormatPtr->Parity = XUN_FORMAT_EVEN_PARITY; } else { FormatPtr->Parity = XUN_FORMAT_ODD_PARITY; } } }
/** * * This function is the interrupt handler for the XIic driver. This function * should be connected to the interrupt system. * * Only one interrupt source is handled for each interrupt allowing * higher priority system interrupts quicker response time. * * @param InstancePtr is a pointer to the XIic instance to be worked on. * * @return * * None. * * @internal * * The XIIC_INTR_ARB_LOST_MASK and XIIC_INTR_TX_ERROR_MASK interrupts must have * higher priority than the other device interrupts so that the IIC device does * not get into a potentially confused state. The remaining interrupts may be * rearranged with no harm. * * All XIic device interrupts are ORed into one device interrupt. This routine * reads the pending interrupts via the IpIf interface and masks that with the * interrupt mask to evaluate only the interrupts enabled. * ******************************************************************************/ void XIic_InterruptHandler(void *InstancePtr) { u8 Status; u32 IntrStatus; u32 IntrPending; u32 IntrEnable; XIic *IicPtr = NULL; u32 Clear = 0; /* * Verify that each of the inputs are valid. */ XASSERT_VOID(InstancePtr != NULL); /* * Convert the non-typed pointer to an IIC instance pointer */ IicPtr = (XIic *) InstancePtr; /* Get the interrupt Status from the IPIF. There is no clearing of * interrupts in the IPIF. Interrupts must be cleared at the source. * To find which interrupts are pending; AND interrupts pending with * interrupts masked. */ IntrPending = XIIC_READ_IISR(IicPtr->BaseAddress); IntrEnable = XIIC_READ_IIER(IicPtr->BaseAddress); IntrStatus = IntrPending & IntrEnable; /* Do not processes a devices interrupts if the device has no * interrupts pending or the global interrupts have been disabled */ if ((IntrStatus == 0) | (XIIC_IS_GINTR_ENABLED(IicPtr->BaseAddress) == FALSE)) { return; } /* Update interrupt stats and get the contents of the status register */ IicPtr->Stats.IicInterrupts++; Status = XIo_In8(IicPtr->BaseAddress + XIIC_SR_REG_OFFSET); /* Service requesting interrupt */ if (IntrStatus & XIIC_INTR_ARB_LOST_MASK) { /* Bus Arbritration Lost */ IicPtr->Stats.ArbitrationLost++; XIic_ArbLostFuncPtr(IicPtr); Clear = XIIC_INTR_ARB_LOST_MASK; } else if (IntrStatus & XIIC_INTR_TX_ERROR_MASK) { /* Transmit errors (no acknowledge) received */ IicPtr->Stats.TxErrors++; TxErrorHandler(IicPtr); Clear = XIIC_INTR_TX_ERROR_MASK; } else if (IntrStatus & XIIC_INTR_NAAS_MASK) { /* Not Addressed As Slave */ XIic_NotAddrAsSlaveFuncPtr(IicPtr); Clear = XIIC_INTR_NAAS_MASK; } else if (IntrStatus & XIIC_INTR_RX_FULL_MASK) { /* Receive register/FIFO is full */ IicPtr->Stats.RecvInterrupts++; if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) { XIic_RecvSlaveFuncPtr(IicPtr); } else { XIic_RecvMasterFuncPtr(IicPtr); } Clear = XIIC_INTR_RX_FULL_MASK; } else if (IntrStatus & XIIC_INTR_AAS_MASK) { /* Addressed As Slave */ XIic_AddrAsSlaveFuncPtr(IicPtr); Clear = XIIC_INTR_AAS_MASK; } else if (IntrStatus & XIIC_INTR_BNB_MASK) { /* IIC bus has transitioned to not busy */ /* check if send callback needs to run */ if (IicPtr->BNBOnly == TRUE) { XIic_BusNotBusyFuncPtr(IicPtr); IicPtr->BNBOnly = FALSE; } else { IicPtr->SendHandler(IicPtr->SendCallBackRef, 0); } Clear = XIIC_INTR_BNB_MASK; /* The bus is not busy, disable BusNotBusy interrupt */ XIic_mDisableIntr(IicPtr->BaseAddress, XIIC_INTR_BNB_MASK); } else if ((IntrStatus & XIIC_INTR_TX_EMPTY_MASK) || (IntrStatus & XIIC_INTR_TX_HALF_MASK)) { /* Transmit register/FIFO is empty or ½ empty * */ IicPtr->Stats.SendInterrupts++; if (Status & XIIC_SR_ADDR_AS_SLAVE_MASK) { XIic_SendSlaveFuncPtr(IicPtr); } else { XIic_SendMasterFuncPtr(IicPtr); } /* Clear Interrupts */ IntrStatus = XIIC_READ_IISR(IicPtr->BaseAddress); Clear = IntrStatus & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK); } XIIC_WRITE_IISR(IicPtr->BaseAddress, Clear); }
static Xuint8 RecvData(Xuint32 BaseAddress, Xuint8 SlaveAddress, Xuint8 *BufferPtr, Xuint8 ByteCount) { Xuint8 IntrStatus, CtrlReg; Xuint8 count = 0; if( ByteCount > 1 ) { /** Receive the data **/ if( !RXSuccess(BaseAddress) ) { //print("RecvData : 1 : RXFailure\r\n"); return 0; } /** Set no-ack for the last byte **/ CtrlReg = XIo_In8(BaseAddress + XIIC_CR_REG_OFFSET) | XIIC_CR_NO_ACK_MASK; XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, CtrlReg); /** Read in the data from the rx_fifo **/ for( count = 0; count < (ByteCount-1); count++ ) { *(BufferPtr++) = XIo_In8(BaseAddress + XIIC_DRR_REG_OFFSET); //xil_printf("Data received: %d\r\n", *(BufferPtr-1)); } /** Clear the rx_full flag **/ XI2c_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK); /** Set the rx_fifo depth to 1 (zero based) **/ XIo_Out8(BaseAddress + XIIC_RFD_REG_OFFSET, 0); } /** Receive the data **/ if( !RXSuccess(BaseAddress) ) { //print("RecvData : 2 : RXFailure\r\n"); return 0; } /** Set up for a clean release of the iic bus **/ CtrlReg = XIIC_CR_ENABLE_DEVICE_MASK; XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, CtrlReg); /** Read in the data from the rx_fifo **/ *BufferPtr = XIo_In8(BaseAddress + XIIC_DRR_REG_OFFSET); //xil_printf("Data received: %d\r\n", *BufferPtr); /** Clear the rx_full mask **/ XI2c_mClearIisr(BaseAddress, XIIC_INTR_RX_FULL_MASK); /* The receive is complete, disable the IIC device and return the number of * bytes that was received, we must wait for the bnb flag to properly * disable the device. THIS DOESN'T WORK RIGHT. */ /* print("Waiting for bnb_high..."); */ /* do { */ /* IntrStatus = XIIF_V123B_READ_IISR(BaseAddress); */ /* } while(!(IntrStatus & XIIC_INTR_BNB_MASK)); */ /* print("done!\r\n"); */ //XIo_Out8(BaseAddress + XIIC_CR_REG_OFFSET, 0); /* Return the number of bytes that was received */ return ++count; } // end RecvData()