Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

QSPI SFDP Flash - Block Device #1

Merged
merged 19 commits into from
Aug 7, 2018
Merged

QSPI SFDP Flash - Block Device #1

merged 19 commits into from
Aug 7, 2018

Conversation

offirko
Copy link
Contributor

@offirko offirko commented Jul 29, 2018

No description provided.

@offirko
Copy link
Contributor Author

offirko commented Jul 29, 2018

Hello: @bulislaw , @donatieng , @ARMmbed/mbed-os-maintainers , @dannybenor , @davidsaada .
I'd appreciate your review of QSPIF Block Device

@offirko
Copy link
Contributor Author

offirko commented Jul 30, 2018

@maciejbocianski you're review is welcome

{
"name": "qspif",
"config": {
"QSPI_IO0": "NC",
Copy link
Contributor

Choose a reason for hiding this comment

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

we can use QSPI FLASH pins that are currently under review, then this lib can be removed?

TEST_ASSERT_EQUAL(0, err);

_mutex->lock();
printf("read %0*llx:%llu ", addrwidth, block, block_size);
Copy link
Contributor

Choose a reason for hiding this comment

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

Assuming these debug prints will be removed later

Copy link
Contributor Author

Choose a reason for hiding this comment

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

indeed will be removed later on

// Mutex is also protecting printouts for clear logs.
// Mutex is NOT protecting Block Device actions: erase/program/read - which is the purpose of the multithreaded test!
void basic_erase_program_read_test(
QSPIFBlockDevice &blockD,
Copy link
Contributor

Choose a reason for hiding this comment

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

I would recommend using Mbed OS astyle configuration and run astyle (use the codestyle for this repository)

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 have used astyle.. must have missed something. Will fix it

size_t tx_length, const char *rx_buffer, size_t rx_length);

// Send Bus configure_format command to Driver
qspi_status_t _qspiConfiureFormat(qspi_bus_width_t inst_width, qspi_bus_width_t address_width,
Copy link
Contributor

Choose a reason for hiding this comment

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

_qspiConfiureFormat typo -> _qspiConfigureFormat



// Soft Reset Flash Memory
int _resetFlashMem();
Copy link
Contributor

Choose a reason for hiding this comment

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

use all_small rather than camel case for function and variable names. Same as above , the public functions. Even tough these are private helpers , should follow


#include "QSPIFBlockDevice.h"
#include <string.h>
#include <mbed_wait_api.h>
Copy link
Contributor

Choose a reason for hiding this comment

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

use "" for this header file

Copy link

@donatieng donatieng left a comment

Choose a reason for hiding this comment

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

Thanks for sharing @offirko - I haven't had the time to look into the implementation but here are my comments on the API

* @param freq Clock frequency of the QSPI bus (defaults to 40MHz)
*
*/
QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel, int clock_mode,

Choose a reason for hiding this comment

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

Can we have use an enum for clock mode?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, though I would have expected the driver/hal to expose such an enum...they haven't.
I'll add an enum.

*
*/
QSPIFBlockDevice(PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName csel, int clock_mode,
int freq = 40000000);

Choose a reason for hiding this comment

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

Any reason why you're using a signed int?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Matching BD to the existing QSPI driver API, didn't wont to risk unnecessary casting:
qspi_status_t set_frequency(int hz);

* QSPIF_BD_ERROR_READY_FAILED - Waiting for Memory ready failed or timedout
* QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
*/
virtual int init();

Choose a reason for hiding this comment

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

Return type should be qspif_bd_error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Please note this virtual function and its signature is inherited from existing 'BlockDevice' base class.
https://github.com/ARMmbed/mbed-os/blob/master/features/filesystem/bd/BlockDevice.h

* QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
* QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
*/
virtual int program(const void *buffer, bd_addr_t addr, bd_size_t size);

Choose a reason for hiding this comment

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

"Program" sounds a bit odd (as opposed to write). Is that standard terminology?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above, this function is inherited from existing 'BlockDevice' base class.

* @return Size of a minimal erase block, common to all regions, in bytes
* @note Must be a multiple of the program size
*/
virtual bd_size_t get_erase_size() const;

Choose a reason for hiding this comment

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

Is that possible that a block erase size won't be a multiple of other ones? (e.g 1 block is 8kB, another one is 6kB for some reason)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SFDP standard dictates erase size to be given as 2^N. So, the different sizes will always be a multiple of other ones.
Still, for this function it is possible for one region, for example, to support minimal size of 32KB erase size, and other regions to support minimal erase size of 4KB - and then they have no common erase size.

* @note Must be a multiple of the program size
*/
//virtual bd_size_t get_erase_size(bd_addr_t addr) const;
virtual bd_size_t get_erase_size(bd_addr_t addr);

Choose a reason for hiding this comment

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

How do I know the start address of the block?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The given address can be any offset within the Flash size. I'll make it clear in the remarks.

/* Calls to QSPI Driver APIs */
/********************************/
// Send Program => Write command to Driver
qspi_status_t _qspi_send_program_command(unsigned int prog_instruction, const void *buffer, bd_addr_t addr,

Choose a reason for hiding this comment

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

Shouldn't instructions fit within one byte (uint8_t)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're correct, but I was matching the BD code to the existing lower levels QSPI driver where the instructions are 'unsigned int':
qspi_status_t write(unsigned int instruction, unsigned int alt, unsigned int address, const char *tx_buffer, size_t *tx_length);

* QSPIF_BD_ERROR_WREN_FAILED - Write Enable failed
* QSPIF_BD_ERROR_PARSING_FAILED - unexpected format or values in one of the SFDP tables
*/
virtual int erase(bd_addr_t addr, bd_size_t size);

Choose a reason for hiding this comment

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

Erasing is a very long operation - would it make sense to have an asynchronous API as well? Same for writing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently BlockDevice base class does not support Async APIs.
I believe what you suggest would make sense. I think it should be raised as new requirement to add Async BlockDevice async APIs, or maybe add a different base class 'AsyncBlockDevice'.
It would require architecture and design.
Once this API is added at base class, other BlockDevices (SD, SPI, QSPI,..) could adapt.

bool _is_initialized;

// mutex is required for sequence of driver commands that can not be disrupted
static SingletonPtr<PlatformMutex> _mutex;

Choose a reason for hiding this comment

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

Using a singleton mutex across all instances means you cannot use two QSPI flash chips concurrently. Shouldn't "transactions" be a requirement on the driver? (I imagine something like _qspi.lock())

Copy link
Contributor Author

Choose a reason for hiding this comment

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

_qspi.lock is implemented in driver level to protect single driver operations: e.g. write .
BD lock is protecting from a sequence of operations that must be carried sequentially: e.g. (a) _set_write_enable , (b) write, (c) _is_mem_ready . The QSPI driver requires these 3 operations to be carried with no interruption.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@donatieng - after further discussions, the BD mutex was moved to instance level to support multiple QSPI flash chips, as you suggested - Thanks!

Copy link

Choose a reason for hiding this comment

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

It looks like the QSPI driver itself has exposed lock/unlock functions:
https://github.com/ARMmbed/mbed-os/blob/feature-qspi/drivers/QSPI.h#L174-L176

Should we actually be using those?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@geky - QSPI's lock is protecting the bus driver. QSPIF BD lock is protecting the Flash device:
e.g.

QSPI's lock will lock 3 times, each of: Set Write Enable, Send Write Command, Register Read
QSPIF BD lock will lock "program" command for that flash device (on other threads) that contains all of the above 3 because another flash command, such as read, can not be handled in between (a second QSPI Flash device can use the bus driver in between the first flash device commands though)

@maciejbocianski
Copy link

maciejbocianski commented Aug 1, 2018

@offirko
Are we going to have API for QSPI read/write mode configuration (1-1-1/1-2-2/...)?
What will allow to choose what read/write speed/width we want to use

list<mode> get_supported_write_modes() from SFDP
list<mode> get_supported_read_modes() from SFDP
bool set_write_mode(mode)
bool set_read_mode(mode)

@offirko
Copy link
Contributor Author

offirko commented Aug 1, 2018

@maciejbocianski

Are we going to have API for QSPI read/write mode configuration (1-1-1/1-2-2/...)?

According to the design we decided not to add this flexibility.
An internal logic selects the "fastest" mode from the supported ones (as described in SFDP Tables)
See Section 3.5 at the design doc link:
https://armh.sharepoint.com/:w:/r/sites/IoT-Project-Morpheus/Shared%20Documents/design-docs/QSPI%20Block%20Device%201.0.1.docx?d=w70bb086fb2be4d0e92c62a42040197dc&csf=1&e=2UlrqT

Copy link

@davidsaada davidsaada left a comment

Choose a reason for hiding this comment

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

Looks very good. Some minor changes required.

// Soft Reset
if ( -1 == _reset_flash_mem()) {
QSPIF_LOG(QSPIF_DEBUG_INFO, "ERROR: init - Unable to initialize flash memory, tests failed\n");
return QSPIF_BD_ERROR_DEVICE_ERROR;

Choose a reason for hiding this comment

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

Forgot to unlock the mutex (here, and in all following error cases).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

missed this one - Thanks! I'll add an exit point for errors with unlocking

@@ -0,0 +1,339 @@
#include "mbed.h"

Choose a reason for hiding this comment

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

Is this needed if use the mbed namespace?

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 checked again, both are not required - I'll remove

rtos::Thread first_qspif_bd_thread;
rtos::Thread second_qspif_bd_thread;
rtos::Thread third_qspif_bd_thread;

Choose a reason for hiding this comment

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

Why not use an array and loop here?

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 thought 3 would be enough (-:
I'll upgrade to an array

}

bd_size_t block_size = blockD.get_erase_size();
uint8_t *write_block = new uint8_t[block_size];

Choose a reason for hiding this comment

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

I don't know how large this block size can get. If it's large, the test can fail on low memory boards. In this case, would suggest to add std::nothrow to the allocation. This can be used as a good reference.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It can get quite large (Typically 4KB) - I'll add 'std::nothrow' - thanks

@offirko
Copy link
Contributor Author

offirko commented Aug 1, 2018

@0xc0170 , @donatieng , @davidsaada

I related to your comments and pushed changes related to them.
Please re-review - thanks.

Copy link

@davidsaada davidsaada 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.

@@ -0,0 +1,368 @@
#include "greentea-client/test_env.h"
Copy link
Contributor

Choose a reason for hiding this comment

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

Add license header here on the top of the file

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

@@ -0,0 +1,1263 @@

/* mbed Microcontroller Library
* Copyright (c) 2016 ARM Limited
Copy link
Contributor

Choose a reason for hiding this comment

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

year 2018

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

SingletonPtr<PlatformMutex> QSPIFBlockDevice::_mutex;

// Local Function
int localMathPower(int base, int exp);
Copy link
Contributor

Choose a reason for hiding this comment

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

static missing here if local only

Copy link
Contributor

Choose a reason for hiding this comment

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

should be local_math_power

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

#define QSPIF_LOG(level,...) {\
if (level <= QSPIF_DEFAULT_DEBUG_LEVEL) {\
char str[256];\
sprintf(str, "\n[%s][%s:%d], ", __FILENAME__, __FUNCTION__, __LINE__);\
Copy link
Contributor

Choose a reason for hiding this comment

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

misaligned line 113 and 115

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

};

// Remove Remark To Enalbe Logs
//#define QSPIF_ENABLE_LOGS 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than touching sources, use config ? The default one would have this set as disabled?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@0xc0170 , please advise: What is the common practice in mbed-os? I would prefer to enable logs at either Warning or Error level? also, can you pls refer me to a good configuration example?

Copy link
Contributor

Choose a reason for hiding this comment

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

@geky @davidsaada Do you have anything similar in filesystem somewhere - logging ?

Copy link

Choose a reason for hiding this comment

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

LittleFS adopted custom macros because unfortunately there hasn't been a common practice for logging. (I need to go adopt mbed-trace at some point).

Here's the config for LittleFS, you're welcome to the same. It makes it easy to change if the OS logging APIs change:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@geky - thanks!! , eventually with Martin's help I adopted mbed-trace

/*********************************************/
/************* Utility Functions *************/
/*********************************************/
int QSPIFBlockDevice::_utils_find_addr_region(int offset)
Copy link
Contributor

Choose a reason for hiding this comment

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

address is defined as bd_address_t, so why here is int and then cast everywhere in this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed, thanks

bd_size_t size)
{
// Send Read command to device driver
size_t bufLen = size;
Copy link
Contributor

Choose a reason for hiding this comment

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

buf_len , same as read_inst in this scope

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

int dummy_cycles)
{
// Configure QSPI driver Bus format
_qspi.configure_format(inst_width, address_width, address_size, alt_width, alt_size, data_width, dummy_cycles);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is the return value ignored and always returns OK (line 1242) ?

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 saw that driver's 'configure_format' always return OK so I thought not to take its returned value.. Its my mistake I'll take it, just in case the driver changes one day.

unsigned int _erase_type_size_arr[MAX_NUM_OF_ERASE_TYPES];

// Sector Regions Map
int _regions_count; //number of regions
Copy link
Contributor

Choose a reason for hiding this comment

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

why these are int ? compare to command instructions for instance t hat are unsigned int ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

command instructions are defined as 'unsigned int' in driver level, I didnt want to change it to avoid lots of casting. Here I chose 'int' just because its the simplest, it matches the purpose with no impact.

for (int i_ind = 0; i_ind < 15; i_ind++) {
printf("%02x", read_block[block_size - 16 + i_ind]);
}
printf("...\n");
Copy link
Contributor

Choose a reason for hiding this comment

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

Test should minimize debug output by default (these debug msg are important but only if something in the test goes wrong). Instead of printf, use utest_printf

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will fix - thanks

@offirko
Copy link
Contributor Author

offirko commented Aug 2, 2018

@0xc0170 - I added the changes related to your comments, please review - thanks.

@@ -433,7 +406,7 @@ int QSPIFBlockDevice::erase(bd_addr_t addr, bd_size_t inSize)
}
wait_ms(QSPIF_DEFAULT_TIMEOUT_MSEC);
if ( false == _is_mem_ready()) {
QSPIF_LOG(QSPIF_DEBUG_ERROR, "ERROR: QSPI After Erase Device not ready - failed\n");
tr_error("ERROR: QSPI After Erase Device not ready - failed\n");
erase_failed = true;
status = QSPIF_BD_ERROR_READY_FAILED;
goto Exit_Point;
Copy link

@geky geky Aug 2, 2018

Choose a reason for hiding this comment

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

nit: @0xc0170 do we have a naming convention for labels? I would expect them to be similar to functions.

Copy link
Contributor

Choose a reason for hiding this comment

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

not specifically but should be similar

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 fix to match convention

Copy link

@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.

This looks great 👍

QSPI will be a great feature to have


if (QSPI_STATUS_OK != _qsp_set_frequency(freq)) {
tr_error("ERROR: QSPI Set Frequency Failed");
tr_error("ERROR: QSPI Set Frequency Failed");
Copy link

Choose a reason for hiding this comment

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

Intentionally duplicated?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

late night typo (-:

}
tr_debug("/nDEBUG: Read Bus Mode set to 1-1-1, Instruction: 0x%xh", _read_instruction);
is_done = true;
} while (is_done == false);
Copy link

Choose a reason for hiding this comment

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

I'm not sure what the "is_done" variable is doing, it looks like this is always set to true? Would it be better as a series of goto statements?

Or you could just make this while (false);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Its just an easy way to avoid multiple returns (or multiple gotos).
I believe, when possible:

  1. 'goto' should be avoided
  2. function should have minimum 'return' points

I'll change it to 'while (false);' to avoid confusions.

@geky
Copy link

geky commented Aug 2, 2018

Out of curiousity, how much code size does the library cost?

@offirko
Copy link
Contributor Author

offirko commented Aug 5, 2018

@geky , Thanks for your remarks!
Code size is 5Kbyte compiled with GCC_ARM

Copy link

@donatieng donatieng left a comment

Choose a reason for hiding this comment

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

Thanks @offirko, that singleton mutex was my main remaining concern so thanks for addressing it :). Great stuff.

Copy link
Contributor

@0xc0170 0xc0170 left a comment

Choose a reason for hiding this comment

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

Only minor style changes, the rest LGTM


namespace mbed {

enum qspif_default_instructions {
Copy link
Contributor

Choose a reason for hiding this comment

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

where are these used ? I can't locate any code referencing this enum

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@0xc0170 - removed the unused ones -thanks


int QSPIFBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
{

Copy link
Contributor

Choose a reason for hiding this comment

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

can you remove empty lines like this, 247-248 at least

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 for entire file

int status = QSPIF_BD_ERROR_OK;
uint32_t offset = 0;
uint32_t chunk = 0;
bd_size_t writtenBytes = 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

written_bytes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

}


qspi_status_t QSPIFBlockDevice::_qspi_send_erase_command(unsigned int eraseInst, bd_addr_t addr, bd_size_t size)
Copy link
Contributor

Choose a reason for hiding this comment

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

erase_inst

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

README.md Outdated
#include "QSPIFBlockDevice.h"

QSPIFBlockDevice blockD(MBED_CONF_QSPIF_QSPI_IO0,MBED_CONF_QSPIF_QSPI_IO1,MBED_CONF_QSPIF_QSPI_IO2,MBED_CONF_QSPIF_QSPI_IO3,
Copy link
Contributor

Choose a reason for hiding this comment

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

block_d or block_qspi

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

// Mutex is also protecting printouts for clear logs.
// Mutex is NOT protecting Block Device actions: erase/program/read - which is the purpose of the multithreaded test!
void basic_erase_program_read_test(
QSPIFBlockDevice& blockD,
Copy link
Contributor

Choose a reason for hiding this comment

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

fine to have all args on the line 46

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@0xc0170 - moved all to one line - fixed all comments thanks.

@offirko offirko merged commit 98e6694 into master Aug 7, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants