IIC控制器(2):PS端

书接上文:

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;}
#endifif ((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;
#endifInstancePtr->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;}
#endifPlatform = 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;}
#endifBaseAddr = 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.xdnf.cn/news/149434.html

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

相关文章

GhostNet原理解析及pytorch实现

论文&#xff1a;https://arxiv.org/abs/1911.11907 源码&#xff1a;https://github.com/huawei-noah/ghostnet 简要论述GhostNet的核心内容。 Ghost Net 1、Introduction 在训练良好的深度神经网络的特征图中&#xff0c;丰富甚至冗余的信息通常保证了对输入数据的全面理…

【数据结构】红黑树(C++实现)

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;数据结构 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【数据…

妙不可言的Python之旅----(二)

Python基础语法 什么是字面量 字面量&#xff1a;在代码中&#xff0c;被写下来的的固定的值&#xff0c;称之为字面量 常用的值类型 类型 描述 说明 数字&#xff08;Number&#xff09; 支持 • 整数&#xff08;int&#xff09; • 浮点数&#xff08;float&#xff…

手边酒店V2独立版小程序 1.0.21 免授权+小程序前端

手边酒店小程序独立版酒店宾馆订房系统支持创建多个小程序&#xff0c;让每一个客户单独管理属于自己的小程序。后台支持一键入住&#xff0c;一键退款、退押金、钟点房支持微信支付、模板消息。客服实时收到新的订单信息&#xff0c;可以在手机端处理订单。支持按日期维护房价…

在PHP8中使用instanceof操作符检测对象类型-PHP8知识详解

在PHP8中使用instanceof操作符可以检测当前对象属于哪个类。语法格式如下&#xff1a; objectName instanceof classname下面我们用一个实例来讲解使用instanceof操作符检测对象类型。 本实例将将创建3个类&#xff0c;其中有两个类是父类和子类的关系&#xff0c;然后实例化…

堆排序详解

堆排序 一.前言二.堆排序思路三.堆的创建1.堆的向上调整2.堆的向下调整3.向上建堆4.向下建堆5.两种建堆方式比较 四.堆排序五.复杂度分析六.Topk问题七.结语 一.前言 堆排序在生活中主要有两大应用场景&#xff1a;一是大数据排序&#xff0c;二是优先队列。其中典型的实例就是…

【算法与数据结构】归并排序的代码实现(详细图解)以及master公式的讲解

目录 1、归并排序 1.1、算法描述 1.2、图解说明 2、代码实现 3、master公式 3.1、公式以及结论 3.2、适用于某些特殊的递归 3.3、计算归并排序的时间复杂度 1、归并排序 归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用递归或者说是分治法&#xff08;Di…

JAVA学习(5)-全网最详细~

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

第八章 Linux文件系统权限

目录 8.1 文件的一般权限 1.修改文件或目录的权限---chmod命令 2.对于文件和目录&#xff0c;r&#xff0c;w&#xff0c;x有不同的作用&#xff1a; 3.修改文件或目录的所属主和组---chown,chgrp 8.2 文件和目录的特殊权限 三种通过字符描述文件权限 8.3 ACL 权限 1.A…

redis高可用(主从复制,哨兵,集群)

目录 一、主从复制&#xff1a; 1.主从复制介绍&#xff1a; 2.主从复制的作用&#xff1a; 3.主从复制流程&#xff1a; 4.搭建Redis 主从复制&#xff1a; 4.1 环境准备&#xff1a; 4.2 安装redis&#xff1a; 4.3 master节点修改 Redis 配置文件&#xff1a; 4.4 slave节点…

JAVA面经整理(7)

一)什么是AQS&#xff1f; 1)AQS也被称之为是抽象同步队列&#xff0c;它是JUC包底下的多个组件的底层实现&#xff0c;Lock&#xff0c;CountDownLatch和Semphore底层都使用到了AQS AQS的核心思想就是给予一个等待队列和同步状态来实现的&#xff0c;它的内部使用一个先进先出…

【C语言】循环结构程序设计(第二部分 -- 习题讲解)

前言:昨天我们学习了C语言中循环结构程序设计&#xff0c;并分析了循环结构的特点和实现方法&#xff0c;有了初步编写循环程序的能力&#xff0c;那么今天我们通过一些例子来进一步掌握循环程序的编写和应用。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &am…

提示msvcp140.dll丢失的5个解决方法,msvcp140.dll丢失问题全面分析

在我们的日常生活和工作中&#xff0c;电脑已经成为不可或缺的工具。然而&#xff0c;在使用电脑的过程中&#xff0c;我们经常会遇到各种问题&#xff0c;其中就包括提示 msvcp140.dll 丢失的问题。msvcp140.dll 是 Visual C Redistributable for Visual Studio 2015 的运行时…

动态内存管理<C语言>

✨Blog&#xff1a;&#x1f970;不会敲代码的小张:)&#x1f970; &#x1f251;推荐专栏&#xff1a;C语言&#x1f92a;、Cpp&#x1f636;‍&#x1f32b;️、数据结构初阶&#x1f480; &#x1f4bd;座右铭&#xff1a;“記住&#xff0c;每一天都是一個新的開始&#x1…

微信小程序代驾系统源码(含未编译前端,二开无忧) v2.5

简介&#xff1a; 如今有越来越多的人在网上做代驾&#xff0c;打造一个代驾平台&#xff0c;既可以让司机增加一笔额外的收入&#xff0c;也解决了车主酒后不能开发的问题&#xff0c;代驾系统基于微信小程序开发的代驾系统支持一键下单叫代驾&#xff0c;支持代驾人员保证金…

Python的NumPy库(一)基础用法

NumPy库并不是Python的标准库&#xff0c;但其在机器学习、大数据等很多领域有非常广泛的应用&#xff0c;NumPy本身就有比较多的内容&#xff0c;全部的学习可能涉及许多的内容&#xff0c;但我们在这里仅学习常见的使用&#xff0c;这些内容对于我们日常使用NumPy是足够的。 …

2023.10.5 文件操作IO 经典例题

目录 例题一 例题二 例题一 扫描指定目录&#xff0c;并找到名称中包含指定字符的所有普通文件&#xff08;不包含目录&#xff09;&#xff0c;并且后续询问用户是否删除该文件 代码如下&#xff1a; package io;import java.io.File; import java.util.Scanner;//扫描指定目…

RSA攻击:模数分解

目录 一、模数分解总览 1.1直接分解法 1.2费马分解与Pollard_rho分解 1.3公约数分解 1.4其他模数分解 二、实战特训 2.1[黑盾杯 2020]Factor 2.2[GWCTF 2019]babyRSA 2.3[LitCTF 2023]yafu (中级) 2.4[RoarCTF 2019]RSA 2.5[CISCN 2022 西南]rsa 三、总结 一、模数分解总览 …

使用idea 中的rest 将 git 合并部分分支代码到主分支

需求&#xff1a;当要将dev的分支中的部分代码合并到test分支时&#xff0c;又不想把dev的全部代码合并到test分支 例如dev分支已经提交了 demo1到4&#xff0c;到想把demo1-3的代码合并到test分支&#xff0c;demo4暂时不合并 可以使用idea的reset 功能满足以上需求 1首先切…