Initialize array starting from specific address in memory - C programming - c

Do you have idea how to initialize array of structs starting from specific address in memory (not virtual, physical DDR memory). I am working on implementation of TxRx on SoC (ARM-FPGA). Basically ARM (PS) and FPGA (PL) communicate to each other by using shared RAM memory. Currently I am working on transmitter side, so I need to constantly load packets that I get from MAC layer to memory, then my Tx reads data and sends it in air. To achieve this I want to implement circular FIFO buffer on (ARM) side, in way that I can store up to 6 packets into buffer and send them one by one, in same time loading other packets on places of already sent packages. Because I need to use specific memory addresses I am interested is it possible to initialize array of structure that will be stored on specific addresses in memory. For example I want that my array starts at adress 0x400000 and ends at address 0x400000 + MaximumNumberOfPackets x SizeOfPackets I know how to do it for one instantiate of structure for example like this:
buffer_t *tmp = (struct buffer_t *)234881024;
But how to do it for array of structures?

A pointer to a single struct (or int, float, or anything else) is inherently a pointer to an array of them. The pointer type provides the sizeof() value for an array entry, and thus allows pointer arithmetic to work.
Thus, given a struct buffer you can simply do
static struct buffer * const myFIFO = (struct buffer *) 0x40000
and then simply access myFIFO as an array
for (size_t i = 0; i < maxPackets; ++i)
{
buffer[i].someField = initialValue1;
buffer[i].someOtherField = 42;
}
This works just the way you expect.
What you can't do (using pure standard C) is declare an array at a particular address like this:
struct buffer myFIFO[23] # 0x400000;
However, your compiler may have extensions to allow it. Many embedded compilers do (after all, that's often how they declare memory-mapped device registers), but it will be different for every compiler vendor, and possibly for every chip because it is a vendor extension.
GCC does allow it for AVR processors via an attribute, for example
volatile int porta __attribute__((address (0x600)));
But it doesn't seem to support it for an ARM.

Generally #kdopen is right but for arm you should create an entry in MEMORY section linker script that shows to linker where is your memory:
MEMORY
{
...
ExternalDDR (w) : ORIGIN = 0x400000, LENGTH = 4M
}
And than, when you are declaring variable just use the
__attribute__((section("ExternalDDR")))

I found the way how to do it. So could I do it like this. I set this into linker script:
MEMORY {
ps7_ddr_0_S_AXI_BASEADDR : ORIGIN = 0x00100000, LENGTH = 0x1FF00000
ps7_ram_0_S_AXI_BASEADDR : ORIGIN = 0x00000000, LENGTH = 0x00030000
ps7_ram_1_S_AXI_BASEADDR : ORIGIN = 0xFFFF0000, LENGTH = 0x0000FE00
DAC_DMA (w) : ORIGIN = 0xE000000, LENGTH = 64K
}
.dacdma : {
__dacdma_start = .;
*(.data)
__dacdma_end = .;
} > DAC_DMA
And then I set this into code
static buffer_t __attribute__((section("DAC_DMA"))) buf_pool[6];

Related

Keil uVision - Atmel SAM3U Read Unique Identifier

I've been trying to read the Unique Identifier (UID) from a Atmel SAM3U MCU, but it's proven more difficult than it needs to be to make it happen. Does anyone have any examples or can suggest how to read it properly? Whenever I do, I wait in a do while loop (like the documentation states) for the EEFC (Flash ROM) status register to change states, but it never does so the MCU is then stuck in a loop.
Here is the code I'm using
// must run this from SRAM
__attribute__((section(".ARM.__at_0x20080000"))) void Get_Unique_ID(unsigned int *pdwUniqueID)
{
Efc *p_efc;
unsigned int status;
// clear the array
pdwUniqueID[0] = 0;
pdwUniqueID[1] = 0;
pdwUniqueID[2] = 0;
pdwUniqueID[3] = 0;
// send the Start Read Unique Identifier command (STUI) by writing the Flash Command Register with the STUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
// wait for the Flash Programming Status Register (EEFC_FSR) to fall
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY);
// the Unique Identifier is located in the first 128 bits of the Flash memory mapping
pdwUniqueID[0] = *(unsigned int *)IFLASH0_ADDR;
pdwUniqueID[1] = *(unsigned int *)(IFLASH0_ADDR + 4);
pdwUniqueID[2] = *(unsigned int *)(IFLASH0_ADDR + 8);
pdwUniqueID[3] = *(unsigned int *)(IFLASH0_ADDR + 12);
// to stop the Unique Identifier mode, the user needs to send the Stop Read unique Identifier
// command (SPUI) by writing the Flash Command Register with the SPUI command
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_SPUI;
// when the Stop Read Unique Unique Identifier command (SPUI) has been performed
// the FRDY bit in the Flash Programming Status Register (EEFC_FSR) rises
do { status = p_efc->EEFC_FSR; }
while ((status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY);
}
Note that __attribute__((section(".ARM.__at_0x20080000"))) isn't the best method to dynamically assign this function to SRAM via the linker and any suggestions on how to make it more dynamic would be appreciated.
SOLVED The problem was the chips I had were fake so SAM-BA was returning whatever was at the SRAM buffer address it specified. It's a bug in SAM-BA since if it received 0x00000000, it should give an error or warning message and then stop reading. Do not buy fake chips from China!
Thanks.
I don't believe p_efc is correctly initialized.
You create a pointer to a Efc datastructure which thus points to something.
You then write something to somewhere and are expect it to work.
Efc *p_efc;
p_efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
My guess would be that you need to intialize it to the correct EEFC base address. The datasheet has the following to say:
The SAM3U4 (256 Kbytes internal Flash
version) embeds two EEFC (EEFC0 for Flash0 and EEFC1 for Flash1)
whereas the SAM3U2/1 embeds one EEFC.
So depending on your MCU version you need to address EEFC0 or EEFC1. I'm assuming that you use libopencm3 but this will work for any other library. Look for the EEFC location define. Following the defines/files/links we get to this page, it tells us to point our Efc pointer to EEFC0_BASE or EEFC1_BASE. I would advise you to use the EEFC0 and EEFC1 defines though as it makes your code portabler.
So your code should work if your Efc is located in EEFC0 if you do:
Efc *p_efc = EEFC0;

Understanding the writing to flash process in the STM32 reference manual

I am programming the stm32l412kb where at one point I will be writing data to flash (from UART). From the stm32l41xx reference manual, I understand the steps in how to clear the memory before writing to it but on page 84 there is one step that I do not know how to do when writing the actual data. That step is the
Perform the data write operation at the desired memory address
What data write operation is it mentioning? I can't see any register the memory address goes to so I assume its going to use pointers? How would I go about doing this?
Your help is much appreciated,
Many thanks,
Harry
Apart from a couple of things (e.g. only write after erase, timings, alignment, lock/unlock) their ain't much difference between writing to RAM and writing to FLASH memory. So if you have followed the steps from the reference manual and the FLASH memory is ready (i.e. cleared and unlocked) then you can simply take an aligned memory address and write to it.
STMs very own HAL library contains a function which does all the cumbersome boilerplate for you and allows you to "just write":
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
Internally this function uses a subroutine which performs the actual write and it looks like this:
static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
{
/* Check the parameters */
assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));
/* Set PG bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program first word */
*(__IO uint32_t*)Address = (uint32_t)Data;
/* Barrier to ensure programming is performed in 2 steps, in right order
(independently of compiler optimization behavior) */
__ISB();
/* Program second word */
*(__IO uint32_t*)(Address+4U) = (uint32_t)(Data >> 32);
}
As you can see there is no magic involved. It's just a dereferenced pointer and an assignment.
What data write operation is it mentioning?
The "data write" is just a normal write to a address in memory that is the flash memory. It is usually the STR assembly instruction. Screening at your datasheet, I guess the flash memory addresses are between 0x08080000 and 0x00080000.
Ex. the following C code would write the value 42 to the first flash memory address:
*(volatile uint32_t*)0x00080000 = 42.
For a reference implementation you can see stm32 hal drivers:
/* Set PG bit */
SET_BIT(FLASH->CR, FLASH_CR_PG);
/* Program the double word */
*(__IO uint32_t*)Address = (uint32_t)Data;
*(__IO uint32_t*)(Address+4) = (uint32_t)(Data >> 32);

STM32, variable stored in flash could not be updated in other file

I use a STM32F411RE.
Since I've no more memory in my RAM. I decided to store large variable in my flash. For that I created a section in section.ld.
.large_buffer: ALIGN(4)
{
. = ALIGN(4) ;
*(.large_buffer.large_buffer.*)
. = ALIGN(4) ;
} >FLASH
In the main.c file, I declare the variable as follow :
uint8_t buffer[60 * 200] __attribute__ ((section(".large_buffer"), used));
At this point everything is OK, the buffer is not stocked in the RAM (bss), I can access it and rewrite it.
buffer[25] = 42;
printf("%d\n", buffer[25]); // 42
The problem comes when I want to edit the variable from an other file.
main.c
uint8_t buffer[60 * 200] __attribute__ ((section(".large_buffer"), used));
int main()
{
myFunc(buffer);
}
other.c
myFunc(uint8_t* buffer)
{
buffer[25] = 42;
printf("%d\n", buffer[25]); // 0
}
buffer never change in another file (passed as parameter).
Did I miss something ?
You cannot write to flash memory the same way as you write to RAM, because of physical design of flash memories. To be exact you need to erase sector/page (let's say ~ 1-4kB, it's specified in your MCU datasheet). The reason is that flash are made that they retain state even if they're not powered, whenever you want to change any bit from value 0 -> 1 you need to erase whole sector (After erase all of bits will be set to 1).
So you cannot use Flash as data memory, what you could do is use Flash as storing variables that are const (read-only) value, so any look-up tables will perfectly fit in there (usually compilers when you stat variable to const will put them inside of flash). How to write to flash you can read in Reference Manual of your MCU.

How to preserve RAM cell from being used

I use GNU for ARM and want to define some cell in RAM memory space as following:
#define FOO_LOCATION 0x20000000
#define foo (*((volatile uint32_t *) FOO_LOCATION ))
My question is - if such declaration will prohibit usage of the cell with FOO_LOCATION address in stack or heap? What address preffered to avoid memory fragmentation?
Update
I want to place some variable at a certain memory address and access it after watchdog reset. I guess that if i will declare it as usual
uint32_t foo;
it will have another physical location after reset. Also i read a post where said that most probably there is no such way to declare variable adddress. And i have idea to tell the GNU not to use some memory address. As for example special registers are not used by custom variables.
Update 2
In addition to previous definitions i added section to linker script
SECTIONS
{
. = 0x20000000
.fooSection :
{
*(.fooSection)
. = 0x04 /* size = 4 bytes */
}
/* other placements follow here... */
}

How to view Linux memory map info in C?

I'm dynamically loading some Linux libraries in C.
I can get the start addresses of the libraries using the
dlinfo
(see 1).
I can't find any information to get the size of a library, however.
The only thing that I've found is that one must read the
/proc/[pid]/maps
file and parse it for the relevant information (see 2).
Is there a more elegant method?
(This answer is LINUX/GLIBC specific)
According to http://s.eresi-project.org/inc/articles/elf-rtld.txt
there are link_map *map; map->l_map_start & map->l_map_end
/*
** Start and finish of memory map for this object.
** l_map_start need not be the same as l_addr.
*/
ElfW(Addr) l_map_start, l_map_end;
It is a bit not exact, as said here http://www.cygwin.com/ml/libc-hacker/2007-06/msg00014.html
= some libraries are not continous in memory; the letter linked has some examples... e.g. this is the very internal (to rtld) function to detect is the given address inside lib's address space or not, based on link_map and direct working with ELF segments:
/* Return non-zero if ADDR lies within one of L's segments. */
int
internal_function
_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
{
int n = l->l_phnum;
const ElfW(Addr) reladdr = addr - l->l_addr;
while (--n >= 0)
if (l->l_phdr[n].p_type == PT_LOAD
&& reladdr - l->l_phdr[n].p_vaddr >= 0
&& reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
return 1;
return 0;
}
And this function is the Other alternative, which is to find program headers/ or section headers of ELF loaded (there are some links to such information in link_map)
And the easiest is to use some stat syscall with map->l_name - to read file size from the disk (inexact in detecting huge bss section).
Parsing /proc/self/maps (or perhaps popen-ing a pmap command) seems still the easiest thing to me. And there is also the dladdr function (provided you have some adress to start with).

Resources