feat(spi_flash): Refactor SPI flash for saving IRAM

This commit is contained in:
Dong Heng
2018-09-17 14:54:57 +08:00
parent c8ecf01b56
commit b3b3f9d3ef
5 changed files with 718 additions and 625 deletions

View File

@ -211,4 +211,49 @@
#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC)
#define SPI_INT_HOLD_ENA 0x00000003
#define SPI_INT_HOLD_ENA_S 0
#define SPI_EXT2(i) (REG_SPI_BASE(i) + 0xF8)
#define SPI_EXT3(i) (REG_SPI_BASE(i) + 0xFC)
#define SPI_ENABLE_AHB BIT17
#define SPI_FLASH_CLK_EQU_SYSCLK BIT12
//SPI flash command
#define SPI_FLASH_READ BIT31
#define SPI_FLASH_WREN BIT30
#define SPI_FLASH_WRDI BIT29
#define SPI_FLASH_RDID BIT28
#define SPI_FLASH_RDSR BIT27
#define SPI_FLASH_WRSR BIT26
#define SPI_FLASH_PP BIT25
#define SPI_FLASH_SE BIT24
#define SPI_FLASH_BE BIT23
#define SPI_FLASH_CE BIT22
#define SPI_FLASH_RES BIT20
#define SPI_FLASH_DPD BIT21
#define SPI_FLASH_HPM BIT19
//SPI address register
#define SPI_FLASH_BYTES_LEN 24
#define SPI_BUFF_BYTE_NUM 32
#define IODATA_START_ADDR BIT0
//SPI status register
#define SPI_FLASH_BUSY_FLAG BIT0
#define SPI_FLASH_WRENABLE_FLAG BIT1
#define SPI_FLASH_BP0 BIT2
#define SPI_FLASH_BP1 BIT3
#define SPI_FLASH_BP2 BIT4
#define SPI_FLASH_TOP_BOT_PRO_FLAG BIT5
#define SPI_FLASH_STATUS_PRO_FLAG BIT7
#define FLASH_WR_PROTECT (SPI_FLASH_BP0|SPI_FLASH_BP1|SPI_FLASH_BP2)
#define SPI 0
#define PERIPHS_SPI_FLASH_C0 SPI_W0(SPI)
#define PERIPHS_SPI_FLASH_CTRL SPI_CTRL(SPI)
#define PERIPHS_SPI_FLASH_CMD SPI_CMD(SPI)
#endif // SPI_REGISTER_H_INCLUDED

View File

@ -103,7 +103,7 @@ SECTIONS
*(.init.literal)
*(.init)
*(.iram1 .iram1.*)
*libspi_flash.a:spi_flash.o(.literal .text .literal.* .text.*)
*libspi_flash.a:spi_flash_raw.o(.literal .text .literal.* .text.*)
*(.literal .text .stub .gnu.warning .gnu.linkonce.literal.* .gnu.linkonce.t.*.literal .gnu.linkonce.t.*)
*(.fini.literal)
*(.fini)

View File

@ -0,0 +1,71 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "esp8266/rom_functions.h"
#ifdef __cplusplus
extern "C" {
#endif
enum GD25Q32C_status {
GD25Q32C_STATUS1=0,
GD25Q32C_STATUS2,
GD25Q32C_STATUS3,
};
typedef enum {
SPI_TX = 0x1,
SPI_RX = 0x2,
SPI_WRSR = 0x4,
SPI_RAW = 0x8, /*!< No wait spi idle and no read status */
} spi_cmd_dir_t;
typedef struct {
uint16_t cmd;
uint8_t cmd_len;
uint32_t *addr;
uint8_t addr_len;
uint32_t *data;
uint8_t data_len;
uint8_t dummy_bits;
} spi_cmd_t;
bool spi_user_cmd_raw(esp_spi_flash_chip_t *chip, spi_cmd_dir_t mode, spi_cmd_t *p_cmd);
uint32_t spi_flash_get_id_raw(esp_spi_flash_chip_t *chip);
esp_err_t spi_flash_enable_qmode_raw(esp_spi_flash_chip_t *chip);
esp_err_t spi_flash_read_status_raw(esp_spi_flash_chip_t *chip, uint32_t *status);
esp_err_t spi_flash_write_status_raw(esp_spi_flash_chip_t *chip, uint32_t status_value);
esp_err_t spi_flash_read_raw(esp_spi_flash_chip_t *chip, size_t src_addr, void *dest, size_t size);
esp_err_t spi_flash_write_raw(esp_spi_flash_chip_t *chip, size_t dest_addr, const void *src, size_t size);
esp_err_t spi_flash_erase_sector_raw(esp_spi_flash_chip_t *chip, size_t sec, size_t sec_size);
void spi_flash_switch_to_qio_raw(void);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,290 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "spi_flash.h"
#include "priv/esp_spi_flash_raw.h"
#include "esp8266/eagle_soc.h"
#include "esp8266/pin_mux_register.h"
#include "driver/spi_register.h"
void Cache_Read_Disable_2(void)
{
CLEAR_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT);
while(REG_READ(SPI_EXT2(0)) != 0) { }
CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB);
}
void Cache_Read_Enable_2()
{
SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL,SPI_ENABLE_AHB);
SET_PERI_REG_MASK(CACHE_FLASH_CTRL_REG,CACHE_READ_EN_BIT);
}
void Cache_Read_Enable_New(void) __attribute__((alias("Cache_Read_Enable_2")));
uint32_t spi_flash_get_id_raw(esp_spi_flash_chip_t *chip)
{
uint32_t rdid = 0;
Cache_Read_Disable();
Wait_SPI_Idle(chip);
WRITE_PERI_REG(PERIPHS_SPI_FLASH_C0, 0); // clear regisrter
WRITE_PERI_REG(PERIPHS_SPI_FLASH_CMD, SPI_FLASH_RDID);
while(READ_PERI_REG(PERIPHS_SPI_FLASH_CMD)!=0);
rdid = READ_PERI_REG(PERIPHS_SPI_FLASH_C0)&0xffffff;
Cache_Read_Enable_New();
return rdid;
}
esp_err_t spi_flash_read_status_raw(esp_spi_flash_chip_t *chip, uint32_t *status)
{
esp_err_t ret;
Cache_Read_Disable_2();
ret = SPI_read_status(chip, status);
Cache_Read_Enable_2();
return ret;
}
esp_err_t spi_flash_write_status_raw(esp_spi_flash_chip_t *chip, uint32_t status_value)
{
Cache_Read_Disable_2();
Wait_SPI_Idle(chip);
if (ESP_OK != SPI_write_enable(chip))
return ESP_ERR_FLASH_OP_FAIL;
if(ESP_OK != SPI_write_status(chip, status_value))
return ESP_ERR_FLASH_OP_FAIL;
Wait_SPI_Idle(chip);
Cache_Read_Enable_2();
return ESP_OK;
}
esp_err_t spi_flash_erase_sector_raw(esp_spi_flash_chip_t *chip, size_t sec, size_t sec_size)
{
esp_err_t ret = ESP_OK;
Cache_Read_Disable_2();
if (ESP_OK != SPI_write_enable(chip)) {
ret = ESP_ERR_FLASH_OP_FAIL;
}
if (ESP_OK != SPI_sector_erase(chip, sec * sec_size)) {
ret = ESP_ERR_FLASH_OP_FAIL;
}
Cache_Read_Enable_2();
return ret;
}
esp_err_t spi_flash_enable_qmode_raw(esp_spi_flash_chip_t *chip)
{
esp_err_t ret;
Cache_Read_Disable_2();
ret = Enable_QMode(chip);
Wait_SPI_Idle(chip);
Cache_Read_Enable_2();
return ret;
}
esp_err_t spi_flash_write_raw(esp_spi_flash_chip_t *chip, size_t dest_addr, const void *src, size_t size)
{
esp_err_t ret;
Cache_Read_Disable_2();
ret = SPI_page_program(chip, dest_addr, (void *)src, size);
Cache_Read_Enable_2();
return ret;
}
esp_err_t spi_flash_read_raw(esp_spi_flash_chip_t *chip, size_t src_addr, void *dest, size_t size)
{
esp_err_t ret;
Cache_Read_Disable_2();
ret = SPI_read_data(chip, src_addr, dest, size);
Cache_Read_Enable_2();
return ret;
}
bool spi_user_cmd_raw(esp_spi_flash_chip_t *chip, spi_cmd_dir_t mode, spi_cmd_t *p_cmd)
{
int idx = 0;
// Cache Disable
Cache_Read_Disable_2();
//wait spi idle
if((mode & SPI_RAW) == 0) {
Wait_SPI_Idle(chip);
}
//save reg
uint32_t io_mux_reg = READ_PERI_REG(PERIPHS_IO_MUX_CONF_U);
uint32_t spi_clk_reg = READ_PERI_REG(SPI_CLOCK(SPI));
uint32_t spi_ctrl_reg = READ_PERI_REG(SPI_CTRL(SPI));
uint32_t spi_user_reg = READ_PERI_REG(SPI_USER(SPI));
if (mode & SPI_WRSR) {
// enable write register
SPI_write_enable(chip);
}
SET_PERI_REG_MASK(SPI_USER(SPI),SPI_USR_COMMAND);
//Disable flash operation mode
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE);
//SET SPI SEND BUFFER MODE
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO_HIGHPART);
//CLEAR EQU SYS CLK
CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_CONF_U,SPI0_CLK_EQU_SYS_CLK);
SET_PERI_REG_MASK(SPI_USER(SPI), SPI_CS_SETUP|SPI_CS_HOLD|SPI_USR_COMMAND|SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_FLASH_MODE);
//CLEAR DAUL OR QUAD LINES TRANSMISSION MODE
CLEAR_PERI_REG_MASK(SPI_CTRL(SPI), SPI_QIO_MODE|SPI_DIO_MODE|SPI_DOUT_MODE|SPI_QOUT_MODE);
WRITE_PERI_REG(SPI_CLOCK(SPI),
((3&SPI_CLKCNT_N)<<SPI_CLKCNT_N_S)|
((1&SPI_CLKCNT_H)<<SPI_CLKCNT_H_S)|
((3&SPI_CLKCNT_L)<<SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
//Enable fast read mode
SET_PERI_REG_MASK(SPI_CTRL(SPI), SPI_FASTRD_MODE);
//WAIT COMMAND DONE
while(READ_PERI_REG(SPI_CMD(SPI)) & SPI_USR);
//SET USER CMD
if (p_cmd->cmd_len != 0) {
//Max CMD length is 16 bits
SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, p_cmd->cmd_len * 8 - 1, SPI_USR_COMMAND_BITLEN_S);
//Enable CMD
SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND);
//LOAD CMD
SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_VALUE, p_cmd->cmd, SPI_USR_COMMAND_VALUE_S);
} else {
//CLEAR CMD
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_COMMAND);
SET_PERI_REG_BITS(SPI_USER2(SPI), SPI_USR_COMMAND_BITLEN, 0, SPI_USR_COMMAND_BITLEN_S);
}
if (p_cmd->dummy_bits != 0) {
//SET dummy bits
SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, p_cmd->dummy_bits - 1, SPI_USR_DUMMY_CYCLELEN_S);
//Enable dummy
SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY);
} else {
//CLEAR DUMMY
SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_DUMMY_CYCLELEN, 0, SPI_USR_DUMMY_CYCLELEN_S);
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_DUMMY);
}
//SET USER ADDRESS
if (p_cmd->addr_len != 0) {
//Set addr lenght
SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, p_cmd->addr_len * 8 - 1, SPI_USR_ADDR_BITLEN_S);
//Enable user address
SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR);
WRITE_PERI_REG(SPI_ADDR(SPI), *p_cmd->addr);
} else {
//CLEAR ADDR
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_ADDR);
SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_ADDR_BITLEN, 0, SPI_USR_ADDR_BITLEN_S);
}
uint32_t *value = p_cmd->data;
if (((mode & SPI_TX) || (mode & SPI_WRSR)) && p_cmd->data_len != 0) {
//Enable MOSI, disable MISO
SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO);
do {
WRITE_PERI_REG((SPI_W0(SPI) + (idx << 2)), *value++);
} while ( ++idx < (p_cmd->data_len / 4));
SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, ((p_cmd->data_len) * 8 - 1), SPI_USR_MOSI_BITLEN_S);
} else if ((mode & SPI_RX) && p_cmd->data_len != 0) {
//Enable MISO, disable MOSI
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI);
SET_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO);
SET_PERI_REG_BITS(SPI_USER1(SPI),SPI_USR_MISO_BITLEN, p_cmd->data_len * 8 - 1, SPI_USR_MISO_BITLEN_S);
int fifo_idx = 0;
do {
WRITE_PERI_REG((SPI_W0(SPI) + (fifo_idx << 2)), 0);
} while ( ++fifo_idx < (p_cmd->data_len / 4));
} else {
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER(SPI), SPI_USR_MISO);
SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MISO_BITLEN, 0, SPI_USR_MISO_BITLEN_S);
SET_PERI_REG_BITS(SPI_USER1(SPI), SPI_USR_MOSI_BITLEN, 0, SPI_USR_MOSI_BITLEN_S);
}
//Start command
SET_PERI_REG_MASK(SPI_CMD(SPI), SPI_USR);
while (READ_PERI_REG(SPI_CMD(SPI)) & SPI_USR);
if (mode & SPI_RX) {
do {
*p_cmd->data ++ = READ_PERI_REG(SPI_W0(SPI) + (idx << 2));
} while (++idx < (p_cmd->data_len / 4));
}
//recover
WRITE_PERI_REG(PERIPHS_IO_MUX_CONF_U,io_mux_reg);
WRITE_PERI_REG(SPI_CTRL(SPI),spi_ctrl_reg);
WRITE_PERI_REG(SPI_CLOCK(SPI),spi_clk_reg);
WRITE_PERI_REG(SPI_USER(SPI),spi_user_reg);
if((mode & SPI_RAW) == 0) {
Wait_SPI_Idle(chip);
}
//enable icache
Cache_Read_Enable_2();
return true;
}
void spi_flash_switch_to_qio_raw(void)
{
CLEAR_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE
|SPI_QOUT_MODE
|SPI_DIO_MODE
|SPI_DOUT_MODE
|SPI_FASTRD_MODE);
SET_PERI_REG_MASK(PERIPHS_SPI_FLASH_CTRL, SPI_QIO_MODE | SPI_FASTRD_MODE);
}