esp8266 RTOS驱动 MX25L12835E
esp8266 RTOS驱动 MX25L12835E
硬件方面 MX251L12835E的 RESET引脚与WP引脚要接入高电平(3.3V),其它对着连就好了
因esp8266 RTOS下的SPI传输只能最多64位字节,另外其传输时是低位先行。
无奈的调试了一多次,完成如下代码,具体的请各位大神自己体会吧
已知写入前要保证存储的内容已重置
头文件user_25l12835.h
#ifndef _USER_25L12835E_h_
#define _USER_25L12835E_h_
/*
*使用说明
* uint8_t send_data[] = "abcdafghejklimopnrstqvwsuz";
* uint8_t Read_data[313];
* user_spi_master_init();
* get_Manufacturer_ID();
* SPI_FLASH_SectorErase(FLASH_WriteAddress);
* SPI_FLASH_BufferWrite(send_data,FLASH_WriteAddress,countof(send_data)-1);
* SPI_FLASH_BufferRead(Read_data,FLASH_WriteAddress,countof(Read_data)-1);
* Read_data[313-1] ='\0'; //字符串与字节类型注意一下
* user_uart0_print ("data=%s\r\n",Read_data);
* vTaskDelay(1000);
* user_uart0_print ("OK");
*/
#define SPI_FLASH_PageSize 256
#define SPI_FLASH_Transport_MAX_Size 64 //esp8266一次只能送输64字节
#define W25l_WriteEnable 0x06 //写入模式使能
#define W25l_WriteDisable 0x04
#define W25l_ReadStatusReg 0x05 //寄存器状态
#define W25l_WriteStatusReg 0x01
#define W25l_ReadData 0x03 //读取数据
#define W25l_FastReadData 0x0B
#define W25l_FastReadDual 0x3B
#define W25l_PageProgram 0x02 //写入一页的数据
#define W25l_BlockErase 0xD8 //擦除块
#define W25l_SectorErase 0x20 //擦除扇区
#define W25l_ChipErase 0xC7 //擦除整个falsh
#define W25l_PowerDown 0xB9
#define W25l_ReleasePowerDown 0xAB
#define W25l_DeviceID 0xAB
#define W25l_ManufactDeviceID 0x90
#define W25l_JedecDeviceID 0x9F
#define W25l_Block_Unlock 0x98
esp_err_t user_spi_master_init();
void get_Manufacturer_ID();
void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void get_flash_status();
void FLASH_Write_Enable();
void FLASH_Block_Unlock();
void SPI_FLASH_ChipErase();
void SPI_FLASH_WaitForWriteEnd();
void SPI_FLASH_SectorErase(uint32_t sector_addr);
void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite);
void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead);
#endif
C文件
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/stream_buffer.h"
#include "esp8266/spi_struct.h"
#include "esp8266/gpio_struct.h"
#include "esp_system.h"
#include "esp_log.h"
#include "user_uart.h"
#include "driver/gpio.h"
#include "driver/spi.h"
#include "user_25l12835e.h"
#include "time.h"
//反转32bit位
void turnbit(uint32_t*nun,uint32_t len)
{
for (size_t i = 0; i < (len/4); i++)
{
*nun= (((*nun & 0xff00ff00) >> 8) | ((*nun& 0x00ff00ff) << 8));
*nun= *nun>>16|*nun<<16;
nun++;
}
}
//这里的事件为空的
static void spi_event_callback(int event, void *arg)
{
switch (event) {
case SPI_INIT_EVENT: {
}
break;
case SPI_TRANS_START_EVENT: {
}
break;
case SPI_TRANS_DONE_EVENT: {
}
break;
case SPI_DEINIT_EVENT: {
}
break;
}
}
//初始化spi接口
esp_err_t user_spi_master_init()
{
spi_config_t spi_config;
// 加载默认配置
// CS_EN:1, MISO_EN:1, MOSI_EN:1, BYTE_TX_ORDER:1, BYTE_TX_ORDER:1, BIT_RX_ORDER:0, BIT_TX_ORDER:0, CPHA:0, CPOL:0
spi_config.interface.val = SPI_DEFAULT_INTERFACE;
spi_config.intr_enable.val = SPI_MASTER_DEFAULT_INTR_ENABLE;
spi_config.interface.cpol = 1;
spi_config.interface.cpha = 1;
spi_config.mode = SPI_MASTER_MODE;
spi_config.clk_div = SPI_8MHz_DIV;
spi_config.event_cb = spi_event_callback; // 注册回调函数,这里没什么用处!
return spi_init(HSPI_HOST, &spi_config);
}
//写入模式使能
void FLASH_Write_Enable()
{
uint16_t data_cmd =W25l_WriteEnable;
spi_trans_t trans;
trans.cmd = &data_cmd;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 0;
trans.bits.mosi = 0;
trans.bits.miso = 0;
spi_trans(HSPI_HOST, &trans);
}
//块去保护
void FLASH_Block_Unlock()
{
uint16_t data_cmd =W25l_Block_Unlock;
spi_trans_t trans;
trans.cmd = &data_cmd;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 0;
trans.bits.mosi = 0;
trans.bits.miso = 0;
spi_trans(HSPI_HOST, &trans);
}
//擦除整个Flash
void SPI_FLASH_ChipErase()
{
FLASH_Write_Enable();
uint16_t data_cmd=W25l_ChipErase;
//uint32_t data_addr = sector_addr<<8;//转换24位为32位
spi_trans_t trans;
trans.cmd = &data_cmd;
// trans.addr = &data_addr;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 0;
trans.bits.mosi = 0;
trans.bits.miso = 0;
spi_trans(HSPI_HOST, &trans);
}
//擦除指定地址的扇区(注意地址为32位,请补全后面二位)
void SPI_FLASH_SectorErase(uint32_t sector_addr)
{
FLASH_Write_Enable();
uint16_t data_cmd=W25l_SectorErase;
uint32_t data_addr = sector_addr<<8;//转换24位为32位
spi_trans_t trans;
trans.cmd = &data_cmd;
trans.addr = &data_addr;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 8*3;
trans.bits.mosi = 0;
trans.bits.miso = 0;
spi_trans(HSPI_HOST, &trans);
}
void SPI_FLASH_WaitForWriteEnd()
{
uint32_t get_data;
uint16_t data_cmd =W25l_ReadStatusReg;
spi_trans_t trans;
trans.miso = &get_data;
trans.cmd = &data_cmd;
// trans.addr = &data_add;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 0;
trans.bits.mosi = 0;
trans.bits.miso = 8;
do{
spi_trans(HSPI_HOST, &trans);
vTaskDelay(1);
} while ((get_data&0x01)==0x01);
}
//取得flash的ID号
void get_Manufacturer_ID()
{
SPI_FLASH_WaitForWriteEnd();//等待BUSY标志位被置0
spi_trans_t trans;
uint32_t get_data;
uint32_t data_add = 0x12345600; //3*8位地址补全后面二位,不然不正确
uint16_t data_cmd =W25l_ManufactDeviceID;
trans.miso = &get_data;
trans.cmd = &data_cmd;
trans.addr = &data_add;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 8*3;
trans.bits.mosi = 0;
trans.bits.miso = 8*2;
spi_trans(HSPI_HOST, &trans);
user_uart0_print("Manufacturer ID =%#x,Device ID=%#x\r\n",(get_data&0x0000ff00)>>8,get_data&0x000000ff);
}
//单次传输出去的数据 u单次不能超SPI_FLASH_Transport_MAX_Size64位
void SPI_FLASH_Transfer_Write(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
SPI_FLASH_WaitForWriteEnd();//等待BUSY标志位被置0
FLASH_Write_Enable(); //写入使能
uint16_t data_cmd =W25l_PageProgram;//写入代码
uint32_t data_add =WriteAddr<<8; //3*8位地址补全后面二位,不然不正确(这里的writeadd位移8位,24转32位的数据)
uint32_t write_data[16];
memset(write_data,0,sizeof(write_data));
uint32_t * P_write_data =write_data;
for (size_t i = 0; i < NumByteToWrite; i++)
{
if((i)%4 ==0 && i!=0)
{
P_write_data++;
}
//因为esp8266是低位先发,所以高位放到32位的低位
*P_write_data = (*pBuffer)<<((i%4)*8)|*P_write_data;
pBuffer++;
}
spi_trans_t trans;
P_write_data =write_data;
trans.mosi = P_write_data;
trans.cmd = &data_cmd;
trans.addr = &data_add;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 8*3;
trans.bits.mosi = 8*NumByteToWrite;
spi_trans(HSPI_HOST, &trans);
}
/**
* @brief 对FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
* @param pBuffer,要写入数据的指针
* @param WriteAddr,写入地址
* @param NumByteToWrite,写入数据长度,因为esp8266的问题,不能超过SPI_FLASH_Transport_MAX_Bit/8=64
* @retval 无
*/
void SPI_FLASH_PageWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint8_t NumOfTransfer = 0, /*计算出要传送几次*/
NumOfSingle = 0; /*计算出剩余不满一页的字节数*/
NumOfTransfer = NumByteToWrite / SPI_FLASH_Transport_MAX_Size;
NumOfSingle = NumByteToWrite % SPI_FLASH_Transport_MAX_Size;
if (NumOfTransfer==0)
{
SPI_FLASH_Transfer_Write(pBuffer, WriteAddr, NumByteToWrite);
}
else
{
while (NumOfTransfer--)
{
SPI_FLASH_Transfer_Write(pBuffer, WriteAddr, SPI_FLASH_Transport_MAX_Size);
WriteAddr += SPI_FLASH_Transport_MAX_Size;
pBuffer += SPI_FLASH_Transport_MAX_Size;
}
if (NumOfSingle != 0)
{
SPI_FLASH_Transfer_Write(pBuffer, WriteAddr, NumOfSingle);
}
}
}
/**
* @brief 对FLASH按页写入数据,调用本函数写入数据前需要先擦除扇区
* @param pBuffer,要写入数据的指针
* @param WriteAddr,写入地址为24位的地址,如0x00100,增加一页等于0x00100+256(0x00100)得到第二页的地址
* @param NumByteToWrite,写入数据长度
* @retval 无
*/
void SPI_FLASH_BufferWrite(uint8_t* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
uint8_t NumOfPage = 0, /*计算出要写多少整数页*/
NumOfSingle = 0, /*计算出剩余不满一页的字节数*/
Addr = 0, //地址偏移量,用于看地址是否对齐 判定是否为0x00100这样的地址
count = 0,/*差count个数据值,刚好可以对齐到页地址*/
temp = 0;
/*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
Addr = WriteAddr % SPI_FLASH_PageSize;
count = SPI_FLASH_PageSize - Addr;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
/* Addr=0,则WriteAddr 刚好按页对齐 aligned */
if (Addr == 0)
{
/* NumByteToWrite < SPI_FLASH_PageSize */
if (NumOfPage == 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
/*先把整数页都写了*/
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
/*若有多余的不满一页的数据,把它写完*/
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
/* 若地址与 SPI_FLASH_PageSize 不对齐 */
else
{
/* NumByteToWrite < SPI_FLASH_PageSize */
if (NumOfPage == 0)
{
/*当前页剩余的count个位置比NumOfSingle小,一页写不完*/
if (NumOfSingle > count)
{
temp = NumOfSingle - count;
/*先写满当前页*/
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
WriteAddr += count;
pBuffer += count;
/*再写剩余的数据*/
SPI_FLASH_PageWrite(pBuffer, WriteAddr, temp);
}
else /*当前页剩余的count个位置能写完NumOfSingle个数据*/
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
}
}
else /* NumByteToWrite > SPI_FLASH_PageSize */
{
/*地址不对齐多出的count分开处理,不加入这个运算*/
NumByteToWrite -= count;
NumOfPage = NumByteToWrite / SPI_FLASH_PageSize;
NumOfSingle = NumByteToWrite % SPI_FLASH_PageSize;
/* 先写完count个数据,为的是让下一次要写的地址对齐 */
SPI_FLASH_PageWrite(pBuffer, WriteAddr, count);
/* 接下来就重复地址对齐的情况 */
WriteAddr += count;
pBuffer += count;
/*把整数页都写了*/
while (NumOfPage--)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, SPI_FLASH_PageSize);
WriteAddr += SPI_FLASH_PageSize;
pBuffer += SPI_FLASH_PageSize;
}
/*若有多余的不满一页的数据,把它写完*/
if (NumOfSingle != 0)
{
SPI_FLASH_PageWrite(pBuffer, WriteAddr, NumOfSingle);
}
}
}
}
//读取单次传输数据最多64字节
void SPI_FLASH_Transfer_Read(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
//FLASH_Write_Enable(); //写入使能
uint16_t data_cmd =W25l_ReadData;
uint32_t data_add = ReadAddr<<8; //3*8位地址补全后面二位,不然不正确
spi_trans_t trans;
uint32_t get_data[16];
uint32_t * p_get_data =get_data;
memset(get_data,0,sizeof(get_data));
trans.miso = p_get_data;
trans.cmd = &data_cmd;
trans.addr = &data_add;
trans.bits.val = 0;
trans.bits.cmd = 8;
trans.bits.addr = 8*3;
trans.bits.mosi = 0;
trans.bits.miso = 8*NumByteToRead;//最多512bit
spi_trans(HSPI_HOST, &trans);
// turnbit(get_data,sizeof(get_data));
p_get_data =get_data;
//user_uart0_print("p_get_data=%x",*p_get_data);
for (size_t i = 0; i < NumByteToRead; i++)
{
if((i)%4 ==0 && i!=0)
{
p_get_data++;
}
//因为esp8266是低位先发,所以高位放到32位的低位
*pBuffer = (*p_get_data>>((i%4)*8))&0x000000ff;
pBuffer++;
}
}
void SPI_FLASH_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
SPI_FLASH_WaitForWriteEnd();//等待BUSY标志位被置0
// uint8_t tempbuffer[SPI_FLASH_Transport_MAX_Size];
uint8_t NumOfTransfer = 0, /*计算出要传送几次*/
NumOfSingle = 0; /*计算出剩余不满一页的字节数*/
NumOfTransfer = NumByteToRead / SPI_FLASH_Transport_MAX_Size;
NumOfSingle = NumByteToRead % SPI_FLASH_Transport_MAX_Size;
/*mod运算求余,若writeAddr是SPI_FLASH_PageSize整数倍,运算结果Addr值为0*/
if(NumOfTransfer==0)
{
SPI_FLASH_Transfer_Read(pBuffer, ReadAddr, NumByteToRead);
}
else
{
for (size_t i = 0; i < NumOfTransfer; i++)
{
SPI_FLASH_Transfer_Read(pBuffer, ReadAddr, SPI_FLASH_Transport_MAX_Size);
ReadAddr += SPI_FLASH_Transport_MAX_Size;
pBuffer += SPI_FLASH_Transport_MAX_Size;
}
if (NumOfSingle != 0)
{
SPI_FLASH_Transfer_Read(pBuffer, ReadAddr, NumOfSingle);
}
}
}
void get_flash_status()
{
uint32_t data ='\0';
spi_slave_get_status(HSPI_HOST, &data);
user_uart0_print ("status=%x",data);
}