关于flashW25Q256的驱动问题

qq_39780508 2019-01-11 02:43:12
您们好,现在有个很急的问题想请教各位,麻烦抽点时间指教下,万分感谢;
关于flashW25Q256的驱动问题:1、我每次向flash里写m个常数数据(如rx[m] = 1),写n组,地址是连续递增的,但读出来只有前m个数据是正常的,后m*n-m个数据全是255,并且当写入的是变量数据(如rx[m] += 1)时,读出来的前m位还是0或其他错误的数;而一次性将m*n个数据写进flash则不会出现以上两种问题;

...全文
964 3 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
co_sherry 2019-01-19
  • 打赏
  • 举报
回复
写入之前擦除没?有没有注意写入地址与页地址偏移问题
fly 100% 2019-01-12
  • 打赏
  • 举报
回复
擦完没写入就是255 看样子是没有翻页 ,地址位宽不够
qq_39780508 2019-01-11
  • 打赏
  • 举报
回复
/**
  * @file  w25q.c
  * @brief w25q flash驱动
	*        接口: 1个SPI + 1个GPIO 
  * @par   date        version    author    remarks
	*        2018-12-01  v4.0       esone      
  *
  */
	
/** 头文件包含区 ------------------------------------------------ */
#include "w25q128.h" 
#include "spi.h"


/** 接口 -------------------------------------------------------- */

/** ★ SPI口CUBE配置: 8bit, MSB First,5.25Mbits/s, HIGH, 2 edge, disable, software  */
/** ★ GPIO口CUBE配置(接w25q128的CS的引脚): 输出推挽 + 上拉电阻; 标签: W25Q_CS */

static SPI_HandleTypeDef* p_w25q_spi = &hspi1;    /**< ★ SPI口  */			

#define W25Q_CS_LOW()     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET) /**< ★ GPIO口  */	
#define W25Q_CS_HIGH()    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET)
#define W25Q_WP_HIGH()    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_12, GPIO_PIN_SET)
#define W25Q_RST_HIGH()    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_10, GPIO_PIN_SET)

/** 私有变量 -------------------------------------------------------- */
static uint8_t addr_4b_flg = 0;


/** 内部函数 --------------------------------------------------- */
static void w25q_cmd(uint8_t* p_data, uint16_t size);
static void w25q_wr_cmd(uint8_t* p_data, uint16_t size);
static void w25q_wr_enable(void);
static void w25q_wr_disable(void);
static void w25q_busy_wait(void);
static void w25q_erase_4k(uint32_t addr);
static uint8_t w25q_rd_ads(void);
static void w25q_set_4b(void);
static uint16_t w25q_id(void);


/** 私有宏(类型定义) -------------------------------------------- */ 
#define W25Q256                 0XEF18

#define W25Q_ID 			          0x90    /**< 4: 制造商ID(0xEF);5:设备ID */
#define W25Q_STATUS_1       	  0x05    /**< 读取状态寄存器(S7 -S0 ) */
#define W25Q_STATUS_3       	  0x15    /**< 读取状态寄存器(S23-S16) */
#define W25Q_WR_ENABLE        	0x06    
#define W25Q_WR_DISABLE       	0x04
#define W25Q_4K_ERASE     			0x20    /**< 擦除4K空间 */
#define W25Q_64K_ERASE     			0xD8    /**< 擦除64K空间 */
#define W25Q_RD_DATA_1B    			0x03    /**< 读取1B数据 */
#define W25Q_RD_DATA    				0x0B    /**< 快速读取数据 */
#define W25Q_WR_PAGE        		0x02    /**< 写不超过1页数据 */
#define W25Q_4BYTE_ADDR         0xB7    /**< 设置4字节地址 */
#define DUMMY              			0xFF    /**< 无效命令 */

#define W25Q_BUSY      					0x01    /**< BUSY位 */
#define W25Q_ADS      					0x01    /**< ADS位 */

#define W25Q_ERASE_CHIP               0xC7

/** 公有函数 --------------------------------------------------- */

/**
  * @brief  芯片初始化
  * @param	None
  * @retval None
  * @note   
  */
void w25q_init(void)
{
	/** 片选除能 */
	W25Q_CS_HIGH();
  
  W25Q_WP_HIGH();
  W25Q_RST_HIGH();
	
	/** SPI使能 */
	__HAL_SPI_ENABLE(p_w25q_spi);
  
  /** 读取flash的id */
  uint16_t id = w25q_id();
	printf("id = %x \r\n", id);  
  
  /** 如果是W25Q256,设置为4字节地址*/
  if(id == W25Q256)                
  {
    uint8_t ads = w25q_rd_ads();        /**< 读取状态位ads,判断是否为4字节地址  */
    if(ads == 0)			            /**< 如果不是4字节地址  */
    {
      w25q_set_4b();                    /**< 设置为4字节地址  */  
      addr_4b_flg = 1;
    }
  }
//  w25q_test();
}

/**
  * @brief  在指定地址,读指定长度的数据
  * @param	addr   32位地址
  * @param	size   字节数(< 256)
  * @param	p_dat  数据存储区指针
  * @retval NONE
  * @note  
  */
void w25q_rd_data(uint32_t addr, uint16_t size, uint8_t* p_dat)
{
  uint8_t addr_len = 3;
  uint8_t cmd_buf[6] = {W25Q_RD_DATA, DUMMY, DUMMY, DUMMY, DUMMY, DUMMY};
  
  if(addr_4b_flg)
  {
    addr_len = 4;
    cmd_buf[1] = (uint8_t)(addr >> 24); 
    cmd_buf[2] = (uint8_t)(addr >> 16); 
    cmd_buf[3] = (uint8_t)(addr >>  8);
    cmd_buf[4] = (uint8_t)addr;
  }	
  else
  {
    cmd_buf[1] = (uint8_t)(addr >> 16); 
    cmd_buf[2] = (uint8_t)(addr >>  8);
    cmd_buf[3] = (uint8_t)addr;  
  }

	W25Q_CS_LOW();
	HAL_SPI_Transmit(p_w25q_spi, &cmd_buf[0], addr_len + 2, 1000);		
	HAL_SPI_Receive(p_w25q_spi, p_dat, size, 1000);
	W25Q_CS_HIGH();
}

/**
  * @brief  在指定地址,写指定长度的数据
  * @param	addr   32位地址
  * @param	size   字节数(< 256)
  * @param	p_dat  数据存储区指针
  * @retval NONE
  * @note   
  */
void w25q_wr_data(uint32_t addr, uint16_t size, uint8_t* p_dat)
{
  uint8_t page_remain = 256 - addr % 256;           /**< 当前页剩余字节数  */
  uint8_t wr_bytes_cur_page;                        /**< 当前页写入字节数  */
  uint8_t wr_bytes_next_page;                       /**< 下一页写入字节数  */  
  uint8_t addr_len = 3;
  uint8_t cmd_buf[5] = {W25Q_WR_PAGE, DUMMY, DUMMY, DUMMY, DUMMY}; 
  
  /** 写入数据在新的8K区域,擦除新区域  */
  if((addr % 8192) == 0)       
  {
    w25q_erase_4k(addr);
    w25q_busy_wait();
    w25q_erase_4k(addr + 4096);
    w25q_busy_wait();
  }

  /** 写入数据是否跨页  */
  if(size <= page_remain)                 /**< 未跨页  */
  {
    wr_bytes_cur_page  = size;
    wr_bytes_next_page = 0;    
  } 
  else                                    /**< 跨页  */
  {
    wr_bytes_cur_page  = page_remain;
    wr_bytes_next_page = size - page_remain;    
  } 
  printf("flash_addr is %d\r\n", addr);
  /** 输入地址  */
  if(addr_4b_flg)
  {
    addr_len = 4;
    cmd_buf[1] = (uint8_t)(addr >> 24); 
    cmd_buf[2] = (uint8_t)(addr >> 16); 
    cmd_buf[3] = (uint8_t)(addr >>  8);
    cmd_buf[4] = (uint8_t)addr;
  }	
  else
  {
    cmd_buf[1] = (uint8_t)(addr >> 16); 
    cmd_buf[2] = (uint8_t)(addr >>  8);
    cmd_buf[3] = (uint8_t)addr;  
  } 
  for(int j = 1; j < 5; j++)
  {
      printf("cmd_buf[%d] is %d\r\n", j, cmd_buf[j]);
  }
  /** 写数据到当前页  */
  w25q_wr_enable();	
  W25Q_CS_LOW();
	HAL_SPI_Transmit(p_w25q_spi, &cmd_buf[0], addr_len + 1, 1000);		
	HAL_SPI_Transmit(p_w25q_spi, p_dat, wr_bytes_cur_page, 1000);
	W25Q_CS_HIGH();
  w25q_wr_disable();
  
  /** 写数据到下一页  */
  if(wr_bytes_next_page)
  {
    if(addr_4b_flg)
    {
      cmd_buf[1] = (uint8_t)((addr + page_remain) >> 24); 
      cmd_buf[2] = (uint8_t)((addr + page_remain) >> 16); 
      cmd_buf[3] = (uint8_t)((addr + page_remain) >>  8);
      cmd_buf[4] = 0;
    }	
    else
    {
      cmd_buf[1] = (uint8_t)((addr + page_remain) >> 16); 
      cmd_buf[2] = (uint8_t)((addr + page_remain) >>  8);
      cmd_buf[3] = 0;  
    } 
    for(int j = 1; j < 5; j++)
   {
      printf("cmd_buf[%d] is %d\r\n", j, cmd_buf[j]);
   }
    w25q_wr_enable();	
    W25Q_CS_LOW();
    HAL_SPI_Transmit(p_w25q_spi, &cmd_buf[0], addr_len + 1, 1000);		
    HAL_SPI_Transmit(p_w25q_spi, p_dat + wr_bytes_cur_page, wr_bytes_next_page, 1000);
    W25Q_CS_HIGH();  
    w25q_wr_disable();
  }
	
}

void w25q_erase_chip(void)
{
    uint8_t cmd_buf[1] = {W25Q_ERASE_CHIP}; 
	w25q_wr_enable();		
	w25q_busy_wait();
	
	W25Q_CS_LOW();
	HAL_SPI_Transmit(p_w25q_spi, cmd_buf, 1, 1000);
	W25Q_CS_HIGH();	
    w25q_busy_wait();
//	w25q_wr_disable();
}


/** 私有函数 --------------------------------------------------- */



/**
  * @brief  w25q通讯命令(读写)
  * @param	p_data 命令缓冲区指针
  * @param	size   命令字节数
  * @retval None
  * @note   
  */
static void w25q_cmd(uint8_t* p_data, uint16_t size)
{
	w25q_busy_wait();
	
	W25Q_CS_LOW();
	HAL_SPI_TransmitReceive(p_w25q_spi, p_data, p_data, size, 1000);
	W25Q_CS_HIGH();	
}

/**
  * @brief  w25q通讯命令(单写)
  * @param	p_data 命令缓冲区指针
  * @param	size   命令字节数
  * @retval None
  * @note   
  */
static void w25q_wr_cmd(uint8_t* p_data, uint16_t size)
{
	w25q_busy_wait();
	
	W25Q_CS_LOW();
	HAL_SPI_Transmit(p_w25q_spi, p_data, size, 1000);
	W25Q_CS_HIGH();	
	HAL_Delay(1);
}

/**
  * @brief  写使能
  * @param	None
  * @retval None
  * @note   
  */
static void w25q_wr_enable(void)
{
	uint8_t cmd_buf = W25Q_WR_ENABLE;	
	w25q_wr_cmd(&cmd_buf, 1);
}

/**
  * @brief  写除能
  * @param	None
  * @retval None
  * @note   
  */
static void w25q_wr_disable(void)
{
	uint8_t cmd_buf = W25Q_WR_DISABLE;	
	w25q_wr_cmd(&cmd_buf, 1);
}

/**
  * @brief  w25q忙等待
  * @param	None
  * @retval None
  * @note   
  */
static void w25q_busy_wait(void)
{
	uint8_t cmd_buf[2] = {W25Q_STATUS_1, DUMMY};	
	
	W25Q_CS_LOW();
	
	HAL_SPI_TransmitReceive(p_w25q_spi, cmd_buf, cmd_buf, 2, 1000);

	do
	{
		HAL_SPI_TransmitReceive(p_w25q_spi, cmd_buf, cmd_buf, 2, 1000);	
		cmd_buf[1] &= W25Q_BUSY;
	}while(cmd_buf[1]);
	
	W25Q_CS_HIGH();
}

/**
  * @brief  4k块擦除
  * @param	addr   32位地址
  * @retval None
  * @note   
  */
static void w25q_erase_4k(uint32_t addr)
{
  uint8_t addr_len = 3;
  uint8_t cmd_buf[5] = {W25Q_4K_ERASE, DUMMY, DUMMY, DUMMY, DUMMY}; 
  
  if(addr_4b_flg)
  {
    addr_len = 4;
    cmd_buf[1] = (uint8_t)(addr >> 24); 
    cmd_buf[2] = (uint8_t)(addr >> 16); 
    cmd_buf[3] = (uint8_t)(addr >>  8);
    cmd_buf[4] = (uint8_t)addr;
  }	
  else
  {
    cmd_buf[1] = (uint8_t)(addr >> 16); 
    cmd_buf[2] = (uint8_t)(addr >>  8);
    cmd_buf[3] = (uint8_t)addr;  
  } 
	
	w25q_wr_enable();		
	w25q_cmd(&cmd_buf[0], addr_len + 1);	
	w25q_wr_disable();
}

/**
  * @brief  读取状态位ADS
  * @param	None
  * @retval ADS
  * @note   ADS = 0 为3字节地址;  ADS = 1 为4字节地址
  */
static uint8_t w25q_rd_ads(void)
{
	uint8_t cmd_buf[2] = {W25Q_STATUS_3, DUMMY};	
	
	W25Q_CS_LOW();
	
	HAL_SPI_TransmitReceive(p_w25q_spi, cmd_buf, cmd_buf, 2, 1000);	
	cmd_buf[1] &= W25Q_ADS;
	W25Q_CS_HIGH();
  
  return(cmd_buf[1]);
}

/**
  * @brief  设置为4字节地址
  * @param	None
  * @retval None
  * @note   
  */
static void w25q_set_4b(void)
{
	uint8_t cmd_buf[2] = {W25Q_4BYTE_ADDR, DUMMY};		
	w25q_cmd(&cmd_buf[0], 2);
}

/**
  * @brief  制造商ID(0xEF) + 设备ID
  * @param	None
  * @retval 0xEF00 + 0xID
  * @note   
  */
static uint16_t w25q_id(void)
{
  uint16_t id;
	uint8_t cmd_buf[6] = {W25Q_ID, DUMMY, DUMMY, 0, DUMMY, DUMMY};	
	w25q_cmd(&cmd_buf[0], 6);
  id = (uint16_t)(cmd_buf[4] << 8) + cmd_buf[5];
	return(id);
}
[/code]

21,616

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 驱动开发/核心开发
社区管理员
  • 驱动开发/核心开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧