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;
}
沒有留言:
張貼留言