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.
Related
I am struggling with swapping from Arduino/Wire library to ESP-IDF's I2C driver. I got stuck at the very first stage, trying to simply read the register.
The function I use is esp_err_t i2c_master_write_read_device(i2c_port_t i2c_num, uint8_t device_address, const uint8_t* write_buffer, size_t write_size, uint8_t* read_buffer, size_t read_size, TickType_t ticks_to_wait).
The problem I face is that my write_buffer is uint16_t.
How to get over it?
Thanks
You need to pass to the function a pointer to the buffer and the size of that buffer.
If you want to write a simple uint16_t variable:
uint8_t *write_buffer = (uint8_t*)&old_buffer;
size_t write_size = 2
Take into consideration that you are responsible to accomodate the memory for that buffer, so make sure the uint16_t variable is not destroyed before the write function has finished.
Objective: Writing to an internal buffer from the values of members of a structure.
I have a structure that contains members of type Uint16 (unsigned int); here is a small portion of it:
typedef unsigned int Uint16;
typedef struct
{
Uint16 ee_Speed_Control_Mode;
Uint16 ee_Motor_Type;
Uint16 ee_Max_Electrical_Speed;
Uint16 ee_Carrier_Frequency;
Uint16 ee_Rated_Motor_Frequency;
Uint16 ee_Rated_Motor_Current;
Uint16 ee_Rs; // extern
Uint16 ee_Rr; // extern
Uint16 ee_L_lkg; // extern
Uint16 ee_Lm; // extern
Uint16 ee_No_Load_Current;
Uint16 ee_Phase_Reversal;
.....
.....
} EEPROM_PARAMETERS;
EEPROM_PARAMETERS eepromParameters;
My attempt:
Here is a function that is intended to write to eeprom: (Most of it is not shown for simplicity; the focus is occurring in the 'for' loop
void eeprom_write(Uint16 address, Uint32 *data, Int16 len)
{
Uint16 i;
// Multiple bytes will be written
// Page Write operation will be used
// Page Write bits to be sent:
// bit 0: Start condition, a high-to-low transition of SDA with SCL high
startCondition();
// bits 1-8: Device address
I2caRegs.I2CDXR = DEVICE_ADDRESS_WRITE;
// bit 9: EEPROM outputs 0 as ACK bit
// Check for ACK bit
while (I2caRegs.I2CDRR != 0)
{
wait();
}
// bits 10-17, bit 18 (ACK) and bits 19-26: two 8-bit word addresses
I2caRegs.I2CDXR = address;
// After setting the address, page write is capable of writing 64 bytes without stopping
// The EEPROM will respond with a zero after each data word has been received
// The data word address lower 6 bits are internally incremented following the receipt of each data word
// If more than 64 data words are written, data word addresses will "roll over" and previous data will be overwritten
for (i = 0; i < len; i++)
{
// How to increment address in data structure?
I2caRegs.I2CDXR = *data++;
}
// After page write operation is complete, execute stop condition
stopCondition();
}
When I try to call this function with my parameters..
eeprom_write(0, &eepromParameters, sizeof(eepromParameters) );
I get a incompatible type error:
error #169: argument of type "EEPROM_PARAMETERS *" is incompatible with parameter of type "Uint16 *"
My next thought would be that I need a middle man to bring them together and make it a compatible match. Any tips please on what I can try? Thanks
The problem is the declaration and usage of data. If you declare it as
void eeprom_write(Uint16 address, EEPROM_PARAMETERS* data, Int16 len);
and call it as
eeprom_write(0, &eepromParameters, sizeof(eepromParameters));
It will fall over in
*data++
since it will increment by the size of EEPROM_PARAMTERS. If the prototype is declared as
void eeprom_write(Uint16 address, UInt16* data, Int16 len);
It needs to be called as
eeprom_write(0, &eepromParameters.ee_Speed_Control_Mode, sizeof(eepromParameters) / sizeof(Uint16));
This assumes that everything in EEPROM_PARAMETERS is Uint16. Another way of doing this is to use enums.
enum EEOffsets
{
ee_Speed_Control_Mode,
ee_Motor_Type,
ee_Max_Electrical_Speed,
ee_Carrier_Frequency,
...
ee_Max
};
// Initialize the parameters
Uint16 eepromParameters[ee_Max] = { ... };
// If you need to assign
eepromParameters[ee_Carrier_Frequency] = 85;
...
eeprom_write(0, eepromParameters, ee_Max);
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));
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);
I need to write data into a structure where the length of the data depends on the command I want to send to a device. For that I have defined the following structure:
typedef struct {
uint8 len; // Command length (cmd ... crc)
uint8 cmd; // Command code
uint8 data_length; // Data length
uint8 data[12]; // Data: max 12 Byte
uint8 crc_h; // CRC value MSB
uint8 crc_l; // CRC value LSB
}CMD_TYPE;
Note: the members cmd, *data_length* and crc that are always present, instead member data can be empty or contains up to 12 Bytes.
I have created a function that returns a initialized command according to the parameters passed to the function:
CMD_TYPE Device::get_cmd(uint8 cmd, uint8 data_len, uint8 *data)
{
CMD_TYPE cmd;
cmd.len = (4 + data_len) * sizeof(uint8);
cmd.cmd = cmd;
cmd.data_length = data_len;
cmd.data = (uint8 *)realloc(cmd.data, data_len*sizeof(uint8));
if(data_len > 0) memcpy(cmd.data, data, data_len);
add_crc16((uint8*)&cmd);
return cmd;
}
The function get_cmd() is used like this:
uint8 cmd_code = 0x01;
uint8 data[2] = {0xAB, 0xCD};
CMD_TYPE cmd = local_device->get_cmd(cmd_code, 2, data);
retVal = local_device->send(cmd);
When I try to compile this code I get an error from the compiler for that line:
cmd.data = (uint8 *)realloc(cmd.data, data_len*sizeof(uint8));
and the compiler error is:
error: lvalue required as left operand of assignment
The aim of using realloc() is to re-size the array data or to remove it at all from my new command structure. What is wrong in my code? Is that the right way to initialize structures with dynamic memory allocation?
What you want is the infamous struct hack:
typedef struct
{
uint8 len; // Command length (cmd ... crc)
uint8 cmd; // Command code
uint8 data_length; // Data length
uint8 crc_h; // CRC value MSB
uint8 crc_l; // CRC value LSB
uint8 data[1]; // Data: max 12 Byte
} CMD_TYPE;
The trick is to allocate enough room for all of the members of the struct up to data[], then add enough bytes for the data[] member:
CMD_TYPE * allocCmd(int dataSize)
{
int len;
CMD_TYPE * p;
len = sizeof(CMD_TYPE) + (dataSize-1)*sizeof(uint8);
p = (CMD_TYPE *) malloc(len);
memset(p, 0, len);
p->data_length = dataSize;
return p;
}
Here, len is calculated to be the size of the struct, minus the size of the empty data member, plus however many elements dataSize specifies for the data array.
The catch is that you have to be careful never to access any elements of p->data[] beyond what is actually allocated in it (inside the struct).
Your CMD_TYPE.data is an array, not a pointer. Since you want it to track dynamically allocated memory, it has to be a pointer:
uint8_t * data;
Just don't forget to initialize it with malloc() (or by setting it to zero before realloc()) and to clean up after yourself
By the way, do not cast the result of malloc() and co.
array defined as a[..] are immutable, you can't assign anything to them. Instead you should use pointers.