I've been struggling with this issue for a while where this code
uint8_t *PMTK = "$PSIMIPR,W,115200*1C";
gives me the error
pointer targets in initialization differ in signedness [-Wpointer-sign]
Changing it to only char * or unsigned char * does not make a difference, and const char * causes the program to complain further down where PMTK is supposed to be used, in the following code:
if (HAL_UART_Transmit(&huart3, PMTK, 32, 2000) != HAL_TIMEOUT)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_7);
}
else
{ ....
The program is supposed to establish uart communication from STM32F0xx to a GPS receiver (SIM33ELA), using HAL driver.
Yeah, that's a really annoying corner of the STM32 Cube libs. Someone should give them a big clue that random read-only buffers are best expressed as const void * in C ... mumble.
So, to fix it: It's convenient to use a string literal since the data is textual. So, make it so and then cast in the call, instead:
const char PMTK[] = "$PSIMIPR,W,115200*1C";
if (HAL_UART_Transmit(&huart3, (uint8_t *) PMTK, strlen(PMTK), 2000) != HAL_TIMEOUT)
Note use of strlen() to get the proper length, hardcoding literal values is never the right choice and was broken here (the string is not 32 characters long). We could use sizeof (it's an array, after all) too but that's bit more error-prone since you must subtract 1 for the terminator. I'm pretty sure compilers will optimize this strlen() call out, anyway.
c Strings are treated by the compiler as char[]. If you add a cast to (uint8_t *) before the String the warning is quieted.
uint8_t *PMTK = (uint8_t *)"$PSIMIPR,W,115200*1C";
Related
In my auto-generated HAL code for implementing CRC I have the following function:
uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)
{
uint32_t index; /* CRC input data buffer index */
uint32_t temp = 0U; /* CRC output (read from hcrc->Instance->DR register) */
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_BUSY;
switch (hcrc->InputDataFormat)
{
case CRC_INPUTDATA_FORMAT_WORDS:
/* Enter Data to the CRC calculator */
for (index = 0U; index < BufferLength; index++)
{
hcrc->Instance->DR = pBuffer[index];
}
temp = hcrc->Instance->DR;
break;
case CRC_INPUTDATA_FORMAT_BYTES:
temp = CRC_Handle_8(hcrc, (uint8_t *)pBuffer, BufferLength);
break;
case CRC_INPUTDATA_FORMAT_HALFWORDS:
temp = CRC_Handle_16(hcrc, (uint16_t *)(void *)pBuffer, BufferLength); /* Derogation MisraC2012 R.11.5 */
break;
default:
break;
}
/* Change CRC peripheral state */
hcrc->State = HAL_CRC_STATE_READY;
/* Return the CRC computed value */
return temp;
}
The problem is that my own inBuff is of type uint8_t * inBuff and I can see in the auto-generated code that it needs a uint32_t as input, and also later on just typecasts it to a uint8_t as i use the CRC_INPUTDATA_FORMAT_BYTES option for my CRC. The reason for needing my uint8_t buff is to make it work with the rest of my code (pretty big project). Is there any reason to work around this in an efficient way without damaging my own inBuff content? It needs to be aligned correctly.
STMCubeMX does NOT generate the best code and you have found a good example of this.
First of all, they(ST) DO want you to pass in a uint32_t buffer because they want the data aligned on a 32-bit boundary. See this line:
hcrc->Instance->DR = pBuffer[index];
They are expecting to read a uint32_t value and write it to the 32-bit DR register. A misaligned pointer would cause a fault right there.
You trying to cast your uint8_t buffer to a uint32_t could be problematic if the buffer isn't actually aligned on a 32-bit boundary. You could align yours like this:
uint8_t mybuf[128] __attribute__((aligned(4)));
You would still need to cast your pointer to a uint32_t* to pass it to HAL_CRC_Accumulate so the compiler wouldn't complain, BUT it would work because it is really aligned!
I would highly encourage you to NOT modify code generated by CubeMX. Unless your code is added within special /* USER */ sections of the ST code, it will be lost each time you regenerate the project. This will bite you in the ass over and over and over.
Problems:
A function which does not intend to access a pointer parameter through the pointed-at type should not be declared with that type. If HAL_CRC_Accumulate never intends to access pBuffer as an (array of) uint32_t then it shouldn't be using that type. It should then have been declared as uint8_t*.
Passing an uint8_t* pointing at the first item of an array to a function accepting uint32_t* is highly fishy code and could indeed cause misalignment problems. Most of your problems boils down to: why does this function use uint32_t[]? It doesn't make any sense.
Casting a uint32* to a uint16_t* is similarly bad practice and undefined behavior in case the function that this uint16_t* is passed to will access that parameter as uint16_t. Not only because of possible misalignment but also because of strict aliasing. Again, if that function has no intention of using the uint16_t* to access a uint16_t object, then it shouldn't be using that pointer type. Again, it seems like this whole code should be working on uint8_t* types.
"Chaining" multiple casts like this (uint16_t *)(void *) is nonsense. The void* adds nothing and solves nothing.
Normally a function that calculates CRC would work on a const qualified buffer, because it isn't supposed to change anything. If the so-called "FCS" (calculated checksum) should be appended at the end of the data buffer, then it might be better design to do that separately.
Since MISRA-C is mentioned in comments: all of the above is particularly unacceptable in a mission-critical code base. Auto-generated code is no excuse for sloppy, potentially broken use of types - on the contrary. More importantly than advisory rule 11.5, you have multiple violations of (Required) MISRA-C:2012 rule 11.3 and none of this is MISRA compliant.
Allocate your buffer to the desired size plus sizeof(uint32_t) - 1.
For example, if you buffer is statically allocated to SIZE, then you can do:
uint8_t buff[SIZE + sizeof(uint32_t) - 1];
Set your pointer to the lowest address within your buffer, which aligned to uint32_t:
size_t addr = (size_t)buff + sizeof(uint32_t) - 1;
uint8_t* inBuff = (uint8_t*)(addr / sizeof(uint32_t) * sizeof(uint32_t));
How to convert/align my uint8_t pointer buffer to uint32 for it to work with auto-generated HAL functions
Do nothing.
The problem is that my own inBuff is of type uint8_t * inBuff and I can see in the auto-generated code that it needs a uint32_t as input
So cast the pointer.
HAL_CRC_Accumulate(..., (uint32_t*)your_buffer, ...)
Is there any reason to work around this in an efficient way without damaging my own inBuff content?
No. (?)
Yes, it is unpleasant that it doesn't take a void* pointer or that there aren't just separate API for each INPUTDATA_FORMAT. Still, there is nothing for you to do, just pass the pointer value - the internal routines will access them via uint8_t* proper handle anyway.
The alignment needed for INPUTDATA_FORMAT_BYTES is 1, at bytes boundaries.
I quiet do not understand why I get error "Stack around the variable "tmp" was corrupted".
I use same code in different functions and it works well but now when function is "returning" it throws error mentioned above.
struct frame {
uint8_t dst[6];
uint8_t src[6];
};
//fill frame.dst || src exactly same way as code below without any errors or warnings
bool fcn() {
uint8_t tmp[6];
sscanf_s("00-00-00-00-00-00", "%x-%x-%x-%x-%x-%x", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]);
//here I compare tmp[0] == frame.mac[0]...
return true;
} //here pops the error while debugging
I use exactly same code in different part of the program but no error what so ever.
Referring C-Standard confirming systems:
To scan in an 8bit value on a 32bit machine, one needs to use the "hh" length modifier. The half of the half of 32 is 8.
For VC one needs to use a workaround scanning into unsigned ints.
The %x specifier writes to an int parameter, but you are passing pointers to uint8_t instead. Since int is a larger type on your platform, you are overwriting memory when those fields are written out. Pass in pointers to int instead and convert them to your required type as appropriate.
You will want to do this everywhere else you use this code too!
I am new to C programming and microcontrollers. I am using a PIC18F24K20 microcontroller with C18. I have it set up to receive information from a computer input using USART transmit and receive functions. My goal is to compare the received word against known words, and transmit something back to the computer based on what word was received. Below is the relevant code.
#include "p18f24k20.h"
#include "delays.h"
#include "string.h"
#include "stdlib.h"
void CommTransmit ( rom char * );
void main (void)
{
char buf[11], data, T;
int i;
i = 0;
memset(buf, 0, sizeof buf);
while(1)
{
if (PIR1bits.RCIF)
{
data = USART_receive();
if (data != 47) // 47 is /, indicates end of string
{
buf[i] = data;
i++;
}
else
{
// T = strcmppgm2ram(buf,(const far rom char*)"test");
CommTransmit(buf);
USART_transmit('t');
buf[0] = 0'
}
}
}
}
void CommTransmit ( rom char *CommVariable )
{
char test;
test = strcmppgm2ram(CommVariable, (const far rom char*)"test");
if (test == 0)
{
USART_transmit('g');
}
}
The code is currently set up to test to try to determine what is wrong. If I run it as is, the computer will receive a 't', as if the microcontroller ran through the CommTransmit function. However, it never transmits the 'g'. Even if I put a USART_transmit('g') call in the CommTransmit function, outside of and after the if statement, it never gets called (like it gets stuck in the strcmppgm2ram function?) but yet it still transmits the 't'.
It is also strange because if I put a break at the CommTransmit function and run through line by line, it seems to work properly. However, if I watch the CommVariable inside MPLAB IDE, it is never what it supposed to be (though the 'buf' variable prior to being called into the function is correct). From what I can tell, the value of CommVariable when I watch it depends on the size of the array.
From reading, I think it may caused by how the microcontroller stores the variable (program vs data memory?) but I'm not sure. Any help is greatly appreciated!
edit: I should also add that if I uncomment the T = strcmppgm2ram line in the else statement before the CommTransmit line, it works properly (T = 0 when the two strings are the same). I believe the array changes when I pass it through the function, which causes the strcmppgm2ram function to not work properly.
Looking at signature for strcmppgm2ram
signed char strcmppgm2ram(const char * str1, const rom char * str2 );
I don't understand why do you have rom char * for CommVariable. From chapter 2.4.3 ram/rom Qualifiers of MPLAB® C18 C Compiler User’s Guide
Because the PICmicro microcontrollers use separate program memory and
data memory address busses in their design, MPLAB C18 requires
extensions to distinguish between data located in program memory and
data located in data memory. /---/ Pointers can point to either data memory (ram pointers) or program
memory (rom pointers). Pointers are assumed to be ram pointers unless
declared as rom.
And in 2.7.3 String Constants:
An important consequence of the separate address spaces for MPLAB C18
is that pointers to data in program memory and pointers to data in
data memory are not compatible. /---/ because they refer to different
address spaces. /---/
MPLAB C18 automatically places all string constants in program memory.
This type of a string constant is “array of char located in program
memory”, (const rom char []).
And also it's not clear the purpose of type casting to const far rom char* for the second argument. That may cause stack corruption because far pointer has bigger size (24 bits). So, it looks like it should be rewritten as:
void CommTransmit (const char *CommVariable )
{
if (!strcmppgm2ram(CommVariable, "test")) {
USART_transmit('g');
}
}
I looked at
http://www.opensource.apple.com/source/xnu/xnu-2050.24.15/libsyscall/wrappers/memcpy.c
and didn't understand the following :
1-
inside
void * memcpy(void *dst0, const void *src0, size_t length) {
char *dst = dst0;
const char *src = src0;
line:
if ((unsigned long)dst < (unsigned long)src) {
How can we cast dst to an unsigned long ? it's a pointer !
2- Why do they sometimes prefer forward copying and sometimes backwards??
You are right, this implementation is non-portable, because it is assuming that a pointer is going to fit in unsigned long. This is not guaranteed by the standard.
A proper type for this implementation would have been uintptr_t, which is guaranteed to fit a pointer.
When comparing a void* and char* pointer, the compiler will give a warning (gcc -Wall):
warning: comparison of distinct pointer types lacks a cast
I imagine that the developer decided to "make the warning go away" - but the correct way to do this is with a void* cast (which is portable):
if((void*) dst < (void*) src) {
As for the second point - as was pointed out, you have to take care of overlapping memory locations. Imagine the following 8 characters in successive memory locations:
abcdefgh
Now we want to copy this "3 to the right". Starting with a, we would get (with left-to-right copy):
abcdefgh
abcaefgh
^
abcabfgh
^^
abcabcgh
^^^
etc until you end up with
abcabcabcab
^^^^^^^^
When we wanted to get
abcabcdefgh
Starting from the other end, we don't overwrite things we still have to copy. When the destination is to the left of the source, you have to do it in the opposite direction. And when there is no overlap between source and destination, it doesn't matter what you do.
I am relatively new to writing in C. I have self taught myself using what resources I have found online and in print. This is my first real project in C programming. Gotta love on-the-job training.
I am writing some code in C that is being used on a Texas Instruments C6701 Digital Signal Processor. Specifically, I am writing a set of communication functions to interface through a serial port.
The project I'm on has an existing packet protocol for sending data through the serial port. This works by handing over a pointer to the data to be transmitted and its length in bytes. All I have to do is write in the bytes to be transmitted into an "array" in memory (the transmitter copies that sequence of bytes into a buffer and transmits that).
My question pertains to how best to format the data to be transmitted, the data I have to send is composed of several different data types (unsigned char, unsigned int, float etc...). I can't expand everything up to float (or int) because I have a constrained communication bandwidth and need to keep packets as small as possible.
I originally wanted to use arrays to format the data,
unsigned char* dataTx[10];
dataTx[0]=char1;
dataTx[1]=char2;
etc...
This would work except not all my data is char, some is unsigned int or unsigned short.
To handle short and int I used bit shifting (lets ignore little-endian vs big-endian for now).
unsigned char* dataTx[10];
dataTx[0]=short1>>8;
dataTx[1]=short1;
dataTx[2]=int1>>24;
dataTx[3]=int1>>16;
etc...
However, I believe another (and better?) way to do this is to use pointers and pointer arithmetic.
unsigned char* dataTx[10]
*(dataTx+0) = int1;
*(dataTx+4) = short1;
*(dataTx+6) = char1;
etc...
My question (finally) is, is which method (bit shifting or pointer arithmetic) is the more acceptable method? Also, is one faster to run? (I also have run-time constraints).
My requirement: The data be located in memory serially, without gaps, breaks or padding.
I don't know enough about structures yet to know if a structure would work as a solution. Specifically, I don't know if a structure always allocates memory locations serially and without breaks. I read something that indicates they allocates in 8 byte blocks, and possibly introduce padding bytes.
Right now I'm leaning towards the pointer method. Thanks for reading this far into what seems to be a long post.
Usually you would use the bit shifting approach, because many chips do not allow you to copy, for example, a 4-byte integer to an odd byte address (or, more accurately, to a set of 4 bytes starting at an odd byte address). This is called alignment. If portability is an issue, or if your DSP does not allow misaligned access, then shifting is necessary. If your DSP incurs a significant performance hit for misaligned access, you might worry about it.
However, I would not write the code with the shifts for the different types done longhand as shown. I would expect to use functions (possibly inline) or macros to handle both the serialization and deserialization of the data. For example:
unsigned char dataTx[1024];
unsigned char *dst = dataTx;
dst += st_int2(short1, dst);
dst += st_int4(int1, dst);
dst += st_char(str, len, dst);
...
In function form, these functions might be:
size_t st_int2(uint16_t value, unsigned char *dst)
{
*dst++ = (value >> 8) & 0xFF;
*dst = value & 0xFF;
return 2;
}
size_t st_int4(uint32_t value, unsigned char *dst)
{
*dst++ = (value >> 24) & 0xFF;
*dst++ = (value >> 16) & 0xFF;
*dst++ = (value >> 8) & 0xFF;
*dst = value & 0xFF;
return 4;
}
size_t st_char(unsigned char *str, size_t len, unsigned char *dst)
{
memmove(dst, str, len);
return len;
}
Granted, such functions make the code boring; on the other hand, they reduce the chance for mistakes too. You can decide whether the names should be st_uint2() instead of st_int2() -- and, indeed, you can decide whether the lengths should be in bytes (as here) or in bits (as in the parameter types). As long as you're consistent and boring, you can do as you will. You can also combine these functions into bigger ones that package entire data structures.
The masking operations (& 0xFF) may not be necessary with modern compilers. Once upon a very long time ago, I seem to remember that they were necessary to avoid occasional problems with some compilers on some platforms (so, I have code dating back to the 1980s that include such masking operations). Said platforms have probably gone to rest in peace, so it may be pure paranoia on my part that they're (still) there.
Note that these functions are passing the data in big-endian order. The functions can be used 'as is' on both big-endian and little-endian machines, and the data will be interpreted correctly on both types, so you can have diverse hardware talking over the wire, using this code, and there will be no miscommunication. If you have floating point values to convey, you have to worry a bit more about the representations over the wire. Nevertheless, you should probably aim to have the data transferred in a platform-neutral format so that interworking between chip types is as simple as possible. (This is also why I used the type sizes with numbers in them; 'int' and 'long' in particular can mean different things on different platforms, but 4-byte signed integer remains a 4-byte signed integer, even if you are unlucky - or lucky - enough to have a machine with 8-byte integers.)
You might want to use an array of unions.
The easiest and most traditional way to handle your problem is to set up the data you want to send, and then pass a pointer to your data on to the transmission routine. The most common example would be the POSIX send() routine:
ssize_t send(int socket, const void *buffer, size_t length, int flags);
Which for your case you can simplify to:
ssize_t send(const void *buffer, size_t length);
And then use something like:
send(&int1, sizeof int1);
send(&short1, sizeof short1);
To send it out. An example (but pretty naive) implementation for your situation might be:
ssize_t send(const void *buffer, size_t length)
{
size_t i;
unsigned char *data = buffer;
for (i = 0; i < length; i++)
{
dataTx[i] = data[i];
}
}
In other words, use the automatic conversion to void * and then back to char * to get byte-wise access to your data, and then send it out appropriately.
Long question, I'll try shorter answer.
Don't go on *(dataTx+4) = short1; etc. because this method may fail because most chips may do read/write only on some aligned positions. You can access by 16bit to positions aligned by 2, and 32bit on positions aligned by 4, but take an example of: "int32 char8 int32" - the second int32 have a position of (dataTx+5) - which is not 4-byte aligned, and you probably get the "bus error" or something like that (depending of CPU you'll use). Hope you understand this issue.
1st way - you can try struct, if you declare:
struct
{
char a;
int b;
char c;
short d;
};
you are now out-of-trouble, as the compilator itself would take care about struct alignment. Of course, read about alignment-related options in your compiler (if this is gcc, then this is simply called alignment), because there is probably a setting which force some alignment of struct fields or packing of struct fields. The GCC can even define alignment-per-struct (more here).
The other way is to use some "buffer-like approach" - something like in answer-post of Carl Norum (I won't be duplicating that answer), but also considering of use of memcpy() calls when more data is copied (e.g. long long or string), as this may be faster than copying byte-by-byte.