正点原子触摸屏驱动移植,无24c02使用flash(w25q16)代替

最近在一块新板子移植正点原子触摸屏驱动,但板子不带24c02,每次运行都需要重新校准屏幕,正好板子自带了一个w25q16,用来代替储存校准数据。

移植好正点原子的屏幕驱动确定无误可以使用后,添加以下代码:

这是w25q16的头文件指令集,如果是其他型号,只需要修改对应的指令集即可,W25Q_SPI、W25Q_CS_Port、W25Q_CS_Pin修改为自己对应的。

#ifndef _W25Q16_H_
#define _W25Q16_H_

#include "spi.h"                      
#define W25Q_SPI					hspi1         /* <句柄重命名> */
#define W25Q_CS_Port			GPIOB         /* <片选引脚NSS> */
#define W25Q_CS_Pin 			GPIO_PIN_0    
#define W25Q_WRITE_ENABLE				0x06		/* <写使能> */
#define W25Q_WRITE_DISABLE			0x04    /* <写禁止> */
#define W25Q_READ_DATA					0x03		/* <读数据> */ 
#define W25Q_READ_STATA_REG1		0x05		/* <读状态寄存器1,紧跟着的字节就是当前状态> */
#define	W25Q_READ_STATA_REG2		0x35	  /* <读状态寄存器2,紧跟着的字节就是当前状态> */
#define W25Q_WRITE_STATA_REG		0x01		/* <写状态寄存器,写入两个字节,分别到寄存器1,和寄存器2> */
#define W25Q_Page_Program 			0x02		/* <页编程,先跟3个地址字节,再跟一个数据字节> */
#define W25Q_Block_Erase				0xD8		/* <块擦除64k,三个地址字节> */
#define W25Q_Sector_Erase				0x20		/* <扇区擦除,跟三个地址> */
#define W25Q_Full_Erase					0xC7		/* <全片擦除> */											
#define W25Q_Susp_Erase					0x75		/* <暂停擦除> */	
#define W25Q_Rest_Erase					0x7A		/* <恢复擦除> */
#define W25Q_PowDow_Mode				0xB9		/* <掉电模式> */
#define W25Q_HPer_Mode					0xA3		/* <高性能模式> */
#define W25Q_JEDEC_ID						0x9F		/* <读3个字节分别是生产厂家、存储器类型、容量> */
HAL_StatusTypeDef W25Q16_Read_State_Reg(uint8_t Select, uint8_t *State);
/* <判忙> */
void W25Q16_Judge_Busy(void);
/* <写状态寄存器> */
HAL_StatusTypeDef W25Q16_Write_State_Reg(uint8_t * State);
/* <读数据> */
HAL_StatusTypeDef W25Q16_Read_Data(uint32_t Read_Address, uint8_t *Read_Data, uint16_t Read_Size);
/* <页写> */
HAL_StatusTypeDef W25Q16_Page_Write(uint32_t Write_Address, uint8_t * PW_Data, uint16_t PW_Size);
/* <扇区擦除> */
HAL_StatusTypeDef W25Q16_Sector_Erase(uint32_t Sector_Address);
/* <块擦除> */
HAL_StatusTypeDef	W25Q16_Block_Erase(uint32_t Block_Address);
/* <全片擦除> */
HAL_StatusTypeDef	W25Q16_Full_Erase(void);
/* <读ID> */
HAL_StatusTypeDef W25Q16_Read_Jedec_ID(uint8_t * Read_Jedec_ID);
/* <写使能> */
HAL_StatusTypeDef W25Q16_Write_Enable(void);
/* <写失能> */
HAL_StatusTypeDef W25Q16_Write_Disable(void);

#endif

下面是w25q16.c文件

#include "w25q16.h"

/**
* @brief		将SPI发送函数封装
*      @param		*Tr_Data: 要发送的缓冲区
*       @param		要发送数据的长度
*       @retval	
*/

static HAL_StatusTypeDef W25Q16_Transmit(uint8_t * Tr_Data, uint16_t Tr_Size)
{
  return HAL_SPI_Transmit(&W25Q_SPI, Tr_Data, Tr_Size, 0xff);
}

/**
*   @brief		将SPI接收函数封装
*  @param		*Rr_pData: 接收数据并放置到接收数据缓冲区中
*   @param		Rr_Size: 需要接收的数据的长度
*   @retval		
*/
static HAL_StatusTypeDef W25Q16_Receive(uint8_t * Re_Data, uint16_t Re_Size)
{
  return HAL_SPI_Receive(&W25Q_SPI, Re_Data, Re_Size, 0xff);
}

/**
* @brief		写使能或失能
* @param		Type: 为1时使能; 为0时失能
* @param		无
* @retval	Ret: 0(使能成功), 1(使能失败)
*/
HAL_StatusTypeDef W25Q16_Write_Enable(void)
{
  HAL_StatusTypeDef Ret = HAL_ERROR;  
  uint8_t CMD;
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  CMD = W25Q_WRITE_ENABLE;
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
    {Ret = HAL_OK;}
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  return Ret;
}
HAL_StatusTypeDef W25Q16_Write_Disable(void)
{
  uint8_t CMD;
  HAL_StatusTypeDef Ret = HAL_ERROR;
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  CMD = W25Q_WRITE_DISABLE;
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK){Ret = HAL_OK;}
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  return Ret;
}

/**
*@brief		读状态寄存器(flash接收命令后处于,需要时间处理命令,会有忙状态,flash无法接收命令,只能给MCU读取是否在忙)
*@param		Select:为0时是寄存器1; 为1时是寄存器2
*@param		State(指针):返回的状态标志
*@retval	Ret: 0(读状态寄存器成功), 1(读状态寄存器失败)
*/
HAL_StatusTypeDef W25Q16_Read_State_Reg(uint8_t Select, uint8_t *State)
{
  HAL_StatusTypeDef Ret = HAL_ERROR;
  uint8_t CMD[4] = {0,0,0,0};
	HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
	switch(Select){
    case 0:CMD[0] = W25Q_READ_STATA_REG1;
      break;
    case 1:CMD[0] = W25Q_READ_STATA_REG2;
      break;    
    default: ;}
  if(W25Q16_Transmit(CMD, 4) == HAL_OK)
  {
    if(W25Q16_Receive(State,1) == HAL_OK)
    {
      Ret = HAL_OK;
    }
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  return Ret;
}

/**
* @brief		判忙(阻塞等待Flash处于空闲状态)
* @param		无
* @param		无
* @retval	无
*/
void W25Q16_Judge_Busy(void)
{
  uint8_t State;	
  do{
      W25Q16_Read_State_Reg(0, &State);	//不要用指针类型局部变量传进去,必被卡死
      State &= 0x01;
    }while(State == 0x01);
}
  
/**
*@brief		写状态寄存器
*@param		State(数组指针): (长度为两个字节的数组指针) 第一个字节写入状态寄存器1;第二个字节写入状态寄存器2。
*@param		无
*@retval	Ret: 0(写状态寄存器成功), 1(写状态寄存器失败)
*/
HAL_StatusTypeDef W25Q16_Write_State_Reg(uint8_t * State)
{
  uint8_t CMD = W25Q_WRITE_STATA_REG;
  HAL_StatusTypeDef Ret = HAL_ERROR;
  W25Q16_Judge_Busy();
  W25Q16_Write_Enable();
	HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
  {
    if(W25Q16_Transmit(State, 2) == HAL_OK)
    {
      Ret = HAL_OK;
    }
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  W25Q16_Write_Disable();
  return Ret;
}

/**
* @brief		读取数据
* @param		R_Addr : 读取数据的地址
* @param		R_Data(数组指针) : 获取读取的数据
* @param		R_Size : 读取的数据的大小
* @retval	  Ret: 0(读取数据成功), 1(读取数据失败)
*/
HAL_StatusTypeDef W25Q16_Read_Data(uint32_t Read_Address, uint8_t *Read_Data, uint16_t Read_Size)
{
  uint8_t CMD = W25Q_READ_DATA;
  HAL_StatusTypeDef Ret = HAL_ERROR;
  Read_Address <<= 8;	//只要24位,3个字节
  W25Q16_Judge_Busy();	//判忙
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
  {
    if(W25Q16_Transmit((uint8_t *)&Read_Address, 3) == HAL_OK)
    {
      if(W25Q16_Receive(Read_Data,Read_Size) == HAL_OK)
      {
        Ret = HAL_OK;
      }
    }
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  return Ret;
}

/**
* @brief		写页(步骤:先判忙, 再使能, 判忙,再使能片选, 再写命令, 再写3个字节的地址,后写入数据,最后写失能)
* @param		WriteAddr: 写入的地址(三个字节地址)
* @param		PW_Data(数组指针): 要写入的数据(高位先传)
* @param		PW_Size: 要写入的数据长度
* @retval 	Ret: 0(写页成功), 1(写页失败)
*/
HAL_StatusTypeDef W25Q16_Page_Write(uint32_t Write_Address, uint8_t * PW_Data, uint16_t PW_Size)
{
  HAL_StatusTypeDef Ret = HAL_ERROR;
  uint8_t CMD = W25Q_Page_Program;/* <左移8位是因为只需要24位,总共32位左移8位后低8位都是0> */
  Write_Address <<= 8;	//只要24位,3个字节
  W25Q16_Write_Enable();	
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
  {
    if(W25Q16_Transmit((uint8_t *)&Write_Address, 3) == HAL_OK)
    {
      if(W25Q16_Transmit(PW_Data, PW_Size) == HAL_OK)
      {
        Ret = HAL_OK;
      }
    }
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  W25Q16_Judge_Busy();
  return Ret;
}

/**
* @brief		扇区擦除(W25Q64总共8MB,分为128块(每块64KB),每块16个扇区,每个扇区4K个字节。)
* @param		Sector_Addr: 擦除地址(以4KB为单位寻址, 高位先发)
* @param		无
* @retval		
*/
HAL_StatusTypeDef W25Q16_Sector_Erase(uint32_t Sector_Address)
{
  uint8_t CMD = W25Q_Sector_Erase;
  HAL_StatusTypeDef Ret = HAL_ERROR;/* <每个块有16个扇区(一个扇区有4KB的大小),需要换算为实际地址(为了使找到对应的扇区地址,所以要乘以4KB)> */
  Sector_Address *= 4096;/* <只需要24位表示地址,并且高位先传> */
  Sector_Address <<= 8;
	W25Q16_Write_Enable();	
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
  {
    if(W25Q16_Transmit((uint8_t *)&Sector_Address, 3) == HAL_OK)
    {
      Ret = HAL_OK;
    }
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  W25Q16_Judge_Busy();
  return Ret;
}

/**
* @brief		块擦除(W25Q64有8MB的容量,而8MB有128个块,所以1块有64kB的大小,所以这个函数一次能擦除64KB的大小)
* @param		Block_Addr: (1、块地址,共128个块,对应128个地址,以64K为单位寻址2、高位先传)
* @param		无
* @retval		
*/
HAL_StatusTypeDef	W25Q16_Block_Erase(uint32_t Block_Address)
{
  uint8_t CMD = W25Q_Block_Erase;HAL_StatusTypeDef Ret = HAL_ERROR;//总共有128个块,而一个块有64KB的大小,//为了使找到对应的块地址,所以要乘以64KB
  Block_Address *= (1<<16);Block_Address <<= 8;	//只需要24位表示地址,并且高位先传
  W25Q16_Write_Enable();
	HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
  {
    if(W25Q16_Transmit((uint8_t *)&Block_Address, 3) == HAL_OK)
    {
      Ret = HAL_OK;
    }
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  W25Q16_Judge_Busy();
  return Ret;
}

/**
* @brief		全片擦除(该函数尽量少使用)
* @param		
* @param		
* @retval		
*/
HAL_StatusTypeDef	W25Q16_Full_Erase(void)
{
  HAL_StatusTypeDef Ret = HAL_ERROR;
  uint8_t CMD = W25Q_Full_Erase;W25Q16_Write_Enable();	
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
  {
    Ret = HAL_OK;
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  W25Q16_Judge_Busy();
  return Ret;
}

/**
* @brief	  读取 W25Q16 ID (读3个字节分别是生产厂家、存储器类型、容量)
* @param		*R_Jedec_ID: 保存W25Q16 ID 的数组
* @param		无
* @retval	
*/
HAL_StatusTypeDef W25Q16_Read_Jedec_ID(uint8_t * Read_Jedec_ID)
{
  uint8_t CMD = W25Q_JEDEC_ID;
  HAL_StatusTypeDef Ret = HAL_ERROR;
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_RESET);
  if(W25Q16_Transmit(&CMD, 1) == HAL_OK)
  {
    if(W25Q16_Receive(Read_Jedec_ID, 3) == HAL_OK)
    {
      Ret = HAL_OK;
    }
  }
  HAL_GPIO_WritePin(W25Q_CS_Port, W25Q_CS_Pin, GPIO_PIN_SET);
  return Ret;
}

修改正点原子保存校准数据函数与数据保存地址

/* TP_SAVE_ADDR_BASE定义触摸屏校准参数保存在w25q16里面的位置(起始地址)
 * 占用空间 : 13字节.
 */
#define TP_SAVE_ADDR_BASE   0x000001

/**
 * @brief       保存校准参数
 *   @note      参数保存在flash芯片里面(w25q16),起始地址为TP_SAVE_ADDR_BASE.
 *              占用大小为13字节
 * @param       无
 * @retval      无
 */
void tp_save_adjust_data(void)
{
    uint8_t *p = (uint8_t *)&tp_dev.xfac;   /* 指向首地址 */

    /* p指向tp_dev.xfac的地址, p+4则是tp_dev.yfac的地址
     * p+8则是tp_dev.xoff的地址,p+10,则是tp_dev.yoff的地址
     * 总共占用12个字节(4个参数)
     * p+12用于存放标记电阻触摸屏是否校准的数据(0X0A)
     * 往p[12]写入0X0A. 标记已经校准过.
     */
    W25Q16_Sector_Erase(TP_SAVE_ADDR_BASE);     
    W25Q16_Page_Write(TP_SAVE_ADDR_BASE, p, 13);   //保存13个字节数据(xfac,yfac,xc,yc,flag) 
}

修改获取校准数据函数

/**
 * @brief       获取保存在EEPROM里面的校准值
 * @param       无
 * @retval      0,获取失败,要重新校准
 *              1,成功获取数据
 */
uint8_t tp_get_adjust_data(void)
{
    uint8_t *p = (uint8_t *)&tp_dev.xfac;
    uint8_t temp = 0;

    /* 由于我们是直接指向tp_dev.xfac地址进行保存的, 读取的时候,将读取出来的数据
     * 写入指向tp_dev.xfac的首地址, 就可以还原写入进去的值, 而不需要理会具体的数
     * 据类型. 此方法适用于各种数据(包括结构体)的保存/读取(包括结构体).
     */
    W25Q16_Read_Data(TP_SAVE_ADDR_BASE, p, 13);                 /* 读取13字节数据 */
    temp = *(p+12);

    if (temp == 0X0A)
    {
        return 1;
    }

    return 0;
}

修改tp_init(void)屏幕初始函数,注释掉24c02的初始化函数,添加自己的w25qxx初始化函数。

//at24cxx_init();         /* 初始化24CXX */
MX_SPI1_Init();         /* 初始化w25q16 */

修改touch.h的触摸屏控制器结构体

    /* 5点校准触摸屏校准参数(电容屏不需要校准) */
    float xfac;                 /* 5点校准法x方向比例因子 */
    float yfac;                 /* 5点校准法y方向比例因子 */
    short xc;                   /* 中心X坐标物理值(AD值) */
    short yc;                   /* 中心Y坐标物理值(AD值) */

在结构体中添加一个参数flag,用来存放是否校准标志

    /* 5点校准触摸屏校准参数(电容屏不需要校准) */
    float xfac;                 /* 5点校准法x方向比例因子 */
    float yfac;                 /* 5点校准法y方向比例因子 */
    short xc;                   /* 中心X坐标物理值(AD值) */
    short yc;                   /* 中心Y坐标物理值(AD值) */
    uint8_t flag;

在touch.c中_m_tp_dev tp_dev加多一个0

_m_tp_dev tp_dev =
{
    tp_init,
    tp_scan,
    tp_adjust,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
};

修改完成后,就可以用w25q16来存储屏幕校准数据。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值