Initialising .noinit section

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi all

 

I ran into some trouble a while back where certain locations in the SRAM upon power up contained some bogus values and this was traced to having a USB-Serial converter plugged in when power was cycled. In effect, the converter was powering the AVR through the protection diodes.

 

In my current project I rely on the .noinit section to save state across an external reset. The problem is now I cannot fully rely on the SRAM being initialised to 0 when power is applied. I can differentiate a power on reset from an external reset so I suppose one way to do this is put all my variables that reside in the .noinit section in one module and initialise these when I detect the power on reset flag but I would like to know if I can use a more elegant method, something like how the AVR libc initialises the .bss section upon reset. Particularly if I go on to develop other programs that might have a lot more data residing in the .noinit section.

 

I know the .noinit section is defined within a linker script so are there any variables I can access (by marking with extern) that can tell me the offset and size of particular sections?

 

Thanks for any help

 

Adam Hamilton

This topic has a solution.
Last Edited: Sat. Aug 5, 2017 - 09:21 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Write a magic value to the .noinit section when you have a power-on reset.
Subsequent external, watchdog, ... will examine the magic.
.
Bear in mind that SRAM is random at power up. So you need a sensible magic e.g. uint32_t or an ascii string.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MCUSR can be used to detect the different types of reset sources. For my specific problem it is simple enough to initialse my state machine variable residing in the .noinit section using an if statement.

But I am trying to envision future projects where I might require many data structures residing in a .noinit section and looking for an elegant method where I zero the the entire .noinit section only when the PORF (from MCUSR) flag is set.

Cheers
Adam Hamilton

Last Edited: Sat. Aug 5, 2017 - 08:07 AM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

adam3141 wrote:
looking for an elegant method where I zero the the entire .noinit section

 

extern uint8_t __noinit_start, __noinit_end;

for (uint8_t *p = &__noinit_start; p < &__noinit_end; p++)
	*p = 0;

 

Stefan Ernst

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Surely that is the point. BSS and DATA have defined behaviour.
NOINIT can be used in whatever way that you want.
.
Testing PORF and calling memset() looks like a single statement to me.
Of course, if you are obsessed with braces, single line blocks etc, you can waste large sections of screen editor.
.
Readability and style is a personal opinion.
.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you sternst, this is exactly what I was after.

 

Cheers

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Surely that is the point.

Exactly!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

Even the thread title is an oxymoron!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

adam3141 wrote:
The problem is now I cannot fully rely on the SRAM being initialised to 0 when power is applied.

Actually you can rely completely on the data not being initialised.

Any assumptions about the content of this part is very bad programming practice.

 

adam3141 wrote:
and initialise these when I detect the power on reset flag but I would like to know if I can use a more elegant method

Actually I think this is a very elegant solution.

Upvoted Clawson #8

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Paulvdh wrote:

adam3141 wrote:
and initialise these when I detect the power on reset flag but I would like to know if I can use a more elegant method

Actually I think this is a very elegant solution.

Yes, for maybe a handful of variables I would agree and is currently what I use. Sheesh, I was asking for some help regarding a way to initialise a section of memory.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No one knows how you are using NOINIT or even what you are putting there.
.
The linker puts all the BSS items in a contiguous block. Then it can zero the whole block in one go.
Likewise, the linker puts all the DATA items in a contiguous block. And all the initialisation values in a contiguous block in Flash.
Then the CRTS can copy the whole block from Flash to SRAM.
.
You can do whatever YOU want. In whichever way you choose. If you want random storage of random components, you need to do the necessary housekeeping e.g. source location, size, destination of every item.
The contiguous method means a single memclr() and a single memcpy_P(), Or the hand crafted loops from sternst in #4.
.
David.

Last Edited: Sat. Aug 5, 2017 - 08:57 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

david.prentice wrote:

No one knows how you are using NOINIT or even what you are putting there

To put it bluntly, it doesn't matter what goes in there. However, I did give some context as to what I was putting in there.

 

david.prentice wrote:

If you want random storage of random components, you need to do the necessary housekeeping e.g. source location, size, destination of every item. The contiguous method means a single memclr() and a single memcpy_P(), Or the hand crafted loops from sternst in #4

This is exactly my point and in my post I was asking if anyone knew if there was an external variable I could pull in that defined the start and the size of the memory section so that I could initialise a contiguous block of memory. I could not find the answers in the AVR LIBC documentation nor could I find using a Google search, Bing search, etc... I am not familiar with linker scripts hence the post on here.

 

I don't mean to be rude but a solution exists and comments such as these are non constructive and add nothing to the conversation.

 

Adam

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All the sections have start/end markers defined in the linker script.
.
EDIT: for example...
.noinit :
{
PROVIDE (__noinit_start = .) ;
*(.noinit*)
PROVIDE (__noinit_end = .) ;
_end = . ;
PROVIDE (__heap_start = .) ;
} > data

Last Edited: Sat. Aug 5, 2017 - 09:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Cheers

 

My knowledge of linker scripts is limited only to their existence.

 

Adam

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I give up.   sternst showed the specific linker names.   And for the specific case of clearing a whole NOINIT section with contiguous items.

 

People ask technical questions.   And they get good answers.   

But they have a certain responsibility to read the replies carefully and ask for any clarification.

 

Think about it.   You are trying to do "similar" things as the regular CRTS (C runtime startup)

So it is worth studying how the Compiler does it.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

I give up.   sternst showed the specific linker names.   And for the specific case of clearing a whole NOINIT section with contiguous items.

 

I think you forgot to read this at #4.

adam3141 wrote:

Thank you sternst, this is exactly what I was after.

 

david.prentice wrote:

People ask technical questions.   And they get good answers.   

But they have a certain responsibility to read the replies carefully and ask for any clarification.

To be honest, I didn't quite understand the point of using magic values from your reply in #2 so I reworded my original question.

 

I suspected there might be a start and end variable because when I used to program an STM32, there was a startup assembler file that used __sdata and __edata so I asked a question about if something existed in the AVR world.

 

david.prentice wrote:

Think about it.   You are trying to do "similar" things as the regular CRTS (C runtime startup)

So it is worth studying how the Compiler does it.

 

Possibly I should have and I didn't think about it. I didn't have the AVR libc sources at hand and thought that maybe someone from AVR freaks has been in this situation before and would gladly help. Now some of the replies subsequent to the solution seem to indicate that I was somehow rude to people. The only time I was rather blunt was in #12 when I thought this thread was being derailed by unhelpful comments.

 

If I offended you somehow then I apologise.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No offence taken.    Your question was fairly technical.   So we can assume some knowledge.

 

If you don't understand something,  ask the direct question.    I expect that Googling "magic value" may not be very helpful.

 

You had already marked this as solution:

extern uint8_t __noinit_start, __noinit_end;

for (uint8_t *p = &__noinit_start; p < &__noinit_end; p++)
	*p = 0;

There are several clues in the names:

double underscore means Compiler symbol

noinit, start, end are self-explanatory

 

Regarding size or complexity of code.    There is generally plenty of Flash.    Concentrate on readability and clarity.    So what if it uses an extra 100 bytes.

 

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think more than half of the posts in this tread are based on miscommunications.

A part of the miscommunication is that the "complaint" that .noinit is not initialized

It is my opinion that even having a .noinit section is a tremendous advantage of a language as C.

 

As an alternative as the (not so) elegant solution in #4 I would put all the data for the .noinit section in a large structure and then use use EEmem_read_block(... , ... , sizeof( NoInitStruct))  and EEmem_write_block(... , ... , sizeof( NoInitStruct))  or similar  to put a "stable" backup version of the .noinit variables in EEprom and put them back in the proper place after a power failure. With "sizeof ( NoInitStruct)" you just copy what's needed without having to worry about the amount of data or the size of the .noinit section.

If it doesn't fit the compiler will (should?) complain.

 

adam3141 wrote:
But I am trying to envision future projects
Do not spend to much thought on things which might never become relevant. Design code in a clear and portable way. If the code is clear to read and understand now that helps tremendously if you have to adopt it to some unknown future situation.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry. I only posted #13 because in #12 OP said  "there must be a solution". Reading on a phone I'm afraid I missed the fact that Stefan had already given that in #4. In which case I don't understand #12.