10 changed files with 396 additions and 259 deletions
@ -0,0 +1,51 @@ |
|||||
|
#include "small_spi.h" |
||||
|
#include "../../inc/MarlinConfig.h" |
||||
|
|
||||
|
/*
|
||||
|
SPI2 |
||||
|
MISO - PB14 Input floating / Input pull-up |
||||
|
MOSI - PB15 Alternate function push-pull |
||||
|
SCK - PB13 Alternate function push-pull |
||||
|
W25Q CS - PB12 Out push-pull |
||||
|
TOUCH CS - PA7 |
||||
|
*/ |
||||
|
|
||||
|
void spi2_init(uint8_t prescaler){ |
||||
|
uint32_t tmp; |
||||
|
|
||||
|
if(prescaler > SPI_FREQ_140Khz){ |
||||
|
prescaler = SPI_FREQ_140Khz; |
||||
|
} |
||||
|
|
||||
|
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN|RCC_APB2ENR_IOPAEN|RCC_APB2ENR_AFIOEN; |
||||
|
|
||||
|
tmp = PORTB->CRH; |
||||
|
tmp &= ~(GPIO_CRH_MODE14|GPIO_CRH_CNF14|GPIO_CRH_CNF12|GPIO_CRH_CNF13|GPIO_CRH_CNF14|GPIO_CRH_CNF15); |
||||
|
tmp |= (GPIO_CRH_MODE12|GPIO_CRH_MODE13|GPIO_CRH_MODE15|GPIO_CRH_CNF13_1|GPIO_CRH_CNF15_1|GPIO_CRH_CNF14_0); |
||||
|
PORTB->CRH = tmp; |
||||
|
|
||||
|
//CS PIN
|
||||
|
tmp= PORTA->CRL; |
||||
|
tmp &= ~GPIO_CRL_CNF7; |
||||
|
tmp |= GPIO_CRL_MODE7; |
||||
|
PORTA->CRL = tmp; |
||||
|
|
||||
|
SPI2_STOP_ALL; |
||||
|
|
||||
|
RCC->APB1ENR|= RCC_APB1ENR_SPI2EN; |
||||
|
|
||||
|
SPI2->CR1 = SPI_CR1_SSM|\ |
||||
|
SPI_CR1_SSI|\ |
||||
|
(prescaler << SPI_CR1_BR_Pos)|\ |
||||
|
SPI_CR1_MSTR; |
||||
|
|
||||
|
SPI2->CR1 |= SPI_CR1_SPE; |
||||
|
} |
||||
|
|
||||
|
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; |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
#ifndef SMALL_SPI_H |
||||
|
#define SMALL_SPI_H |
||||
|
|
||||
|
#include "../HAL.h" |
||||
|
#include "../../module/mks_wifi/small_cmsis.h" |
||||
|
|
||||
|
#define SPI_FREQ_18Mhz (uint8_t)0 |
||||
|
#define SPI_FREQ_9Mhz (uint8_t)1 |
||||
|
#define SPI_FREQ_4_5Mhz (uint8_t)2 |
||||
|
#define SPI_FREQ_2_25Mhz (uint8_t)3 |
||||
|
#define SPI_FREQ_1_125Mhz (uint8_t)4 |
||||
|
#define SPI_FREQ_560KHz (uint8_t)5 |
||||
|
#define SPI_FREQ_280KHz (uint8_t)6 |
||||
|
#define SPI_FREQ_140Khz (uint8_t)7 |
||||
|
|
||||
|
#define SPI_DIR_READ 0 |
||||
|
#define SPI_DIR_WRITE 1 |
||||
|
|
||||
|
#define W25Q_START do{PORTB->BSRR=GPIO_BSRR_BR12;PORTA->BSRR=GPIO_BSRR_BS7;}while(0) |
||||
|
#define W25Q_STOP PORTB->BSRR=GPIO_BSRR_BS12 |
||||
|
|
||||
|
#define TOUCH_CS_START do{PORTB->BSRR=GPIO_BSRR_BS12;PORTA->BSRR=GPIO_BSRR_BR7;}while(0) |
||||
|
#define TOUCH_CS_STOP PORTA->BSRR=GPIO_BSRR_BS7 |
||||
|
|
||||
|
#define SPI2_STOP_ALL do{PORTB->BSRR=GPIO_BSRR_BS12;PORTA->BSRR=GPIO_BSRR_BS7;}while(0) |
||||
|
|
||||
|
|
||||
|
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); |
||||
|
void spi2_init(uint8_t prescaler); |
||||
|
|
||||
|
|
||||
|
#endif |
@ -0,0 +1,167 @@ |
|||||
|
#include "w25q64.h" |
||||
|
|
||||
|
volatile uint8_t spi_eeprom[SPI_EEPROM_SIZE]; |
||||
|
|
||||
|
volatile uint32_t spi_cr; |
||||
|
|
||||
|
void w25q_set_spi_speed(void){ |
||||
|
|
||||
|
spi_cr = SPI2->CR1; |
||||
|
spi2_init(SPI_FREQ_18Mhz); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
void w25q_restore_spi_speed(void){ |
||||
|
|
||||
|
spi2_init(SPI_FREQ_280KHz); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
void w25q_init(void){ |
||||
|
uint8_t device_id, manuf_id; |
||||
|
uint16_t chip_id; |
||||
|
|
||||
|
dwt_init(); |
||||
|
|
||||
|
spi2_init(SPI_FREQ_4_5Mhz); |
||||
|
|
||||
|
//Wake up
|
||||
|
W25Q_START; |
||||
|
spi_send(W25X_ReleasePowerDown); |
||||
|
W25Q_STOP; |
||||
|
|
||||
|
for(uint32_t i=0; i<0x1000; i++){NOP;} //3us для выхода из power down
|
||||
|
|
||||
|
//Device ID
|
||||
|
W25Q_START; |
||||
|
spi_send(W25X_DeviceID); |
||||
|
for(uint32_t i=0; i<3; i++){spi_send(0);} |
||||
|
device_id = spi_send(0); |
||||
|
W25Q_STOP; |
||||
|
|
||||
|
//Jedec ID
|
||||
|
W25Q_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); |
||||
|
W25Q_STOP; |
||||
|
} |
||||
|
|
||||
|
void w25q_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
|
||||
|
|
||||
|
W25Q_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); |
||||
|
} |
||||
|
W25Q_STOP; |
||||
|
} |
||||
|
|
||||
|
void w25q_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 (w25q_read_status() & 1){ //Busy
|
||||
|
NOP; |
||||
|
} |
||||
|
//Write Enable
|
||||
|
|
||||
|
while (len > 0){ |
||||
|
uint16_t batch_size = (len <= bytes_in_page) ? len : bytes_in_page; |
||||
|
|
||||
|
W25Q_START; |
||||
|
spi_send(W25X_WriteEnable); |
||||
|
W25Q_STOP; |
||||
|
|
||||
|
while (w25q_read_status() & 1){ //Busy
|
||||
|
NOP; |
||||
|
} |
||||
|
|
||||
|
W25Q_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]); |
||||
|
} |
||||
|
|
||||
|
W25Q_STOP; |
||||
|
|
||||
|
//wait till it's programmed
|
||||
|
while (w25q_read_status() & 2){ //Busy
|
||||
|
NOP; |
||||
|
} |
||||
|
|
||||
|
addr += batch_size; |
||||
|
offset += batch_size; |
||||
|
len -= batch_size; |
||||
|
bytes_in_page = SPIFLASH_PAGESIZE; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
uint8_t w25q_read_status(void){ |
||||
|
uint8_t data; |
||||
|
|
||||
|
W25Q_START; |
||||
|
spi_send(W25X_ReadStatusReg); |
||||
|
data = spi_send(0); |
||||
|
W25Q_STOP; |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
void w25q_write_enable(void){ |
||||
|
//Write Enable
|
||||
|
W25Q_START; |
||||
|
spi_send(W25X_WriteEnable); |
||||
|
W25Q_STOP; |
||||
|
|
||||
|
while (w25q_read_status() & 1){ //Busy
|
||||
|
NOP; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void w25q_sector_erase(uint32_t addr){ |
||||
|
|
||||
|
//Erase 4K
|
||||
|
W25Q_START; |
||||
|
spi_send(W25X_SectorErase); |
||||
|
spi_send((addr >> 16) & 0xFF); |
||||
|
spi_send((addr >> 8) & 0xFF); |
||||
|
spi_send(addr & 0xFF); |
||||
|
W25Q_STOP; |
||||
|
|
||||
|
while (w25q_read_status() & 1){ //Busy
|
||||
|
NOP; |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,42 @@ |
|||||
|
#ifndef W25Q_HAL_H |
||||
|
#define W25Q_HAL_H |
||||
|
#include "../../inc/MarlinConfig.h" |
||||
|
#include "small_spi.h" |
||||
|
#include "../../module/mks_wifi/dwt.h" |
||||
|
|
||||
|
#define SPI_HI_SPEED SPI_FREQ_18Mhz |
||||
|
#define SPI_LOW_SPEED SPI_FREQ_1_125Mhz |
||||
|
|
||||
|
#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 1024 |
||||
|
#define SPIFLASH_PAGESIZE 256 |
||||
|
#define SPI_TIMEOUT 2000 //таймаут на ожидание опереций
|
||||
|
#define CHECK_TIMEOUT do{if(dwt_get_timeout() == 0){ERROR("Timeout");return 0;}}while(0) |
||||
|
|
||||
|
extern volatile uint8_t spi_eeprom[SPI_EEPROM_SIZE]; |
||||
|
|
||||
|
void w25q_init(void); |
||||
|
void w25q_read(uint32_t addr, uint8_t *buf, uint32_t len); |
||||
|
void w25q_write(uint32_t addr, uint8_t *buf, uint32_t len); |
||||
|
uint8_t w25q_read_status(void); |
||||
|
void w25q_write_enable(void); |
||||
|
void w25q_sector_erase(uint32_t addr); |
||||
|
|
||||
|
void w25q_set_spi_speed(void); |
||||
|
void w25q_restore_spi_speed(void); |
||||
|
|
||||
|
#endif |
Loading…
Reference in new issue