IIC控制器(2):PS端

news2024/9/22 4:12:16

书接上文:

I2C控制器练习(1)_NoNoUnknow的博客-CSDN博客

SPI协议与FPGA的自动升级和多启动-CSDN博客

本文主要做一些基本知识的补充和工程参考。

        写IIC需要注意的事情:

        1.查询芯片手册获得slave地址,以及寄存器地址(或者叫寄存器命令)。

        2.约定好每次读/写的数据长度。

        对于这类芯片而言,读取一般都使用了顺序读,即读完一个地址自动读下一个地址,所以约定好长度通过no ack来打断很重要。

        (SPI设备是通过停止输入时钟和拉高CS_N来打断的)

FLASH使用笔记~M25P64_m25p16_NoNoUnknow的博客-CSDN博客

操作时序:写(单字节写入)

随机读

顺序读

页写:(不是每个设备都有)

        所有 I2C 设备均支持单字节数据写入操作,但只有部分 I2C 设备支持页写操作; 且支持页写操作的设备,一次页写操作写入的字节数不能超过设备单页包含的存储单元

        本章节使用的 AT24CXX 系列的 EEPROM 存储芯片,单页存储单元个数为 32 个,一 次页写操作只能写入 32 字节数据。

PS端的API可以在板载支持包里找到。

        SDK可以直接在简历平台的界面找到,Vitis则是被整合到了spr里。

BSP板级支持包(board support package)-CSDN博客

一些API。

主模式下中断驱动的接收:XIicPs_MasterRecv() 

* 该函数在主模式下启动中断驱动的接收。
* 它设置传输大小寄存器,以便从机可以向我们发送数据。
* 其余工作由中断处理程序管理。

/*****************************************************************************/
/**
* @brief
* 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, s32 ByteCount,
		 u16 SlaveAddr)
{
	UINTPTR BaseAddr;

	/*
	 * Assert validates the input arguments.
	 */
	Xil_AssertVoid(InstancePtr != NULL);
	Xil_AssertVoid(MsgPtr != NULL);
	Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
	Xil_AssertVoid((u16)XIICPS_ADDR_MASK >= SlaveAddr);

	BaseAddr = InstancePtr->Config.BaseAddress;
	InstancePtr->RecvBufferPtr = MsgPtr;
	InstancePtr->RecvByteCount = ByteCount;
	InstancePtr->SendBufferPtr = NULL;
	InstancePtr->IsSend = 0;

#if defined  (XCLOCKING)
	if (InstancePtr->IsClkEnabled == 0) {
		Xil_ClockEnable(InstancePtr->Config.RefClk);
		InstancePtr->IsClkEnabled = 1;
	}
#endif

	if ((ByteCount > XIICPS_FIFO_DEPTH) ||
		((InstancePtr->IsRepeatedStart) !=0))
	{
		XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
				XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |
						(u32)XIICPS_CR_HOLD_MASK);
	}

	/*
	 * Initialize for a master receiving role.
	 */
	(void)XIicPs_SetupMaster(InstancePtr, RECVING_ROLE);
	/*
	 * Setup the transfer size register so the slave knows how much
	 * to send to us.
	 */
	if (ByteCount > (s32)XIICPS_MAX_TRANSFER_SIZE) {
		XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET,
				XIICPS_MAX_TRANSFER_SIZE);
		InstancePtr->CurrByteCount = (s32)XIICPS_MAX_TRANSFER_SIZE;
		InstancePtr->UpdateTxSize = 1;
	}else {
		InstancePtr->CurrByteCount = ByteCount;
		XIicPs_WriteReg(BaseAddr, (u32)(XIICPS_TRANS_SIZE_OFFSET),
			 (u32)ByteCount);
		InstancePtr->UpdateTxSize = 0;
	}

	/*
	 * Clear the interrupt status register before use it to monitor.
	 */
	XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, XIICPS_IXR_ALL_INTR_MASK);

	XIicPs_EnableInterrupts(BaseAddr,
		(u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_DATA_MASK |
		(u32)XIICPS_IXR_RX_OVR_MASK | (u32)XIICPS_IXR_COMP_MASK |
		(u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TO_MASK);
	/*
	 * Do the address transfer to signal the slave.
	 */
	XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr);

}

主模式下中断驱动的发送:XIicPs_MasterSend() 

* 该函数在主模式下启动中断驱动的发送。
* 它尝试发送第一个 FIFO 满的数据,

* 然后让中断处理程序处理其余数据(如果有)。

#define TX_MAX_LOOPCNT 1000000U	/**< Used to wait in polled function */

/************************** Function Prototypes ******************************/

/************************* Variable Definitions *****************************/

/*****************************************************************************/
/**
* @brief
* 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)
{
	UINTPTR 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((u16)XIICPS_ADDR_MASK >= SlaveAddr);

	BaseAddr = InstancePtr->Config.BaseAddress;
	InstancePtr->SendBufferPtr = MsgPtr;
	InstancePtr->SendByteCount = ByteCount;
	InstancePtr->RecvBufferPtr = NULL;
	InstancePtr->IsSend = 1;

#if defined  (XCLOCKING)
	if (InstancePtr->IsClkEnabled == 0) {
		Xil_ClockEnable(InstancePtr->Config.RefClk);
		InstancePtr->IsClkEnabled = 1;
	}
#endif
	/*
	 * Set repeated start if sending more than FIFO of data.
	 */
	if (((InstancePtr->IsRepeatedStart) != 0)||
		(ByteCount > XIICPS_FIFO_DEPTH)) {
		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);

	/*
	 * Clear the interrupt status register before use it to monitor.
	 */
	XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, XIICPS_IXR_ALL_INTR_MASK);

	XIicPs_EnableInterrupts(BaseAddr,
		(u32)XIICPS_IXR_NACK_MASK | (u32)XIICPS_IXR_COMP_MASK |
		(u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TO_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));
	}

}

参考资料:

Zynq SDK开发之外设信息描述 - 简书 (jianshu.com)

zynq7000系列PS端GPIO初始化函数XGpioPs_LookupConfig()和XGpioPs_CfgInitialize()详解-CSDN博客

 Xilinx sdk 学习笔记 之 IIC(二)-CSDN博客

配置查找函数:XIicPs_LookupConfig(DeviceId)

* 根据唯一设备ID查找设备配置表

* 表中包含系统中每个设备的配置信息。

DeviceId需要在xparameters.h中找到。

/************************** Constant Definitions *****************************/


/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/


/************************** Function Prototypes ******************************/

/************************** Variable Definitions *****************************/

/*****************************************************************************/
/**
*
* @brief
* Looks up the device configuration based on the unique device ID. A table
* contains the configuration info for each device in the system.
*
* @param	DeviceId contains the ID of the device to look up the
*		configuration for.
*
* @return	A pointer to the configuration found or NULL if the specified
*		device ID was not found. See xiicps.h for the definition of
*		XIicPs_Config.
*
* @note		None.
*
******************************************************************************/
XIicPs_Config *XIicPs_LookupConfig(u16 DeviceId)
{
	XIicPs_Config *CfgPtr = NULL;
	s32 Index;

	for (Index = 0; Index < XPAR_XIICPS_NUM_INSTANCES; Index++) {
		if (XIicPs_ConfigTable[Index].DeviceId == DeviceId) {
			CfgPtr = &XIicPs_ConfigTable[Index];
			break;
		}
	}

	return (XIicPs_Config *)CfgPtr;
}
/** @} */

初始化函数:XIicPs_CfgInitialize

* 初始化特定的 XIicPs 实例,以便驱动程序可供使用。
* 初始化后设备的状态为:

        * - 设备已禁用

        * - 从机模式

ConfigPtr即Lookup函数的返回值。

/************************** Variable Definitions *****************************/


/*****************************************************************************/
/**
*
* @brief
* Initializes a specific XIicPs instance such that the driver is ready to use.
*
* The state of the device after initialization is:
*   - Device is disabled
*   - Slave mode
*
* @param	InstancePtr is a pointer to the XIicPs instance.
* @param	ConfigPtr is a reference to a structure containing information
*		about a specific IIC device. This function initializes an
*		InstancePtr object for a specific device specified by the
*		contents of Config.
* @param	EffectiveAddr is the device base address in the virtual memory
*		address space. The caller is responsible for keeping the address
*		mapping from EffectiveAddr to the device physical base address
*		unchanged once this function is invoked. Unexpected errors may
*		occur if the address mapping changes after this function is
*		called. If address translation is not used, use
*		ConfigPtr->BaseAddress for this parameter, passing the physical
*		address instead.
*
* @return	The return value is XST_SUCCESS if successful.
*
* @note		None.
*
******************************************************************************/
s32 XIicPs_CfgInitialize(XIicPs *InstancePtr, XIicPs_Config *ConfigPtr,
				  u32 EffectiveAddr)
{
	/*
	 * Assert validates the input arguments.
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(ConfigPtr != NULL);

	/*
	 * Set some default values.
	 */
	InstancePtr->Config.DeviceId = ConfigPtr->DeviceId;
	InstancePtr->Config.BaseAddress = EffectiveAddr;
	InstancePtr->Config.InputClockHz = ConfigPtr->InputClockHz;
#if defined  (XCLOCKING)
	InstancePtr->Config.RefClk = ConfigPtr->RefClk;
	InstancePtr->IsClkEnabled = 0;
#endif

	InstancePtr->StatusHandler = StubHandler;
	InstancePtr->CallBackRef = NULL;

	InstancePtr->IsReady = (u32)XIL_COMPONENT_IS_READY;

	/*
	 * Reset the IIC device to get it into its initial state. It is expected
	 * that device configuration will take place after this initialization
	 * is done, but before the device is started.
	 */
	XIicPs_Reset(InstancePtr);

	/*
	 * Keep a copy of what options this instance has.
	 */
	InstancePtr->Options = XIicPs_GetOptions(InstancePtr);

	/* Initialize repeated start flag to 0 */
	InstancePtr->IsRepeatedStart = 0;

	return (s32)XST_SUCCESS;
}

速率配置函数 XIicPs_SetSClk

* 该函数设置IIC 器件的串行时钟速率。

* 在设置这些设备选项之前,设备必须处于空闲状态而不是忙于传输数据。


* 数据速率由控制寄存器中的值设置。

* 确定正确寄存器值的公式为:

* Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))

* 有关设置串行时钟速率的完整说明,请参阅硬件数据表。

/*****************************************************************************/
/**
*
* @brief
* 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.
*
******************************************************************************/
s32 XIicPs_SetSClk(XIicPs *InstancePtr, u32 FsclHz)
{
	u32 Div_a;
	u32 Div_b;
	u32 ActualFscl;
	u32 Temp;
	u32 TempLimit;
	u32 LastError;
	u32 BestError;
	u32 CurrentError;
	u32 ControlReg;
	u32 CalcDivA;
	u32 CalcDivB;
	u32 BestDivA;
	u32 BestDivB;
	u32 FsclHzVar = FsclHz;

	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid(FsclHzVar > 0U);

	if (0U != XIicPs_In32((InstancePtr->Config.BaseAddress) +
					XIICPS_TRANS_SIZE_OFFSET)) {
		return (s32)XST_DEVICE_IS_STARTED;
	}

	/*
	 * Assume Div_a is 0 and calculate (divisor_a+1) x (divisor_b+1).
	 */
	Temp = (InstancePtr->Config.InputClockHz) / ((u32)22U * FsclHzVar);

	/*
	 * If the answer is negative or 0, the Fscl input is out of range.
	 */
	if ((u32)(0U) == Temp) {
		return (s32)XST_FAILURE;
	}

	/*
	 * If frequency 400KHz is selected, 384.6KHz should be set.
	 * If frequency 100KHz is selected, 90KHz should be set.
	 * This is due to a hardware limitation.
	 */
	if(FsclHzVar > (u32)384600U) {
		FsclHzVar = (u32)384600U;
	}

	if((FsclHzVar <= (u32)100000U) && (FsclHzVar > (u32)90000U)) {
		FsclHzVar = (u32)90000U;
	}

	/*
	 * TempLimit helps in iterating over the consecutive value of Temp to
	 * find the closest clock rate achievable with divisors.
	 * Iterate over the next value only if fractional part is involved.
	 */
	TempLimit = (((InstancePtr->Config.InputClockHz) %
			((u32)22 * FsclHzVar)) != 	(u32)0x0U) ?
						 (Temp + (u32)1U) : Temp;
	BestError = FsclHzVar;

	BestDivA = 0U;
	BestDivB = 0U;
	for ( ; Temp <= TempLimit ; Temp++)
	{
		LastError = FsclHzVar;
		CalcDivA = 0U;
		CalcDivB = 0U;

		for (Div_b = 0U; Div_b < 64U; Div_b++) {

			Div_a = Temp / (Div_b + 1U);

			if (Div_a != 0U){
				Div_a = Div_a - (u32)1U;
			}
			if (Div_a > 3U){
				continue;
			}
			ActualFscl = (InstancePtr->Config.InputClockHz) /
						(22U * (Div_a + 1U) * (Div_b + 1U));

			if (ActualFscl > FsclHzVar){
				CurrentError = (ActualFscl - FsclHzVar);}
			else{
				CurrentError = (FsclHzVar - ActualFscl);}

			if (LastError > CurrentError) {
				CalcDivA = Div_a;
				CalcDivB = Div_b;
				LastError = CurrentError;
			}
		}

		/*
		 * Used to capture the best divisors.
		 */
		if (LastError < BestError) {
			BestError = LastError;
			BestDivA = CalcDivA;
			BestDivB = CalcDivB;
		}
	}


	/*
	 * Read the control register and mask the Divisors.
	 */
	ControlReg = XIicPs_ReadReg(InstancePtr->Config.BaseAddress,
					  (u32)XIICPS_CR_OFFSET);
	ControlReg &= ~((u32)XIICPS_CR_DIV_A_MASK | (u32)XIICPS_CR_DIV_B_MASK);
	ControlReg |= (BestDivA << XIICPS_CR_DIV_A_SHIFT) |
		(BestDivB << XIICPS_CR_DIV_B_SHIFT);

	XIicPs_WriteReg(InstancePtr->Config.BaseAddress, (u32)XIICPS_CR_OFFSET,
			  ControlReg);

	return (s32)XST_SUCCESS;
}

/*****************************************************************************/

轮询模式接收:XIicPs_MasterRecvPolled

* 该函数在主模式下启动轮询模式接收。
* 它重复设置传输大小寄存器,以便从机可以

* 向我们发送数据。它轮询数据寄存器以获取要输入的数据。
* 如果主机由于仲裁失败而无法读取数据,将返回 :仲裁失败状态。
* 如果从机无法向我们发送数据,则会因超时而失败。

/*****************************************************************************/
/**
* @brief
* 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 master fails to read data due arbitration lost, will return
* with arbitration lost status.
* 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.
*		- XST_IIC_ARB_LOST if arbitration lost
*
* @note		This receive routine is for polled mode transfer only.
*
****************************************************************************/
s32 XIicPs_MasterRecvPolled(XIicPs *InstancePtr, u8 *MsgPtr,
				s32 ByteCount, u16 SlaveAddr)
{
	u32 IntrStatusReg;
	u32 Intrs;
	UINTPTR BaseAddr;
	s32 Result;
	s32 IsHold;
	s32 UpdateTxSize = 0;
	s32 ByteCountVar = ByteCount;
	u32 Platform;

	/*
	 * Assert validates the input arguments.
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(MsgPtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid((u16)XIICPS_ADDR_MASK >= SlaveAddr);

	BaseAddr = InstancePtr->Config.BaseAddress;
	InstancePtr->RecvBufferPtr = MsgPtr;
	InstancePtr->RecvByteCount = ByteCountVar;

#if defined  (XCLOCKING)
	if (InstancePtr->IsClkEnabled == 0) {
		Xil_ClockEnable(InstancePtr->Config.RefClk);
		InstancePtr->IsClkEnabled = 1;
	}
#endif

	Platform = XGetPlatform_Info();

	if((ByteCountVar > XIICPS_FIFO_DEPTH) ||
		((InstancePtr->IsRepeatedStart) !=0))
	{
		XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
				XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |
						(u32)XIICPS_CR_HOLD_MASK);
		IsHold = 1;
	} else {
		IsHold = 0;
	}

	(void)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);


	/*
	 * Set up the transfer size register so the slave knows how much
	 * to send to us.
	 */
	if (ByteCountVar > (s32)XIICPS_MAX_TRANSFER_SIZE) {
		XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET,
				XIICPS_MAX_TRANSFER_SIZE);
		ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE;
		UpdateTxSize = 1;
	}else {
		XIicPs_WriteReg(BaseAddr, XIICPS_TRANS_SIZE_OFFSET,
			 ByteCountVar);
	}


	XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, SlaveAddr);

	/*
	 * Intrs keeps all the error-related interrupts.
	 */
	Intrs = (u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_RX_OVR_MASK |
			(u32)XIICPS_IXR_RX_UNF_MASK | (u32)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) == 0U)) {

		while ((XIicPs_RxDataValid(InstancePtr)) != 0U) {
			if ((InstancePtr->RecvByteCount <
				XIICPS_DATA_INTR_DEPTH) && (IsHold != 0) &&
				(InstancePtr->IsRepeatedStart == 0) &&
				(UpdateTxSize == 0)) {
				IsHold = 0;
				XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
						XIicPs_ReadReg(BaseAddr,
						XIICPS_CR_OFFSET) &
						(~XIICPS_CR_HOLD_MASK));
			}
			XIicPs_RecvByte(InstancePtr);
		    ByteCountVar --;

			if (Platform == (u32)XPLAT_ZYNQ) {
			    if ((UpdateTxSize != 0) &&
				    (ByteCountVar == (XIICPS_FIFO_DEPTH + 1))) {
				    break;
				}
			}
		}
		if (Platform == (u32)XPLAT_ZYNQ) {
			if ((UpdateTxSize != 0) &&
				(ByteCountVar == (XIICPS_FIFO_DEPTH + 1))) {
			    /*  wait while fifo is full */
			while (XIicPs_RxFIFOFull(InstancePtr, ByteCountVar) != 0U) { ;
				}
				if ((InstancePtr->RecvByteCount - XIICPS_FIFO_DEPTH) >
					(s32)XIICPS_MAX_TRANSFER_SIZE) {

					XIicPs_WriteReg(BaseAddr,
						XIICPS_TRANS_SIZE_OFFSET,
						XIICPS_MAX_TRANSFER_SIZE);
				    ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE +
							XIICPS_FIFO_DEPTH;
				} else {
					XIicPs_WriteReg(BaseAddr,
						XIICPS_TRANS_SIZE_OFFSET,
						InstancePtr->RecvByteCount -
						XIICPS_FIFO_DEPTH);
					UpdateTxSize = 0;
				    ByteCountVar = InstancePtr->RecvByteCount;
				}
			}
		} else {
		    if ((InstancePtr->RecvByteCount > 0) && (ByteCountVar == 0)) {
				/*
				 * 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);

				if ((InstancePtr->RecvByteCount) >
					(s32)XIICPS_MAX_TRANSFER_SIZE) {

					XIicPs_WriteReg(BaseAddr,
						XIICPS_TRANS_SIZE_OFFSET,
						XIICPS_MAX_TRANSFER_SIZE);
				    ByteCountVar = (s32)XIICPS_MAX_TRANSFER_SIZE;
				} else {
					XIicPs_WriteReg(BaseAddr,
						XIICPS_TRANS_SIZE_OFFSET,
						InstancePtr->RecvByteCount);
					UpdateTxSize = 0;
				    ByteCountVar = InstancePtr->RecvByteCount;
				}
			}
		}

		IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);
	}

	if (InstancePtr->IsRepeatedStart == 0) {
		XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
				XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &
						(~XIICPS_CR_HOLD_MASK));
	}

	if ((IntrStatusReg & Intrs) != 0U) {
		if ((IntrStatusReg & XIICPS_IXR_ARB_LOST_MASK) != 0U) {
			Result = (s32) XST_IIC_ARB_LOST;
		} else {
			Result = (s32)XST_FAILURE;
		}
	} else {
		Result = (s32)XST_SUCCESS;
	}

	return Result;
}

 轮询模式发送:XIicPs_MasterSendPolled

* 该函数在主模式下启动轮询模式发送。
* 它将数据发送到 FIFO 并等待从机接收它们。
* 如果主设备由于仲裁丢失而无法发送数据,将停止传输

* 并处于仲裁丢失状态

* 如果从设备无法从 FIFO 中删除数据,则发送失败并

* 超时。

/*****************************************************************************/
/**
* @brief
* 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 master fails to send data due arbitration lost, will stop transfer
* and with arbitration lost status
* 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.
*		- XST_IIC_ARB_LOST if arbitration lost
*
* @note		This send routine is for polled mode transfer only.
*
****************************************************************************/
s32 XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr,
		 s32 ByteCount, u16 SlaveAddr)
{
	u32 IntrStatusReg;
	u32 StatusReg;
	UINTPTR BaseAddr;
	u32 Intrs;
	s32 Status = (s32)XST_FAILURE;
	u32 timeout = 0;
	_Bool Value;

	/*
	 * Assert validates the input arguments.
	 */
	Xil_AssertNonvoid(InstancePtr != NULL);
	Xil_AssertNonvoid(MsgPtr != NULL);
	Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
	Xil_AssertNonvoid((u16)XIICPS_ADDR_MASK >= SlaveAddr);

#if defined  (XCLOCKING)
	if (InstancePtr->IsClkEnabled == 0) {
		Xil_ClockEnable(InstancePtr->Config.RefClk);
		InstancePtr->IsClkEnabled = 1;
	}
#endif

	BaseAddr = InstancePtr->Config.BaseAddress;
	InstancePtr->SendBufferPtr = MsgPtr;
	InstancePtr->SendByteCount = ByteCount;

	if (((InstancePtr->IsRepeatedStart) != 0) ||
		(ByteCount > XIICPS_FIFO_DEPTH)) {
		XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
				XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |
						(u32)XIICPS_CR_HOLD_MASK);
	}

	(void)XIicPs_SetupMaster(InstancePtr, SENDING_ROLE);

	/*
	 * Intrs keeps all the error-related interrupts.
	 */
	Intrs = (u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TX_OVR_MASK |
		(u32)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.
	 */
	(void)TransmitFifoFill(InstancePtr);

	XIicPs_WriteReg(BaseAddr, XIICPS_ADDR_OFFSET, (u32)SlaveAddr);

	IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);

	/*
	 * Continue sending as long as there is more data and
	 * there are no errors.
	 */
	Value = ((InstancePtr->SendByteCount > (s32)0) &&
		((IntrStatusReg & Intrs) == (u32)0U));
	while (Value != FALSE) {
		StatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_SR_OFFSET);

		/*
		 * Wait until transmit FIFO is empty.
		 */
		if ((StatusReg & XIICPS_SR_TXDV_MASK) != 0U) {
			IntrStatusReg = XIicPs_ReadReg(BaseAddr,
					XIICPS_ISR_OFFSET);
			Value = ((InstancePtr->SendByteCount > (s32)0) &&
				((IntrStatusReg & Intrs) == (u32)0U));
			continue;
		}

		/*
		 * Send more data out through transmit FIFO.
		 */
		(void)TransmitFifoFill(InstancePtr);
		Value = ((InstancePtr->SendByteCount > (s32)0) &&
			((IntrStatusReg & Intrs) == (u32)0U));
	}

	/*
	 * 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) != 0U) {
			if ((IntrStatusReg & XIICPS_IXR_ARB_LOST_MASK) != 0U) {
				Status = (s32) XST_IIC_ARB_LOST;
			}
			break;
		}
		/*
		 * Timeout if stuck for more than 1 second
		 */
		usleep(1);
		timeout++;
		if (timeout == TX_MAX_LOOPCNT) {
			break;
		}
	}

	if (InstancePtr->IsRepeatedStart == 0) {
		XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,
				XIicPs_ReadReg(BaseAddr,XIICPS_CR_OFFSET) &
						(~XIICPS_CR_HOLD_MASK));
	}

	/* Set the Status for XST_SUCCESS */
	if (((IntrStatusReg & Intrs) == 0U) && (timeout != TX_MAX_LOOPCNT)) {
		Status = (s32)XST_SUCCESS;
	}

	return Status;
}

头文件导入:

#include "xiicps.h"

The xiicps.h header file is an implementation of IIC driver in the PS block. 


#include "xparameters.h"

里面列出了各个外设对应的地址、Device_ID、中断号,等等。

运行步骤:

1.通过XIicPs_LookupConfig查找到设备的配置列表;

2.通过配置列表使用XIicPs_CfgInitialize进行初始化配置;

3.配置完成后使用XIicPs_SetSClk配置速率;

4.使用XIicPs_MasterSendPolled向指定的实例、从机发送寄存器地址

        (MsgPtr is the pointer to the send buffer.)部分设备可能会将此项作为操作命令使用。

5.假如是读指令则还需要使用XIicPs_MasterRecvPolled来接收数据。

        其中XIicPs_MasterRecvPolled API的MsgPtr是用以配置接收缓存的,可以定义合适的数组(寄存器)来存储它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1060956.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

『力扣每日一题12』:只出现一次的数字

一、题目 给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 示例 1 &#xff1a; 输入&…

MySQL备份恢复

MySQL日志管理 在数据库保存数据时&#xff0c;有时候不可避免会出现数据丢失或者被破坏&#xff0c;这样情况下&#xff0c;我们必须保证数据的安全性和完整性&#xff0c;就需要使用日志来查看或者恢复数据了。 MySQL日志类型 日志类型计入文件中的信息类型错误日志记录启…

Android Studio实现简易计算器(带横竖屏,深色浅色模式,更该按钮颜色,selector,style的使用)

目录 前言 运行结果&#xff1a; 运行截屏&#xff08;p50e&#xff09; apk文件 源码文件 项目结构 总览 MainActivity.java drawable 更改图标的方法&#xff1a; blackbutton.xml bluebuttons.xml greybutton.xml orangebuttons.xml whitebutton.xml layout 布…

uniapp项目实践总结(二十七)苹果应用商店上架教程

导语&#xff1a;之前介绍了如何打包一个苹果安装包文件&#xff0c;如果想要上架苹果 ios 应用商店&#xff0c;那么就来这里学习一下方法吧。 目录 准备材料上架步骤审核事项 准备材料 基本信息 构建版本&#xff1a;需要一个 ipa 格式安装包&#xff1b;logo&#xff1a…

YOLOv5、YOLOv8改进:RepVGG结构

1.简介 论文参考&#xff1a;最新RepVGG结构: Paper 我们所说的“VGG式”指的是&#xff1a; 没有任何分支结构。即通常所说的plain或feed-forward架构。 仅使用3x3卷积。 仅使用ReLU作为激活函数。 主要创新点为结构重参数化。在训练时&#xff0c;网络的结构是多分支进…

计数排序详解

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言 这种排序在部分情境下出奇地好&#xff0c;也是一种不错的排序 思路 有一个无序数组&#xff0c;我们从中找到最小和最大的数&#xff0c;最大的数减最小的数1的大小就是我们将要新建数组的大小&#xff0c;这个新建数…

14链表-环形链表、龟兔赛跑算法

目录 LeetCode之路——141. 环形链表 分析&#xff1a; 解法一&#xff1a;哈希表 解法二&#xff1a;龟兔赛跑 LeetCode之路——141. 环形链表 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针…

美团外卖优惠券小程序 美团优惠券微信小程序 自带流量主模式 带教程

小程序带举牌小人带菜谱流量主模式&#xff0c;挺多外卖小程序的&#xff0c;但是都没有搭建教程 搭建&#xff1a; 1、下载源码&#xff0c;去微信公众平台注册自己的账号 2、解压到桌面 3、打开微信开发者工具添加小程序-把解压的源码添加进去-appid改成自己小程序的 4、…

第十七章:Java连接数据库jdbc(java和myql数据库连接)

1.进入命令行&#xff1a;输入cmd&#xff0c;以管理员身份运行 windowsr 2.登录mysql 3.创建库和表 4.使用Java命令查询数据库操作 添加包 导入包的快捷键 选择第四个 找到包的位置 导入成功 创建java项目 二&#xff1a;连接数据库&#xff1a; 第一步&#xff1a;注册驱动…

单层神经网络

神经网络 人工神经网络&#xff08;Artificial Neural Network&#xff0c;ANN&#xff09;&#xff0c;简称神经网络&#xff08;Neural Network&#xff0c;NN&#xff09;&#xff0c;是一种模仿生物神经网络的结构和功能的数学模型或计算模型。1943年&#xff0c;McCulloc…

软件工程从理论到实践客观题汇总(头歌第九章至第十七章)

九、软件体系结构设计 1、软件体系结构设计概述 2、软件体系结构模型的表示方法 3、软件体系结构设计过程 4、设计初步的软件体系结构 5、重用已有软件资源 6、精化软件体系结构 7、设计软件部署模型 8、文档化和评审软件体系结构设计 十、软件用户界面设计 1、用户界面设计概…

十四天学会C++之第四天(面向对象编程基础)

类和对象是什么&#xff1f; 在C中&#xff0c;类是一种用户定义的数据类型&#xff0c;它可以包含数据成员&#xff08;也就是属性&#xff09;和成员函数&#xff08;也就是方法&#xff09;。类是一种模板或蓝图&#xff0c;用于创建具体的对象。 对象是类的实例&#xff…

【C++类和对象】:构造函数、析构函数、拷贝构造函数、赋值运算符重载

【C类和对象】&#xff1a;构造函数、析构函数、拷贝构造函数、赋值运算符重载 一、构造函数1.1 概念1.2 性质1.3 实例 二、析构函数2.1 概念2.2 性质2.3 实例 三、拷贝构造函数3.1 概念3.2 性质3.3 实例 四、赋值运算符重载4.1 运算符重载4.2 2 赋值运算符重载1. 赋值运算符重…

一文读懂UTF-8的编码规则

之前写过一篇文章“一文彻底搞懂计算机中文编码”里面只是介绍了GB2312编码知识&#xff0c;关于utf8没有涉及到&#xff0c;经过查询资料发现utf8是对unicode的一种可变长度字符编码&#xff0c;所以再记录一下。 现在国家对于信息技术中文编码字符集制定的标准是《GB 18030-…

yolov8封装进入ROS系统

一,yolov8的环境配置工作 说明:需要相关工程全部源码的可私聊博主或评论留言 配置工作可以参考我的一篇关于yolov8环境配置的博客。 需要说明的是:直接使用: pip install ultralytics 会导致后面对于网络结构的改进无法运行。所以如果需要对网络结构进行改进的同学,不要使用…

学信息系统项目管理师第4版系列17_干系人管理

1. 项目经理和团队管理干系人的能力决定着项目的成败 2. 干系人满意度应作为项目目标加以识别和管理 3. 发展趋势和新兴实践 3.1. 识别所有干系人&#xff0c;而非在限定范围内 3.2. 确保所有团队成员都涉及引导干系人参与的活 3.3. 定期审查干系人群体&#xff0c;可与单…

互联网Java工程师面试题·Dubbo篇·第一弹

目录 1、为什么要用 Dubbo&#xff1f; 2、Dubbo 的整体架构设计有哪些分层? 3、默认使用的是什么通信框架&#xff0c;还有别的选择吗? 4、服务调用是阻塞的吗&#xff1f; 5、一般使用什么注册中心&#xff1f;还有别的选择吗&#xff1f; 6、默认使用什么序列化框架&…

CUDA+cuDNN+TensorRT 配置避坑指南

深度学习模型加速部署的环境配置&#xff0c;需要在本地安装NVIDIA的一些工具链和软件包&#xff0c;这是一个些许繁琐的过程&#xff0c;而且一步错&#xff0c;步步错。笔者将会根据自己的经验来提供建议&#xff0c;减少踩坑几率。当然可以完全按照官方教程操作&#xff0c;…

新手学习笔记-----⽂件操作

目录 1. 为什么使⽤⽂件&#xff1f; 2. 什么是⽂件&#xff1f; 2.1 程序⽂件 2.2 数据⽂件 2.3 ⽂件名 3. ⼆进制⽂件和⽂本⽂件&#xff1f; 4. ⽂件的打开和关闭 4.1 流和标准流 4.1.1 流 4.1.2 标准流 4.2 ⽂件指针 4.3 ⽂件的打开和关闭 5. ⽂件的顺序读写 …

多层神经网络和激活函数

多层神经网络的结构 多层神经网络就是由单层神经网络进行叠加之后得到的&#xff0c;所以就形成了层的概念&#xff0c;常见的多层神经网络有如下结构&#xff1a; 1&#xff09;输入层&#xff08;Input layer&#xff09;&#xff0c;众多神经元&#xff08;Neuron&#xff…