2021-07-21 08:20 AM
Hello,
I can't find any example code of flash write or read using LL_drivers, only HAL drivers. I work with Blue NRG and I do have rf_drivers_ll_flash.c with functions that looks like those in rf_drivers_hal_flash.c. But I can't make flash working with LL functions... The only meaningful difference is HAL_Init(), which I can't find any LL drivers equivalent. The other differences are locking the access of the flash during write. Is there something obvious I am missing? (clock init? )
Is there some example code using LL drivers for flash? Even MCU different from Blue NRG will be fine, I'll adapt it.
Thank you !
Solved! Go to Solution.
2021-07-26 01:13 AM
Found it. It was simple actually. We must not declare Flashx instance. We have to use already defined instance FLASH. (why it is needed as a parameter in LL while it is not in HAL?)
LL_FLASH_Program(FLASH, Address, DATA_32);
2021-07-21 09:25 AM
I've written most of my flash update code in assembler, using the RM and HAL/SPL code as a reference.
Typically no, you don't have to enable any special clocks. You have to unlock the peripheral, and pay attention to status/error flags, and that the operations are performed with alignment meeting the flash array's geometry, and that the flash-words are erased, especially where the words are long, and also have ECC bits attached.
Some STM32 expect you to have the code in RAM (check #pragma and attributes on functions, and .MAP from working examples), most will simply stall the MCU with wait-states if you try to read access flash while it is busy with a write/erase operation.
2021-07-22 03:06 AM
Thank you for your answer. More precisely, here is a code with HAL, which runs fine :
/* Includes ------------------------------------------------------------------*/
#include "FLASH_EraseProgram_main.h"
/* Private define ------------------------------------------------------------*/
#define FLASH_USER_START_ADDR (FLASH_END_ADDR - FLASH_PAGE_SIZE - 0xF) /* Start @ of user Flash area */
#define FLASH_USER_END_ADDR (FLASH_END_ADDR - 0xF) /* End @ of user Flash area */
#define DATA_32 ((uint32_t)0xDEADBEEF)
/* Private variables ---------------------------------------------------------*/
uint32_t FirstPage = 0, NbOfPages = 0;
uint32_t Address = 0, PageError = 0;
__IO uint32_t data32 = 0 , MemoryProgramStatus = 0;
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* System initialization function */
if (SystemInit(SYSCLK_32M, RADIO_SYSCLK_NONE) != SUCCESS)
{
/* Error during system clock configuration take appropriate action */
while(1);
}
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* IO pull configuration with minimum power consumption */
BSP_IO_Init();
/* Initialization of COM port */
BSP_COM_Init(NULL);
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* Initialize LED1, LED2 and LED3 */
BSP_LED_Init(BSP_LED1);
BSP_LED_Init(BSP_LED2);
BSP_LED_Init(BSP_LED3);
/* Program the user Flash area word by word
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
printf("Program the user Flash area word by word.\n\r");
Address = FLASH_USER_START_ADDR;
while (Address < FLASH_USER_END_ADDR)
{
if (HAL_FLASH_Program(Address, DATA_32) == HAL_OK)
{
// LL_FLASH_Program(&Flash_instance, Address, DATA_32);
Address = Address + 4;
}
else
{
/* Error occurred while writing data in Flash memory.
User can add here some code to deal with this error */
printf("Error occurred while writing data in Flash memory.\n\r");
while (1)
{
BSP_LED_On(BSP_LED3);
}
}
}
/*
Check if the programmed data is OK
MemoryProgramStatus = 0: data programmed correctly
MemoryProgramStatus != 0: number of words not programmed correctly
*/
Address = FLASH_USER_START_ADDR;
MemoryProgramStatus = 0x0;
printf("Check the programmed data:\n\r");
while (Address < FLASH_USER_END_ADDR)
{
data32 = *(__IO uint32_t *)Address;
if (data32 != DATA_32)
{
MemoryProgramStatus++;
}
Address = Address + 4;
}
/*Check if there is an issue to program data*/
if (MemoryProgramStatus == 0)
{
/* No error detected. Switch on LED2*/
printf("No error detected.\n\r");
BSP_LED_On(BSP_LED2);
}
else
{
/* Error detected. Switch on LED1*/
printf("Error detected.\n\r");
BSP_LED_On(BSP_LED1);
}
/* Infinite loop */
while (1)
{
}
}
and here is my code not running : (it compiles but doesn't write in flash) :
/* Private macro -------------------------------------------------------------*/
#define LL_FLASH_USER_START_ADDR (LL_FLASH_END_ADDR - LL_FLASH_PAGE_SIZE - 0xF) /* Start @ of user Flash area */
#define LL_FLASH_USER_END_ADDR (LL_FLASH_END_ADDR - 0xF) /* End @ of user Flash area */
#define DATA_32 ((uint32_t)0x12345678)
#ifdef DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/* Private variables ---------------------------------------------------------*/
uint32_t Address = 0;
__IO uint32_t data32 = 0;
FLASH_TypeDef Flash_instance;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void ModulesTick(void)
{
/* Timer tick */
HAL_VTIMER_Tick();
/* Bluetooth stack tick */
BLE_STACK_Tick();
/* NVM manager tick */
NVMDB_Tick();
}
int main(void)
{
WakeupSourceConfig_TypeDef wakeupIO;
PowerSaveLevels stopLevel;
/* System initialization function */
if (SystemInit(SYSCLK_64M, BLE_SYSCLK_16M) != SUCCESS)
{
/* Error during system clock configuration take appropriate action */
while(1);
}
// /* Configure IOs for power save modes */
// BSP_IO_Init();
LL_Init1msTick(SystemCoreClock);
/* No Wakeup Source needed */
wakeupIO.IO_Mask_High_polarity = 0;
wakeupIO.IO_Mask_Low_polarity = 0;
wakeupIO.RTC_enable = 0;
wakeupIO.LPU_enable = 0;
Address = LL_FLASH_USER_START_ADDR;
while (Address < LL_FLASH_USER_END_ADDR)
{
LL_FLASH_Program(&Flash_instance, Address, DATA_32);
Address = Address + 4;
}
Address = LL_FLASH_USER_START_ADDR;
printf("Check the programmed data:\n\r");
while (Address < LL_FLASH_USER_END_ADDR)
{
data32 = *(__IO uint32_t *)Address;
printf("%x %x \r\n",Address, data32);
if (data32 != DATA_32)
{
printf("eRRoR !\n\r");
}
Address = Address + 4;
}
/* Infinite loop */
while (1)
{
}
}
here is the codes of HAL_FLASH_Program() and LL_FLASH_Program() :
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t Address, uint32_t Data)
{
HAL_StatusTypeDef status;
/* Check the parameters */
assert_param(IS_ADDR_ALIGNED_32BITS(Address));
assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));
/* Process Locked */
__HAL_LOCK(&pFlash);
/* Reset error code */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* Program a word (32-bit) at a specified address */
FLASH_Program_Word(Address, Data);
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
/* Process Unlocked */
__HAL_UNLOCK(&pFlash);
/* return status */
return status;
}
// Flash_Program_Word() :
static void FLASH_Program_Word(uint32_t Address, uint32_t Data)
{
/* Clear All Flags */
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_CMDDONE|FLASH_FLAG_CMDSTART|FLASH_FLAG_CMDERR|FLASH_FLAG_ILLCMD);
/* Load the word address */
FLASH->ADDRESS = ((Address>>2) & 0xFFFF);
/* Load the data to program */
FLASH->DATA0 = Data;
/* Load the WRITE command */
FLASH->COMMAND = FLASH_CMD_WRITE;
}
void LL_FLASH_Program(FLASH_TypeDef *FLASHx, uint32_t Address, uint32_t Data)
{
/* Check the parameters */
assert_param(IS_LL_ADDR_ALIGNED_32BITS(Address));
assert_param(IS_LL_FLASH_PROGRAM_ADDRESS(Address));
/* Clear All Flags */
LL_FLASH_ClearFlag(FLASHx, LL_FLASH_FLAG_CMDDONE|LL_FLASH_FLAG_CMDSTART|LL_FLASH_FLAG_CMDERR|LL_FLASH_FLAG_ILLCMD);
/* Load the word address */
FLASHx->ADDRESS = ((Address>>2) & 0xFFFF);
/* Load the data to program */
FLASHx->DATA0 = Data;
/* Load the WRITE command */
FLASHx->COMMAND = LL_FLASH_CMD_WRITE;
/* Wait for last operation to be completed */
while(LL_FLASH_GetFlag(FLASHx, LL_FLASH_FLAG_CMDDONE) != SET);
}
Regarding the functions, nothing changes except some securities like __HAL_LOCK(&pFlash) and timeouts. In the main program, the differences are clock initialization and HAL_Init() which I can't find LL_Init() or equivalent.
the comment above HAL_Init() says : "Initializes the Flash interface". Can someone tell me where? When I develop the function, I can't see anything related to flash. But it does perform HAL_InitTick(). Can clock initialization can make the difference between flash writable and not writable?
Thank you for your answer
2021-07-26 01:13 AM
Found it. It was simple actually. We must not declare Flashx instance. We have to use already defined instance FLASH. (why it is needed as a parameter in LL while it is not in HAL?)
LL_FLASH_Program(FLASH, Address, DATA_32);
2021-07-28 11:25 AM
One could argue that the first parameter in LL API is (an unnecessary) placeholder for a future multiple FLASH peripheral instances, but in reality it's just an usual lack of logic thinking...