I have following code :
/* Window size in bytes. */
static uint32_t size = 0;
/* Window address. */
static uint32_t address = 0;
/* Memory Base Address */
static uint8_t *sharedMemory=NULL;
sharedMemory = memalign(size, size);
void rioShardMemoryWindowGet (uint8_t *baseAddr,uint32_t *memorySize,uint32_t *windowAddress )
{
*baseAddr=(int)sharedMemory;
printf("sharedMemory: #%x",sharedMemory);
*memorySize=size;
*windowAddress=address;
}
rioShardMemoryWindowGet(&baseAddr0, &baseSize, &(Addrs.virtualBaseAddr));
printf("baseAddr0 : #%x",baseAddr0);
I have no clue why baseAddr0 is 0 in the second printf, while in the first sharedMemory is 0x500000.
Ok I think I understand your problem.
You're trying to store the address number in baseAddr0, am I right? (not sure the reasons but this is the only thing I came up with).
The reason that a 0x500000 is showing as a 0 is because a uint8_t has not enough bits to represent an address and so it's "culling it down" to only 1 byte (therefore showing a 0).
Change the baseAddr to a uint32_t and voila, everything works.
Anyways, the reason the other posters are telling you to use a pointer to pointer is because what you seem to be doing is weird, unless you're planning on using the address for something special such as displaying it or using as an offset, perhaps?
p.s.: you're also going to need to change this line
*baseAddr=(uint32_t)sharedMemory;
edit: your code should look like this to get what you want:
/* Window size in bytes. */
static uint32_t size = 0;
/* Window address. */
static uint32_t address = 0;
/* Memory Base Address */
static uint8_t *sharedMemory=NULL;
sharedMemory = memalign(size, size);
void rioShardMemoryWindowGet (uint32_t *baseAddr,uint32_t *memorySize,uint32_t *windowAddress )
{
*baseAddr=(uint32_t)sharedMemory;
printf("sharedMemory: #%x",sharedMemory);
*memorySize=size;
*windowAddress=address;
}
rioShardMemoryWindowGet(&baseAddr0, &baseSize, &(Addrs.virtualBaseAddr));
printf("baseAddr0 : #%x",baseAddr0);
The reason why you NEED an uint32 to store the numeric address is because addresses are 32 bits, and that's the reason why you see a 0 using an 8 bit value, because 0x500000 maps to 0x00 to a byte
rioShardMemoryWindowGet should accept uint8_t **baseAddrPtr if you want it to modify baseAddr0. Then you'll have *baseAddr = sharedMemory without a cast.
You must pass a pointer to pointer as a function argument.
Only then you will be able to store the value in it. In your case, you tried to store the address of sharedMemory in baseAddr[0] location.
/* Window size in bytes. */
static uint32_t size = 0;
/* Window address. */
static uint32_t address = 0;
/* Memory Base Address */
static uint8_t *sharedMemory=NULL;
sharedMemory = memalign(size, size);
void rioShardMemoryWindowGet (uint8_t **baseAddr,uint32_t *memorySize,uint32_t *windowAddress )
{
*baseAddr=sharedMemory;
printf("sharedMemory: #%x",sharedMemory);
*memorySize=size;
*windowAddress=address;
}
uint8_t *baseAddr0;
rioShardMemoryWindowGet(&baseAddr0, &baseSize, &(Addrs.virtualBaseAddr));
printf("baseAddr0 : #%x",baseAddr0);
Related
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];
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 trying to copy a byte array to my struct, then serialize my struct to a byte array again.
But, after I serialize my struct array, I cant get my data value (0x12, 0x34, 0x56) again, instead i get some rubbish data.
What is wrong here?
#pragma pack(push, 1)
typedef struct {
uint8_t length;
uint8_t *data;
} Tx_Packet;
#pragma pack(pop)
static void create_tx_packet(uint8_t *packet, uint8_t *src, int length);
int main(void)
{
uint8_t packet[32];
uint8_t data[] = { 0x12, 0x34, 0x56 };
create_tx_packet(packet, data, 3);
//i check using debugger, i cant get the data value correctly
//but i could get length value correctly
return 0;
}
static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
Tx_Packet *tx_packet = malloc(sizeof(*tx_packet ));
tx_packet->length = length;
tx_packet->data = (uint8_t *)malloc(length);
memcpy(tx_packet->data, src, length);
memcpy(packet, tx_packet, sizeof(*tx_packet));
}
Right now, your create_tx_packet() function copies a Tx_Packet struct created in the function to a uint8_t array. That struct contains the length and a pointer to the data, but not the data itself. It's actually not necessary to use the struct as an intermediate step at all, particularly for such a simple packet, so you could instead do:
static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
*packet = length; /* set (first) uint8_t pointed to by packet to the
length */
memcpy(packet + 1, src, length); /* copy length bytes from src to
the 2nd and subsequent bytes of
packet */
}
You still need to make sure packet points to enough space (at least length + 1 bytes) for everything (which it does). Since the version above doesn't dynamically allocate anything, it also fixes the memory leaks in your original (which should have freed tx_packet->data and tx_packet before exiting).
--
If you do want to use a struct, you can (since the data is at the end) change your struct to use an array instead of a pointer for data -- then extra space past the size of the struct can be used for the data, and accessed through the data array in the struct. The struct might be:
typedef struct {
uint8_t length;
uint8_t data[];
} Tx_Packet;
and the function becomes (if a temporary struct is used):
static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
/* allocate the temporary struct, with extra space at the end for the
data */
Tx_Packet *tx_packet = malloc(sizeof(Tx_Packet)+length);
/* fill the struct (set length, copy data from src) */
tx_packet->length = length;
memcpy(tx_packet->data, src, length);
/* copy the struct and following data to the output array */
memcpy(packet, tx_packet, sizeof(Tx_Packet) + length);
/* and remember to free our temporary struct/data */
free(tx_packet);
}
Rather than allocate a temporary struct, though, you could also use struct pointer to access the byte array in packet directly and avoid the extra memory allocation:
static void create_tx_packet(uint8_t *packet, uint8_t *src, int length)
{
/* Set a Tx_Packet pointer to point at the output array */
Tx_Packet *tx_packet = (Tx_Packet *)packet;
/* Fill out the struct as before, but this time directly into the
output array so we don't need to allocate and copy so much */
tx_packet->length = length;
memcpy(tx_packet->data, src, length);
}
If you use memcpy(packet, tx_packet, sizeof(*tx_packet)); you are copying the memory representation of tx_Packet into packet, starting with tx_packet->length.
Additionally when mallocating tx_packet that size should be sizeof(*packet)+sizeof(uint8_t) (length of packet plus length field)
And again when copying the tx_packet back to packet you are writing out of the boundaries of packet.
EDIT:
I forgot to mention that depending on your compiler memory alignment parameter you could get any length for the fields (including tx_packet->length) to accelerate memory operation. On 32bits machine it could be 4 and padded with rubbish.
When you serialize your struct with
memcpy(packet, tx_packet, sizeof(*tx_packet));
you're copying the length and the pointer to the data, but not the data itself. You'll probably need two memcpy calls: one of sizeof(uint8_t) to copy the length field, and one of length to copy the data.
This line:
Tx_Packet *tx_packet = malloc(sizeof(*packet));
only allocates one byte for the packet header, which you then immediately write off the end of, causing undefined behavior. You probably meant
Tx_Packet *tx_packet = malloc(sizeof(*tx_packet));
Compiler reports error:
"argument of type "uint8_t" is incompatible with parameter of type "void *" (see code below)
Declarations of the two functions are:
// param[in] addr - First Radio register address
// param[out] buffer - Buffer where to copy the registers data
// param[in] size - Number of registers to be read
void SX1276ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size );
and
// param[in] handle - Pointer to a SPI driver handle
// param[in] txBuffer - Transmit data buffer
// param[out] rxBuffer - Receive data buffer
// param[in] count - Number of bytes in transfer
Ecode_t SPIDRV_MTransferB( SPIDRV_Handle_t handle, const void *txBuffer, void *rxBuffer, int count )
The first function is platform independent, while the second one is not. The definition of the first function (which is called by the higher layers of the chip driver, written by manufacturer) is:
void SX1276ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
{
uint8_t i;
uint8_t *rxBuffer;
uint8_t startAddr = addr & 0x7F;
SPIDRV_MTransferB(handle, &startAddr, rxBuffer, 1);
for( i = 0; i < size; i++ )
{
SPIDRV_MTransferB(handle, 0, buffer[i], 1); ////// THIS LINE REPORTS ERROR
}
}
Any ideas?
txBuffer and rxBuffer must be valid addresses of memory chunks. So your call is probably false for two reasons :
It is highly not probable that the address of a uint8_t could be
used as a good transmit buffer.
For rxBuffer the problem is that it does not point to any memory
(the pointer is not initialized).
So you must define where the data will be read/write from/to. I did not know how the function SPIDRV_MTransferB really work. count is not clearly specified, which length it refers to ?
Your call should probably look like :
txBuffer = malloc(some_size); // or derive an address from addr param ?
rxBuffer = malloc(some_size); // or ?
SPIDRV_MTransferB(handle, &startAddr, rxBuffer, some_size);
here is the function prototype:
Ecode_t SPIDRV_MTransferB(
SPIDRV_Handle_t handle,
const void *txBuffer,
void *rxBuffer,
int count )
here is the call to that function:
SPIDRV_MTransferB(
handle, // code not posted to verify this parameter
0, // this, at best, defines a pointer to addr 0
buffer[i], // this is the contents of buffer[i], not a pointer
1); // this parameter is ok.
suggest:
SPIDRV_MTransferB(handle, NULL, &(buffer[i]), 1);
to be of any further assistance, we need a description
of exactly what the SPIDRV_MTransferB()
is expected to perform when any pointer passed to it is NULL.
I have to copy Mac address stored as an array with a pointer reference to another. I want to perform a swap but, i dont know if i am copying right.
uint8_t * custom_mac_store;
memcpy(custom_mac_store, ehdr->ether_shost, sizeof(ehdr->ether_shost));
memcpy(ehdr->ether_shost, ehdr->ether_dhost, sizeof(ehdr->ether_shost));
memcpy(ehdr->ether_dhost, custom_mac_store, sizeof(ehdr->ether_shost));
ehdr->ether_shost refers to a Mac address which is 48 bits long and stored in 6 arrays as 8 bits.
struct sr_ethernet_hdr
{
#ifndef ETHER_ADDR_LEN
#define ETHER_ADDR_LEN 6
#endif
uint8_t ether_dhost[ETHER_ADDR_LEN]; /* destination ethernet address */
uint8_t ether_shost[ETHER_ADDR_LEN]; /* source ethernet address */
uint16_t ether_type; /* packet type ID */
} __attribute__ ((packed)) ;
Thanks in advance!!!
custom_mac_store is a pointer, not an array, you should allocate the memory doing the following:
uint8_t * custom_mac_store = malloc(sizeof(ehdr->ether_shost) * sizeof(uint8_t));
Then do the memcpy
This way you can erase or overwrite ehdr->ether_shost but you already copied your array to the new array.
#alk You are right you need to delete the memory
uint8_t * custom_mac_store = malloc(sizeof(ehdr->ether_shost) * sizeof(uint8_t));
memcpy(custom_mac_store, ehdr->ether_shost, sizeof(ehdr->ether_shost));
memcpy(ehdr->ether_shost, ehdr->ether_dhost, sizeof(ehdr->ether_shost));
memcpy(ehdr->ether_dhost, custom_mac_store, sizeof(ehdr->ether_shost));
free(custom_mac_store); //< Destroys everything in the array
custom_mac_store = NULL; //< NULL must be defined in a macro preferanly DEFINE NULL 0
or you could use c++
uint8_t * custom_mac_store = new uint8_t[sizeof(ehdr->ether_shost)];
std::copy ( ehdr->ether_shost, ehdr->ether_shost+sizeof(ehdr->ether_shost), custom_mac_store );
std::copy ( ehdr->ether_dhost, ehdr->ether_dhost+sizeof(ehdr->ether_shost), ehdr->ether_shost );
std::copy ( custom_mac_store, custom_mac_store+sizeof(ehdr->ether_shost), ehdr->ether_dhost );
delete[] custom_mac_store; //< Destroys everything in the array
or you could use the stack instead of the heap (this should be faster, just don't break the stack)
const std::size_t size_custom_mac_store = 48000;
uint8_t custom_mac_store[size_custom_mac_store]; //< The size must be either a const or a macro
std::copy ( ehdr->ether_shost, ehdr->ether_shost+sizeof(ehdr->ether_shost), custom_mac_store );
std::copy ( ehdr->ether_dhost, ehdr->ether_dhost+sizeof(ehdr->ether_shost), ehdr->ether_shost );
std::copy ( custom_mac_store, custom_mac_store+sizeof(ehdr->ether_shost), ehdr->ether_dhost );
delete[] custom_mac_store; //< Destroys everything in the array
Good luck.
PS: Love memory management, it's the only way
You can define ethernet length as 6 then making use of a temporary array, just perform memcpy as below,
#define ETH_ALEN 6
uint8_t tmp[ETH_ALEN];
memcpy(tmp, eth->ether_shost, ETH_ALEN);
memcpy(eth->ether_shost, eth->ether_dhost, ETH_ALEN);
memcpy(eth->ether_dhost, tmp, ETH_ALEN);
It might work if some memory was allocated for your temporary buffer custom_mac_store.
Like that it's just an uninitialized pointer waiting to cause a crash.
You can either allocate explicitly some memory to it, or use directly a 6 byte array instead.