Skip to content

Thoughts on Flash API? #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
idubrov opened this issue Jan 20, 2018 · 17 comments
Closed

Thoughts on Flash API? #28

idubrov opened this issue Jan 20, 2018 · 17 comments
Labels

Comments

@idubrov
Copy link

idubrov commented Jan 20, 2018

Do you mind taking a quick look at https://github.com/idubrov/stm32-hal/blob/master/src/flash.rs to see if Flash trait I created is a good candidate to be included into this embedded-hal crate?

It appears to me that the trait itself could go into embedded-hal and implementation (line #97 and below) would go into device-specific crate (which in my case is stm32f103xx, but there is not stm32f103xx-hal yet, as far as I can see).

I also have an EEPROM emulation crate (https://github.com/idubrov/eeprom) which uses Flash trait, but, I guess, it should stay as a separate "driver" crate, which will depend on embedded-hal, right?

@thenewwazoo
Copy link
Contributor

I'm resurrecting this, as I'll be adding flash support to the stm32l0x1-hal crate today or tomorrow, and so am looking for traits to use. @idubrov, I think I'll probably adapt your proposal into its own flash-only traits crate with an eye toward adding its contents to an embedded-hal PR soon-ish.

@thenewwazoo
Copy link
Contributor

I'm currently experimenting with these traits. I've impl'd them for stm32l0x1-hal, and will be doing lpc177x_8x-hal soon.

@ryankurte
Copy link
Contributor

ryankurte commented Nov 8, 2018

Neat! i think it'd be good to have a page write as well, and maybe it could be generic over word size? (edit: I see that's already the case for write, just not read yet)

I don't know if it's the right approach / maybe there's something simpler, but maybe write_word(&mut self, word: W) with default impls for write_u8/write_u16/write_u32 where W is u8, u16 and u32 would work?

@eldruin
Copy link
Member

eldruin commented Nov 9, 2018

Sounds good @thenewwazoo! I wrote this EEPROM 24x driver and what I would miss in your traits would mostly be reading an array of words and writing a page (array of words) (see docs). These devices also support reading sequentially (read current address + advance address pointer) but this is probably not implemented in all devices.

I think I would only implement Read and WriteRead and would have no need for Latency or Locking.
The erase_page would not make sense for these devices but I guess I could overwrite the whole page with 0s and that would be fine.

The flash traits presented at the beginning of this thread do not seem to fit the EEPROM 24x devices very well.

Is the Latency used for devices that support communicating at different rates? If so, would it make sense to have a getter method for latency for generic drivers that read the latency from the device?

About the wording, I am not very sure about program_word, I think I would name it write_word but maybe I associate the word program with programming (as in writing code) too much.

There is one thing that I would not know how to model, though: In these devices, after you write a word or page, the device enters an internally-timed write cycle and it does not respond to I2C for a short while (device-dependent).
However, this is not available in the form of some BUSY bit or IO pin. Do you have any idea on how to implement an is_busy()?

@thenewwazoo
Copy link
Contributor

I haven’t had a chance to do any coding in a few days but I did just have an idea about the is_busy question: you could take a non-Periodic hal::timer::Timer in the constructor, and start it when you write; is_busy then becomes a thin shim over Timer::wait

@eldruin
Copy link
Member

eldruin commented Nov 13, 2018

I haven’t had a chance to do any coding in a few days but I did just have an idea about the is_busy question: you could take a non-Periodic hal::timer::Timer in the constructor, and start it when you write; is_busy then becomes a thin shim over Timer::wait

Interesting solution! I think that could be done. However, it seems to me like the whole API will have to use nb::Result if I do not want to forcefully block on is_busy() in the rest of methods, but I think it could be worth it.
Ok I have to apologize I forgot about this: The devices support "Acknowledge polling". I will try to implement the is_busy() just using normal I2C and mapping the errors although that could mask other errors. If that does not work, I will try with the timer.
Thanks @thenewwazoo!

@nickray
Copy link

nickray commented Jan 31, 2019

Should the program_* method be generic over data/value size, taking &[u8; N]? Implementations would specify N; I need this for STM32L432 where N = 8.
Would something like a wear-leveled counter fit in a HAL? It's not exactly a driver either.

@nickray
Copy link

nickray commented May 28, 2019

I've started to iterate on these Flash traits: https://github.com/nickray/stm32l4xx-hal/blob/wip/src/extra_traits/flash.rs

One tricky issue is the fact that in a general Flash trait, the size/alignment rules for reads, writes and erases are chip dependent. I'm currently using the generic-array approach, an alternative would be the "config crate" approach demo'd in https://github.com/jamesmunns/mcf-config-demo

Question: are there any (many?) chips where e.g. read/write/erase sizes and alignment requirements are different? Because then there would be at least 6 instead of 3 constants to configure.

@austinglaser
Copy link
Contributor

Many chips I'm aware of (specifically the STM32 line) do have different alignment and size requirements for all three. Reads are usually allowed pretty freely -- down to byte resolution, and aligned to the size of the read. Writes must be aligned to 4-byte words, and usually only clear bits (never set them). Erases usually are page-aligned -- 1024 bytes is a common size for a page.

I'd encourage you to double check this on some device datasheets, since I'm going from memory here and this is just for one family of MCUs.

@nickray
Copy link

nickray commented May 28, 2019

I'm aware of that, e.g. the STM32L432 I'm using has read/write/erase sizes of 8/8/2048 bytes. My question is whether something like like read size 2 but read alignment 1 occurs (i.e., not "Reads are usually allowed (...) aligned to the size of the read"), or write size != write alignment, or erase size != erase alignment.

@IGBC
Copy link

IGBC commented May 29, 2019

has anyone considered opening this up to all forms of NVS?

while not as popular as it used to be some chips are still shipping with eeprom which is really useful when available.

@austinglaser
Copy link
Contributor

austinglaser commented May 29, 2019

Ah, I misunderstood -- apologies. Unfortunately I can't provide as clear-cut an answer there -- I've never seen such an MCU, but my experience is far from comprehensive.

It does seem to me that for a given operation alignment can never be greater than size -- otherwise, there'd be inaccessible holes in your address space. So if you assume that size == alignment, and encounter an architecture where size > alignment, all you're missing is a potential optimization (and probably a minor one at that), rather than running into a fundamental incompatibility.

With that said, my assumption should probably be challenged before anyone relies on it.

has anyone considered opening this up to all forms of NVS?

while not as popular as it used to be some chips are still shipping with eeprom which is really useful when available.

I think this could be extremely useful. However, I'd propose a generic byte-oriented nonvolatile storage trait rather than trying to make a flash trait encompass all necessary functionality. Such a trait could be built on top of a flash implementer, or directly on top of a hardware EEPROM, or on top of an I2C trait accessing an off-SoC part.

@nickray
Copy link

nickray commented May 30, 2019

One of my goals is to have traits that easily implement the Storage trait used in the LittleFS wrapper: https://docs.rs/littlefs/0.2.0/littlefs/trait.Storage.html

@twitchyliquid64
Copy link

twitchyliquid64 commented Sep 20, 2019

The traits as implemented seems to be very specific to on-die flash. Would it make sense to have a more generic Storage or Memory trait, and then a Flash trait can get more specific from there?

There's lots of memory types to consider:

  • SRAM
  • EEPROM
  • Flash
  • FRAM
  • SDIO/MMC
  • Remote (such as iSCSI)
  • Magnetic core (lol)

@eldruin
Copy link
Member

eldruin commented Dec 10, 2020

@MathiasKoch has created embedded-storage and it would be great to move the discussion around this there for a more focused forum. Once we achieve a good API, we could merge it to embedded-hal but we can discuss this separately.
For this reason, I will close this issue now. If you think otherwise, feel free to ask for reopening.

@eldruin eldruin closed this as completed Dec 10, 2020
@Resonanz
Copy link

Resonanz commented Mar 3, 2025

has anyone considered opening this up to all forms of NVS?

while not as popular as it used to be some chips are still shipping with eeprom which is really useful when available.

Yes yes yes please !!!

@Resonanz
Copy link

Resonanz commented Mar 3, 2025

I originally posted the following on Embassy's Github page, and then found this thread addresses the issue directly.

Question: Does Embassy support unlocking / reading / writing to INTERNAL EEPROM memory in devices such as the STM32L0xx and STM32Lxx series?

These devices are described as having (for example):

Memories
– Up to 192-Kbyte Flash memory with ECC (2 banks with read-while-write capability)
– 20-Kbyte RAM
– 6 Kbytes of data EEPROM with ECC

or again:

The non-volatile memory is divided into three arrays:
– 128 or 192 Kbytes of embedded Flash program memory
– 6 Kbytes of data EEPROM
– Information block containing 32 user and factory options bytes plus Kbytes of system memory

Flash program and data EEPROM are divided into two banks. This allows writing in one
bank while running code or reading data from the other bank. (p.26)

30 year data retention and 100 k write cycles are also mentioned.

Reference: https://www.mouser.com/datasheet/2/389/stm32l082kb-1851150.pdf

The ST Reference Manual RM0367 describes in the code examples Appendix on pages 973-979 how to write to EEPROM (and FLASH ) using C. e.g.

A.3.1 Unlocking the data EEPROM and FLASH_PECR register code example
A.3.2 Locking data EEPROM and FLASH_PECR register code example
A.3.5 Write to data EEPROM code example
A.3.6 Erase to data EEPROM code example

and then for FLASH memory:

A.3.9 Program a single word to Flash program memory code example
A.3.10 Program half-page to Flash program memory code example
A.3.11 Erase a page in Flash program memory code example
A.3.12 Mass erase code example

The example code for writing a byte (or 2, or 4 bytes) is given below:

A.3.5 Write to data EEPROM code example

*(uint8_t *)(DATA_E2_ADDR+i) = DATA_BYTE;
*(uint16_t *)(DATA_E2_ADDR+j) = DATA_16B_WORD;
*(uint32_t *)(DATA_E2_ADDR) = DATA_32B_WORD;
DATA_E2_ADDR is an aligned address in the data EEPROM area.
i can be any integer.
j must be an even integer

Reference: https://www.st.com/resource/en/reference_manual/rm0367-ultralowpower-stm32l0x3-advanced-armbased-32bit-mcus-stmicroelectronics.pdf

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
10 participants