I have some functions to read-and write to memory to STM32F103 internal memory. This functions work on the gcc and standard linker script. When I want to use the internal flash with stm32 and freertos. FreeRtos does not allow to me access when I want to write a data into internal flash. Here is the standard freertos linker script file.
Default linker script file for freertos for stm32.
/*************************************************
* linker script for ST32F103 & MPU REV 1.02
************************************************/
GROUP(libgcc.a libc.a)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* Higher address of the user mode stack */
_estack = ORIGIN(SRAM)+LENGTH(SRAM);
/*
*There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 1K;
_Minimum_Heap_Size = 1K;
/* Variables used by FreeRTOS-MPU. */
_Privileged_Functions_Region_Size = 16K;
_Privileged_Data_Region_Size = 512;
__FLASH_segment_start__ = ORIGIN( FLASH );
__FLASH_segment_end__ = __FLASH_segment_start__ + LENGTH( FLASH );
__privileged_functions_start__ = ORIGIN( FLASH );
__privileged_functions_end__ = __privileged_functions_start__ + _Privileged_Functions_Region_Size;
__SRAM_segment_start__ = ORIGIN( SRAM );
__SRAM_segment_end__ = __SRAM_segment_start__ + LENGTH( SRAM );
__privileged_data_start__ = ORIGIN( SRAM );
__privileged_data_end__ = ORIGIN( SRAM ) + _Privileged_Data_Region_Size;
ENTRY(Reset_Handler)
SECTIONS
{
/*
Privileged section at the start of the flash.
Vectors must be first whatever.
*/
.isr_vectors :
{
. = ALIGN(4);
_isr_vectors_offs = . - __FLASH_segment_start__;
KEEP(*(.isr_vectors)) /* Startup code */
} >FLASH
privileged_functions :
{
. = ALIGN(4);
*(privileged_functions)
} > FLASH
/* Non privileged code starts here. */
.text_offset :
{
. = ALIGN(4);
. = . + _Privileged_Functions_Region_Size;
} > FLASH
.text :
{
. = ALIGN(4);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
} > FLASH
/*
.ARM.exidx is sorted, so has to go in its own output section.
*/
. = ALIGN(4);
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >FLASH
__exidx_end = .;
/* -- */
.data.align :
{
. = ALIGN(4);
_etext = .;
_sipdata = _etext; /* Used by the startup in order to initialize privileged variables */
} >FLASH
/* -- */
.pdata.align :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
_sidata = .; /* Used by the startup in order to initialize variables */
} >FLASH
/*
* This is the Privileged data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
privileged_data : AT ( _sipdata ) /* AT makes the LMA follow on in the binary image */
{
. = ALIGN(4);
_bss = .;
_spdata = . ;
*(privileged_data)
_epdata = . ;
} > SRAM
/*
* This is the initialized data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
.data_offset :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
} > SRAM
.data : AT ( _sidata ) /* AT makes the LMA follow on in the binary image */
{
_sdata = . ; /* Used by the startup in order to initialize the .data section */
KEEP(*(vtable))
KEEP( *(.data) )
KEEP( *(.data.*) )
. = ALIGN(4);
_edata = . ; /* Used by the startup in order to initialize the .data section */
} >SRAM
/*
* This is the uninitialized data section. Date here is stored in RAM and will be
* set to zero by the startup code.
*/
.bss :
{
. = ALIGN(4);
_sbss = .; /* Used by the startup in order to initialize the .bss section */
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ; /* Used by the startup in order to initialize the .bss section */
} >SRAM
/*
* This is the heap section
* This is just to check that there is enough RAM left for the heap
* It should generate an error if it's full.
*/
._sheap :
{
. = ALIGN(4);
_heap_begin = . ;
. = . + _Minimum_Heap_Size ;
. = ALIGN(4);
_heap_end = . ;
} >SRAM
/*
* This is the user stack section
* This is just to check that there is enough RAM left for the User mode stack
* It should generate an error if it's full.
*/
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ;
. = ALIGN(4);
_eusrstack = . ;
} >SRAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE( _heap = _heap_begin );
PROVIDE ( _eheap = _heap_end );
}
and here is the my new linker script file here to access the last page of the stm32f103 which is page 255. When I want to modify the page255. It does not allow me. Do you have suggestion that how can use the internal flash of the stm32 with freertos? I just need to use one page in the flash when freertos in the usage. Everything works if I do not use freertos
/*************************************************
* linker script for ST32F103 & MPU REV 1.02
************************************************/
GROUP(libgcc.a libc.a)
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1022K
FLASH_STORAGE (rwx) : ORIGIN = 0x08000000+1022K, LENGTH = 2K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* Higher address of the user mode stack */
_estack = ORIGIN(SRAM)+LENGTH(SRAM);
/*
*There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 1K;
_Minimum_Heap_Size = 1K;
/* Variables used by FreeRTOS-MPU. */
_Privileged_Functions_Region_Size = 16K;
_Privileged_Data_Region_Size = 512;
__FLASH_segment_start__ = ORIGIN( FLASH );
__FLASH_segment_end__ = __FLASH_segment_start__ + LENGTH( FLASH );
__privileged_functions_start__ = ORIGIN( FLASH );
__privileged_functions_end__ = __privileged_functions_start__ + _Privileged_Functions_Region_Size;
__SRAM_segment_start__ = ORIGIN( SRAM );
__SRAM_segment_end__ = __SRAM_segment_start__ + LENGTH( SRAM );
__privileged_data_start__ = ORIGIN( SRAM );
__privileged_data_end__ = ORIGIN( SRAM ) + _Privileged_Data_Region_Size;
ENTRY(Reset_Handler)
SECTIONS
{
/*
Privileged section at the start of the flash.
Vectors must be first whatever.
*/
.isr_vectors :
{
. = ALIGN(4);
_isr_vectors_offs = . - __FLASH_segment_start__;
KEEP(*(.isr_vectors)) /* Startup code */
} >FLASH
privileged_functions :
{
. = ALIGN(4);
*(privileged_functions)
} > FLASH
/* Non privileged code starts here. */
.text_offset :
{
. = ALIGN(4);
. = . + _Privileged_Functions_Region_Size;
} > FLASH
.text :
{
. = ALIGN(4);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
} > FLASH
/*
.ARM.exidx is sorted, so has to go in its own output section.
*/
. = ALIGN(4);
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >FLASH
__exidx_end = .;
/* -- */
.data.align :
{
. = ALIGN(4);
_etext = .;
_sipdata = _etext; /* Used by the startup in order to initialize privileged variables */
} >FLASH
/* -- */
.pdata.align :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
_sidata = .; /* Used by the startup in order to initialize variables */
} >FLASH
/*
* This is the Privileged data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
privileged_data : AT ( _sipdata ) /* AT makes the LMA follow on in the binary image */
{
. = ALIGN(4);
_bss = .;
_spdata = . ;
*(privileged_data)
_epdata = . ;
} > SRAM
/*
* This is the initialized data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
.data_offset :
{
. = ALIGN(4);
. = . + _Privileged_Data_Region_Size;
} > SRAM
.data : AT ( _sidata ) /* AT makes the LMA follow on in the binary image */
{
_sdata = . ; /* Used by the startup in order to initialize the .data section */
KEEP(*(vtable))
KEEP( *(.data) )
KEEP( *(.data.*) )
. = ALIGN(4);
_edata = . ; /* Used by the startup in order to initialize the .data section */
} >SRAM
/*
* This is the uninitialized data section. Date here is stored in RAM and will be
* set to zero by the startup code.
*/
.bss :
{
. = ALIGN(4);
_sbss = .; /* Used by the startup in order to initialize the .bss section */
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
_ebss = . ; /* Used by the startup in order to initialize the .bss section */
} >SRAM
/*
* This is the heap section
* This is just to check that there is enough RAM left for the heap
* It should generate an error if it's full.
*/
._sheap :
{
. = ALIGN(4);
_heap_begin = . ;
. = . + _Minimum_Heap_Size ;
. = ALIGN(4);
_heap_end = . ;
} >SRAM
/*
* This is the user stack section
* This is just to check that there is enough RAM left for the User mode stack
* It should generate an error if it's full.
*/
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ;
. = ALIGN(4);
_eusrstack = . ;
} >SRAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
PROVIDE( _heap = _heap_begin );
PROVIDE ( _eheap = _heap_end );
}
The changes are from this linker script
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
to this linker script:
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1022K
FLASH_STORAGE (rwx) : ORIGIN = 0x08000000+1022K, LENGTH = 2K
SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
Here is the my codes to write the flash with FreeRtos. flash.c file.
#include <FreeRTOS.h>
#include <queue.h>
#include <task.h>
/* -- */
#include "FlashMemoryDataStorage_FreeRtos.h"
/* -- */
/********************************************************************************
; Function: FlashMemoryDataStorage_UnLock
;
; Description: unlocks the flash memory
;
; Inputs: nothing
;
; Returns: Nothing
*********************************************************************************/
void FlashMemoryDataStorage_UnLock(void)
{
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
/********************************************************************************
; Function: FlashMemoryDataStorage_Lock
;
; Description: locks the flash memory
;
; Inputs: nothing
;
; Returns: Nothing
*********************************************************************************/
void FlashMemoryDataStorage_Lock(void)
{
FLASH->CR = FLASH_CR_LOCK;
}
/*********************************************************************************
; Function: FlashMemoryDataStorage_SectorErase
;
; Description: erases a sector
;
; Inputs: uint32_t address of erase operation
;
; Returns: Nothing
*********************************************************************************/
void FlashMemoryDataStorage_SectorErase(uint32_t addr)
{
FlashMemoryDataStorage_UnLock();
/* -- */
FLASH->CR |= FLASH_CR_PER;
FLASH->CR &= ~FLASH_CR_PG;
FLASH->CR |= FLASH_CR_OPTER;
FLASH->AR = addr;
FLASH->CR |= FLASH_CR_STRT;
/* wait until the operation finish */
while(FLASH->SR & (uint32_t)FLASH_SR_BSY);
FLASH->CR &= ~(FLASH_CR_PER | FLASH_CR_OPTER);
/* -- */
FlashMemoryDataStorage_Lock();
}
/*********************************************************************************
; Function: FlashMemoryDataStorage_SectorWrite
;
; Description: writes a sector
;
; Inputs: uint32_t address of write operation
;
; Inputs: uint32_t address of write buffer
;
; Returns: Nothing
*********************************************************************************/
ERRCODE FlashMemoryDataStorage_SectorWrite(uint32_t addr,void * pBuff)
{
ERRCODE ec = SUCCESS;
uint16_t size=0, *pAddr=NULL, *pBuffTemp=NULL;
/* -- */
size = FLASH_SECTOR_SIZE;
pAddr = (uint16_t *)addr;
pBuffTemp =(uint16_t *)pBuff;
size = size / 2; /* incoming values are in bytes (It should be 16-bit) */
/* -- */
while(size) {
FlashMemoryDataStorage_UnLock();
/* -- */
FLASH->CR &= ~FLASH_CR_PER;
FLASH->CR |= FLASH_CR_PG;
*(pAddr) = *(pBuffTemp);
tprintf("\r\nPage Erased22: \r\n");
while(1);
/* wait until the operation finish */
while(FLASH->SR & FLASH_SR_BSY);
if (FLASH->SR & FLASH_SR_PGERR) {
ec = FLASH_WRITE_PAGE_ERR;
tprintf("PAGE ERR");
while(1);
goto func_end;
}
/* -- */
if (FLASH->SR & FLASH_SR_WRPRTERR) {
ec = FLASH_WRITE_PROTECTION_ERR;
tprintf("WRTIE PROTEC");
while(1);
goto func_end;
}
pAddr++;
pBuffTemp++;
size--;
}
/* -- */
func_end:
FlashMemoryDataStorage_Lock();
return ec;
}
/*********************************************************************************************
; Function: FlashMemoryDataStorage_SectorDump
;
; Description: dumps a sector
;
; Inputs: uint32_t starting address of dump operation
;
; Returns: Nothing
***********************************************************************************************/
void FlashMemoryDataStorage_SectorDump(uint32_t addr)
{
uint16_t ndx=0, size=0;
size = FLASH_SECTOR_SIZE;
for( ndx=0; ndx < size; ndx++){
if(!(ndx % 16)) tprintf("\n\r0x%04x",ndx);
tprintf(" %02x",*(char *)addr);
addr++;
}
}
/*********************************************************************************************
; Function: FlashMemoryDataStorage_SectorRead
;
; Description: reads a sector
;
; Inputs: uint32_t starting address of read operation
;
; Inputs: char * read buffer pointer
;
; Returns: Nothing
;
***********************************************************************************************/
void FlashMemoryDataStorage_SectorRead(uint32_t addr, char *pBuff)
{
uint16_t index=0, size=0;
size = FLASH_SECTOR_SIZE;
for( index=0; index < size; index++){
pBuff[index] = *(char *)addr;
addr++;
}
}
/*********************************************************************************************
; Function: FlashMemoryDataStorage_SectorFillBuffer
;
; Description: fills the memory with a character
;
; Inputs: char * buffer pointer
;
; Inputs: char chacacter to fill
;
; Returns: Nothing
;
***********************************************************************************************/
void FlashMemoryDataStorage_SectorFillBuffer(char *pBuff, char ch)
{
uint16_t ndx=0, size=0;
size = FLASH_SECTOR_SIZE;
for( ndx=0; ndx < size; ndx++){
pBuff[ndx] = ch;
}
}
/* -- */
static void vTest_Flash( void *pvParameters )
{
/* The parameters are not used in this function. */
(void) pvParameters;
char buffw[FLASH_SECTOR_SIZE];
char buffr[FLASH_SECTOR_SIZE];
while(1) {
/* Erase Memory */
tprintf("\r\nPage Erased: \r\n");
FlashMemoryDataStorage_SectorErase(PAGE_255_ADDR);
/* sector 1 write operation */
FlashMemoryDataStorage_SectorFillBuffer(buffw,'a');
FlashMemoryDataStorage_SectorWrite(PAGE_255_TEST_SECTOR1,buffw);
FlashMemoryDataStorage_SectorRead(PAGE_255_TEST_SECTOR1,buffr);
if(0 != memcmp(buffw,buffr,FLASH_SECTOR_SIZE)) {
tprintf("\r\n flash read/error %d",PAGE_255_TEST_SECTOR1);
}
/* sector dump operations */
/* sector1 dump */
tprintf("\r\nSector 1 Dump: \r\n");
FlashMemoryDataStorage_SectorDump(PAGE_255_TEST_SECTOR1);
vTaskDelay(30000);;
}
}
/* -- */
int main()
{
portBASE_TYPE xReturn;
/* -- */
xReturn = xTaskCreate ( vTest_Flash, ( const signed portCHAR * const )"Test_Flash", configMINIMAL_STACK_SIZE<<5, NULL, tskIDLE_PRIORITY, NULL );
if( xReturn != pdPASS ) {
tprintf("\n\rTest_Flash initilisation problem.\n\r");
}
/* Now all the tasks have been started - start the scheduler. */
vTaskStartScheduler();
return 0;
}
flash.h file
/* -- */
#define FLASH_KEY1 0x45670123 /* These Values Come From PM0075(Programming Manual Section 2.3.1) */
#define FLASH_KEY2 0xCDEF89AB /* We Need To Set The Keys Sequentialy As Described In PM0075 */
/* -- */
#define FLASH_SECTOR_SIZE 128
/* -- */
#define FLASH_WRITE_PAGE_ERR 0x40
#define FLASH_WRITE_PROTECTION_ERR 0x41
/* -- */
#define PAGE_255_ADDR 0x0807F800
#define PAGE_255_TEST_SECTOR1 PAGE_255_ADDR
#define PAGE_255_TEST_SECTOR2 (PAGE_255_TEST_SECTOR1 + 0x200)
#define PAGE_255_TEST_SECTOR3 (PAGE_255_TEST_SECTOR2 + 0x200)
#define PAGE_255_TEST_SECTOR4 (PAGE_255_TEST_SECTOR3 + 0x200)
/* -- */
void FlashMemoryDataStorage_UnLock(void);
void FlashMemoryDataStorage_Lock(void);
void FlashMemoryDataStorage_SectorErase(uint32_t addr);
void FlashMemoryDataStorage_SectorRead(uint32_t addr, char *pBuff);
ERRCODE FlashMemoryDataStorage_SectorWrite(uint32_t addr,void * pBuff);
/* -- */