Skip to main content
Ben1
Associate III
Jul 21, 2021 3:20 PM UTC
Solved

flash example code with Low Layer Drivers ?

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 !

This topic has been closed for replies.
Ben1
Ben1Best answer
Associate III
Jul 26, 2021 8:13 AM UTC

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);

4 replies

Tesla DeLorean
Guru
Jul 21, 2021 4:25 PM UTC

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.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Ben1
Ben1Author
Associate III
Jul 22, 2021 10:06 AM UTC

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

Ben1
Ben1AuthorBest answer
Associate III
Jul 26, 2021 8:13 AM UTC

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);

Piranha
Principal III
Jul 28, 2021 6:25 PM UTC

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