I2C_Master.h
#include "stm32f10x.h" void I2C_Master_Init(void); void I2C_Master_DeInit(void); int I2C_Master_Read(uint8_t deviceAddr, uint8_t readAddr, uint8_t* pBuffer, uint16_t numByteToRead); int I2C_Master_Write(uint8_t deviceAddress, uint8_t WriteAddr, uint8_t* pBuffer, uint16_t numByteToWrite); int I2C_TIMEOUT_UserCallback(void);
I2C_Master.c
#include "I2C_Master.h" #define I2C_MEMS I2C1 #define I2C_MEMS_CLK RCC_APB1Periph_I2C1 #define I2C_MEMS_GPIO GPIOB #define I2C_MEMS_GPIO_CLK RCC_APB2Periph_GPIOB #define I2C_MEMS_SCL GPIO_Pin_6 #define I2C_MEMS_SDA GPIO_Pin_7 #define I2C_Speed 400000 #define I2C_SLAVE_ADDRESS7 0xA0 #define I2C_TIMEOUT 3000 /* I2C STOP mask */ #define CR1_STOP_Set ((uint16_t)0x0200) #define CR1_STOP_Reset ((uint16_t)0xFDFF) /* I2C ACK mask */ #define CR1_ACK_Set ((uint16_t)0x0400) #define CR1_ACK_Reset ((uint16_t)0xFBFF) /* I2C POS mask */ #define CR1_POS_Set ((uint16_t)0x0800) #define CR1_POS_Reset ((uint16_t)0xF7FF) #define NULL ((void *)0) void I2C_Master_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; /* I2C Periph clock enable */ RCC_APB1PeriphClockCmd(I2C_MEMS_CLK, ENABLE); /* GPIO Periph clock enable */ RCC_APB2PeriphClockCmd(I2C_MEMS_GPIO_CLK, ENABLE); /* GPIO configuration */ GPIO_InitStructure.GPIO_Pin = I2C_MEMS_SCL | I2C_MEMS_SDA; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_Init(I2C_MEMS_GPIO, &GPIO_InitStructure); /* I2C configuration */ I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = I2C_Speed; /* I2C Peripheral Enable */ I2C_Cmd(I2C_MEMS, ENABLE); /* Apply I2C configuration after enabling it */ I2C_Init(I2C_MEMS, &I2C_InitStructure); } void I2C_Master_DeInit(void) { GPIO_InitTypeDef GPIO_InitStructure; /* UnConfigure I2C */ I2C_DeInit(I2C_MEMS); I2C_Cmd(I2C_MEMS, DISABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE); /* UnConfigure I2C_MEMS pins: SCL and SDA */ GPIO_InitStructure.GPIO_Pin = I2C_MEMS_SCL | I2C_MEMS_SDA; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(I2C_MEMS_GPIO, &GPIO_InitStructure); } int I2C_Master_Read(uint8_t deviceAddr, uint8_t readAddr, uint8_t* pBuffer, uint16_t numByteToRead) { __IO uint32_t temp = 0; volatile int I2C_TimeOut = 0; // /* While the bus is busy * / I2C_TimeOut = I2C_TIMEOUT; while(I2C_GetFlagStatus(I2C_MEMS, I2C_FLAG_BUSY)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } // * Send START condition * / I2C_GenerateSTART(I2C_MEMS, ENABLE); // / * Test on EV5 and clear it * / I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_MODE_SELECT)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } // / * Send EEPROM address for write * / I2C_Send7bitAddress(I2C_MEMS, deviceAddr, I2C_Direction_Transmitter); // / * Test on EV6 and clear it * / I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } // / * Send the EEPROM's internal address to read from: Only one byte address * / I2C_SendData(I2C_MEMS, readAddr); /// * Test on EV8 and clear it * / I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /// * Send STRAT condition a second time * / I2C_GenerateSTART(I2C_MEMS, ENABLE); /// * Test on EV5 and clear it * / I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_MODE_SELECT)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } // * Send EEPROM address for read * / I2C_Send7bitAddress(I2C_MEMS, deviceAddr, I2C_Direction_Receiver); if (numByteToRead == 1) { /* Wait until ADDR is set */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->SR1&0x0002) != 0x0002) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Clear ACK bit */ I2C_MEMS->CR1 &= CR1_ACK_Reset; /* Disable all active IRQs around ADDR clearing and STOP programming because the EV6_3 software sequence must complete before the current byte end of transfer */ __disable_irq(); /* Clear ADDR flag */ temp = I2C_MEMS->SR2; /* Program the STOP */ I2C_GenerateSTOP(I2C_MEMS, ENABLE); /* Re-enable IRQs */ __enable_irq(); /* Wait until a data is received in DR register (RXNE = 1) EV7 */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->SR1 & 0x00040) != 0x000040) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Read the data */ *pBuffer = I2C_MEMS->DR; } else if (numByteToRead == 2) { /* Set POS bit */ I2C_MEMS->CR1 |= CR1_POS_Set; /* Wait until ADDR is set: EV6 */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->SR1&0x0002) != 0x0002) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* EV6_1: The acknowledge disable should be done just after EV6, that is after ADDR is cleared, so disable all active IRQs around ADDR clearing and ACK clearing */ __disable_irq(); /* Clear ADDR by reading SR2 register */ temp = I2C_MEMS->SR2; /* Clear ACK */ I2C_MEMS->CR1 &= CR1_ACK_Reset; /*Re-enable IRQs */ __enable_irq(); /* Wait until BTF is set */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->SR1 & 0x00004) != 0x000004) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Disable IRQs around STOP programming and data reading */ __disable_irq(); /* Program the STOP */ I2C_GenerateSTOP(I2C_MEMS, ENABLE); /* Read first data */ *pBuffer = I2C_MEMS->DR; /* Re-enable IRQs */ __enable_irq(); /**/ pBuffer++; /* Read second data */ *pBuffer = I2C_MEMS->DR; /* Clear POS bit */ I2C_MEMS->CR1 &= CR1_POS_Reset; } else { //numByteToRead > 2 // * Test on EV6 and clear it * / I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } // * While there is data to be read * / while(numByteToRead) { /* Receive bytes from first byte until byte N-3 */ if (numByteToRead != 3) { /* Poll on BTF to receive data because in polling mode we can not guarantee the EV7 software sequence is managed before the current byte transfer completes */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->SR1 & 0x00004) != 0x000004) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Read data */ *pBuffer = I2C_MEMS->DR; pBuffer++; /* Decrement the read bytes counter */ numByteToRead--; } /* it remains to read three data: data N-2, data N-1, Data N */ if (numByteToRead == 3) { /* Wait until BTF is set: Data N-2 in DR and data N -1 in shift register */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->SR1 & 0x00004) != 0x000004) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Clear ACK */ I2C_MEMS->CR1 &= CR1_ACK_Reset; /* Disable IRQs around data reading and STOP programming */ __disable_irq(); /* Read Data N-2 */ *pBuffer = I2C_MEMS->DR; /* Increment */ pBuffer++; /* Program the STOP */ I2C_MEMS->CR1 |= CR1_STOP_Set; /* Read DataN-1 */ *pBuffer = I2C_MEMS->DR; /* Re-enable IRQs */ __enable_irq(); /* Increment */ pBuffer++; /* Wait until RXNE is set (DR contains the last data) */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->SR1 & 0x00040) != 0x000040) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Read DataN */ *pBuffer = I2C_MEMS->DR; /* Reset the number of bytes to be read by master */ numByteToRead = 0; } } } /* Make sure that the STOP bit is cleared by Hardware before CR1 write access */ I2C_TimeOut = I2C_TIMEOUT; while ((I2C_MEMS->CR1&0x200) == 0x200) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } // * Enable Acknowledgement to be ready for another reception * / I2C_AcknowledgeConfig(I2C_MEMS, ENABLE); return 0; } int I2C_Master_Write(uint8_t deviceAddress, uint8_t WriteAddr, uint8_t* pBuffer, uint16_t numByteToWrite) { volatile int I2C_TimeOut = 0; /* Send STRAT condition */ I2C_GenerateSTART(I2C_MEMS, ENABLE); /* Test on EV5 and clear it */ I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_MODE_SELECT)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Send EEPROM address for write */ I2C_Send7bitAddress(I2C_MEMS, deviceAddress, I2C_Direction_Transmitter); /* Test on EV6 and clear it */ I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } /* Send the EEPROM's internal address to write to : only one byte Address */ I2C_SendData(I2C_MEMS, WriteAddr); /* Test on EV8 and clear it */ I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } while(numByteToWrite > 0) { /* Send the byte to be written */ I2C_SendData(I2C_MEMS, *pBuffer); /* Test on EV8 and clear it */ I2C_TimeOut = I2C_TIMEOUT; while(!I2C_CheckEvent(I2C_MEMS, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if (I2C_TimeOut-- <= 0){ return(I2C_TIMEOUT_UserCallback()); } } pBuffer++; numByteToWrite--; } /* Send STOP condition */ I2C_GenerateSTOP(I2C_MEMS, ENABLE); return 0; } int I2C_TIMEOUT_UserCallback(void) { /* User can add his own implementation to manage TimeOut Communication failure */ /* Block communication and all processes */ I2C_Master_DeInit(); for(int i=0; i<3000; i++){__asm("nop");} I2C_Master_Init(); for(int i=0; i<3000; i++){__asm("nop");} return -1; }
沒有留言:
張貼留言