Topic : relevant or just annoying warrning?

Forum : ST7/STM8

Original Post
Post Information Post
June 11, 2010 - 11:57am
Guest

hi,
i have some problem with flash block programming function from stm8 firmware library in Ride7 environment.
i've added an inram keyword in function declaration in stm8s_flash.h file so function could be executed from RAM area:

void FLASH_ProgramBlock(u16 BlockNum, FLASH_MemType_TypeDef MemType, FLASH_ProgramMode_TypeDef ProgMode, u8 *Buffer) inram;

now i'm reciving linker warrning:
***WARNING 21 : REFERENCE TO CODE FROM INRAM FUNCTION
NAME: ?FC??FLASH_PROGRAMBLOCK?STM8S_FLASH

i've found out that warnning is related with following line of code:

/* Point to the first block address */
StartAddress = StartAddress + ((u32)BlockNum * FLASH_BLOCK_SIZE);

is this warrning in this case relevant and important to notice or just annoying? i can't see the reason why oparations above couldn't be loaded into RAM memory.

definition of FLASH_ProgramBlock() function below:

void FLASH_ProgramBlock(u16 BlockNum, FLASH_MemType_TypeDef MemType, FLASH_ProgramMode_TypeDef ProgMode, u8 *Buffer)
{
u16 Count = 0;
u32 StartAddress = 0;
u16 timeout = OPERATION_TIMEOUT;
/* Check parameters */
assert_param(IS_MEMORY_TYPE_OK(MemType));
assert_param(IS_FLASH_PROGRAM_MODE_OK(ProgMode));
if (MemType == FLASH_MEMTYPE_PROG)
{
assert_param(IS_FLASH_PROG_BLOCK_NUMBER_OK(BlockNum));
StartAddress = FLASH_PROG_START_PHYSICAL_ADDRESS;
}
else
{
assert_param(IS_FLASH_DATA_BLOCK_NUMBER_OK(BlockNum));
StartAddress = FLASH_DATA_START_PHYSICAL_ADDRESS;
}

/* Point to the first block address */
StartAddress = StartAddress + ((u32)BlockNum * FLASH_BLOCK_SIZE);

/* Selection of Standard or Fast programming mode */
if (ProgMode == FLASH_PROGRAMMODE_STANDARD)
{
/* Standard programming mode */ /*No need in standard mode */
FLASH->CR2 |= FLASH_CR2_PRG;
FLASH->NCR2 &= (u8)(~FLASH_NCR2_NPRG);
}
else
{
/* Fast programming mode */
FLASH->CR2 |= FLASH_CR2_FPRG;
FLASH->NCR2 &= (u8)(~FLASH_NCR2_NFPRG);
}

/* Copy data bytes from RAM to FLASH memory */
for (Count = 0; Count < FLASH_BLOCK_SIZE; Count++)
{
*((PointerAttr u8*)StartAddress + Count) = ((u8)(Buffer[Count]));
}

#if defined (STM8S208) || defined(STM8S207) || defined(STM8S105)
if (MemType == FLASH_MEMTYPE_DATA)
{
/* Waiting until High voltage flag is cleared*/
while ((FLASH->IAPSR & FLASH_IAPSR_HVOFF) != 0x00 || (timeout == 0x00))
{
timeout--;
}
}
#endif /* STM8S208, STM8S207, STM8S105 */
}

i also have same problem with FLASH_EraseBlock() function from same library.
any help would be salvation;)

greetz,
wiwid

Replies
Post Information Post
+1
0
-1
June 11, 2010 - 6:32pm
Guest

I think this is just to warn the programmer because the flash may be erased, so care must be taken not to rely on functions or data from that section. Where is the FLASH_ProgramBlock function located? If you make sure that it is not erased then you should be OK. Otherwise, you might be able to eliminate this warning by defining the erase/program functions as inram also. This way, you can still use them even if you erase all the FLASH.

+1
0
-1
June 14, 2010 - 11:33am
Raisonance Support Team

Hello,

Actually the warning may be relevant. The line StartAddress = StartAddress + ((u32)BlockNum * FLASH_BLOCK_SIZE);
requires 32-bit arithmetic, which cannot be inlined in your function. So the C library functions ?C?MULU3232 and ?C?ADD3232 will be linked to your function.

No problem up to here.

However, as the inram function is usually performing some flash erasal, if those functions are erased from flash at the time they are called, you will experience a crash.
In you precise case, the functions are called BEFORE flash is erased, so things should be OK. However, you have so review the assembly produced by the compiler to ensure that it is the case.

If your Flash contents are under 0xFFFF, do not use the u32 pointers and everything will be fine. If this is not the case, you have to be careful.

Regards,
Bruno

+1
0
-1
June 15, 2010 - 11:54am
Guest

ok,
so i've modified my code to:

StartAddress = StartAddress + ((u16)BlockNum * FLASH_BLOCK_SIZE);

and i'm still receiving same warrning. only one warrning pops up this time, without modification there were two same warrnings. any ideas what's causing it?

my flash content is under 0xFFFF so far so 16-bit arithmetic should be enough.

+1
0
-1
June 15, 2010 - 12:49pm
Raisonance Support Team

What you can do is to check in your listing file the assembly code for the inram function. If it contains a CALL to another (non-inram) function, you will have the warning.

If you are not sure, please post your listing file so that we can check it.

Regards,
Bruno

+1
0
-1
June 15, 2010 - 4:44pm
Guest

i've found this:

0028 8D000000 F CALLF ?C?mulu1616

i belive that ?C?mulu1616 is a library function for 16bit arithmetic multiplication.

to be able to access all data (@near) area i need to use a 16-bit pointer, so is there any solution for my problem?
can i somehow move ?C?mulu1616 to RAM? or maybe there is some alternative way of flash reprogramming?

+1
0
-1
June 16, 2010 - 9:17am
Raisonance Support Team

Hi,

The solution is to use some shift operations instead of multiplications: You can write "BlockNum << 8" to have a multiplication by 256.

Regards,
BRuno

+1
0
-1
June 16, 2010 - 12:57pm
Guest

i've finally managed to ellimnate all warrnings:)
Bruno, thanks a lot for your help:)
unfortunately, function have limited scope for action only to "data" (@near) area of memory map, so max. admissible flash size for reprogramming is 32kB:(

listing of both FLASH_EraseBlock() and FLASH_ProgramBlock() functions below:

void FLASH_EraseBlock(u16 BlockNum, FLASH_MemType_TypeDef MemType)
{
u16 timeout = OPERATION_TIMEOUT;
#ifdef PointerAttr_Far
u32 StartAddress = 0;
#else /* PointerAttr_Near */
PointerAttr u32 *pwFlash;
u16 StartAddress = 0;
#endif /*PointerAttr_Far*/

/* Check parameters */
assert_param(IS_MEMORY_TYPE_OK(MemType));
if (MemType == FLASH_MEMTYPE_PROG)
{
assert_param(IS_FLASH_PROG_BLOCK_NUMBER_OK(BlockNum));
StartAddress = FLASH_PROG_START_PHYSICAL_ADDRESS;
}
else
{
assert_param(IS_FLASH_DATA_BLOCK_NUMBER_OK(BlockNum));
StartAddress = FLASH_DATA_START_PHYSICAL_ADDRESS;
}
#ifdef PointerAttr_Far
/* Point to the first block address */
StartAddress = StartAddress + ((u32)BlockNum * FLASH_BLOCK_SIZE);

/* Enable erase block mode */
FLASH->CR2 |= FLASH_CR2_ERASE;
FLASH->NCR2 &= (u8)(~FLASH_NCR2_NERASE);

*((PointerAttr u8*) StartAddress) = FLASH_CLEAR_BYTE;
*((PointerAttr u8*) StartAddress + 1) = FLASH_CLEAR_BYTE;
*((PointerAttr u8*) StartAddress + 2) = FLASH_CLEAR_BYTE;
*((PointerAttr u8*) StartAddress + 3) = FLASH_CLEAR_BYTE;

#else /*PointerAttr_Near*/

/* Point to the first block address */
//pwFlash = (PointerAttr u32 *)(StartAddress + ((u32)BlockNum * FLASH_BLOCK_SIZE));
pwFlash = (PointerAttr u32 *)(StartAddress + (BlockNum << 7));
/* Enable erase block mode */
FLASH->CR2 |= FLASH_CR2_ERASE;
FLASH->NCR2 &= (u8)(~FLASH_NCR2_NERASE);

*pwFlash = (u32)0;
#endif /*PointerAttr_Far*/

#if defined (STM8S208) || defined(STM8S207) || defined(STM8S105)
/* Waiting until High voltage flag is cleared*/
while ((FLASH->IAPSR & FLASH_IAPSR_HVOFF) != 0x00 || (timeout == 0x00))
{
timeout--;
}
#endif /* STM8S208, STM8S207, STM8S105 */
}

void FLASH_ProgramBlock(u16 BlockNum, FLASH_MemType_TypeDef MemType, FLASH_ProgramMode_TypeDef ProgMode, u8 *Buffer)
{
u16 Count = 0;
u16 StartAddress = 0;
u16 timeout = OPERATION_TIMEOUT;
/* Check parameters */
assert_param(IS_MEMORY_TYPE_OK(MemType));
assert_param(IS_FLASH_PROGRAM_MODE_OK(ProgMode));
if (MemType == FLASH_MEMTYPE_PROG)
{
assert_param(IS_FLASH_PROG_BLOCK_NUMBER_OK(BlockNum));
StartAddress = FLASH_PROG_START_PHYSICAL_ADDRESS;
}
else
{
assert_param(IS_FLASH_DATA_BLOCK_NUMBER_OK(BlockNum));
StartAddress = FLASH_DATA_START_PHYSICAL_ADDRESS;
}

/* Point to the first block address */
//StartAddress = StartAddress + ((u32)BlockNum * FLASH_BLOCK_SIZE);
StartAddress = StartAddress + (BlockNum << 7);

/* Selection of Standard or Fast programming mode */
if (ProgMode == FLASH_PROGRAMMODE_STANDARD)
{
/* Standard programming mode */ /*No need in standard mode */
FLASH->CR2 |= FLASH_CR2_PRG;
FLASH->NCR2 &= (u8)(~FLASH_NCR2_NPRG);
}
else
{
/* Fast programming mode */
FLASH->CR2 |= FLASH_CR2_FPRG;
FLASH->NCR2 &= (u8)(~FLASH_NCR2_NFPRG);
}

/* Copy data bytes from RAM to FLASH memory */
for (Count = 0; Count < FLASH_BLOCK_SIZE; Count++)
{
*((PointerAttr u8*)StartAddress + Count) = ((u8)(Buffer[Count]));
}

#if defined (STM8S208) || defined(STM8S207) || defined(STM8S105)
if (MemType == FLASH_MEMTYPE_DATA)
{
/* Waiting until High voltage flag is cleared*/
while ((FLASH->IAPSR & FLASH_IAPSR_HVOFF) != 0x00 || (timeout == 0x00))
{
timeout--;
}
}
#endif /* STM8S208, STM8S207, STM8S105 */
}

+1
0
-1
June 16, 2010 - 5:45pm
Raisonance Support Team

Good job!
In case flash reprogramming for more than 32KB is required, several calls to the function will be necessary. However that should not be a big problem.

Another way to handle the problem is to have the addresses handled as 2 short ints, and to apply appropriate casts so that all arithmetic remains in 16-bit. I realize it seems esoteric, but this works. In case anyone is interested I can post the code.

Regards,
Bruno

+1
0
-1
June 18, 2010 - 10:54am
Guest

I'm very intrested:) post the code please

+1
0
-1
June 21, 2010 - 2:59pm
Raisonance Support Team

Hi wiwid,

Here is the "heart" of your needs: It is a function that computes the address resulting of the addition of a number of 128-byte flash blocks to a base address. It can be "inram" and should be used in your block-by-block programming loop.
It can be used to replace your "StartAddress = StartAddress + ((u32)BlockNum * FLASH_BLOCK_SIZE);" statements.

#pragma SAVE        // Save the current compiler state
#pragma OT(SPEED)   // Speed mode will not call external functions
// Returns an address computed as "addr + nb_page * 128"
// This function does NOT use any C library function,; even for the 32-bit arithmetic.
u32 TranslateAddrEEPROM( u32 addr, u16 page )
{
   u16 wordlo = addr & 0xFFFF;
   u16 wordhi = *(u16*)&addr;
   u16 offslo = (page << 7);
   u16 offshi = (*(u8*)&page >> 1);
   u32 retval;

   wordlo += offslo;

   // In case there is a carry, propagate it to high word
   if(wordlo < offslo)
       ++wordhi;

   wordhi += offshi;

   // Return the 32-bit value (without any 32-bit shift!)
   *(u16*)&retval = wordhi;
   *((u16*)(&retval)+1) = wordlo;
   
   return retval;
}

#pragma RESTORE     // Restore original compiler state

Enjoy,
Bruno