mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-22 01:27:11 +08:00
feat(spi_flash): Refactor SPI flash for saving IRAM
This commit is contained in:
@ -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
|
||||
|
@ -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)
|
||||
|
71
components/spi_flash/include/priv/esp_spi_flash_raw.h
Normal file
71
components/spi_flash/include/priv/esp_spi_flash_raw.h
Normal 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
290
components/spi_flash/src/spi_flash_raw.c
Normal file
290
components/spi_flash/src/spi_flash_raw.c
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user