Sergey
5 years ago
21 changed files with 773 additions and 140 deletions
@ -0,0 +1,198 @@ |
|||||
|
/**
|
||||
|
|
||||
|
AT24C16, 16K SERIAL EEPROM: |
||||
|
Internally organized with 128 pages of 16 bytes each (2048 bytes) |
||||
|
|
||||
|
16K requires an 11-bit data word address for random word addressing. |
||||
|
|
||||
|
The 16K does not use any device address bits but instead the 3 bits are used for mem- |
||||
|
ory page addressing. These page addressing bits on the 4K, 8K and 16K devices |
||||
|
should be considered the most significant bits of the data word address which follows. |
||||
|
The A0, A1 and A2 pins are no connect. |
||||
|
|
||||
|
*/ |
||||
|
#include "../../inc/MarlinConfig.h" |
||||
|
|
||||
|
#if ENABLED(I2C_EEPROM_AT24C16) |
||||
|
|
||||
|
#include "../HAL.h" |
||||
|
#include "../../module/mks_wifi/small_cmsis.h" |
||||
|
#include "../../module/mks_wifi/dwt.h" |
||||
|
|
||||
|
#define DEV_ADDR 0xA0 |
||||
|
#define FSMC_DISABLE RCC->AHBENR &= ~RCC_AHBENR_FSMCEN //Конфликт на ноге FSMC_NADV с I2C. На время передачи приходится отключать FSMC
|
||||
|
#define FSMC_RESTORE RCC->AHBENR |= RCC_AHBENR_FSMCEN; |
||||
|
|
||||
|
#define I2C_TIMEOUT 2000 //таймаут на ожидание опереций I2C.
|
||||
|
|
||||
|
#define CHECK_TIMEOUT do{if(dwt_get_timeout() == 0){ERROR("Timeout");return 0;}}while(0) |
||||
|
|
||||
|
static bool waitSRBitSet(uint32_t Bit); |
||||
|
static uint8_t i2c_write(const uint8_t hw_adr, uint8_t *data, uint32_t len); |
||||
|
static uint8_t i2c_read(const uint8_t hw_adr, uint16_t addr, uint8_t *data, uint32_t len); |
||||
|
|
||||
|
void eeprom_hw_deinit(void){ |
||||
|
DEBUG("Finish I2C"); |
||||
|
} |
||||
|
|
||||
|
void eeprom_hw_init(void){ |
||||
|
/*
|
||||
|
PB6 SCL Alternate function open drain |
||||
|
PB7 SDA Alternate function open drain |
||||
|
*/ |
||||
|
DEBUG("Init I2C"); |
||||
|
dwt_init(); |
||||
|
|
||||
|
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN|RCC_APB2ENR_AFIOEN; |
||||
|
PORTB->CRL |= (GPIO_CRL_MODE6|GPIO_CRL_MODE7|GPIO_CRL_CNF6|GPIO_CRL_CNF7); |
||||
|
|
||||
|
AFIO->MAPR2 |= AFIO_MAPR2_FSMC_NADV_REMAP; //Remap по факту не работает, бит не устанавливается.
|
||||
|
RCC->APB1ENR|= RCC_APB1ENR_I2C1EN; |
||||
|
|
||||
|
I2C1->CR1 = I2C_CR1_SWRST; |
||||
|
I2C1->CR1 = 0; |
||||
|
|
||||
|
//Тактовая 72Mhz, PCLK 36Mhz
|
||||
|
I2C1->CCR = (180 << I2C_CCR_CCR_Pos); |
||||
|
I2C1->CR2 = (36 << I2C_CR2_FREQ_Pos); |
||||
|
I2C1->TRISE = 37; |
||||
|
I2C1->CR1 = I2C_CR1_PE; |
||||
|
} |
||||
|
|
||||
|
void eeprom_write_byte(uint8_t *pos, unsigned char value){ |
||||
|
uint8_t data[2]; |
||||
|
|
||||
|
FSMC_DISABLE; |
||||
|
|
||||
|
data[0]=(uint8_t)((unsigned)pos % 256); |
||||
|
data[1]=(uint8_t)(value); |
||||
|
|
||||
|
if(!i2c_write((DEV_ADDR+(uint8_t)(((unsigned)pos/256)<<1)),data,2)){ |
||||
|
ERROR("write failed"); |
||||
|
} |
||||
|
safe_delay(20); //Задержка на время пока eeprom пишет.
|
||||
|
FSMC_RESTORE; |
||||
|
} |
||||
|
|
||||
|
uint8_t eeprom_read_byte(uint8_t *pos) { |
||||
|
uint8_t data; |
||||
|
|
||||
|
FSMC_DISABLE; |
||||
|
|
||||
|
if(!i2c_read(DEV_ADDR, (uint16_t)((unsigned)pos), &data, 1)){ |
||||
|
ERROR("read failed"); |
||||
|
data=0; |
||||
|
} |
||||
|
|
||||
|
safe_delay(1); //небольшая пауза перед включением FSMC, чтобы состояние STOP успело выставиться на линии.
|
||||
|
FSMC_RESTORE; |
||||
|
return data; |
||||
|
} |
||||
|
|
||||
|
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"); |
||||
|
}; |
||||
|
|
||||
|
static uint8_t i2c_write(const uint8_t hw_adr, uint8_t *data, uint32_t len){ |
||||
|
|
||||
|
DEBUG("i2c write at %d val %0X",data[0],data[1]); |
||||
|
|
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
DEBUG("Wait busy"); |
||||
|
while(I2C1->SR2 & I2C_SR2_BUSY) {CHECK_TIMEOUT;}; |
||||
|
|
||||
|
|
||||
|
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_START; |
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
DEBUG("Wait SB"); |
||||
|
while(!(I2C1->SR1 & I2C_SR1_SB)) {CHECK_TIMEOUT;}; |
||||
|
I2C1->DR = (hw_adr & 0xFE); |
||||
|
|
||||
|
if(!waitSRBitSet(I2C_SR1_ADDR)) return false; |
||||
|
(void)I2C1->SR2; |
||||
|
|
||||
|
while(len--){ |
||||
|
if(!waitSRBitSet(I2C_SR1_TXE)) return false; |
||||
|
I2C1->DR = *data++; |
||||
|
} |
||||
|
|
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
DEBUG("Wait BTF"); |
||||
|
while(!((I2C1->SR1 & I2C_SR1_TXE) && (I2C1->SR1 & I2C_SR1_BTF))) {CHECK_TIMEOUT;}; |
||||
|
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_STOP; |
||||
|
|
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
static uint8_t i2c_read(const uint8_t hw_adr, uint16_t addr, uint8_t *data, uint32_t len){ |
||||
|
|
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
DEBUG("Wait busy"); |
||||
|
while(I2C1->SR2 & I2C_SR2_BUSY) {CHECK_TIMEOUT;}; |
||||
|
|
||||
|
//Запись адреса
|
||||
|
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_START; |
||||
|
|
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
DEBUG("Wait SB"); |
||||
|
while(!(I2C1->SR1 & I2C_SR1_SB)) {CHECK_TIMEOUT;}; //Условие старт
|
||||
|
|
||||
|
|
||||
|
I2C1->DR = ((hw_adr & 0xFE) + ((addr/256) << 1)); |
||||
|
if(!waitSRBitSet(I2C_SR1_ADDR)) return false; //i2c адрес отправлен
|
||||
|
I2C1->SR2; |
||||
|
|
||||
|
if(!waitSRBitSet(I2C_SR1_TXE)) return false; |
||||
|
I2C1->DR = addr%256; //адрес в памяти отправлен
|
||||
|
|
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
DEBUG("Wait BTF"); |
||||
|
while(!((I2C1->SR1 & I2C_SR1_TXE) && (I2C1->SR1 & I2C_SR1_BTF))) {CHECK_TIMEOUT;}; |
||||
|
|
||||
|
//Чтение
|
||||
|
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_START | I2C_CR1_ACK; |
||||
|
|
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
DEBUG("Wait SB"); |
||||
|
while(!(I2C1->SR1 & I2C_SR1_SB)) {CHECK_TIMEOUT;}; |
||||
|
I2C1->DR = hw_adr|1; |
||||
|
|
||||
|
if(!waitSRBitSet(I2C_SR1_ADDR)) return false; |
||||
|
I2C1->SR2; |
||||
|
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_STOP; |
||||
|
|
||||
|
if(!waitSRBitSet(I2C_SR1_RXNE)) return false; |
||||
|
*data = I2C1->DR; |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static bool waitSRBitSet(uint32_t Bit){ |
||||
|
uint32_t sr; |
||||
|
|
||||
|
dwt_settimeout(I2C_TIMEOUT); |
||||
|
do{ |
||||
|
sr = I2C1->SR1; |
||||
|
if(sr & ( I2C_SR1_AF | I2C_SR1_ARLO | I2C_SR1_BERR)){ |
||||
|
I2C1->CR1 = I2C_CR1_PE | I2C_CR1_STOP; |
||||
|
I2C1->SR1 = 0; |
||||
|
ERROR("I2C Error flag %0X",sr); |
||||
|
return false; |
||||
|
} |
||||
|
if(dwt_get_timeout() == 0){ |
||||
|
ERROR("Timeout %0X",Bit); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
}while(!(sr & Bit)); |
||||
|
|
||||
|
return true; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif // I2C_EEPROM
|
@ -0,0 +1,272 @@ |
|||||
|
/**
|
||||
|
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
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue