Skip to content

Feature: Flash IAP c++ class addition #3700

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

Merged
merged 5 commits into from
Feb 10, 2017

Conversation

0xc0170
Copy link
Contributor

@0xc0170 0xc0170 commented Feb 6, 2017

Description

FlashIAP class addition. It provides block device alike API (write/read/program) plus some getters that are useful for applications.

I added a functional test that was tested with k64f, more to come.

+----------+---------------+-----------------------------+--------+--------------------+-------------+
| target   | platform_name | test suite                  | result | elapsed_time (sec) | copy_method |
+----------+---------------+-----------------------------+--------+--------------------+-------------+
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | OK     | 13.08              | shell       |
+----------+---------------+-----------------------------+--------+--------------------+-------------+
mbedgt: test suite results: 1 OK
mbedgt: test case report:
+----------+---------------+-----------------------------+--------------------+--------+--------+--------+--------------------+
| target   | platform_name | test suite                  | test case          | passed | failed | result | elapsed_time (sec) |
+----------+---------------+-----------------------------+--------------------+--------+--------+--------+--------------------+
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - init    | 1      | 0      | OK     | 0.05               |
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - program | 1      | 0      | OK     | 0.1                |
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - write   | 1      | 0      | OK     | 0.1                |
+----------+---------------+-----------------------------+--------------------+--------+--------+--------+--------------------+
mbedgt: test case results: 3 OK

Status

READY

This PR is for feature branch feature-flash-api

cc @c1728p9 @geky

@0xc0170 0xc0170 requested review from geky and c1728p9 February 6, 2017 16:23

}

int FlashIAP::init()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opinions for return types, own enum ? We have int for the core classes but I have seen some new classes go towards defining own types that are descriptive and more readable

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think typdefs help document the intent of different parts of the function declaration:

flash_error_t FlashIAP::read(void *buffer, flash_addr_t addr, flash_size_t size);

However I don't think the error return should be an enum. It allows compilation warnings, but prevents cross module errors and the strict casting rules of c++ limit compatibility with simple ints (which I don't think is unreasonable for users to use). Keeping error types a typedef of int allows -1 as a "miscellaneous" error and gradual adoption of more useful error codes.

Just my 2c, the new classes do diverge here, so a different perspective may be valuable.

uint32_t count = size;
uint8_t *flash_pointer = (uint8_t *)addr;
uint8_t *read_buffer = (uint8_t *)buffer;
while (count) {
Copy link
Contributor

@geky geky Feb 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiousity, why not memcpy? memcpy(buffer, (const void*)addr, size)

return -1;
}

if (flash_program_page(&_flash, addr, (const uint8_t *)buffer, size)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Why not just call program? Keeps you from repeating yourself.


int FlashIAP::erase(uint32_t addr, uint32_t size)
{
MBED_ASSERT((flash_get_sector_size(&_flash, addr) % size) == 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably also check alignment? (addr / sector_size) * sector_size == addr

@geky
Copy link
Contributor

geky commented Feb 6, 2017

Nice work so far 👍

Out of curiousity, how would a user get the range of addresses a FlashIAP covers?

FlashIAP();
~FlashIAP();

/** Initialize a flash block device
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the expected behavior if this function is called twice in a row ? Is it authorized ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comment - required to be called just once per lifetime of an object

namespace mbed {

/** \addtogroup drivers */
/** @{*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you comment on the expected thread safety of the class ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add it


/** Write blocks to a block device
*
* A write is equivalent to an erase followed by a program
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you indicate that in case of error, during the operation. If the data has been erased they are not recovered ?


int FlashIAP::erase(uint32_t addr, uint32_t size)
{
MBED_ASSERT((flash_get_sector_size(&_flash, addr) % size) == 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should it be an assertion rather than a true precondition check which returns an error ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking addr alignment to block address might be a good thing.

}

int FlashIAP::program(const void *buffer, uint32_t addr, uint32_t size)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it valuable to check addr block alignment and size size ?

* @param size Size to read in bytes, must be a multiple of read block size
* @return 0 on success, negative error code on failure
*/
int read(void *buffer, uint32_t addr, uint32_t size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this member function can be tagged as const.

*
* @return Size of a sector in bytes
*/
uint32_t get_sector_size(uint32_t addr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this member function can be tagged as const.

*
* @return Size of the underlying device in bytes
*/
uint32_t get_flash_size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this member function can be tagged as const.

*
* @return Size of a program page in bytes
*/
uint32_t get_page_size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this member function can be tagged as const.

hal/flash_api.h Outdated
* @param obj The flash objects
* @return The size of the flash available
*/
uint32_t flash_get_size(flash_t *obj);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const flash_t *obj ?

uint32_t sector_size = flash_device.get_sector_size(flash_device.get_flash_size() - 1UL);
TEST_ASSERT_NOT_EQUAL(sector_size, 0);
const uint8_t test_value = 0xCE;
uint8_t *data = new uint8_t[sector_size];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be deleted after use. Same for a couple calls below too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, good catch !

if (ret != 0) {
return -1 ;
}
uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good to check or assert sector size in a loop either here or above. If sector size gets bigger then size could underflow.

@0xc0170 0xc0170 force-pushed the feature-flash-api branch 3 times, most recently from ed88d74 to 1b803af Compare February 7, 2017 14:02
@0xc0170
Copy link
Contributor Author

0xc0170 commented Feb 7, 2017

Thanks for the review @geky @pan- @c1728p9 , I should have responded to all of them.

  • fixed preconditions check (I moved it to upper layer, thus HAL does not check it, added doc note)
  • add test cases to test those preconditions into flashiap test
  • thread safety added
+----------+---------------+-----------------------------+---------------------------+--------+--------+--------+--------------------+
| target   | platform_name | test suite                  | test case                 | passed | failed | result | elapsed_time (sec) |
+----------+---------------+-----------------------------+---------------------------+--------+--------+--------+--------------------+
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - init           | 1      | 0      | OK     | 0.04               |
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - program        | 1      | 0      | OK     | 0.1                |
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - program errors | 1      | 0      | OK     | 0.05               |
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - write          | 1      | 0      | OK     | 0.1                |
| K64F-ARM | K64F          | tests-mbed_drivers-flashiap | FlashIAP - write errors   | 1      | 0      | OK     | 0.05               |
+----------+---------------+-----------------------------+---------------------------+--------+--------+--------+--------------------+

@0xc0170 0xc0170 force-pushed the feature-flash-api branch 2 times, most recently from dcccccf to 110ce9c Compare February 7, 2017 15:55
@0xc0170
Copy link
Contributor Author

0xc0170 commented Feb 8, 2017

Please review again, I would like to have this on the feature branch :)

Copy link
Contributor

@c1728p9 c1728p9 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from the missing lock release it looks good to me.

uint32_t current_sector_size = flash_get_sector_size(&_flash, addr);
// addr and size should be aligned to page size, and multiple of page size
// page program should not cross sector boundaries
if ((is_aligned(addr, page_size) == false) || (is_aligned(size, page_size) == false) ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick - this might be clearer if it is broken into individual checks.

if (!is_aligned(addr, page_size)) {
    return -1;
}
if (!is_aligned(size, page_size)) {
    return -1;
}
if (size < page_size) {
    return -1;
}
if (is_crossing_sector(current_sector_size, addr, size)) {
    return -1;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That actually looks more noisy to me. Maybe just one condition per line would help.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That actually looks more noisy to me. Maybe just one condition per line would help.

I'll do that.

int ret = 0;
_mutex->lock();
if (flash_program_page(&_flash, addr, (const uint8_t *)buffer, size)) {
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to release lock before returing

// addr and size should be aligned to page size, and multiple of page size
// page program should not cross sector boundaries
if ((is_aligned(addr, page_size) == false) || (is_aligned(size, page_size) == false) ||
(size < page_size) || (((addr % current_sector_size) + size) > current_sector_size)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: Is sector size ever not a multiple of page size? The BlockDevice currently prohibits this, it could be an assert at construction time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, I dont think it can be not a multiple of page size.

*
* @return Size of the underlying device in bytes
*/
uint32_t get_flash_size() const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question: How does the user find the beginning of flash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be added later - flash regions properly defined and getters for them. Currently flash algo implementations define flash beginning as 0, but that is not correct (there can be app text/data).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plus having flash regions

@0xc0170
Copy link
Contributor Author

0xc0170 commented Feb 9, 2017

Responded to comments, rebased, rerunning CI

/morph test

@mbed-bot
Copy link

mbed-bot commented Feb 9, 2017

Result: FAILURE

Your command has finished executing! Here's what you wrote!

/morph test

Output

mbed Build Number: 1543

Build failed!

@0xc0170
Copy link
Contributor Author

0xc0170 commented Feb 9, 2017

/morph test

@mbed-bot
Copy link

mbed-bot commented Feb 9, 2017

Result: FAILURE

Your command has finished executing! Here's what you wrote!

/morph test

Output

mbed Build Number: 1544

Test failed!

@0xc0170
Copy link
Contributor Author

0xc0170 commented Feb 9, 2017

@c1728p9 If happy, please merge (the failure is for a platform that is not even supported on this branch, I'll investigate to fix it on master).

Edit: I am goign to update this branch, master is green for the platform that fails here.

Copy link
Contributor

@geky geky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me 👍

@sg-
Copy link
Contributor

sg- commented Feb 9, 2017

/morph test

@0xc0170
Copy link
Contributor Author

0xc0170 commented Feb 9, 2017

Added get_flash_start() method + all the functionality in HAL and tests updated

@mbed-bot
Copy link

mbed-bot commented Feb 9, 2017

Result: FAILURE

Your command has finished executing! Here's what you wrote!

/morph test

Output

mbed Build Number: 1547

Test failed!

@c1728p9
Copy link
Contributor

c1728p9 commented Feb 9, 2017

/morph test

@mbed-bot
Copy link

mbed-bot commented Feb 9, 2017

Result: SUCCESS

Your command has finished executing! Here's what you wrote!

/morph test

Output

mbed Build Number: 1549

All builds and test passed!

flash api should include this header file, as it contains required data declarations.
Flash IAP that provides write/read/program to an internal API. It invokes
flash HAL functions.

FlashIAP checks for alignments for erase/write/program. HAL functions do not, to avoid
duplication per target implementation.
It currently tests functionality provided by flash IAP API like
write/read/program/erase and getters.
Plus fixes in the tests to get properly end of flash (start + size)
@c1728p9
Copy link
Contributor

c1728p9 commented Feb 10, 2017

/morph test

@mbed-bot
Copy link

Result: SUCCESS

Your command has finished executing! Here's what you wrote!

/morph test

Output

mbed Build Number: 1558

All builds and test passed!

@c1728p9 c1728p9 merged commit c4d6403 into ARMmbed:feature-flash-api Feb 10, 2017
@cmonr cmonr removed the needs: CI label Apr 3, 2018
@0xc0170 0xc0170 deleted the feature-flash-api branch September 1, 2020 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants