代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
mangui zhang:对比两边工程的工程属性下设置可能还调用了其他文件需要确认搜索路径
代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
desheng yang:单步调试发现只有 void HAL_setupI2C(HAL_Handle handle)初始化时,I2C相关寄存器写入有效;
而后续进行读写操作时 static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite)和
static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) ,这两个函数内对 I2C相关寄存器写入无效,因此造成无法改变寄存器值,无法发送,这是为什么呢?
代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
desheng yang:
回复 mangui zhang:
好的,谢谢你的回复,@mangui zhang
代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
mangui zhang:对比两边工程的工程属性下设置可能还调用了其他文件需要确认搜索路径
代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
Seven Han:
回复 desheng yang:
会不会是eallow的问题。
代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
desheng yang:
回复 Seven Han:
但是在初始化时是可以写寄存器的,后续是使用与初始化使用相同的函数,而且例程中也没有使用EALLOW,手册中寄存器相关操作也没有提到
代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
user5919672:
回复 desheng yang:
老哥,请问这个EEPROM读写程序搞定了吗
代码是从controlsuit例程直接移植到motorware例程中的,配置完全一样,但是例程可以正常读写,移进motorware之后,测试引脚都没有信号,这是为什么呢?使用的是controlsuit例程中的 i2c.c 和 i2c.h。
在motor ware lab4中配置I2C如下:
在hal_init函数中:
obj->i2cHandle = I2C_init((void *)I2CA_BASE_ADDR,sizeof(I2C_Obj));
在hal_setup函数中: // I2C void HAL_setupI2C(HAL_Handle handle) { HAL_Obj *obj = (HAL_Obj *)handle;// Slave address - EEPROM control code I2C_setMasterSlaveAddr(obj->i2cHandle, 0x0050); // I2CCLK = SYSCLK/(I2CPSC+1) // Prescaler - need 7-12 Mhz on module clk // 模块时钟 10MHz;主机时钟 400K,高电平1.5us,低电平1us I2C_setupClock(obj->i2cHandle, 6, 5, 10); // Enable SCD & ARDY interrupts I2C_enableInt(obj->i2cHandle, I2C_IntEn_Stop); I2C_enableInt(obj->i2cHandle, I2C_IntEn_Reg_Rdy); // Take I2C out of reset, enable I2C // Stop I2C when suspended I2C_enable(obj->i2cHandle); // Enable FIFO mode and TXFIFO I2C_enableFifo(obj->i2cHandle); I2C_resetTxFifo(obj->i2cHandle); // Enable RXFIFO, clear RXFFINT I2C_resetRxFifo(obj->i2cHandle); I2C_clearRxFifoInt(obj->i2cHandle); // Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1 PIE_enableInt(obj->pieHandle, PIE_GroupNumber_8, PIE_InterruptSource_I2CA1); // Enable CPU INT8 which is connected to PIE group 8 CPU_enableInt(obj->cpuHandle, CPU_IntNumber_8); return; }
I2C IO设置: // I2C端口配置GPIO_setPullUp(obj->gpioHandle, GPIO_Number_32, GPIO_PullUp_Enable);GPIO_setPullUp(obj->gpioHandle, GPIO_Number_33, GPIO_PullUp_Enable);GPIO_setQualification(obj->gpioHandle, GPIO_Number_32, GPIO_Qual_ASync);GPIO_setQualification(obj->gpioHandle, GPIO_Number_33, GPIO_Qual_ASync);GPIO_setMode(obj->gpioHandle, GPIO_Number_32, GPIO_32_Mode_SDAA);GPIO_setMode(obj->gpioHandle, GPIO_Number_33, GPIO_33_Mode_SCLA);
开启I2C外设时钟:CLK_enableI2cClock(obj->clkHandle);
配置中断向量表: pie->I2CINT1A = &i2ca1_isr;
中断函数: interrupt void i2ca1_isr(void) { uint16_t IntSource, i; // Read interrupt source IntSource = I2C_getIntSource(halHandle->i2cHandle); // Interrupt source = stop condition detected if(IntSource == I2C_IntSrc_Stop)// 检测到STP=1,中断开始(SCD中断) { // If completed message was writing data, reset msg to inactive state if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY) // 发送完成,设置为未启动状态,可以进行下一次写数据 CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE; else { // If a message receives a NACK during the address setup portion of the // EEPROM read, the code further below included in the register access ready // interrupt source code will generate a stop condition. After the stop // condition is received (here), set the message status to try again. // User may want to limit the number of retries before generating an error. if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP; // If completed message was reading EEPROM data, reset msg to inactive state // and read data from FIFO. else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)// 读数据完成。可读取I2C FIFO寄存器数据 { // 设置为未启动状态,允许下一次读写 EEPROMCurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;for(i=0; i < I2C_NUMBYTES; i++) CurrentMsgPtr->MsgBuffer[i] = I2C_getData(halHandle->i2cHandle);// Check received datafor(i=0; i < I2C_NUMBYTES; i++){ if(I2cMsgRead.MsgBuffer[i] == I2cMsgWrite.MsgBuffer[i]) PassCount++; else FailCount++;}if(PassCount == I2C_NUMBYTES){ __asm("ESTOP0"); for(;;);}else{ __asm("ESTOP0"); for(;;);} } } }// end of stop condition detected // Interrupt source = Register Access Ready // This interrupt is used to determine when the EEPROM address setup portion of the // read data communication is complete. Since no stop bit is commanded, this flag // tells us when the message has been sent instead of the SCD flag. If a NACK is // received, clear the NACK bit and command a stop. Otherwise, move on to the read // data portion of the communication. // ARDY中断:①收到 NACK 回复,产生停止位使得长生 SCD 中断; //②在非重复模式中,当没有检测到停止位 STP=0,内部计数器向下计数到 0,ARDY 置位(产生 ARDY 中断); else if(IntSource == I2C_IntSrc_Reg_Rdy) { if(I2C_getStatus(halHandle->i2cHandle) == I2C_Status_NACK)// EEPROM处理数据忙回复 NACK { I2C_MasterControl(halHandle->i2cHandle, I2C_Control_Stop, I2C_BitCount_8_Bits, 0);// 产生一个 STOP 停止位,引发一次 SCD 中断 I2C_clearSTR_NACK_flag(halHandle->i2cHandle);// 清除 NACK位 } // 发送完成数据,没有停止位,收到回复 ACK,内部计数为零,产生 ARDY 中断 else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY) CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;// 更新为重发 START 位状态,为接收数据准备 }// end of register access ready else { // Generate some error due to invalid interrupt source __asm("ESTOP0"); } // Enable future I2C (PIE Group 8) interrupts PIE_clearInt(halHandle->pieHandle, PIE_GroupNumber_8); return; }
I2C 使用相关定义: #define I2C_EEPROM_Block0_ADDRESS0x50 #define I2C_EEPROM_HIGH_ADDR 0x00// 数据地址高位,变化范围 0x00 ~ 0x03 #define I2C_EEPROM_LOW_ADDR0x00// 数据地址低位,变化范围 0x00 ~ 0xFF // Error Messages #define I2C_ERROR0xFFFF #define I2C_ARB_LOST_ERROR0x0001 #define I2C_NACK_ERROR0x0002 #define I2C_BUS_BUSY_ERROR0x1000 #define I2C_STP_NOT_READY_ERROR 0x5555 #define I2C_NO_FLAGS0xAAAA #define I2C_SUCCESS0x0000 // I2CMSG structure defines #define I2C_MAX_BUFFER_SIZE 4// 定义数据存取长度 #define I2C_NUMBYTES 2// 传输字节数 // I2C Message Commands for I2CMSG struct #define I2C_MSGSTAT_INACTIVE0x0000// 未激活:发送成功或接收成功后设置,允许下一次发送或接收数据。 #define I2C_MSGSTAT_SEND_WITHSTOP0x0010// 带停止位发送:用于数据写入,停止位表示写入完成。 #define I2C_MSGSTAT_WRITE_BUSY0x0011// 写数据忙:数据移入缓冲器后使能IIC发送,并设置为此状态,表示数据正在传输,//可通过查询SCD位判断是否传送完毕。 #define I2C_MSGSTAT_SEND_NOSTOP0x0020// 无停止位发送:用于读取数据,发送设备地址后还需发送数据地址,因此不能产生停止位,//发送设备地址后设为此状态,表示可以发送数据地址。 #define I2C_MSGSTAT_SEND_NOSTOP_BUSY 0x0021// 发送无停止位忙:用于读取数据,表示地址已经在传送中,可通过ARDY标志判断是否传送成功。 #define I2C_MSGSTAT_RESTART0x0022// 重发开始为:用于读取数据,表示地址传送成功,可以重发设备地址并接收EEPROM的数据//到缓冲区,接收完成设定的数据个数发送停止位停止数据传输。// 注:写完数据并不能马上读取,EEPROM需要一定的时间存取数据,2ms左右;//因此发送设备地址和数据地址需要执行多次,才能得到 ACK,然后读取数据。 #define I2C_MSGSTAT_READ_BUSY0x0023// 读取数据忙:用于读取数据,在第二次发送START+设备地址后设为此状态,//表示IIC已经开始接收数据,可通过ARDY判断是否接收成功。 //------------ // Structures //------------ // I2C Message Structure typedef struct _I2CMSG_t_ {uint16_t MsgStatus;// Word stating what state msg is in://I2C_MSGCMD_INACTIVE = do not send msg//I2C_MSGCMD_BUSY = msg start has been sent,//awaiting stop//I2C_MSGCMD_SEND_WITHSTOP = command to send//master trans msg complete with a stop bit//I2C_MSGCMD_SEND_NOSTOP = command to send//master trans msg without the stop bit//I2C_MSGCMD_RESTART = command to send a restart//as a master receiver with a stop bituint16_t SlaveAddress;// I2C address of slave msg is intended foruint16_t MemoryHighAddr;// EEPROM address of data associated with msg (high byte)uint16_t MemoryLowAddr;// EEPROM address of data associated with msg (low byte)uint16_t MsgBuffer[I2C_MAX_BUFFER_SIZE];// Array holding msg data - max that// MAX_BUFFER_SIZE can be is 4 due to the FIFO's }I2CMSG_t;
I2C读写文件: /* * I2C_EE.c * I2c EEPROM(AT24C08D) 应用函数 */ #include "I2C_EE.h" #include "i2c.h" uint16_t PassCount=0; uint16_t FailCount=0; I2CMSG_t I2cMsgWrite={I2C_MSGSTAT_SEND_WITHSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x12,// Msg Byte 010x34};// Msg Byte 02 I2CMSG_t I2cMsgRead={I2C_MSGSTAT_SEND_NOSTOP,I2C_EEPROM_Block0_ADDRESS,I2C_EEPROM_HIGH_ADDR,I2C_EEPROM_LOW_ADDR,0x00,0x00}; // Used in interrupts I2CMSG_t *CurrentMsgPtr=&I2cMsgWrite; I2C_Handle i2cHandle; static inline uint16_t I2CA_WriteData(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t i; // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; // Setup number of bytes to send // Send start as master transmitter I2C_enable(i2cHandle); I2C_enable_FREE(i2cHandle); I2C_MasterControl(i2cHandle, I2C_Control_Single_TX, I2C_BitCount_8_Bits, (NumByteToWrite + 2)); // Setup data_adress to send I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); for(i=0; i<NumByteToWrite; i++) { I2C_putData(i2cHandle, *(msg->MsgBuffer+i)); // 若FIFO满,则等待(避免FIFO溢出覆盖先前数据) while(I2C_getTxFifoStatus(i2cHandle) == I2C_FifoStatus_4_Words); } msg->MemoryLowAddr += i;//just for test return I2C_SUCCESS; } static inline uint16_t I2CA_ReadData(I2CMSG_t *msg, uint16_t NumByteToRead) { // Wait until the STP bit is cleared from any previous master communication. // Clearing of this bit by the module is delayed until after the SCD bit is // set. If this bit is not checked prior to initiating a new message, the // I2C could get confused. if(I2C_checkMasterStop(i2cHandle) == 1) return I2C_STP_NOT_READY_ERROR; // Setup slave address I2C_setMasterSlaveAddr(i2cHandle, msg->SlaveAddress); if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP)// 产生第一个START位后发送设备地址和数据地址 { // Check if bus busy if(I2C_isMasterBusy(i2cHandle) == 1) return I2C_BUS_BUSY_ERROR; I2C_MasterControl(i2cHandle, I2C_Control_Burst_TX_Start, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); // Send data to setup EEPROM address I2C_putData(i2cHandle, msg->MemoryHighAddr); I2C_putData(i2cHandle, msg->MemoryLowAddr); } else if(msg->MsgStatus == I2C_MSGSTAT_RESTART)// 产生第二个START位后发送设备地址并开始接收数据 { // Setup how many bytes to expect // Send restart as master receiver I2C_MasterControl(i2cHandle, I2C_Control_Single_RX, I2C_BitCount_8_Bits, NumByteToRead); I2C_enable(i2cHandle); } return I2C_SUCCESS; } // Write data to EEPROM section void I2C_EE_Write(I2CMSG_t *msg, uint16_t NumByteToWrite) { uint16_t Error; // Check the outgoing message to see if it should be sent. // In this example it is initialized to send with a stop bit. if(msg->MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP) { Error = I2CA_WriteData(msg, NumByteToWrite);// If communication is correctly initiated, set msg status to busy// and update CurrentMsgPtr for the interrupt service routine.// Otherwise, do nothing and try again next loop. Once message is// initiated, the I2C interrupts will handle the rest. Search for// ICINTR1A_ISR in the i2c_eeprom_isr.c file.if(Error == I2C_SUCCESS){ CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_WRITE_BUSY;} }// end of write section } // Read data from EEPROM section void I2C_EE_Read(I2CMSG_t *msg, uint16_t NumByteToRead) { // 读数据包括两次发送 START 位,第一次发送地址 // Check outgoing message status. Bypass read section if status is not inactive. if(I2cMsgWrite.MsgStatus == I2C_MSGSTAT_INACTIVE) { // Check incoming message status. if(msg->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP) { // EEPROM address setup portion while(I2CA_ReadData(msg, 2) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while // loop. The EEPROM will send back a NACK while it is performing // a write operation. Even though the write communique is // complete at this point, the EEPROM could still be busy // programming the data. Therefore, multiple attempts are necessary. // 需要一定是时间完成数据的烧写,1.8ms左右;需要多次尝试,直到返回 ACK 确认。 } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP_BUSY; } // Once message has progressed past setting up the internal address// of the EEPROM, send a restart to read the data bytes from the// EEPROM. Complete the communique with a stop bit. MsgStatus is// updated in the interrupt service routine.else if(msg->MsgStatus == I2C_MSGSTAT_RESTART){ // Read data portion while(I2CA_ReadData(msg, NumByteToRead) != I2C_SUCCESS) { // Maybe setup an attempt counter to break an infinite while loop. } // Update current message pointer and message status CurrentMsgPtr = msg; msg->MsgStatus = I2C_MSGSTAT_READ_BUSY;} }// end of read section }
user5919672:
回复 desheng yang:
大佬,方便的话可以教教我怎么用EEPROM读写吗?刚入坑,不是很懂