-
Notifications
You must be signed in to change notification settings - Fork 3k
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
FlashIAP driver modifications #6140
Conversation
It would be good if we split new API from bugfixing current implementation. This splitting adds a bit of overhead (plus separate PR for new API and bugfixing) but brings more benefit in the long run (maintenance, review, etc). I would suggest this PR become bugfixing (improving the current implementation), and singleton addition new PR. This is stated in our workflow document:
|
0xc0170 - can do, although FlashIAP not being a singleton is surely a bug (allocated two instances by mistake in NVStore tests, and the results were erroneous). |
0xc0170 - Not sure if you accepted my answer or not (did you?), but if you did - please don't merge the PR yet. Some of my NVStore tests fail with this change, and I want to be certain that it's not a bug here. |
Still this adds new API thus should be treated separately. Let's split it |
0xc0170 - False alarm. Was a problematic board. All's well. |
drivers/FlashIAP.h
Outdated
@@ -40,6 +40,13 @@ namespace mbed { | |||
*/ | |||
class FlashIAP : private NonCopyable<FlashIAP> { | |||
public: | |||
|
|||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be still removed (you can rebase to clean up the history to have only 1 commit here)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhhh...
return -1; | ||
} | ||
|
||
int ret = 0; | ||
_mutex->lock(); | ||
if (flash_program_page(&_flash, addr, (const uint8_t *)buffer, size)) { | ||
ret = -1; | ||
while (size) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
while reviewing this, this is similar to #6077 (this is however only program, but erase should do the same) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand the comment. Erase seems to be following a similar algorithm as program now. What's the problem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see the problem now.
My thought here is that the entire check should just be eliminated. Why not erase everything that's in the range, and let the driver worry about alignments, not the user.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if I understand correctly, an unaligned erase does this?
--- sector 0 --- -> --- sector 0 ---
data data
data data
data data
--- sector 1 --- --- sector 1 ---
data ff
> data ff
unaligned | data ff
erase | --- sector 2 --- --- sector 2 ---
> data ff
data ff
data ff
That seems like the sort of thing we'd want to error on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As said, don't think there should even be an unaligned erase check. Don't even know what it stands for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me rephrase: I believe the only acceptable validation here is to check that the address is on a sector boundary, and that the size is a sum of all the consecutive sector sizes. The only way to achieve this is by iterating on the sectors for the validation, and then iterating again for the erase action. It's either that or check nothing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok. Don't let me block this pr then.
Could we check that address + size is on a sector boundary? Would that be cheap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, figured this out after writing the answer. This would be the correct check.
59275d8
to
20c6799
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good so far, left a few comments though they may just be me misunderstanding.
drivers/FlashIAP.cpp
Outdated
buf = page_buf; | ||
prog_size = page_size; | ||
} | ||
else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: else should be on same line as }
drivers/FlashIAP.cpp
Outdated
const uint8_t *buf = (uint8_t *) buffer; | ||
|
||
// addr should be aligned to page size | ||
if (!is_aligned(addr, page_size) || (!buffer)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we not still need to check that size is aligned and that program does not go past end of the device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The page alignment check here is for the address only. Don't think we need the size alignment check. Adding such a check would require the user to split the writes to the aligned and unaligned ones, which is basically what the new code does.
Regarding the device end check - good thought. Will add that.
tools/toolchains/gcc.py
Outdated
@@ -26,8 +26,7 @@ class GCC(mbedToolchain): | |||
LIBRARY_EXT = '.a' | |||
|
|||
STD_LIB_NAME = "lib%s.a" | |||
DIAGNOSTIC_PATTERN = re.compile('((?P<file>[^:]+):(?P<line>\d+):)(\d+:)? (?P<severity>warning|[eE]rror|fatal error): (?P<message>.+)') | |||
INDEX_PATTERN = re.compile('(?P<col>\s*)\^') | |||
DIAGNOSTIC_PATTERN = re.compile('((?P<file>[^:]+):(?P<line>\d+):)(?P<col>\d+):? (?P<severity>warning|[eE]rror|fatal error): (?P<message>.+)') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the tools change? @theotherjimmy are you able to double check this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the spot! see my comment below.
@davidsaada You have a rebase of a commit on master (1290863ea7973d7862bc006833cf519100a8a39e) in your PR. Please remove this commit from the series. |
Argh. Probably happened after the squash and force push. Thanks @theotherjimmy. |
a0d5fd7
to
20646dc
Compare
/morph build |
1 similar comment
/morph build |
Build : SUCCESSBuild number : 1194 Triggering tests/morph test |
Build : SUCCESSBuild number : 1195 Triggering tests/morph test |
drivers/FlashIAP.cpp
Outdated
@@ -31,6 +33,8 @@ namespace mbed { | |||
|
|||
SingletonPtr<PlatformMutex> FlashIAP::_mutex; | |||
|
|||
#define BLANK 0xFF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use more descriptive name (BLANK can come from targets code and can have diff value), FLASHIAP_BLANK
or similar would be better
drivers/FlashIAP.h
Outdated
@@ -128,6 +128,7 @@ class FlashIAP : private NonCopyable<FlashIAP> { | |||
bool is_aligned_to_sector(uint32_t addr, uint32_t size); | |||
|
|||
flash_t _flash; | |||
uint8_t *page_buf; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_
prefix for private members
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, forgot that.
drivers/FlashIAP.cpp
Outdated
chunk = std::min(current_sector_size - (addr % current_sector_size), size); | ||
if (chunk < page_size) { | ||
memcpy(page_buf, buf, chunk); | ||
memset(page_buf+chunk, BLANK, page_size-chunk); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be: memset(page_buf + chunk, BLANK, page_size - chunk);
(spaces around operators as line 111
return -1; | ||
} else if (erase_end_addr < flash_end_addr){ | ||
uint32_t following_sector_size = flash_get_sector_size(&_flash, erase_end_addr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this "following" sector or the "last sector size to be erased"? From the code I read it as it is the last sector to be erased.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LiyouZhou please review
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. Following means the one after this range. Couldn't find a better name (any recommendation would be welcome).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are making the assumption that: flash sector always start on an address that is aligned to the flash sector size. This is true for all platfroms that I know but I don't know if it is generally true.
I think this will work for the issue i raised. Can we have a testcase to make sure there is no regression?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also never saw cases where sector addresses weren't aligned to their own sizes. This is pretty easy to fix (subtract flash start from relevant cases). Not sure it justifies a special test (if I understood you correctly).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant a test for trying to erase 2 sectors of different sizes at once. basically the situation i describe here: #6077
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see. The NUCLEO_F410RB has two last sectors having different sizes (16KB and 64KB). I can change my new test to erase the last two sectors in one call, and this would cover the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed the test to erase the two last sectors in one call. This will now check your described scenarios in boards whose last two sector sizes are different (there are a few).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LiyouZhou Can you review the latest changes and leave feedback here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@LiyouZhou Would appreciate a quick review, as it seems your review is all that's needed to apply this PR.
TESTS/mbed_drivers/flashiap/main.cpp
Outdated
} | ||
|
||
address += sector_size - 3 * page_size; | ||
uint32_t aligned_prog_size = 7 * page_size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
some devices might fail to allocate 7page_size (if we consider that data are deleted on line 124, this means we are allocating double than that, results in 14page_size?
Lets review the test results for this test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm mistaken, but AFAIK page sizes are typically 8 bytes. Is this problematic?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I recall there was a problem but was probably with sectors rather than pages (as page size that is returned is the smallest unit thta can be written, thus in most cases would be 8 bytes).
Just checking that this will be ok for all targets
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Appears you were right. Boards (namely ARCH_PRO) have a 1KB page size. Modifying the test accordingly.
One last check, do documentation need any updating with this fixes? It would be good if this is captured in the methods documentation what is supported and what is not. I read t he report this week related to program/erase missing this. |
Looking at the handbook, the md file doesn't require any changes. The code (and derived Doxygen documentation) , however, needs a bit of modifications in the program API: It says that the size needs to be aligned to sector and page sizes. The latter isn't true any more, but the former was never true. Will change that in the code, but Doxy needs to be regenerated. |
Exporter Build : SUCCESSBuild number : 868 |
1 similar comment
Exporter Build : SUCCESSBuild number : 868 |
Test : FAILUREBuild number : 997 |
Test : FAILUREBuild number : 998 |
drivers/FlashIAP.cpp
Outdated
@@ -31,6 +33,8 @@ namespace mbed { | |||
|
|||
SingletonPtr<PlatformMutex> FlashIAP::_mutex; | |||
|
|||
#define FLASHIAP_BLANK 0xFF |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many of the STM32L devices have an erased value of 0x00 rather than 0xFF. (the only reason I know this is because I came across it today while adding DAPLink support to the STM32L151CBU6A) The HAL API should probably to be modified to expose this information if it is used as this level.
In this case it looks like this value may be used just as a pad value. If so you might want to rename it so it isn't confused with the erased/blank value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is indeed used just once as a PAD value in the driver, so the define will be removed.
The driver doesn't assume that blank values are 0xFF, but other code (such as NVStore) does, so will ask for such an API in HAL. If and when implemented, it should be exposed via this driver.
drivers/FlashIAP.cpp
Outdated
if (chunk < page_size) { | ||
memcpy(_page_buf, buf, chunk); | ||
memset(_page_buf + chunk, FLASHIAP_BLANK, page_size - chunk); | ||
buf = _page_buf; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buf
is clobbered here and never restored. It isn't actually a problem though since it should only happen on the last iteration of the loop. It may not hurt to add another variable, something like prog_buf
to go along with prog_size
so buf
doesn't need to be clobbered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea. This was intentional knowing it's the last iteration, but it can be missed if the code is modified later on.
@davidsaada Holding off on the merge until the commit that addresses @c1728p9's review comes in. Separate note, was this PR ever split up, according to @0xc0170's request? (#6140 (comment)) |
@cmonr No problem. Committing a quick fix soon. And yes - the PR was split up. Will issue the second part once this one is merged. |
- Support programming across sectors. - Support program size not aligned to page size. - Fix validations on sector erase.
326ac03
to
0aeeece
Compare
/morph build |
Build : SUCCESSBuild number : 1224 Triggering tests/morph test |
Test : SUCCESSBuild number : 1025 |
Exporter Build : FAILUREBuild number : 893 |
/morph build |
Started morph build again. That exporter build failure seems like a setup glitch. |
Build : SUCCESSBuild number : 1226 Triggering tests/morph test |
Test : SUCCESSBuild number : 1027 |
Exporter Build : SUCCESSBuild number : 896 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Testing the master protection against merging with request changes status (will revert asap)
Description
A few FlashIAP driver modifications
Status
READY