Merge branch 'feature/spi_flash_lock_recursive' into 'master'

spi_flash: Expose recursive op_lock for atomic multi-part flash operations

See merge request !1556
This commit is contained in:
Angus Gratton
2017-11-20 13:24:41 +08:00
5 changed files with 33 additions and 15 deletions

View File

@@ -212,27 +212,27 @@ IRAM_ATTR TEST_CASE("ETSTimers arm & disarm run from IRAM", "[ets_timer]")
/* arm a disabled timer, then disarm a live timer */ /* arm a disabled timer, then disarm a live timer */
g_flash_guard_default_ops.start(); // Disables flash cache spi_flash_guard_get()->start(); // Disables flash cache
ets_timer_arm(&timer1, INTERVAL, false); ets_timer_arm(&timer1, INTERVAL, false);
// redundant call is deliberate (test code path if already armed) // redundant call is deliberate (test code path if already armed)
ets_timer_arm(&timer1, INTERVAL, false); ets_timer_arm(&timer1, INTERVAL, false);
ets_timer_disarm(&timer1); ets_timer_disarm(&timer1);
g_flash_guard_default_ops.end(); // Re-enables flash cache spi_flash_guard_get()->end(); // Re-enables flash cache
TEST_ASSERT_FALSE(flag); // didn't expire yet TEST_ASSERT_FALSE(flag); // didn't expire yet
/* do the same thing but wait for the timer to expire */ /* do the same thing but wait for the timer to expire */
g_flash_guard_default_ops.start(); spi_flash_guard_get()->start();
ets_timer_arm(&timer1, INTERVAL, false); ets_timer_arm(&timer1, INTERVAL, false);
g_flash_guard_default_ops.end(); spi_flash_guard_get()->end();
vTaskDelay(2 * INTERVAL / portTICK_PERIOD_MS); vTaskDelay(2 * INTERVAL / portTICK_PERIOD_MS);
TEST_ASSERT_TRUE(flag); TEST_ASSERT_TRUE(flag);
g_flash_guard_default_ops.start(); spi_flash_guard_get()->start();
ets_timer_disarm(&timer1); ets_timer_disarm(&timer1);
g_flash_guard_default_ops.end(); spi_flash_guard_get()->end();
} }

View File

@@ -105,7 +105,7 @@ TEST_CASE("heap_caps metadata test", "[heap]")
*/ */
static IRAM_ATTR __attribute__((noinline)) bool iram_malloc_test() static IRAM_ATTR __attribute__((noinline)) bool iram_malloc_test()
{ {
g_flash_guard_default_ops.start(); // Disables flash cache spi_flash_guard_get()->start(); // Disables flash cache
bool result = true; bool result = true;
void *x = heap_caps_malloc(64, MALLOC_CAP_32BIT); void *x = heap_caps_malloc(64, MALLOC_CAP_32BIT);
@@ -114,7 +114,7 @@ static IRAM_ATTR __attribute__((noinline)) bool iram_malloc_test()
result = result && (y != NULL); result = result && (y != NULL);
heap_caps_free(y); heap_caps_free(y);
g_flash_guard_default_ops.end(); // Re-enables flash cache spi_flash_guard_get()->end(); // Re-enables flash cache
return result; return result;
} }

View File

@@ -47,18 +47,18 @@ static volatile int s_flash_op_cpu = -1;
void spi_flash_init_lock() void spi_flash_init_lock()
{ {
s_flash_op_mutex = xSemaphoreCreateMutex(); s_flash_op_mutex = xSemaphoreCreateRecursiveMutex();
assert(s_flash_op_mutex != NULL); assert(s_flash_op_mutex != NULL);
} }
void spi_flash_op_lock() void spi_flash_op_lock()
{ {
xSemaphoreTake(s_flash_op_mutex, portMAX_DELAY); xSemaphoreTakeRecursive(s_flash_op_mutex, portMAX_DELAY);
} }
void spi_flash_op_unlock() void spi_flash_op_unlock()
{ {
xSemaphoreGive(s_flash_op_mutex); xSemaphoreGiveRecursive(s_flash_op_mutex);
} }
/* /*
If you're going to modify this, keep in mind that while the flash caches of the pro and app If you're going to modify this, keep in mind that while the flash caches of the pro and app

View File

@@ -137,6 +137,11 @@ void IRAM_ATTR spi_flash_guard_set(const spi_flash_guard_funcs_t *funcs)
s_flash_guard_ops = funcs; s_flash_guard_ops = funcs;
} }
const spi_flash_guard_funcs_t *IRAM_ATTR spi_flash_guard_get()
{
return s_flash_guard_ops;
}
size_t IRAM_ATTR spi_flash_get_chip_size() size_t IRAM_ATTR spi_flash_get_chip_size()
{ {
return g_rom_flashchip.chip_size; return g_rom_flashchip.chip_size;

View File

@@ -289,11 +289,15 @@ typedef void (*spi_flash_op_unlock_func_t)(void);
* is invoked before the call to one of ROM function above. * is invoked before the call to one of ROM function above.
* - 'end' function should restore state of flash cache and non-IRAM interrupts and * - 'end' function should restore state of flash cache and non-IRAM interrupts and
* is invoked after the call to one of ROM function above. * is invoked after the call to one of ROM function above.
* These two functions are not recursive.
* 2) Functions which synchronizes access to internal data used by flash API. * 2) Functions which synchronizes access to internal data used by flash API.
* This functions are mostly intended to synchronize access to flash API internal data * This functions are mostly intended to synchronize access to flash API internal data
* in multithreaded environment and use OS primitives: * in multithreaded environment and use OS primitives:
* - 'op_lock' locks access to flash API internal data. * - 'op_lock' locks access to flash API internal data.
* - 'op_unlock' unlocks access to flash API internal data. * - 'op_unlock' unlocks access to flash API internal data.
* These two functions are recursive and can be used around the outside of multiple calls to
* 'start' & 'end', in order to create atomic multi-part flash operations.
*
* Different versions of the guarding functions should be used depending on the context of * Different versions of the guarding functions should be used depending on the context of
* execution (with or without functional OS). In normal conditions when flash API is called * execution (with or without functional OS). In normal conditions when flash API is called
* from task the functions use OS primitives. When there is no OS at all or when * from task the functions use OS primitives. When there is no OS at all or when
@@ -304,10 +308,10 @@ typedef void (*spi_flash_op_unlock_func_t)(void);
* For example structure can be placed in DRAM and functions in IRAM sections. * For example structure can be placed in DRAM and functions in IRAM sections.
*/ */
typedef struct { typedef struct {
spi_flash_guard_start_func_t start; /**< critical section start func */ spi_flash_guard_start_func_t start; /**< critical section start function. */
spi_flash_guard_end_func_t end; /**< critical section end func */ spi_flash_guard_end_func_t end; /**< critical section end function. */
spi_flash_op_lock_func_t op_lock; /**< flash access API lock func */ spi_flash_op_lock_func_t op_lock; /**< flash access API lock function.*/
spi_flash_op_unlock_func_t op_unlock; /**< flash access API unlock func */ spi_flash_op_unlock_func_t op_unlock; /**< flash access API unlock function.*/
} spi_flash_guard_funcs_t; } spi_flash_guard_funcs_t;
/** /**
@@ -320,6 +324,15 @@ typedef struct {
*/ */
void spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs); void spi_flash_guard_set(const spi_flash_guard_funcs_t* funcs);
/**
* @brief Get the guard functions used for flash access
*
* @return The guard functions that were set via spi_flash_guard_set(). These functions
* can be called if implementing custom low-level SPI flash operations.
*/
const spi_flash_guard_funcs_t *spi_flash_guard_get();
/** /**
* @brief Default OS-aware flash access guard functions * @brief Default OS-aware flash access guard functions
*/ */