Author Topic: How to port IAR compiler code "#pragma location=" and "__no_init" to GCC  (Read 9997 times)

0 Members and 1 Guest are viewing this topic.

Offline jyrgenTopic starter

  • Contributor
  • Posts: 14
  • Country: se
I have a project which is originally written in IAR which I now need to port for GCC. I'm stuck at one perticular section:

Code: [Select]
extern UNSIGNED8 jumpcode[BL_JUMPCODE_SIZE];
#pragma location=0x200027F0
__no_init UNSIGNED8 jumpcode[BL_JUMPCODE_SIZE]; /*  placed on ram adress 0x200027F0*/

As far as I understand the variable should be placed at the perticular memory address and not be initilized to 0.

I have been trying to use the __attribute__ ((section(".noinit"))), but I also need to use that to place the variable at the specific memory address. Does anyone know how to do this?
 

Online Psi

  • Super Contributor
  • ***
  • Posts: 10233
  • Country: nz
This is for the AVR version of GCC, but the info is probably still valid.

Quote
Only uninitialized variables can be placed in the .noinit section. Thus, the following code will cause avr-gcc to issue an error:
int bar __attribute__ ((section (".noinit"))) = 0xaa;

It is possible to tell the linker explicitly where to place the .noinit section by adding -Wl,--section-start=.noinit=0x802000 to the avr-gcc command line at the linking stage. For example, suppose you wish to place the .noinit section at SRAM address 0x2000:

$ avr-gcc ... -Wl,--section-start=.noinit=0x802000 ...

It's from here
https://www.microchip.com/webdoc/AVRLibcReferenceManual/mem_sections_1sec_dot_noinit.html

If you want more than one variable to be .noinit at its own unique address maybe you need a section for each so they can both be given an address ?
dunno
« Last Edit: March 14, 2018, 08:46:48 am by Psi »
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1673
  • Country: pl
  • Troll Cave Electronics!
use a NOLOAD parameter in linker script. It will go something like this:

that is how I declare stuff in battery backed SRAM in STM32 (the same case, I don't want any initialization so as to not overwrite the backed up data;

Code: [Select]
  .backup(NOLOAD):
  {
  . = ALIGN(4);
  KEEP(*(.backup));
  KEEP(*(.backup*));
  . = ALIGN(4);
  } >BKPSRAM

then in code use something like
Code: [Select]
__attribute__((section(".backup"))) u32 someVariable;
I love the smell of FR4 in the morning!
 

Online Psi

  • Super Contributor
  • ***
  • Posts: 10233
  • Country: nz
He needs to hard code the memory address for the variable.
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline jyrgenTopic starter

  • Contributor
  • Posts: 14
  • Country: se
I should add that this is for STM32 and I have multiple sections that look similar in the code.

Code: [Select]
extern UNSIGNED8 flashNodeId;
#define FLASH_ADDRESS_NODEID           0x08007F00
#pragma location=FLASH_ADDRESS_NODEID
__no_init UNSIGNED8 flashNodeId; /*  placed on flash adress 0x08007F00 */

extern UNSIGNED8 bitrateIndex;
#define FLASH_ADDRESS_BITRATE_INDEX    0x08007F08
#pragma location=FLASH_ADDRESS_BITRATE_INDEX
__no_init UNSIGNED8 bitrateIndex; /*  placed on next possible flash adress 0x08007F04 */
 

Online Psi

  • Super Contributor
  • ***
  • Posts: 10233
  • Country: nz
I don't think you can do it in code like you can in IAR.
I think it needs to be done in the stm32fxxxx_sram.ld  file on a section by section basis.
Greek letter 'Psi' (not Pounds per Square Inch)
 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1673
  • Country: pl
  • Troll Cave Electronics!
He needs to hard code the memory address for the variable.

no problem, instead of __attribute... stuff do this:

Code: [Select]
#define myVariable (*(u32*)0x12345678)

myVariable = 3;

or that

Code: [Select]
u32 * const myVariable_p = (u32*)0x12345678;

*myVariable_p = 3

« Last Edit: March 14, 2018, 10:45:03 am by poorchava »
I love the smell of FR4 in the morning!
 

Offline andyturk

  • Frequent Contributor
  • **
  • Posts: 895
  • Country: us
Code: [Select]
u32 * const myVariable_p = (u32*)0x12345678;

*myVariable_p = 3

or, for C++ fans:

Code: [Select]
u32 &myVariable = *reinterpret_cast<u32*>(0x12345678);

myVariable = 3;
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 3327
  • Country: gb
He needs to hard code the memory address for the variable.

no problem, instead of __attribute... stuff do this:

Code: [Select]
#define myVariable (*(u32*)0x12345678)

myVariable = 3;

or that

Code: [Select]
u32 * const myVariable_p = (u32*)0x12345678;

*myVariable_p = 3

If you do that you'll have a very big problem, since you've done nothing to stop the linker placing another variable at 0x12345678.

This is pretty simple to do by defining a custom section in the linker filer, and then using __attribute__(((section(""))) to place variables into it.  There is a simple tutorial here.
 

Offline poorchava

  • Super Contributor
  • ***
  • Posts: 1673
  • Country: pl
  • Troll Cave Electronics!
AFAIK linker won't place data into a custom RAM region, as there is no data or bss sections being specified to be placed there.
I love the smell of FR4 in the morning!
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 855
Looking at the original post, 'BL_JUMPCODE_SIZE' seems to possibly indicate communicating with a bootloader.  Maybe that's how IAR dealt with both accessing and avoiding these locations, by just creating a noinit chunk at a specific location which provides both access and avoidance.

If that is the case, the access part is easy as nothing special needs to be done, as has been shown. But then you also need to make sure your linker is informed where the no-go zones are (what the bootloader uses). This would be done by modifying the linker script, adjusting the memory addresses/sizes.

Maybe more info is needed about whether these locations originate from something like a bootloader (separate from the application), or are from the application only.
 

Offline jyrgenTopic starter

  • Contributor
  • Posts: 14
  • Country: se
Thanks for all replies!

Maybe more info is needed about whether these locations originate from something like a bootloader (separate from the application), or are from the application only.

This is indeed from a bootloader. It is used as "the shared RAM for data exchange between bootloader and application" (taken from the documentation of the bootloader).
 

Online mikeselectricstuff

  • Super Contributor
  • ***
  • Posts: 13995
  • Country: gb
    • Mike's Electric Stuff
Thanks for all replies!

Maybe more info is needed about whether these locations originate from something like a bootloader (separate from the application), or are from the application only.

This is indeed from a bootloader. It is used as "the shared RAM for data exchange between bootloader and application" (taken from the documentation of the bootloader).
If you just need to exchange a byte or two, it may be easier to just use an unused hardware register
Youtube channel:Taking wierd stuff apart. Very apart.
Mike's Electric Stuff: High voltage, vintage electronics etc.
Day Job: Mostly LEDs
 

Offline cv007

  • Frequent Contributor
  • **
  • Posts: 855
Quote
(taken from the documentation of the bootloader)
I assume he really doesn't want to touch the bootloader side.

//bootloader ram array start
uint8_t* const jumpcode = (uint8_t*)0x200027F0;
//existing code can use as before
//array access works fine- jumpcode[n] = 0
//not as perfect as before (4 extra bytes), but compiler may optimize since const)

//bootloader flash variables
#define flashNodeId *(uint8_t*)0x08007F00
#define bitrateIndex *(uint8_t*)0x08007F08
...

You still will need to get at the linker script to make sure those areas are not used by you, unless you already have a custom linker script.
 

Offline bson

  • Supporter
  • ****
  • Posts: 2462
  • Country: us
Symbols are normally put in the linker cmd script, e.g.:

Code: [Select]
/* ARM Core Cortex-M4 system control */
CPUID = 0xe000ed00;
ACTLR = 0xe000e008;
ICSR = 0xe000ed04;
VTOR = 0xe000ed08;
AIRCR = 0xe000ed0c;
SCR = 0xe000ed10;
CCR = 0xe000ed14;
SHPR1 = 0xe000ed18;
SHPR2 = 0xe000ed1c;
SHPR3 = 0xe000ed20;
SHCRS = 0xe000ed24;
CFSR = 0xe000ed28;
MMFSR = 0xe000ed28;
BFSR = 0xe000ed29;
UFSR = 0xe000ed2a;
HFSR = 0xe000ed2c;
MMAR = 0xe000ed34;
BFAR = 0xe000ed38;
AFSR = 0xe000ed3c;

Then in your C code declare them as externs, something along the lines of:

Code: [Select]
#include <stdint.h>

#define DEV_CTL_REG_8(NAME)   extern volatile uint8_t NAME
#define DEV_CTL_REG_16(NAME)  extern volatile uint16_t NAME
#define DEV_CTL_REG(NAME)     extern volatile uint32_t NAME

#ifdef __cplusplus
namespace arm_cm4 {
extern "C" {
#endif
// ARM Core Cortex-M4 system control
DEV_CTL_REG(CPUID);
DEV_CTL_REG(ACTLR);
DEV_CTL_REG(ICSR);
DEV_CTL_REG(VTOR);
DEV_CTL_REG(AIRCR);
DEV_CTL_REG(SCR);
DEV_CTL_REG(CCR);
DEV_CTL_REG(SHPR1);
DEV_CTL_REG(SHPR2);
DEV_CTL_REG(SHPR3);
DEV_CTL_REG(SHCRS);
DEV_CTL_REG(CFSR);
DEV_CTL_REG_8(MMFSR);
DEV_CTL_REG_8(BFSR);
DEV_CTL_REG_16(UFSR);
DEV_CTL_REG(HFSR);
DEV_CTL_REG(MMAR);
DEV_CTL_REG(BFAR);
DEV_CTL_REG(AFSR);

#ifdef __cplusplus
}; // extern "C"
}; // ns arm_cm4
#endif

You generally don't want to put all these symbols in a global #define namespace.
« Last Edit: March 16, 2018, 11:11:36 pm by bson »
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4312
  • Country: us
Quote
Symbols are normally put in the linker cmd script...
Then in your C code declare them as externs...
You generally don't want to put all these symbols in a global #define namespace...
While that presumably works, I don't think I've seen it often enough come close to calling it "normal."  Almost every microcontroller I've seen (mis)uses constant pointers in .h files for peripheral access, usually resulting in some huge "stm32f10x.h" file or similar. 
The only chips I've seen that definesthe peripherals in linker files are the PIC32 chips, and it causes them to miss some obvious optimizations (OTOH, they claim it permits libraries to be distributed in object form, which is a pretty big advantage.)

In fact ARM specifically recommends .h-based peripheral definitions as part of their CMSIS specification:
http://arm-software.github.io/CMSIS_5/Core/html/device_h_pg.html#device_h_sec
https://github.com/ARM-software/CMSIS/blob/master/CMSIS/Include/core_cm3.h
(they also want to (ab)use structure references overlaid on the memory space, so even if linker files were used to define peripheral base addresses, they'd still need a huge .h presence to define the structures and bits that they recommend.)

Using a separate namespace for the peripherals sounds like an excellent idea (for C++), but I've never seen it done.

I'm curious as to where you've seen the scheme you say is "normal"?  (Hmm.  I bet it would work a lot better for other languages, as well.)
 

Offline bson

  • Supporter
  • ****
  • Posts: 2462
  • Country: us
I'm curious as to where you've seen the scheme you say is "normal"?
TI does it that way; they provide a linker script for each CPU.  They've adapted a lot of gcc'isms though, like a significant portion of the attributes and their linker scripts look the same, but they don't use gnu ld for their own compiler.  (They do provide a gcc build for all the ARM and MSP430 based processors they sell, but I don't know about all the others.)

I forget who else I've seen doing that off-hand... but I know when I worked on gcc this was considered the intended way and hence there is no specific support for anything else.  But that was almost 20 years ago.

ARM has their own compiler though and don't use the gcc toolchain... or particularly seem to care about compatibility.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf