-
Notifications
You must be signed in to change notification settings - Fork 108
Added flashing support and extended the flash module #91
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
Conversation
Example code for usage: let mut flash = dp.FLASH.constrain();
let mut rcc = dp.RCC.constrain();
let mut pwr = dp.PWR.constrain(&mut rcc.apb1r1);
let _clocks = rcc
.cfgr
.lse(CrystalBypass::Disable, ClockSecuritySystem::Disable)
.msi(MsiFreq::RANGE4M)
.sysclk(80.mhz())
.freeze(&mut flash.acr, &mut pwr);
let mut prog = flash.keyr.unlock_flash(&mut flash.sr, &mut flash.cr).unwrap();
prog.erase_page(FlashPage(4)).unwrap()
prog.program_dword(FlashPage(4).to_address(), 0x0123_4567_89ab_cdef).unwrap();
assert!(core::ptr::read(FlashPage(4).to_address() as *const u64) == 0x0123_4567_89ab_cdef); |
Looking good! Are you planning on resolving the |
Thanks for the feedback! On the |
I had a look at the fast programming, this is only valid after a mass erase, i.e. only for a program running in RAM. I did not have plans for testing RAM based programs now (though the interface does support it through the normal programming), so I'll leave the fast_programming out for now and maybe revisit that specific feature in the future. Also I moved to a slice based interface as enabling and disabling the flashing interface made it quite slow. I think this is ready for review now. |
New example: fn program_region(mut flash: flash::Parts) -> Result<(), flash::FlashError> {
// Unlock the flashing module
let mut prog = flash.keyr.unlock_flash(&mut flash.sr, &mut flash.cr)?;
let page = flash::FlashPage(5);
// Perform the erase and programing operation
prog.erase_page(page)?;
let data = [
0x1111_1112_1113_1114,
0x2221_2222_2223_2224,
0x3331_3332_3333_3334,
];
prog.program(page.to_address(), &data)?;
// Check result (not needed, but done for this example)
let addr = page.to_address() as *const u64;
assert!(unsafe { core::ptr::read(addr) } == data[0]);
assert!(unsafe { core::ptr::read(addr.offset(1)) } == data[1]);
assert!(unsafe { core::ptr::read(addr.offset(2)) } == data[2]);
Ok(())
} |
Are you thinking about actual embedded-hal flash traits? cf. rust-embedded/embedded-hal#28 |
@nickray Yeah, I had a look in Example: fn write(&mut self, address: usize, data: &[u8]) -> FlashResult {
assert!(data.len() % WriteSize::to_usize() == 0);
assert!(address % WriteSize::to_usize() == 0);
// interrupt::free(|cs| {
for i in (0..data.len()).step_by(8) {
self.write_native(
address + i,
GenericArray::from_slice(&data[i..i + 8]),
// cs,
)?;
}
Ok(())
// })
} Assumes 8 bytes, but also has as |
@nickray I see in the documentation that you were thinking about how to get compile time alignment and data size correct. I would move to use the native data types in I can make an example trait of this if you'd like. |
First one is a bug... Also if this is too off-topic, happy to discuss more in an lpc55-hal issue. Latest iteration is https://github.com/nickray/lpc55-hal/blob/main/src/traits/flash.rs, definitely interested in feedback! I think that is what you meant by adjusting My main/only use case currently is implementing something like https://github.com/nickray/littlefs2/blob/main/src/driver.rs. (On that topic, there is some shared interest with other projects than SoloKeys, e.g. iqlusioninc/usbarmory.rs#39 plan (I think...) to do a rewrite of littlefs in Rust, which would profit from "official"/shared flash traits). I dropped the "unlock guard" for now, not sure if that should be modeled with typestates (giving the user responsibility to lock), a guard (but what if that panics), or with a closure perhaps. If only trusted code has access to the flash (I'm using it for a "crypto service" in TrustZone), then perhaps the trait shouldn't feel responsible for "lock safety". |
Look a lot better in the latest version. What is the issue with using the |
I don't quite remember unfortunately. If you're interested in collaborating on some traits, let me know. We'd then already start out with "two implementations" :) |
Sure, then we have the 2 needed implementations for HAL inclusion! |
I think this looks good. |
I should have a bit of time over towards the end of today, I'll give the flash trait a go to see if we can use it directly. |
I imagine implementing the eventual flash trait would be supplemented by device specific HAL functions anyway. So I'm +1 for merging this as-is for now. The flash trait should go through an RFC process anyway I assume (does it implement any length read from any address? is pulling in generic-array acceptable? are we focused only on on-chip flash or e.g. SPI flash? etc. etc.), so I think that will be a week or two at least. |
@nickray I made a minor change to your trait to get memory alignment and better freedom for the implementer. I pushed the change in my latest commit. I removed all references to |
I forgot to write what I did... |
@nickray I have implemented the read and write trait now as well. You can have a look and give feedback :) |
@nickray Any feedback? Else I'll opt for merging this as is. |
Ah sorry, this fell off my radar, thanks for pinging me. I was thinking/hoping the slice interface would be independent of the native implementation. Is this not possible here with your approach (meaning the trait has a default implementation of slice in terms of native)? |
Not sure how to do taht as we have multiple alignments to take into consideration. Plus the type need to implement the |
What do you mean by multiple alignments? I don't know about flash enough, but I'd assume read/write/page size coincides with their alignments, so one could use that. For the other, I think what you need is to Deref (maybe?) to byte slices? To me the whole slice/native split (with encoding the native interface in the trait) doesn't make much sense if each HAL has to do everything by hand (basically if you can't implement the slice API generically via the native API, how's a potential driver going to use it, or what for?). In my old version with |
The issue does not lay in the In your original code this is checked by assert!(data.len() % WriteSize::to_usize() == 0);
assert!(address % WriteSize::to_usize() == 0); However this can make user applications start failing without compile fail when moved between MCUs. As this alignment of the write function cannot be checked at compile time (without always using the native interface, but then the interop is gone anyways). As I see it, you will need MCU specific adaptations of the |
Ping @nickray If we cannot get a consensus now I suggest we merge this as is and continue the trait development in a separate PR. |
Yeah absolutely! |
Do you have anything you want to add @MabezDev else I propose we merge :) |
LGTM. |
I extended the flash support to be able to flash the internal flash.
It works fine, but feedback in welcome!