Marlin 2.0 for Flying Bear 4S/5
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

273 lines
6.1 KiB

/**
MKS Robin Nano
U5 W25Q64BV, 16K SERIAL EEPROM:
*/
#include "../../inc/MarlinConfig.h"
#if ENABLED(SPI_EEPROM_W25Q)
#include "../HAL.h"
#include "../../module/mks_wifi/small_cmsis.h"
#include "../../module/mks_wifi/dwt.h"
#define SPI_DIR_READ 0
#define SPI_DIR_WRITE 1
#define W25X_WriteEnable 0x06
#define W25X_WriteDisable 0x04
#define W25X_ReadStatusReg 0x05
#define W25X_WriteStatusReg 0x01
#define W25X_ReadData 0x03
#define W25X_FastReadData 0x0B
#define W25X_PageProgram 0x02
#define W25X_BlockErase 0xD8
#define W25X_SectorErase 0x20
#define W25X_ChipErase 0xC7
#define W25X_ReleasePowerDown 0xAB
#define W25X_DeviceID 0xAB
#define W25X_ManufactDeviceID 0x90
#define W25X_JedecDeviceID 0x9F
#define SPI_EEPROM_SIZE 2048
#define SPIFLASH_PAGESIZE 256
#define SPI_TIMEOUT 2000 //таймаут на ожидание опереций
#define CHECK_TIMEOUT do{if(dwt_get_timeout() == 0){ERROR("Timeout");return 0;}}while(0)
#define SPI2_START PORTB->BSRR=GPIO_BSRR_BR12
#define SPI2_STOP PORTB->BSRR=GPIO_BSRR_BS12
volatile uint8_t spi_eeprom[SPI_EEPROM_SIZE];
uint8_t spi_send(uint8_t data);
void spi_read(uint32_t addr, uint8_t *buf, uint32_t len);
void spi_write(uint32_t addr, uint8_t *buf, uint32_t len);
uint8_t spi_read_status(void);
void eeprom_hw_init(void){
uint32_t tmp;
uint8_t device_id, manuf_id;
uint16_t chip_id;
/*
SPI2
MISO - PB14 Input floating / Input pull-up
MOSI - PB15 Alternate function push-pull
SCK - PB13 Alternate function push-pull
CS - PB12 Out push-pull
*/
DEBUG("Start SPI");
dwt_init();
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN|RCC_APB2ENR_AFIOEN;
tmp = PORTB->CRH;
tmp |= (GPIO_CRH_MODE13|GPIO_CRH_MODE15|GPIO_CRH_CNF13|GPIO_CRH_CNF15);
tmp &= ~(GPIO_CRH_MODE14|GPIO_CRH_CNF14);
tmp |= GPIO_CRH_CNF14_0;
tmp &= ~GPIO_CRH_CNF12;
tmp |= GPIO_CRH_MODE12;
PORTB->CRH = tmp;
SPI2_STOP;
RCC->APB1ENR|= RCC_APB1ENR_SPI2EN;
SPI2->CR1 = SPI_CR1_SSM|\
SPI_CR1_SSI|\
(6 << SPI_CR1_BR_Pos)|\
SPI_CR1_CPHA|\
SPI_CR1_MSTR;
SPI2->CR1 |= SPI_CR1_SPE;
//Wake up
SPI2_START;
spi_send(W25X_ReleasePowerDown);
SPI2_STOP;
for(uint32_t i=0; i<0x1000; i++){NOP;} //3us для выхода из power down
//Device ID
SPI2_START;
spi_send(W25X_DeviceID);
for(uint32_t i=0; i<3; i++){spi_send(0);}
device_id = spi_send(0);
SPI2_STOP;
//Jedec ID
SPI2_START;
spi_send(W25X_JedecDeviceID);
manuf_id = spi_send(0);
chip_id = spi_send(0) << 8;
chip_id |= spi_send(0);
DEBUG("W25Q Device ID %0X Manuf ID: %0X Chip ID %0X",device_id,manuf_id,chip_id);
SPI2_STOP;
spi_read(SPI_EEPROM_OFFSET,(uint8_t *)spi_eeprom,SPI_EEPROM_SIZE);
}
void eeprom_hw_deinit(void){
DEBUG("Finish SPI");
//Write Enable
SPI2_START;
spi_send(W25X_WriteEnable);
SPI2_STOP;
while (spi_read_status() & 1){ //Busy
NOP;
}
//Erase 4K
SPI2_START;
spi_send(W25X_SectorErase);
spi_send((SPI_EEPROM_OFFSET >> 16) & 0xFF);
spi_send((SPI_EEPROM_OFFSET >> 8) & 0xFF);
spi_send(SPI_EEPROM_OFFSET & 0xFF);
SPI2_STOP;
while (spi_read_status() & 1){ //Busy
NOP;
}
//write
spi_write(SPI_EEPROM_OFFSET,(uint8_t *)spi_eeprom,SPI_EEPROM_SIZE);
//deinit spi
}
void eeprom_write_byte(uint8_t *pos, unsigned char value){
uint16_t addr=(unsigned)pos;
if(addr < SPI_EEPROM_SIZE){
spi_eeprom[addr]=value;
}else{
ERROR("Write out of SPI size: %d %d",addr,SPI_EEPROM_SIZE);
}
}
uint8_t eeprom_read_byte(uint8_t *pos) {
uint16_t addr=(unsigned)pos;
if(addr < SPI_EEPROM_SIZE){
return spi_eeprom[addr];
}else{
ERROR("Read out of SPI size: %d %d",addr,SPI_EEPROM_SIZE);
return 0;
}
}
void eeprom_read_block(void *__dst, const void *__src, size_t __n){
ERROR("Call to missing function");
};
void eeprom_update_block(const void *__src, void *__dst, size_t __n){
ERROR("Call to missing function");
};
uint8_t spi_send(uint8_t data){
while((SPI2->SR & SPI_SR_TXE) == 0){NOP;};
SPI2->DR = data;
while((SPI2->SR & SPI_SR_RXNE) == 0){NOP;};
return SPI2->DR;
}
void spi_read(uint32_t addr, uint8_t *buf, uint32_t len){
if( (len == 0) || (len > SPI_EEPROM_SIZE) ){
ERROR("Len size error: %d",len);
return;
}
addr &= 0xFFFFFF; //24bit address
SPI2_START;
if(len == 1){
spi_send(W25X_ReadData);
spi_send((addr >> 16) & 0xFF);
spi_send((addr >> 8) & 0xFF);
spi_send(addr & 0xFF);
}else{
spi_send(W25X_FastReadData);
spi_send((addr >> 16) & 0xFF);
spi_send((addr >> 8) & 0xFF);
spi_send(addr & 0xFF);
spi_send(0);
}
while (len--){
*buf++ = spi_send(0);
}
SPI2_STOP;
}
void spi_write(uint32_t addr, uint8_t *buf, uint32_t len){
uint16_t bytes_in_page = SPIFLASH_PAGESIZE - (addr % SPIFLASH_PAGESIZE);
uint16_t offset = 0;
addr &= 0xFFFFFF; //24bit address
while (spi_read_status() & 1){ //Busy
NOP;
}
//Write Enable
while (len > 0){
uint16_t batch_size = (len <= bytes_in_page) ? len : bytes_in_page;
SPI2_START;
spi_send(W25X_WriteEnable);
SPI2_STOP;
while (spi_read_status() & 1){ //Busy
NOP;
}
SPI2_START;
spi_send(W25X_PageProgram);
spi_send((addr >> 16) & 0xFF);
spi_send((addr >> 8) & 0xFF);
spi_send(addr & 0xFF);
for (uint32_t i = 0; i < batch_size; i++){
spi_send(((uint8_t*)buf)[offset + i]);
}
SPI2_STOP;
//wait till it's programmed
while (spi_read_status() & 2){ //Busy
NOP;
}
addr += batch_size;
offset += batch_size;
len -= batch_size;
bytes_in_page = SPIFLASH_PAGESIZE;
}
}
uint8_t spi_read_status(void){
uint8_t data;
SPI2_START;
spi_send(W25X_ReadStatusReg);
data = spi_send(0);
SPI2_STOP;
return data;
}
#endif // SPI_EEPROM_W25Q