/**
|
******************************************************************************
|
* @file stm32_eval_i2c_ee.c
|
* @author MCD Application Team
|
* @version V4.5.0
|
* @date 07-March-2011
|
* @brief This file provides a set of functions needed to manage the I2C M24CXX
|
* EEPROM memory mounted on STM32xx-EVAL board (refer to stm32_eval.h
|
* to know about the boards supporting this memory).
|
*
|
* ===================================================================
|
* Note: This driver is intended for STM32F10x families devices only.
|
* ===================================================================
|
*
|
* It implements a high level communication layer for read and write
|
* from/to this memory. The needed STM32 hardware resources (I2C and
|
* GPIO) are defined in stm32xx_eval.h file, and the initialization is
|
* performed in sEE_LowLevel_Init() function declared in stm32xx_eval.c
|
* file.
|
* You can easily tailor this driver to any other development board,
|
* by just adapting the defines for hardware resources and
|
* sEE_LowLevel_Init() function.
|
*
|
* @note In this driver, basic read and write functions (sEE_ReadBuffer()
|
* and sEE_WritePage()) use the DMA to perform the data transfer
|
* to/from EEPROM memory (except when number of requested data is
|
* equal to 1). Thus, after calling these two functions, user
|
* application may perform other tasks while DMA is transferring
|
* data. The application should then monitor the variable holding
|
* the number of data in order to determine when the transfer is
|
* completed (variable decremented to 0). Stopping transfer tasks
|
* are performed into DMA interrupt handlers (which are integrated
|
* into this driver).
|
*
|
* +-----------------------------------------------------------------+
|
* | Pin assignment |
|
* +---------------------------------------+-----------+-------------+
|
* | STM32 I2C Pins | sEE | Pin |
|
* +---------------------------------------+-----------+-------------+
|
* | . | E0(GND) | 1 (0V) |
|
* | . | E1(GND) | 2 (0V) |
|
* | . | E2(GND) | 3 (0V) |
|
* | . | E0(VSS) | 4 (0V) |
|
* | sEE_I2C_SDA_PIN/ SDA | SDA | 5 |
|
* | sEE_I2C_SCL_PIN/ SCL | SCL | 6 |
|
* | . | /WC(VDD)| 7 (3.3V) |
|
* | . | VDD | 8 (3.3V) |
|
* +---------------------------------------+-----------+-------------+
|
******************************************************************************
|
* @attention
|
*
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
*
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
******************************************************************************
|
*/
|
|
/* Includes ------------------------------------------------------------------*/
|
#include "stm32_eval_i2c_ee.h"
|
|
/** @addtogroup Utilities
|
* @{
|
*/
|
|
/** @addtogroup STM32_EVAL
|
* @{
|
*/
|
|
/** @addtogroup Common
|
* @{
|
*/
|
|
/** @addtogroup STM32_EVAL_I2C_EE
|
* @brief This file includes the I2C EEPROM driver of STM32-EVAL boards.
|
* @{
|
*/
|
|
/** @defgroup STM32_EVAL_I2C_EE_Private_Types
|
* @{
|
*/
|
/**
|
* @}
|
*/
|
|
|
/** @defgroup STM32_EVAL_I2C_EE_Private_Defines
|
* @{
|
*/
|
/**
|
* @}
|
*/
|
|
|
/** @defgroup STM32_EVAL_I2C_EE_Private_Macros
|
* @{
|
*/
|
/**
|
* @}
|
*/
|
|
|
/** @defgroup STM32_EVAL_I2C_EE_Private_Variables
|
* @{
|
*/
|
__IO uint16_t sEEAddress = 0;
|
__IO uint32_t sEETimeout = sEE_LONG_TIMEOUT;
|
__IO uint16_t* sEEDataReadPointer;
|
__IO uint8_t* sEEDataWritePointer;
|
__IO uint8_t sEEDataNum;
|
/**
|
* @}
|
*/
|
|
|
/** @defgroup STM32_EVAL_I2C_EE_Private_Function_Prototypes
|
* @{
|
*/
|
/**
|
* @}
|
*/
|
|
|
/** @defgroup STM32_EVAL_I2C_EE_Private_Functions
|
* @{
|
*/
|
|
/**
|
* @brief DeInitializes peripherals used by the I2C EEPROM driver.
|
* @param None
|
* @retval None
|
*/
|
void sEE_DeInit(void)
|
{
|
sEE_LowLevel_DeInit();
|
}
|
|
/**
|
* @brief Initializes peripherals used by the I2C EEPROM driver.
|
* @param None
|
* @retval None
|
*/
|
void sEE_Init(void)
|
{
|
I2C_InitTypeDef I2C_InitStructure;
|
|
sEE_LowLevel_Init();
|
|
/*!< I2C configuration */
|
/* sEE_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;
|
|
/* sEE_I2C Peripheral Enable */
|
I2C_Cmd(sEE_I2C, ENABLE);
|
/* Apply sEE_I2C configuration after enabling it */
|
I2C_Init(sEE_I2C, &I2C_InitStructure);
|
|
/* Enable the sEE_I2C peripheral DMA requests */
|
I2C_DMACmd(sEE_I2C, ENABLE);
|
|
#if defined (sEE_M24C64_32)
|
/*!< Select the EEPROM address according to the state of E0, E1, E2 pins */
|
sEEAddress = sEE_HW_ADDRESS;
|
#elif defined (sEE_M24C08)
|
/*!< depending on the sEE Address selected in the i2c_ee.h file */
|
#ifdef sEE_Block0_ADDRESS
|
/*!< Select the sEE Block0 to write on */
|
sEEAddress = sEE_Block0_ADDRESS;
|
#endif
|
|
#ifdef sEE_Block1_ADDRESS
|
/*!< Select the sEE Block1 to write on */
|
sEEAddress = sEE_Block1_ADDRESS;
|
#endif
|
|
#ifdef sEE_Block2_ADDRESS
|
/*!< Select the sEE Block2 to write on */
|
sEEAddress = sEE_Block2_ADDRESS;
|
#endif
|
|
#ifdef sEE_Block3_ADDRESS
|
/*!< Select the sEE Block3 to write on */
|
sEEAddress = sEE_Block3_ADDRESS;
|
#endif
|
#endif /*!< sEE_M24C64_32 */
|
}
|
|
/**
|
* @brief Reads a block of data from the EEPROM.
|
* @param pBuffer : pointer to the buffer that receives the data read from
|
* the EEPROM.
|
* @param ReadAddr : EEPROM's internal address to start reading from.
|
* @param NumByteToRead : pointer to the variable holding number of bytes to
|
* be read from the EEPROM.
|
*
|
* @note The variable pointed by NumByteToRead is reset to 0 when all the
|
* data are read from the EEPROM. Application should monitor this
|
* variable in order know when the transfer is complete.
|
*
|
* @note When number of data to be read is higher than 1, this function just
|
* configures the communication and enable the DMA channel to transfer data.
|
* Meanwhile, the user application may perform other tasks.
|
* When number of data to be read is 1, then the DMA is not used. The byte
|
* is read in polling mode.
|
*
|
* @retval sEE_OK (0) if operation is correctly performed, else return value
|
* different from sEE_OK (0) or the timeout user callback.
|
*/
|
uint32_t sEE_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead)
|
{
|
/* Set the pointer to the Number of data to be read. This pointer will be used
|
by the DMA Transfer Completer interrupt Handler in order to reset the
|
variable to 0. User should check on this variable in order to know if the
|
DMA transfer has been complete or not. */
|
sEEDataReadPointer = NumByteToRead;
|
|
/*!< While the bus is busy */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while(I2C_GetFlagStatus(sEE_I2C, I2C_FLAG_BUSY))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send START condition */
|
I2C_GenerateSTART(sEE_I2C, ENABLE);
|
|
/*!< Test on EV5 and clear it (cleared by reading SR1 then writing to DR) */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_MODE_SELECT))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send EEPROM address for write */
|
I2C_Send7bitAddress(sEE_I2C, sEEAddress, I2C_Direction_Transmitter);
|
|
/*!< Test on EV6 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
#ifdef sEE_M24C08
|
|
/*!< Send the EEPROM's internal address to read from: Only one byte address */
|
I2C_SendData(sEE_I2C, ReadAddr);
|
|
#elif defined (sEE_M24C64_32)
|
|
/*!< Send the EEPROM's internal address to read from: MSB of the address first */
|
I2C_SendData(sEE_I2C, (uint8_t)((ReadAddr & 0xFF00) >> 8));
|
|
/*!< Test on EV8 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send the EEPROM's internal address to read from: LSB of the address */
|
I2C_SendData(sEE_I2C, (uint8_t)(ReadAddr & 0x00FF));
|
|
#endif /*!< sEE_M24C08 */
|
|
/*!< Test on EV8 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(I2C_GetFlagStatus(sEE_I2C, I2C_FLAG_BTF) == RESET)
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send STRAT condition a second time */
|
I2C_GenerateSTART(sEE_I2C, ENABLE);
|
|
/*!< Test on EV5 and clear it (cleared by reading SR1 then writing to DR) */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_MODE_SELECT))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send EEPROM address for read */
|
I2C_Send7bitAddress(sEE_I2C, sEEAddress, I2C_Direction_Receiver);
|
|
/* If number of data to be read is 1, then DMA couldn't be used */
|
/* One Byte Master Reception procedure (POLLING) ---------------------------*/
|
if ((uint16_t)(*NumByteToRead) < 2)
|
{
|
/* Wait on ADDR flag to be set (ADDR is still not cleared at this level */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(I2C_GetFlagStatus(sEE_I2C, I2C_FLAG_ADDR) == RESET)
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Disable Acknowledgement */
|
I2C_AcknowledgeConfig(sEE_I2C, DISABLE);
|
|
/* Call User callback for critical section start (should typically disable interrupts) */
|
sEE_EnterCriticalSection_UserCallback();
|
|
/* Clear ADDR register by reading SR1 then SR2 register (SR1 has already been read) */
|
(void)sEE_I2C->SR2;
|
|
/*!< Send STOP Condition */
|
I2C_GenerateSTOP(sEE_I2C, ENABLE);
|
|
/* Call User callback for critical section end (should typically re-enable interrupts) */
|
sEE_ExitCriticalSection_UserCallback();
|
|
/* Wait for the byte to be received */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(I2C_GetFlagStatus(sEE_I2C, I2C_FLAG_RXNE) == RESET)
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Read the byte received from the EEPROM */
|
*pBuffer = I2C_ReceiveData(sEE_I2C);
|
|
/*!< Decrement the read bytes counter */
|
(uint16_t)(*NumByteToRead)--;
|
|
/* Wait to make sure that STOP control bit has been cleared */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(sEE_I2C->CR1 & I2C_CR1_STOP)
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Re-Enable Acknowledgement to be ready for another reception */
|
I2C_AcknowledgeConfig(sEE_I2C, ENABLE);
|
}
|
else/* More than one Byte Master Reception procedure (DMA) -----------------*/
|
{
|
/*!< Test on EV6 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/* Configure the DMA Rx Channel with the buffer address and the buffer size */
|
sEE_LowLevel_DMAConfig((uint32_t)pBuffer, (uint16_t)(*NumByteToRead), sEE_DIRECTION_RX);
|
|
/* Inform the DMA that the next End Of Transfer Signal will be the last one */
|
I2C_DMALastTransferCmd(sEE_I2C, ENABLE);
|
|
/* Enable the DMA Rx Channel */
|
DMA_Cmd(sEE_I2C_DMA_CHANNEL_RX, ENABLE);
|
}
|
|
/* If all operations OK, return sEE_OK (0) */
|
return sEE_OK;
|
}
|
|
/**
|
* @brief Writes more than one byte to the EEPROM with a single WRITE cycle.
|
*
|
* @note The number of bytes (combined to write start address) must not
|
* cross the EEPROM page boundary. This function can only write into
|
* the boundaries of an EEPROM page.
|
* This function doesn't check on boundaries condition (in this driver
|
* the function sEE_WriteBuffer() which calls sEE_WritePage() is
|
* responsible of checking on Page boundaries).
|
*
|
* @param pBuffer : pointer to the buffer containing the data to be written to
|
* the EEPROM.
|
* @param WriteAddr : EEPROM's internal address to write to.
|
* @param NumByteToWrite : pointer to the variable holding number of bytes to
|
* be written into the EEPROM.
|
*
|
* @note The variable pointed by NumByteToWrite is reset to 0 when all the
|
* data are written to the EEPROM. Application should monitor this
|
* variable in order know when the transfer is complete.
|
*
|
* @note This function just configure the communication and enable the DMA
|
* channel to transfer data. Meanwhile, the user application may perform
|
* other tasks in parallel.
|
*
|
* @retval sEE_OK (0) if operation is correctly performed, else return value
|
* different from sEE_OK (0) or the timeout user callback.
|
*/
|
uint32_t sEE_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite)
|
{
|
/* Set the pointer to the Number of data to be written. This pointer will be used
|
by the DMA Transfer Completer interrupt Handler in order to reset the
|
variable to 0. User should check on this variable in order to know if the
|
DMA transfer has been complete or not. */
|
sEEDataWritePointer = NumByteToWrite;
|
|
/*!< While the bus is busy */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while(I2C_GetFlagStatus(sEE_I2C, I2C_FLAG_BUSY))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send START condition */
|
I2C_GenerateSTART(sEE_I2C, ENABLE);
|
|
/*!< Test on EV5 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_MODE_SELECT))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send EEPROM address for write */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
I2C_Send7bitAddress(sEE_I2C, sEEAddress, I2C_Direction_Transmitter);
|
|
/*!< Test on EV6 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
#ifdef sEE_M24C08
|
|
/*!< Send the EEPROM's internal address to write to : only one byte Address */
|
I2C_SendData(sEE_I2C, WriteAddr);
|
|
#elif defined(sEE_M24C64_32)
|
|
/*!< Send the EEPROM's internal address to write to : MSB of the address first */
|
I2C_SendData(sEE_I2C, (uint8_t)((WriteAddr & 0xFF00) >> 8));
|
|
/*!< Test on EV8 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send the EEPROM's internal address to write to : LSB of the address */
|
I2C_SendData(sEE_I2C, (uint8_t)(WriteAddr & 0x00FF));
|
|
#endif /*!< sEE_M24C08 */
|
|
/*!< Test on EV8 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTED))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/* Configure the DMA Tx Channel with the buffer address and the buffer size */
|
sEE_LowLevel_DMAConfig((uint32_t)pBuffer, (uint8_t)(*NumByteToWrite), sEE_DIRECTION_TX);
|
|
/* Enable the DMA Tx Channel */
|
DMA_Cmd(sEE_I2C_DMA_CHANNEL_TX, ENABLE);
|
|
/* If all operations OK, return sEE_OK (0) */
|
return sEE_OK;
|
}
|
|
/**
|
* @brief Writes buffer of data to the I2C EEPROM.
|
* @param pBuffer : pointer to the buffer containing the data to be written
|
* to the EEPROM.
|
* @param WriteAddr : EEPROM's internal address to write to.
|
* @param NumByteToWrite : number of bytes to write to the EEPROM.
|
* @retval None
|
*/
|
void sEE_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite)
|
{
|
uint8_t NumOfPage = 0, NumOfSingle = 0, count = 0;
|
uint16_t Addr = 0;
|
|
Addr = WriteAddr % sEE_PAGESIZE;
|
count = sEE_PAGESIZE - Addr;
|
NumOfPage = NumByteToWrite / sEE_PAGESIZE;
|
NumOfSingle = NumByteToWrite % sEE_PAGESIZE;
|
|
/*!< If WriteAddr is sEE_PAGESIZE aligned */
|
if(Addr == 0)
|
{
|
/*!< If NumByteToWrite < sEE_PAGESIZE */
|
if(NumOfPage == 0)
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = NumOfSingle;
|
/* Start writing data */
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
}
|
/*!< If NumByteToWrite > sEE_PAGESIZE */
|
else
|
{
|
while(NumOfPage--)
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = sEE_PAGESIZE;
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
WriteAddr += sEE_PAGESIZE;
|
pBuffer += sEE_PAGESIZE;
|
}
|
|
if(NumOfSingle!=0)
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = NumOfSingle;
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
}
|
}
|
}
|
/*!< If WriteAddr is not sEE_PAGESIZE aligned */
|
else
|
{
|
/*!< If NumByteToWrite < sEE_PAGESIZE */
|
if(NumOfPage== 0)
|
{
|
/*!< If the number of data to be written is more than the remaining space
|
in the current page: */
|
if (NumByteToWrite > count)
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = count;
|
/*!< Write the data conained in same page */
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
|
/* Store the number of data to be written */
|
sEEDataNum = (NumByteToWrite - count);
|
/*!< Write the remaining data in the following page */
|
sEE_WritePage((uint8_t*)(pBuffer + count), (WriteAddr + count), (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
}
|
else
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = NumOfSingle;
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
}
|
}
|
/*!< If NumByteToWrite > sEE_PAGESIZE */
|
else
|
{
|
NumByteToWrite -= count;
|
NumOfPage = NumByteToWrite / sEE_PAGESIZE;
|
NumOfSingle = NumByteToWrite % sEE_PAGESIZE;
|
|
if(count != 0)
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = count;
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
WriteAddr += count;
|
pBuffer += count;
|
}
|
|
while(NumOfPage--)
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = sEE_PAGESIZE;
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
WriteAddr += sEE_PAGESIZE;
|
pBuffer += sEE_PAGESIZE;
|
}
|
if(NumOfSingle != 0)
|
{
|
/* Store the number of data to be written */
|
sEEDataNum = NumOfSingle;
|
sEE_WritePage(pBuffer, WriteAddr, (uint8_t*)(&sEEDataNum));
|
/* Wait transfer through DMA to be complete */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while (sEEDataNum > 0)
|
{
|
if((sEETimeout--) == 0) {sEE_TIMEOUT_UserCallback(); return;};
|
}
|
sEE_WaitEepromStandbyState();
|
}
|
}
|
}
|
}
|
|
/**
|
* @brief Wait for EEPROM Standby state.
|
*
|
* @note This function allows to wait and check that EEPROM has finished the
|
* last Write operation. It is mostly used after Write operation: after
|
* receiving the buffer to be written, the EEPROM may need additional
|
* time to actually perform the write operation. During this time, it
|
* doesn't answer to I2C packets addressed to it. Once the write operation
|
* is complete the EEPROM responds to its address.
|
*
|
* @note It is not necessary to call this function after sEE_WriteBuffer()
|
* function (sEE_WriteBuffer() already calls this function after each
|
* write page operation).
|
*
|
* @param None
|
* @retval sEE_OK (0) if operation is correctly performed, else return value
|
* different from sEE_OK (0) or the timeout user callback.
|
*/
|
uint32_t sEE_WaitEepromStandbyState(void)
|
{
|
__IO uint16_t tmpSR1 = 0;
|
__IO uint32_t sEETrials = 0;
|
|
/*!< While the bus is busy */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while(I2C_GetFlagStatus(sEE_I2C, I2C_FLAG_BUSY))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/* Keep looping till the slave acknowledge his address or maximum number
|
of trials is reached (this number is defined by sEE_MAX_TRIALS_NUMBER define
|
in stm32_eval_i2c_ee.h file) */
|
while (1)
|
{
|
/*!< Send START condition */
|
I2C_GenerateSTART(sEE_I2C, ENABLE);
|
|
/*!< Test on EV5 and clear it */
|
sEETimeout = sEE_FLAG_TIMEOUT;
|
while(!I2C_CheckEvent(sEE_I2C, I2C_EVENT_MASTER_MODE_SELECT))
|
{
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send EEPROM address for write */
|
I2C_Send7bitAddress(sEE_I2C, sEEAddress, I2C_Direction_Transmitter);
|
|
/* Wait for ADDR flag to be set (Slave acknowledged his address) */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
do
|
{
|
/* Get the current value of the SR1 register */
|
tmpSR1 = sEE_I2C->SR1;
|
|
/* Update the timeout value and exit if it reach 0 */
|
if((sEETimeout--) == 0) return sEE_TIMEOUT_UserCallback();
|
}
|
/* Keep looping till the Address is acknowledged or the AF flag is
|
set (address not acknowledged at time) */
|
while((tmpSR1 & (I2C_SR1_ADDR | I2C_SR1_AF)) == 0);
|
|
/* Check if the ADDR flag has been set */
|
if (tmpSR1 & I2C_SR1_ADDR)
|
{
|
/* Clear ADDR Flag by reading SR1 then SR2 registers (SR1 have already
|
been read) */
|
(void)sEE_I2C->SR2;
|
|
/*!< STOP condition */
|
I2C_GenerateSTOP(sEE_I2C, ENABLE);
|
|
/* Exit the function */
|
return sEE_OK;
|
}
|
else
|
{
|
/*!< Clear AF flag */
|
I2C_ClearFlag(sEE_I2C, I2C_FLAG_AF);
|
}
|
|
/* Check if the maximum allowed numbe of trials has bee reached */
|
if (sEETrials++ == sEE_MAX_TRIALS_NUMBER)
|
{
|
/* If the maximum number of trials has been reached, exit the function */
|
return sEE_TIMEOUT_UserCallback();
|
}
|
}
|
}
|
|
/**
|
* @brief This function handles the DMA Tx Channel interrupt Handler.
|
* @param None
|
* @retval None
|
*/
|
void sEE_I2C_DMA_TX_IRQHandler(void)
|
{
|
/* Check if the DMA transfer is complete */
|
if(DMA_GetFlagStatus(sEE_I2C_DMA_FLAG_TX_TC) != RESET)
|
{
|
/* Disable the DMA Tx Channel and Clear all its Flags */
|
DMA_Cmd(sEE_I2C_DMA_CHANNEL_TX, DISABLE);
|
DMA_ClearFlag(sEE_I2C_DMA_FLAG_TX_GL);
|
|
/*!< Wait till all data have been physically transferred on the bus */
|
sEETimeout = sEE_LONG_TIMEOUT;
|
while(!I2C_GetFlagStatus(sEE_I2C, I2C_FLAG_BTF))
|
{
|
if((sEETimeout--) == 0) sEE_TIMEOUT_UserCallback();
|
}
|
|
/*!< Send STOP condition */
|
I2C_GenerateSTOP(sEE_I2C, ENABLE);
|
|
/* Perform a read on SR1 and SR2 register to clear eventualaly pending flags */
|
(void)sEE_I2C->SR1;
|
(void)sEE_I2C->SR2;
|
|
/* Reset the variable holding the number of data to be written */
|
*sEEDataWritePointer = 0;
|
}
|
}
|
|
/**
|
* @brief This function handles the DMA Rx Channel interrupt Handler.
|
* @param None
|
* @retval None
|
*/
|
void sEE_I2C_DMA_RX_IRQHandler(void)
|
{
|
/* Check if the DMA transfer is complete */
|
if(DMA_GetFlagStatus(sEE_I2C_DMA_FLAG_RX_TC) != RESET)
|
{
|
/*!< Send STOP Condition */
|
I2C_GenerateSTOP(sEE_I2C, ENABLE);
|
|
/* Disable the DMA Rx Channel and Clear all its Flags */
|
DMA_Cmd(sEE_I2C_DMA_CHANNEL_RX, DISABLE);
|
DMA_ClearFlag(sEE_I2C_DMA_FLAG_RX_GL);
|
|
/* Reset the variable holding the number of data to be read */
|
*sEEDataReadPointer = 0;
|
}
|
}
|
|
#ifdef USE_DEFAULT_TIMEOUT_CALLBACK
|
/**
|
* @brief Basic management of the timeout situation.
|
* @param None.
|
* @retval None.
|
*/
|
uint32_t sEE_TIMEOUT_UserCallback(void)
|
{
|
/* Block communication and all processes */
|
while (1)
|
{
|
}
|
}
|
#endif /* USE_DEFAULT_TIMEOUT_CALLBACK */
|
|
#ifdef USE_DEFAULT_CRITICAL_CALLBACK
|
/**
|
* @brief Start critical section: these callbacks should be typically used
|
* to disable interrupts when entering a critical section of I2C communication
|
* You may use default callbacks provided into this driver by uncommenting the
|
* define USE_DEFAULT_CRITICAL_CALLBACK.
|
* Or you can comment that line and implement these callbacks into your
|
* application.
|
* @param None.
|
* @retval None.
|
*/
|
void sEE_EnterCriticalSection_UserCallback(void)
|
{
|
__disable_irq();
|
}
|
|
/**
|
* @brief Start and End of critical section: these callbacks should be typically used
|
* to re-enable interrupts when exiting a critical section of I2C communication
|
* You may use default callbacks provided into this driver by uncommenting the
|
* define USE_DEFAULT_CRITICAL_CALLBACK.
|
* Or you can comment that line and implement these callbacks into your
|
* application.
|
* @param None.
|
* @retval None.
|
*/
|
void sEE_ExitCriticalSection_UserCallback(void)
|
{
|
__enable_irq();
|
}
|
#endif /* USE_DEFAULT_CRITICAL_CALLBACK */
|
|
/**
|
* @}
|
*/
|
|
/**
|
* @}
|
*/
|
|
/**
|
* @}
|
*/
|
|
/**
|
* @}
|
*/
|
|
/**
|
* @}
|
*/
|
|
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|