Skip to content

Commit d707766

Browse files
sobiehinib
authored andcommitted
Eeprom in external SPI flash (MarlinFirmware#7)
tested over the weekend - works great * Enable EEPROM auto init as we will probably start with invalid data in flash. * Fix XPT2046 to begin/end with it's soft spi pins when needed and to not block SPI2 and vice versa. * Added SPIFlash class to STM32F1 hal. * Added persistent_store_spi_flash and updated persistent_store_sdcard to still be default. * Added required config to pins_MKS_ROBIN_NANO.h.
1 parent 0672e7e commit d707766

8 files changed

+412
-11
lines changed

Marlin/Configuration.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1448,7 +1448,7 @@
14481448
//#define DISABLE_M503 // Saves ~2700 bytes of PROGMEM. Disable for release!
14491449
#define EEPROM_CHITCHAT // Give feedback on EEPROM commands. Disable to save PROGMEM.
14501450
#if ENABLED(EEPROM_SETTINGS)
1451-
//#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors.
1451+
#define EEPROM_AUTO_INIT // Init EEPROM automatically on any errors.
14521452
#endif
14531453

14541454
//

Marlin/src/HAL/HAL_STM32F1/persistent_store_sdcard.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
#include "../../inc/MarlinConfig.h"
3131

32-
#if ENABLED(EEPROM_SETTINGS) && NONE(FLASH_EEPROM_EMULATION, SPI_EEPROM, I2C_EEPROM)
32+
#if ENABLED(EEPROM_SETTINGS) && NONE(SPI_FLASH_EEPROM_EMULATION, FLASH_EEPROM_EMULATION, SPI_EEPROM, I2C_EEPROM)
3333

3434
#include "../shared/persistent_store_api.h"
3535

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#ifdef __STM32F1__
2+
#include "../../inc/MarlinConfig.h"
3+
4+
#if BOTH(EEPROM_SETTINGS, SPI_FLASH_EEPROM_EMULATION)
5+
6+
#include "../shared/persistent_store_api.h"
7+
#include <SPI.h>
8+
#include "spi_flash.h"
9+
10+
#define SPI_FLASH_EEPROM_SIZE 0x1000 // 4K - do not change!
11+
12+
#ifndef E2END
13+
#define E2END SPI_FLASH_EEPROM_SIZE - 1
14+
#endif
15+
16+
static char __attribute__ ((aligned(4))) _eeprom_data[SPI_FLASH_EEPROM_SIZE];
17+
18+
SPIClass _spi(SPI_FLASH_DEVICE);
19+
hal::SPIFlash _flash(_spi, SPI_FLASH_CS_PIN);
20+
21+
bool PersistentStore::access_start()
22+
{
23+
_flash.begin();
24+
_flash.read_array(SPI_FLASH_EEPROM_OFFSET, _eeprom_data, SPI_FLASH_EEPROM_SIZE);
25+
_flash.end();
26+
}
27+
28+
bool PersistentStore::access_finish()
29+
{
30+
_flash.begin();
31+
_flash.erase_4K(SPI_FLASH_EEPROM_OFFSET);
32+
_flash.write_array(SPI_FLASH_EEPROM_OFFSET, _eeprom_data, SPI_FLASH_EEPROM_SIZE);
33+
_flash.end();
34+
}
35+
36+
bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc)
37+
{
38+
for (size_t i = 0; i < size; i++)
39+
{
40+
_eeprom_data[pos + i] = value[i];
41+
}
42+
crc16(crc, value, size);
43+
pos += size;
44+
return false;
45+
}
46+
47+
bool PersistentStore::read_data(int &pos, uint8_t* value, const size_t size, uint16_t *crc, const bool writing/*=true*/)
48+
{
49+
for (size_t i = 0; i < size; i++)
50+
{
51+
uint8_t c = _eeprom_data[pos + i];
52+
if (writing) value[i] = c;
53+
crc16(crc, &c, 1);
54+
}
55+
pos += size;
56+
return false;
57+
}
58+
59+
size_t PersistentStore::capacity()
60+
{
61+
return SPI_FLASH_EEPROM_SIZE;
62+
}
63+
64+
#endif
65+
#endif
+279
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
#include "spi_flash.h"
2+
3+
namespace hal
4+
{
5+
constexpr size_t SPIFLASH_PAGESIZE = 256;
6+
7+
enum SPICommand
8+
{
9+
WRITEENABLE = 0x06,
10+
WRITEDISABLE = 0x04,
11+
BLOCKERASE_4K = 0x20,
12+
BLOCKERASE_32K = 0x52,
13+
BLOCKERASE_64K = 0xD8,
14+
CHIPERASE = 0x60,
15+
STATUSREAD = 0x05,
16+
STATUSWRITE = 0x01,
17+
ARRAYREAD = 0x0B,
18+
ARRAYREADLOWFREQ = 0x03,
19+
SLEEP = 0xB9,
20+
WAKE = 0xAB,
21+
BYTEPAGEPROGRAM = 0x02,
22+
IDREAD = 0x9F,
23+
MACREAD = 0x4B
24+
};
25+
26+
SPIFlash::SPIFlash(SPIClass &spi_instance, uint8_t cs_pin, uint16_t chip_id)
27+
: m_spi(spi_instance)
28+
, m_cs_pin(cs_pin)
29+
, m_chip_id(chip_id)
30+
{
31+
}
32+
33+
void SPIFlash::select()
34+
{
35+
m_spi.beginTransaction(m_settings);
36+
digitalWrite(m_cs_pin, LOW);
37+
}
38+
39+
void SPIFlash::unselect()
40+
{
41+
digitalWrite(m_cs_pin, HIGH);
42+
m_spi.endTransaction();
43+
}
44+
45+
boolean SPIFlash::begin()
46+
{
47+
pinMode(m_cs_pin, OUTPUT);
48+
m_spi.begin();
49+
m_settings = SPISettings(25000000, MSBFIRST, SPI_MODE0);
50+
51+
unselect();
52+
wakeup();
53+
54+
if (m_chip_id == 0 || read_chip_id() == m_chip_id)
55+
{
56+
command(SPICommand::STATUSWRITE, true);
57+
m_spi.transfer(0);
58+
unselect();
59+
return true;
60+
}
61+
62+
return false;
63+
}
64+
65+
uint16_t SPIFlash::read_chip_id()
66+
{
67+
command(SPICommand::IDREAD);
68+
uint16_t chip_id = m_spi.transfer(0) << 8;
69+
chip_id |= m_spi.transfer(0);
70+
unselect();
71+
return chip_id;
72+
}
73+
74+
uint8_t SPIFlash::read(uint32_t addr)
75+
{
76+
command(SPICommand::ARRAYREADLOWFREQ);
77+
m_spi.transfer(addr >> 16);
78+
m_spi.transfer(addr >> 8);
79+
m_spi.transfer(addr);
80+
uint8_t result = m_spi.transfer(0);
81+
unselect();
82+
return result;
83+
}
84+
85+
void SPIFlash::read_array(uint32_t addr, void* buf, uint16_t len)
86+
{
87+
command(SPICommand::ARRAYREAD);
88+
m_spi.transfer(addr >> 16);
89+
m_spi.transfer(addr >> 8);
90+
m_spi.transfer(addr);
91+
m_spi.transfer(0); // dummy 8 clocks
92+
93+
for (uint16_t i = 0; i < len; ++i)
94+
{
95+
((uint8_t*)buf)[i] = m_spi.transfer(0);
96+
}
97+
98+
unselect();
99+
}
100+
101+
void SPIFlash::read_array_dma(uint32_t addr, void* buf, uint16_t len)
102+
{
103+
command(SPICommand::ARRAYREAD);
104+
m_spi.transfer(addr >> 16);
105+
m_spi.transfer(addr >> 8);
106+
m_spi.transfer(addr);
107+
m_spi.transfer(0); // dummy 8 clocks
108+
109+
m_spi.dmaTransfer(nullptr, buf, len);
110+
111+
for (uint16_t i = 0; i < len; ++i)
112+
{
113+
((uint8_t*)buf)[i] = m_spi.transfer(0);
114+
}
115+
116+
unselect();
117+
}
118+
119+
void SPIFlash::command(uint8_t cmd, bool write)
120+
{
121+
if (cmd != SPICommand::WAKE)
122+
{
123+
while(busy());
124+
}
125+
126+
if (write)
127+
{
128+
select();
129+
m_spi.transfer(SPICommand::WRITEENABLE);
130+
unselect();
131+
while(busy());
132+
}
133+
134+
select();
135+
m_spi.transfer(cmd);
136+
}
137+
138+
boolean SPIFlash::busy()
139+
{
140+
return read_status() & 1;
141+
}
142+
143+
boolean SPIFlash::write_enable_latch()
144+
{
145+
return read_status() & 2;
146+
}
147+
148+
uint8_t SPIFlash::read_status()
149+
{
150+
select();
151+
m_spi.transfer(SPICommand::STATUSREAD);
152+
uint8_t status = m_spi.transfer(0);
153+
unselect();
154+
return status;
155+
}
156+
157+
void SPIFlash::write(uint32_t addr, uint8_t bt)
158+
{
159+
command(SPICommand::BYTEPAGEPROGRAM, true);
160+
m_spi.transfer(addr >> 16);
161+
m_spi.transfer(addr >> 8);
162+
m_spi.transfer(addr);
163+
m_spi.transfer(bt);
164+
unselect();
165+
}
166+
167+
void SPIFlash::write_array(uint32_t addr, const void* buf, uint16_t len)
168+
{
169+
uint16_t bytes_in_page = SPIFLASH_PAGESIZE - (addr % SPIFLASH_PAGESIZE);
170+
uint16_t offset = 0;
171+
172+
while (len > 0)
173+
{
174+
uint16_t batch_size = (len <= bytes_in_page) ? len : bytes_in_page;
175+
176+
command(SPICommand::BYTEPAGEPROGRAM, true);
177+
m_spi.transfer(addr >> 16);
178+
m_spi.transfer(addr >> 8);
179+
m_spi.transfer(addr);
180+
181+
for (uint16_t i = 0; i < batch_size; i++)
182+
{
183+
m_spi.transfer(((uint8_t*)buf)[offset + i]);
184+
}
185+
186+
unselect();
187+
188+
//wait till it's programmed
189+
while(write_enable_latch());
190+
191+
addr += batch_size;
192+
offset += batch_size;
193+
len -= batch_size;
194+
bytes_in_page = SPIFLASH_PAGESIZE;
195+
}
196+
}
197+
198+
void SPIFlash::write_array_dma(uint32_t addr, const void* buf, uint16_t len)
199+
{
200+
const uint8_t * byte_buf = (const uint8_t*)buf;
201+
uint16_t bytes_in_page = SPIFLASH_PAGESIZE - (addr % SPIFLASH_PAGESIZE);
202+
203+
while (len > 0)
204+
{
205+
uint16_t batch_size = (len <= bytes_in_page) ? len : bytes_in_page;
206+
207+
command(SPICommand::BYTEPAGEPROGRAM, true);
208+
m_spi.transfer(addr >> 16);
209+
m_spi.transfer(addr >> 8);
210+
m_spi.transfer(addr);
211+
212+
m_spi.dmaSend(byte_buf, batch_size);
213+
214+
unselect();
215+
216+
//wait till it's programmed
217+
while(write_enable_latch());
218+
219+
addr += batch_size;
220+
byte_buf += batch_size;
221+
len -= batch_size;
222+
bytes_in_page = SPIFLASH_PAGESIZE;
223+
}
224+
}
225+
226+
void SPIFlash::erase_full_chip()
227+
{
228+
command(SPICommand::CHIPERASE, true);
229+
unselect();
230+
while(write_enable_latch());
231+
}
232+
233+
void SPIFlash::erase_4K(uint32_t addr)
234+
{
235+
command(SPICommand::BLOCKERASE_4K, true);
236+
m_spi.transfer(addr >> 16);
237+
m_spi.transfer(addr >> 8);
238+
m_spi.transfer(addr);
239+
unselect();
240+
while(write_enable_latch());
241+
}
242+
243+
void SPIFlash::erase_32K(uint32_t addr)
244+
{
245+
command(SPICommand::BLOCKERASE_32K, true);
246+
m_spi.transfer(addr >> 16);
247+
m_spi.transfer(addr >> 8);
248+
m_spi.transfer(addr);
249+
unselect();
250+
while(write_enable_latch());
251+
}
252+
253+
void SPIFlash::erase_64K(uint32_t addr)
254+
{
255+
command(SPICommand::BLOCKERASE_64K, true);
256+
m_spi.transfer(addr >> 16);
257+
m_spi.transfer(addr >> 8);
258+
m_spi.transfer(addr);
259+
unselect();
260+
while(write_enable_latch());
261+
}
262+
263+
void SPIFlash::sleep()
264+
{
265+
command(SPICommand::SLEEP);
266+
unselect();
267+
}
268+
269+
void SPIFlash::wakeup()
270+
{
271+
command(SPICommand::WAKE);
272+
unselect();
273+
}
274+
275+
void SPIFlash::end()
276+
{
277+
m_spi.end();
278+
}
279+
}

0 commit comments

Comments
 (0)