AT24Cxx驱动

发布于 2022-07-04  555 次阅读


增加 i2c读写失败后,重新初始化i2c总线

初始化代码需要增加下面代码:

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */
	__HAL_RCC_GPIOB_CLK_ENABLE();

	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);       //拉高SCL
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);       //拉高SDA
	GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;      //此行原有
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;   //GPIO配置为输出
	GPIO_InitStruct.Pull = GPIO_PULLUP;
	GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;         //强上拉
	HAL_GPIO_Init(GPIOB,&GPIO_InitStruct);
	HAL_Delay(2);
	i2cHandle->Instance->CR1= I2C_CR1_SWRST;          //复位I2C控制器
	i2cHandle->Instance->CR1= 0;     
  /* USER CODE END I2C1_MspInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }
}
/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-04-13     XiaojieFan   the first version
 * 2019-12-04     RenMing      Use PAGE WRITE instead of BYTE WRITE and input address can be selected 
 */

#ifndef __AT24CXX_H__
#define __AT24CXX_H__

#include "main.h"

#define AT24C01     0
#define AT24C02     1
#define AT24C04     2
#define AT24C08     3
#define AT24C16     4
#define AT24C32     5
#define AT24C64     6
#define AT24C128    7
#define AT24C256    8
#define AT24C512    9
#define AT24CTYPE   10   // Number of supported types

#define EE_TWR      5

#ifndef EE_TYPE
#define EE_TYPE     AT24C256
#endif



typedef enum
{
	AT_EOK = 1,
	AT_ERROR = 2
}at24cxx_s;


struct at24cxx_device
{
    I2C_HandleTypeDef *i2c;
    osMutexId_t lock;
    uint8_t AddrInput;
};
typedef struct at24cxx_device *at24cxx_device_t;

void at24cxx_deinit(at24cxx_device_t dev);
at24cxx_device_t at24cxx_init(I2C_HandleTypeDef *hi2c, uint8_t AddrInput);
uint8_t at24cxx_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead);
uint8_t at24cxx_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite);
uint8_t at24cxx_page_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead);
uint8_t at24cxx_page_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite);
uint8_t at24cxx_page_erase(at24cxx_device_t dev, uint32_t WriteAddr, uint16_t NumToWrite);
#endif
#include <string.h>
#include <stdlib.h>
#include "stdio.h"

#include "at24cxx.h"


#define PKG_USING_AT24CXX

#ifdef PKG_USING_AT24CXX

//#define DRV_DEBUG

#ifdef DRV_DEBUG 
#define LOG_E(...)	lwlog_debug(__VA_ARGS__, "")
#define LOG_D(...)	lwlog_debug(__VA_ARGS__, "")
#else
#define LOG_E(...)
#define LOG_D(...)
#endif

#define AT24CXX_ADDR (0xA0)                      //A0 A1 A2 connect GND


#if (EE_TYPE == AT24C01)
    #define AT24CXX_PAGE_BYTE               8
    #define AT24CXX_MAX_MEM_ADDRESS         128
#elif (EE_TYPE == AT24C02)
    #define AT24CXX_PAGE_BYTE               8
    #define AT24CXX_MAX_MEM_ADDRESS         256
#elif (EE_TYPE == AT24C04)
    #define AT24CXX_PAGE_BYTE               16
    #define AT24CXX_MAX_MEM_ADDRESS         512
#elif (EE_TYPE == AT24C08)
    #define AT24CXX_PAGE_BYTE               16
    #define AT24CXX_MAX_MEM_ADDRESS         1024
#elif (EE_TYPE == AT24C16)
    #define AT24CXX_PAGE_BYTE               16
    #define AT24CXX_MAX_MEM_ADDRESS         2048
#elif (EE_TYPE == AT24C32)
    #define AT24CXX_PAGE_BYTE               32
    #define AT24CXX_MAX_MEM_ADDRESS         4096
#elif (EE_TYPE == AT24C64)
    #define AT24CXX_PAGE_BYTE               32
    #define AT24CXX_MAX_MEM_ADDRESS         8192
#elif (EE_TYPE == AT24C128)
    #define AT24CXX_PAGE_BYTE               64
    #define AT24CXX_MAX_MEM_ADDRESS         16384
#elif (EE_TYPE == AT24C256)
    #define AT24CXX_PAGE_BYTE               64
    #define AT24CXX_MAX_MEM_ADDRESS         32768
#elif (EE_TYPE == AT24C512)
    #define AT24CXX_PAGE_BYTE               128
    #define AT24CXX_MAX_MEM_ADDRESS         65536
#endif


/** 函数名:rt_hw_ms_delay
  * 功能	:
  * 输入	:
	* 输出	:
	* 编写人:XMW
  */
void rt_hw_ms_delay(uint32_t ms)
{
	osDelay(ms);
}

/** 函数名:read_regs
  * 功能	:读取寄存器
  * 输入	:
	* 输出	:
	* 编写人:XMW
  */
static uint8_t read_regs(at24cxx_device_t dev, uint8_t len, uint8_t *buf)
{
    if (HAL_I2C_Master_Receive(dev->i2c,AT24CXX_ADDR,buf,len,10) == HAL_OK)
    {
        return AT_EOK;
    }
    else
    {
        return AT_ERROR;
    }
}

/** 函数名:at24cxx_read_one_byte
  * 功能	:
  * 输入	:
	* 输出	:
	* 编写人:XMW
  */
uint8_t at24cxx_read_one_byte(at24cxx_device_t dev, uint16_t readAddr)
{
    uint8_t buf[2];
    uint8_t temp;
#if	(EE_TYPE > AT24C16)  
    buf[0] = (uint8_t)(readAddr>>8);	
    buf[1] = (uint8_t)readAddr;
    if (HAL_I2C_Master_Transmit(dev->i2c, AT24CXX_ADDR, buf, 2 ,10) != 0) 
#else
    buf[0] = readAddr;
    if (HAL_I2C_Master_Transmit(dev->i2c, AT24CXX_ADDR+((readAddr/256)<<1), buf, 1,10) != 0)
#endif        
    {
        return AT_ERROR;
    }
    read_regs(dev, 1, &temp);
    return temp;
}

/** 函数名:at24cxx_write_one_byte
  * 功能	:
  * 输入	:
	* 输出	:
	* 编写人:XMW
  */
uint8_t at24cxx_write_one_byte(at24cxx_device_t dev, uint16_t writeAddr, uint8_t dataToWrite)
{
    uint8_t buf[3];
#if	(EE_TYPE > AT24C16)      
    buf[0] = (uint8_t)(writeAddr>>8);	
    buf[1] = (uint8_t)writeAddr;
    buf[2] = dataToWrite;
    if (HAL_I2C_Master_Transmit(dev->i2c, AT24CXX_ADDR, buf, 3,10) == 0)    
#else    
    buf[0] = writeAddr; //cmd
    buf[1] = dataToWrite;
    if (HAL_I2C_Master_Transmit(dev->i2c, AT24CXX_ADDR+((writeAddr/256)<<1), buf, 2 , 10)  == 0)
#endif        
        return AT_EOK;
    else
        return AT_ERROR;
}

/** 函数名:at24cxx_read_page
  * 功能	:
  * 输入	:
	* 输出	:
	* 编写人:XMW
  */
uint8_t at24cxx_read_page(at24cxx_device_t dev, uint32_t readAddr, uint8_t *pBuffer, uint16_t numToRead)
{
	HAL_StatusTypeDef status;
	
	if (HAL_I2C_IsDeviceReady(dev->i2c, dev->AddrInput, 2, 0x1000) != HAL_OK)
  {
		HAL_I2C_DeInit(dev->i2c);
		HAL_I2C_Init(dev->i2c);
  }
	
#if	(EE_TYPE > AT24C16) 
		status = HAL_I2C_Mem_Read(dev->i2c,dev->AddrInput,readAddr,I2C_MEMADD_SIZE_16BIT,pBuffer,numToRead,20);
#else
    status = HAL_I2C_Mem_Read(dev->i2c,dev->AddrInput,readAddr,I2C_MEMADD_SIZE_8BIT,pBuffer,numToRead,20);
#endif
	if(status == HAL_OK)	
	{
		return AT_EOK;
	}
	else
	{
		HAL_I2C_DeInit(dev->i2c);
		HAL_I2C_Init(dev->i2c);	
		#if	(EE_TYPE > AT24C16) 
		status = HAL_I2C_Mem_Read(dev->i2c,dev->AddrInput,readAddr,I2C_MEMADD_SIZE_16BIT,pBuffer,numToRead,20);
		#else
    status = HAL_I2C_Mem_Read(dev->i2c,dev->AddrInput,readAddr,I2C_MEMADD_SIZE_8BIT,pBuffer,numToRead,20);
		#endif		
		return AT_ERROR;
	}
	
//	while (HAL_I2C_IsDeviceReady(dev->i2c, dev->AddrInput, 2, 0x1000) != HAL_OK){};
}

uint8_t at24cxx_write_page(at24cxx_device_t dev, uint32_t wirteAddr, uint8_t *pBuffer, uint16_t numToWrite)
{
		HAL_StatusTypeDef status;
	if (HAL_I2C_IsDeviceReady(dev->i2c, dev->AddrInput, 2, 0x1000) != HAL_OK)
  {
		HAL_I2C_DeInit(dev->i2c);
		HAL_I2C_Init(dev->i2c);
  }
#if	(EE_TYPE > AT24C16) 
		status = HAL_I2C_Mem_Write(dev->i2c,dev->AddrInput,wirteAddr,I2C_MEMADD_SIZE_16BIT,pBuffer,numToWrite,20);
#else
    status = HAL_I2C_Mem_Write(dev->i2c,dev->AddrInput,wirteAddr,I2C_MEMADD_SIZE_8BIT,pBuffer,numToWrite,20);
#endif    
		if(status != HAL_OK)  
		{
			HAL_I2C_DeInit(dev->i2c);
			HAL_I2C_Init(dev->i2c);
			#if	(EE_TYPE > AT24C16) 
			status = HAL_I2C_Mem_Write(dev->i2c,dev->AddrInput,wirteAddr,I2C_MEMADD_SIZE_16BIT,pBuffer,numToWrite,20);
			#else
			status = HAL_I2C_Mem_Write(dev->i2c,dev->AddrInput,wirteAddr,I2C_MEMADD_SIZE_8BIT,pBuffer,numToWrite,20);
			#endif
			return AT_ERROR;	
		}
		else 
		{
			return AT_EOK;
		}
//		while (HAL_I2C_IsDeviceReady(dev->i2c, dev->AddrInput, 2, 0x1000) != HAL_OK){};
}

uint8_t at24cxx_check(at24cxx_device_t dev)
{
    volatile uint8_t temp = 0x0 ,old_data;
		if(dev == NULL)  
			return AT_ERROR;
		rt_hw_ms_delay(EE_TWR);
    old_data = at24cxx_read_one_byte(dev, AT24CXX_MAX_MEM_ADDRESS - 1);

		at24cxx_write_one_byte(dev, AT24CXX_MAX_MEM_ADDRESS - 1, 0x55);
		rt_hw_ms_delay(EE_TWR);
		temp = at24cxx_read_one_byte(dev, AT24CXX_MAX_MEM_ADDRESS - 1);
		if (temp == 0x55) 
		{
			at24cxx_write_one_byte(dev, AT24CXX_MAX_MEM_ADDRESS - 1, old_data);
			rt_hw_ms_delay(EE_TWR);
			return AT_EOK;	
		}
 
    return AT_ERROR;
}

/**
 * This function read the specific numbers of data to the specific position
 *
 * @param bus the name of at24cxx device
 * @param ReadAddr the start position to read
 * @param pBuffer  the read data store position
 * @param NumToRead
 * @return AT_EOK  write ok.
 */
uint8_t at24cxx_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead)
{
    uint8_t result = AT_EOK;
		if(dev == NULL)  
			result = AT_ERROR;
	
    if(ReadAddr + NumToRead > AT24CXX_MAX_MEM_ADDRESS)
    {
        result = AT_ERROR;
    }
    osMutexAcquire(dev->lock,osWaitForever);

    if (result == AT_EOK)
    {
        while (NumToRead)
        {
            *pBuffer++ = at24cxx_read_one_byte(dev, ReadAddr++);
            NumToRead--;
        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }
		osMutexRelease(dev->lock);

    return result;
}

/**
 * This function read the specific numbers of data to the specific position
 *
 * @param bus the name of at24cxx device
 * @param ReadAddr the start position to read
 * @param pBuffer  the read data store position
 * @param NumToRead 
 * @return AT_EOK  write ok.
 */
uint8_t at24cxx_page_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead)
{
    uint8_t result = AT_EOK;
    uint16_t pageReadSize = AT24CXX_PAGE_BYTE - ReadAddr % AT24CXX_PAGE_BYTE;
	  
    if(ReadAddr + NumToRead > AT24CXX_MAX_MEM_ADDRESS)
    {
        return AT_ERROR;
    }
		osMutexAcquire(dev->lock,osWaitForever);
    if(result == AT_EOK)
    {
        while (NumToRead)
        {
            if(NumToRead > pageReadSize)
            {
                if(at24cxx_read_page(dev, ReadAddr, pBuffer, pageReadSize))
                {
                    result = AT_ERROR;
                }
//								rt_hw_ms_delay(EE_TWR);
                ReadAddr += pageReadSize;
                pBuffer += pageReadSize;
                NumToRead -= pageReadSize;
                pageReadSize = AT24CXX_PAGE_BYTE;
            }
            else
            {
                if(at24cxx_read_page(dev, ReadAddr, pBuffer, NumToRead))
                {
                    result = AT_ERROR;
                }
//								rt_hw_ms_delay(EE_TWR);
                NumToRead = 0;
            }
        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }
		osMutexRelease(dev->lock);
    return result;
}

/**
 * This function write the specific numbers of data to the specific position
 *
 * @param bus the name of at24cxx device
 * @param WriteAddr the start position to write
 * @param pBuffer  the data need to write
 * @param NumToWrite
 * @return AT_EOK  write ok.at24cxx_device_t dev
 */
uint8_t at24cxx_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite)
{
    uint16_t i = 0;
    uint8_t result= AT_EOK;
    if(dev == NULL)  
			result= AT_ERROR;
    if(WriteAddr + NumToWrite > AT24CXX_MAX_MEM_ADDRESS)
    {
        result= AT_ERROR;
    }
    osMutexAcquire(dev->lock,osWaitForever);
    if (result == AT_EOK)
    {
        while (1) //NumToWrite--
        {
            if (at24cxx_write_one_byte(dev, WriteAddr, pBuffer[i]) != AT_EOK)
            {
                rt_hw_ms_delay(EE_TWR);
            }
            else
            {
                WriteAddr++;
                i++;
            }
            if (i == NumToWrite)
            {
                break;
            }

        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }
		osMutexRelease(dev->lock);

    return result;
}

/**
 * This function write the specific numbers of data to the specific position
 *
 * @param bus the name of at24cxx device
 * @param WriteAddr the start position to write
 * @param pBuffer  the data need to write
 * @param NumToWrite
 * @return AT_EOK  write ok.at24cxx_device_t dev
 */
uint8_t at24cxx_page_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite)
{
    uint8_t result = AT_EOK;
    uint16_t pageWriteSize = AT24CXX_PAGE_BYTE - WriteAddr % AT24CXX_PAGE_BYTE;
    if(WriteAddr + NumToWrite > AT24CXX_MAX_MEM_ADDRESS)
    {
        return AT_ERROR;
    }
		osMutexAcquire(dev->lock,osWaitForever);
    if(result == AT_EOK)
    {
        while (NumToWrite)
        {
            if(NumToWrite > pageWriteSize)
            {
                if(at24cxx_write_page(dev, WriteAddr, pBuffer, pageWriteSize))
                {
                    result = AT_ERROR;
                }
                rt_hw_ms_delay(EE_TWR);    // wait 5ms befor next operation

                WriteAddr += pageWriteSize;
                pBuffer += pageWriteSize;
                NumToWrite -= pageWriteSize;
                pageWriteSize = AT24CXX_PAGE_BYTE;
            }
            else
            {
                if(at24cxx_write_page(dev, WriteAddr, pBuffer, NumToWrite))
                {
                    result = AT_ERROR;
                }
                rt_hw_ms_delay(EE_TWR);   // wait 5ms befor next operation

                NumToWrite = 0;
            }
        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }
		osMutexRelease(dev->lock);
    return result;
}

uint8_t pageErase[128];
/**
 * This function write the specific numbers of data to the specific position
 *
 * @param bus the name of at24cxx device
 * @param WriteAddr the start position to write
 * @param pBuffer  the data need to write
 * @param NumToWrite
 * @return AT_EOK  write ok.at24cxx_device_t dev
 */
uint8_t at24cxx_page_erase(at24cxx_device_t dev, uint32_t WriteAddr, uint16_t NumToWrite)
{
    uint8_t result = AT_EOK;
    uint16_t pageWriteSize = AT24CXX_PAGE_BYTE - WriteAddr % AT24CXX_PAGE_BYTE;
    if(WriteAddr + NumToWrite > AT24CXX_MAX_MEM_ADDRESS)
    {
        return AT_ERROR;
    }
		osMutexAcquire(dev->lock,osWaitForever);
    if(result == AT_EOK)
    {
        while (NumToWrite)
        {
            if(NumToWrite > pageWriteSize)
            {
                if(at24cxx_write_page(dev, WriteAddr, pageErase, pageWriteSize))
                {
                    result = AT_ERROR;
                }
                rt_hw_ms_delay(EE_TWR);    // wait 5ms befor next operation

                WriteAddr += pageWriteSize;
//                pBuffer += pageWriteSize;
                NumToWrite -= pageWriteSize;
                pageWriteSize = AT24CXX_PAGE_BYTE;
            }
            else
            {
                if(at24cxx_write_page(dev, WriteAddr, pageErase, NumToWrite))
                {
                    result = AT_ERROR;
                }
                rt_hw_ms_delay(EE_TWR);   // wait 5ms befor next operation

                NumToWrite = 0;
            }
        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }
		osMutexRelease(dev->lock);
    return result;
}

/**
 * This function initializes at24cxx registered device driver
 *
 * @param dev the name of at24cxx device
 *
 * @return the at24cxx device.
 */
static struct at24cxx_device atxdevice;
at24cxx_device_t at24cxx_init(I2C_HandleTypeDef *hi2c, uint8_t AddrInput)
{
	at24cxx_device_t dev;
	dev = &atxdevice;
	dev->i2c = hi2c;
	dev->lock = osMutexNew(NULL);
	dev->AddrInput = AT24CXX_ADDR;
	if (at24cxx_check(dev) != AT_EOK)
	{
		if(dev->lock != NULL)
			osMutexDelete(dev->lock);
		dev = NULL;
	}
  return dev;
}

/**
 * This function releases memory and deletes mutex lock
 *
 * @param dev the pointer of device driver structure
 */
void at24cxx_deinit(at24cxx_device_t dev)
{
	if(dev->lock != NULL)
			osMutexDelete(dev->lock);
	dev = NULL;
}

#endif

一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。