I am writing in C on a BeagleBone Black MCU.
I need to create a 2D unsigned int array to store some collected analog data from two sensors.
Currently I have individual unsigned int arrays for each sensor's data but I'd like to change this to have one variable that is 2 dimensions with one dimension being the sensor the data originated from.
Here's what I have so far and it works just fine. (Apologies if this isn't formatting correctly. I tried to bold the code but it doesn't seem to work in Chrome the way I'd expect.)
#define SHARE_MEM 0x10000
#define E_RING_BUFFER_SIZE 200
volatile unsigned int *DetTSampleSet = (unsigned int *) SHARE_MEM;
volatile unsigned int *DetBSampleSet = (unsigned int *) (SHARE_MEM + (E_RING_BUFFER_SIZE * sizeof(unsigned int)));
I believe this code ensures that DetBSampleSet is located immediately after DetTSampleSet with no overlap. It works fine. I am able to use these variables like this.
int pnr;
for (pnr = 0; pnr <10;pnr++)
{
// do some stuff to get RawAnalog from sensor T.
DetTSampleSet[pnr] = RawAnalog;
// do some stuff to get RawAnalog from sensor B.
DetBSampleSet[pnr] = RawAnalog;
}
What I want is this.
int pnr;
for (pnr = 0; pnr <10; pnr++)
{
// do some stuff to get RawAnalog from sensor T (0)
DetSampleSet[0][pnr] = RawAnalog;
// do some stuff to get RawAnalog from sensor B (1)
DetSampleSet[1][pnr] = RawAnalog;
I think I can just declare this as the first variable in this memory space like this.
#define SHARE_MEM 0x10000
#define E_RING_BUFFER_SIZE 200
volatile unsigned int *DetSampleSet = (unsigned int *) SHARE_MEM
If I do then, I don't think I have to worry about how this data is actually structured in memory as in
are the first four bytes DetSampleSet[0][0] and the next four bytes DetSampleSet[0][1] or DetSampleSet[1][0] because I don't plan to access this data with any pointers/addresses?
However, if I want to declare another variable in memory adjacent to this variable with no overlap, do I just double the size offset like this?
volatile unsigned int *NewIntVariableAfterFirstOne = (unsigned int *) (SHARE_MEM + (E_RING_BUFFER_SIZE * 2 * sizeof(unsigned int)));
Thanks for any and all help and your patience as I'm getting back into C after nearly 30 years.
I appreciate the comments and answers. I've tried to post a response but it seems I can't comment at length but have to add to my original question. So here goes...
So, I readily admit to getting lost sometimes in the declaration of pointers like this. The original code I posted works fine. I need to declare multiple variables in this memory space so my primary concern is to declare them properly so as to not overwrite one. Basically, ensure the start of the next variable declared is past the end of the one declared prior. So, for example, if the pointer to integer variable A is to be used as a 1-D array of X elements, then Xsizeof(int) should be a safe start of the next variable, say integer variable B. Right? And if I want to use variable A as an array to be accessed as a 2-D array, then I would just do 2X*sizeof(int) to get the start of the next variable after A, right?
Supposing that it is a valid and appropriate thing in the first place, according to your C implementation, to create a pointer value in the way you are doing, what you need is a to declare your pointer as a pointer to an array, and cast appropriately:
#define SHARE_MEM 0x10000
#define E_RING_BUFFER_SIZE 200
volatile unsigned int (*DetSampleSet)[E_RING_BUFFER_SIZE] =
(unsigned int (*)[E_RING_BUFFER_SIZE]) SHARE_MEM;
You should then be able to access the block by doubly indexing DetSampleSet, just as you say you want, with all the values for DetSampleSet[0] laid out in memory contiguously, and immediately preceding those for DetSampleSet[1].
I would rather suggest to use when accessing hardware fixed size integers
You can use the pointer to array:
#define SHARE_MEM 0x10000
#define E_RING_BUFFER_SIZE 200
typedef int32_t buff[E_RING_BUFFER_SIZE];
#define DetSampleSet ((volatile buff *)SHARE_MEM)
//example usage
int32_t foo(size_t sample, size_t sensor)
{
return DetSampleSet[sensor][sample];
}
#define is used to avoid unnecessary memory reads.
https://godbolt.org/z/c45rKvvvh
EDIT. The comments have changed the requirements. You need to change linkerscript.
Add memory area (length gas to be set by you as I do not know how bit it is):
MEMORY
{
/* the stuff which was already here */
SHAREDMEM (rw) : ORIGIN = 0x10000, LENGTH = 32M
}
In the sections add new section
.shared_mem_section (NOLOAD):
{
shared_mem_section_start = .;
KEEP(*(.shared_mem_section))
KEEP(*(.shared_mem_section*))
shared_mem_section_end = .;
} > SHAREDMEM
In your C code:
unsigned __attribute__((section(".shared_mem_section"))) DetSampleSet[NSENSORS][E_RING_BUFFER_SIZE];
Related
Abstract:
I need to copy all elements of a struct containing a float array into a byte buffer, in order to send it out via UART. The next call of malloc after the copy operation leads (allways) to a hard fault, which is a good indicator that somewhere the memory gets corrupted, but I have no clue where this could happen (after 2 days debugging ...)
Description:
I have a nested Typtedef, that contains a float array:
#define DRV_SCALE_MAXSZ 32
#define DRV_CHANNELS 2
typedef struct {
float x1;
float step;
uint8_t aSz;
float Y[DRV_SCALE_MAXSZ];
} DRV_linscale_TDS;
typedef struct {
DRV_linscale_TDS scale;
uint32_t active;
} DRV_ChScale_TDS;
DRV_ChScale_TDS DRV_scale[DRV_CHANNELS] = {0,}; // Channel Scales
And I need to copy the whole content of either DRV_scale[0] or [1] into a byte buffer, in order to send it out via UART.
As a little extra complication I copy it element by element, with a copy function, that reverts the bytes of the value if necessary:
#define TXBUFSZ 255
volatile uint8_t TxBuf[TXBUFSZ] = {0,};
void FillTxBuf(uint8_t idx, uint8_t *pBo) {
if(idx < DRV_CHANNELS) {
volatile uint8_t *pDst = TxBuf;
*pDst++ = DRV_SCALE_MAXSZ;
*pDst++ = DRV_scale[idx].active;
pDst += COM_ElementCopyU32((uint8_t*)&DRV_scale[idx].scale.x1, pDst, pBo);
pDst += COM_ElementCopyU32((uint8_t*)&DRV_scale[idx].scale.step, pDst, pBo);
*pDst++ = DRV_scale[idx].scale.aSz;
uint8_t i = *pDst;
float *pSrc = DRV_scale[idx].scale.Y;
while(i--) {
pDst += COM_ElementCopyU32((uint8_t*)pSrc, pDst, pBo);
pSrc++;
}
}
}
Note: the code above is a shrinked version just for explanation. In reality TxBuf[TXBUFSZ] is a static preallocated byte buffer (declared extern in the header file, and defined in the c file)
The function COM_ElementCopyU32 looks like this:
uint8_t COM_ElementCopyU32(volatile uint8_t* pSrc, volatile uint8_t* pDst, uint8_t* ByteOrder) {
// #brief copy data from Source to Destination and revert bytes if necessary
// #param U8* pSrc: Pointer to data Source Buffer
// #param U8* pDst: Pointer to Destination Buffer
// #param U8 ByteOder: 0 = little endian, 1=big endian
// #return u16 number of copied bytes
if(pSrc && pDst) {
if(*ByteOrder != isBigEndian) {
pDst[0] = pSrc[3];
pDst[1] = pSrc[2];
pDst[2] = pSrc[1];
pDst[3] = pSrc[0];
} else {
pDst[0] = pSrc[0];
pDst[1] = pSrc[1];
pDst[2] = pSrc[2];
pDst[3] = pSrc[3];
}
}
return(sizeof(uint32_t));
}
The issue:
as soon as the line
pDst += COM_ElementCopyU32((uint8_t*)pSrc, pDst, pBo);
is involved, the call of FillTxBuf() leads to an hard fault with the next call of malloc(). The next malloc() comes immediately after FillTxBuf() when the CRC32 is appended to the byte stream. The general workflow is: check the incoming request, fill the Tx Buffer, append the CRC32 and send it out.
What have i tried to solve this so far?
Well, i tried a lot:
I removed the line mentioned above. As long i do not copy any bytes
from DRV_scale[idx].scale.Y to TxBuf[] in the while loop is
disabled, anything works fine.
I replaced float pSrc = DRV_scale[idx].scale.Y; with * float pSrc =
DebugArray; where DebugArray is a "stand alone" static pre-allocated
float array of the same size as DRV_scale[idx].scale.Y (32
Elements) and anything works fine
I tried to copy the Elements from DRV_scale[idx].scale.Y to
another float array (lets call it "DupArray"), which worked fine but
when I tried to copy "DupArray" bytewise into TxBuf[] it crashes.
and I tried to copy the Elements from DRV_scale[idx].scale.Y to
TxBuf[] in another function, right after Hardware initialisation, using the same code (copy & paste), it worked fine
I tried several versions of the DRV_linscale_TDS Typdef, with the
Byte variable at the end and at the beginning, with no effect
I checked if there would be a buffer overflow in the while loop, but
as expected there is none, as the total number of copied bytes is
~100, so there are 155 bytes "free" (note: the overrun prevention
code is still in the original code but left out here for better
readability)
I have no clue what's going on here. Each part of the code - when I debug it separatey - works fine. Copying the original Array to another float preallocated float array works fine, copying the float array to a byte array and writing it back works fine. Just if I do exactly that, whats working fine verywhere else, in that particular function, it generates a hard fault.
Through all the testing and debugging it points out clearly: the hard fault only happens, when I try to copy DRV_scale[idx].scale.Y into TxBuf[], anything else works without problems.
One might say: well, then somewhere before FillTxBuf() TxBuf[] gets corrupted, but why works anything flawless in FillTxBuf() when I use a different float array than DRV_scale[idx].scale.Y?
Remarks:
One possible workaround would most probably be to split up the struct and use separate preallocated "stand alone" float arrays. The reason why I glued it together in one variable is, that this variable is written to flash and I'd really like the approach FlashWrite(VariablePointer, SizeInBytes) ...
If there is no other option, i will have to separate it, but I'd really like to understand in which pitfall I stumbled in ...
The Question:
Where could I search?
I have no idea about the problem but you can use union to send struct data within a array. Here is an example;
typedef union
{
your struct object; (should be packed
struct)
uint8_t uartBuff[your struct size];
}unExample;
Variables in union use same memory address via this you can easily send your data.
hardfault errors always because of pointer-alingment
i usually use my own library for binary serialize in c
this library can help you
it's have examples in c and for STM32F4 already
it's support endiness and have configuration part for customization
For an embedded system project, an array is supposed to be placed in RAM. I have split the device's RAM into two sections, one which stores globals and other data, and another section, RAM_DATA, which I wish to store two arrays (a source location and a destination location).
There is a global value mem_val that is set to the start of the RAM_DATA address, and now wanted to make the source array begin at the location which is stored held in location.
From what I have garnered from online sources, they utilize the stdint.h header file to use uintptr_t and uint32_t values to set start of the array. When debugging the program, the array does not start at this value, and was inquiring about how to fix this problem. Here is some code that is relevant to the question.
volatile uintptr_t mem_val = 0x0219;
int main(void)
{
char cur_loc[128];
uint32_t *cur_loc = (void *)mem_val;
...
return 0;
}
Obviously there is something wrong with the array initialization and then making it pointer, but beyond that, is there a method of making the array cur_loc begin at the value given to mem_val? If it helps, I am working with a Texas Instruments MSP430 embedded device. Thank you
There were some valuable remarks concerning the MSP430. Here, my two cents concerning the array at a specified memory location:
volatile uintptr_t mem_val = 0x0219;: If I got it right the address shall be "burnt" into binary. Hence volatile doesn't make sense but const would:
const uintptr_t mem_val = 0x0219;`
Instead, (assuming the fix address is in an I/O range mapped into address space) it makes much more sense to mark the contents of array/pointer as volatile:
volatile uint32_t *cur_loc = (void*)mem_val;
The below is a "duplicate symbol error":
char cur_loc[128];
uint32_t *cur_loc = (void *)mem_val;
Actually, the 2nd line is fully sufficient as pointers can be used like arrays. C hasn't any bound checking per standard. Hence, the pointer to uint32_t can be used like an array of uint32_t elements.
With some extra parentheses, it is even possible to set the address of an array:
volatile uint32_t (*curLoc)[128 / sizeof (uint32_t)] = (void*)mem_val;
But, to access the array the "contents" operator has to be used always: (*curLoc)[i]. Not to mention, that the parentheses are essential (*curLoc[i] does it wrong).
So, I made a little sample (for 3. as "counter-example" and to practice my C-typing abilities):
#include <stdint.h>
#include <stdio.h>
int main()
{
char storage[32] = {
'\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
'\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
'\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
'\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f'
};
const uintptr_t mem_val
= (uintptr_t)&storage; /* 0x0219 <- a fix address wouldn't work on wandbox. */
enum { size = sizeof storage / sizeof (uint32_t) };
printf("size: %u\n", size);
/* using pointer */
volatile uint32_t *pCurLoc = (uint32_t*)mem_val;
for (unsigned i = 0; i < size; ++i) printf(" %08x", pCurLoc[i]);
puts("");
/* using array */
volatile uint32_t (*curLoc)[size] = (void*)mem_val;
for (unsigned i = 0; i < size; ++i) printf(" %08x", (*curLoc)[i]);
puts("");
/* done */
return 0;
}
Output:
size: 8
03020100 07060504 0b0a0908 0f0e0d0c 13121110 17161514 1b1a1918 1f1e1d1c
03020100 07060504 0b0a0908 0f0e0d0c 13121110 17161514 1b1a1918 1f1e1d1c
Live Demo on wandbox
I am seeking for an advice for creating a frame of unsigned char
values using a structure which is to be used in an Embedded system
application which is having less RAM.
Eg. I am having 10 bytes RAM(say). Need to create a frame(frame1)
within the RAM memory dynamically using structures in c and print
it and then free it. Then create (frame2), print and then free it
within the same 10 bytes of RAM memory. This is an interview
question for me.
My answer:
struct frame1 /* first frame */
{
unsigned char value1; /* Structure members*/
unsigned char value2;
unsigned char value3;
unsigned char value4;
/* created upto 10 values (say value10)*/
}*p;
p = (struct frame1*)malloc(sizeof(struct frame1)); /* dynamically
allocating memory for frame1 */
p->value1 = 0x10; /* Assigning values to the members */
p->value2 = 0x20;
p->value3 = 0x30;
p->value4 = 0x40;
/* Given upto 10 values */
/*print it*/
free(p);
/* Then created another structure for frame2 done the same as above
and freed it */
I am not sure what the interviewer expected from me. But I have
written based on the suggestions he gave.
The Interviewer said like it's ok to do like this in one angle. But
it looks like very basic level of code in terms of structure. So he
need to do it in advanced level. Kindly help me how to handle this.
Thanks in advance!
I am working on one Embedded C project. I am having trouble understanding the use of array and structure in code.
for example:
Structure:
struct example_struct{
char a;
char b;
char array[4];
}
Note: The default size for Int and char is 1 byte.
The compiler I am using provide the functionality of memory allocation for variables and other parameters using '#' symbol
for example:
Memory Allocation
int example # 0x125
// Compiler allocate the RAM memory location 0x125 to my variable "example"
Issue:
The person who coded this project have used the structure and array as given below
example.h
struct example_struct{
char a;
char b;
char array[4];
}
Memory.h
volatile struct example_struct node # 0x130 ;
//allocate memory location 0x130 - 0x135 to node
volatile char buffer[6] # 0x130;
//allocate memory location 0x130 - 0x135 to buffer
Question
1.Instead of using the pointer to access the member of structure is it appropriate to use the array placed on same memory location?
Does it cause the memory issue?
Would you please help me to understand the use of stuct and array in this particular situation.
Thank you
Kunal
The (weird) coder that developed that code was "simulating" an union to be able to access the same location as struct example_struct or byte per byte.
Like:
#pragma pack(1)
union struct_and_raw_byte_access
{
struct example_struct
{
char a;
char b;
char array[4];
}structured;
char buffer[sizeof(struct example_struct)];
};
#pragma pack()
int main(void)
{
union struct_ad_raw_byte_access temp;
int i;
temp.structured.a = 1;
temp.structured.b = 2;
temp.structured.array[0] = 3;
temp.structured.array[1] = 4;
temp.structured.array[2] = 5;
temp.structured.array[3] = 6;
for (i=0; i< sizeof(temp.buffer)/sizeof(temp.buffer[0]); i++)
printf("buffer[%d] = %d\n", i, temp.buffer[i]);
return 0;
}
1.Instead of using the pointer to access the member of structure is it appropriate to use the array placed on same memory location?
2.Does it cause the memory issue?
IMHO you cannot do that. It may work in some archs, but keep in mind that you are trusting the compiler to put everything packed and aligned.
Some compilers have packing directives (pragmas or parameteres), but it is much more safer to use an union.
Make sure that buffer is also a pointer, so allocating "buffer" to absolute address is the same like make a pointer to that address.
volatile char buffer[6] # 0x130;
//allocate memory location 0x130 - 0x135 to buffer
In your case, developer; I think; he decided to access strcutre elements using array for work with them in loop or something.
So, answering your questions:
No, It is not appropriate, as you said, it is better to make pointer and access this pointer by casting it to (char *)
If you know how you will use "buffer", no memory issue will happen. I mean make sure no out of index will happen.
Your comment "if I am declaring any global variable and watching it using debugger I can see the change in value. Even if I am not using them anywhere" probably means that you are looking at a hardware register of some IO controller.
The
volatile char buffer[6] # 0x130;
Is intended to map those IO controller addresses to a variable name in your embedded programming. That is the IO controller is presenting status and data at memory address 0x130 to 0x135 -- and the C program maps this to a symbolic value through the declaration.
Since the format of this area is determined by the IO controller (nothing you can do in your C code will change the format), you need to make sure that the strct and the example_struct is exactly 6 bytes long, or if not you have some padding which will kill you.
Test this using your debugger (if it is gdb use can use sizeof, but your debugger may differ)
Also, I recommend that you find some kind of documentation on what is on hardware address 0x130
I gor an array/ram buffer
char* bitmap_bufer;
int bitmap_buffer_size_x;
int bitmap_buffer_size_y;
bitmap_buffer is mallocked (and is often reallocked to different
sizes too), efficiency of acces to it contents is of absolutely TOP IMPORTANCE as i use it as a target to various rasterization/ per pixel drawing routines
bitmap_bufer[bitmap_buffer_size_x*y + x] = color; //etc
The question is if i move it to dll and import it in another module
__declspec(dllimport) char* bitmap_bufer;
__declspec(dllimport) int bitmap_buffer_size_x;
__declspec(dllimport) int bitmap_buffer_size_y;
will the read/write acces thru
bitmap_bufer[bitmap_buffer_size_x*y + x]
will be slower? Im suspectiing thet probably it may be a bit slower
(probably acces thru two pointers than one) but im not sure
one would be bitmap_buffer pointer itself and teh second
would be pointer pointing to it (?)
If so it is sad as in relity one would be needed? Do someone knows more on this and could explain this?
Accessing data allocated in a dynamic library is not slower, as a matter of fact, malloc itself resides in a dynamic library.
Accessing an array through a global variable may be inefficient even if it is in the process data segment. Store the pointer and the size into local variables and access the array this way:
char *bitmap = bitmap_bufer;
int pitch = bitmap_buffer_size_x;
int height = bitmap_buffer_size_y;
bitmap[y * span + x] = 0;
...
If you access pixels on a row-wise manner, use a pointer to the bitmap row:
char *row = bitmap + y * span;
for (int x = 0; x < width; x++) {
row[x] = 1;
}
Also do not use char for pixel values, either use unsigned char for byte values between 0 and UCHAR_MAX or use signed char for values between CHAR_MIN and CHAR_MAX. You might also use int8_t and uint8_t for clarity. Reserve the type char for C strings.