Need help for this syntax: "#define LEDs (char *) 0x0003010" - c

I'm doing programming of a softcore processor, Nios II from Altera, below is the code in one of the tutorial, I manage to get the code working by testing it on the hardware (DE2 board), however, I could not understand the code.
#define Switches (volatile char *) 0x0003000
#define LEDs (char *) 0x0003010
void main()
{ while (1)
*LEDs = *Switches;
}
What I know about #define is that, it is either used to define a constant, or a macro, but
why in the above code, there are casting like, (char *) 0x0003010, in #define?
why the 2 constants, Switches and LEDs act like a variable instead of a constant?

1) why in the above code, there are casting like, (char *) 0x0003010, in #define?
Preprocessor macros are textual replacements. So the code comes out as
while (1) {
*(char *) 0x0003010 = *(volatile char *) 0x0003000
}
which repeated assigns the contents of the input (switch) mapped at 0x3000 to the output (led) mapped at 0x3010.
2) why the 2 constants, Switches and LEDs act like a variable instead of a constant?
Note that those are pointer. So they always point to the same place (which happens to be a couple of memory mapped IO pins or something similar), but there is no guarantee the the contents of those constant locations are constant, and the * appearing before each preprocessor symbol is the pointer de-reference operator.

It appears that Switches and LEDs represent the memory-mapping to the actual input (in the case of Switches) and output (in the case of LEDs).
So your answers include:
The byte for the input switches is memory-mapped to address 0x0003000. In order to access that as a byte, you need to tell the compiler that whatever is at address 0x0003000 is a char (in fact, you tell it that the value at that address is a volatile char, so that the compiler doesn't optimize away the fact that the value at that address may change at any time).
They are constants, but they are constant pointers. That is to say, the address is constant, but the values contained at those addresses are not constant.
What happens is that every clock cycle (or so), whatever is read from memory address 0x0003000 is then written to address 0x0003010. This gives the illusion that the switches instantly toggle the LEDs.

In C, macros are simple substitutions.
Every time the compiler sees LEDs in your code it will replace it with (char *) 0x0003010.
So your code is effectively the same as this:
void main()
{
while (1)
*(char *) 0x0003010 = *(volatile char *) 0x0003000;
}

Without the type casting at the #defines, they wouldn't be treated as char* and volatile char*. What is at *Switches is copied into *LEDs.

Related

What does this complex expression using volatile, pointers and memory allocation does under the hood?

I know that people have already answered what volatile is and that (int *) is just casting but I cannot understand what really goes under the hood in this expression: volatile int *p = (int *)0x0
So we have a pointer p to an int that can obviously have its value changed unexpectedly. We assign it another pointer that points to the memory address 0? So is it a pointer to a pointer or am I making it more complex than it should be? I would really appreciate it if you could provide a simple sketch like this as it helps me understand.
Sketch
volatile NULL pointer does not have too much sense as no one is going to dereference it.
But if I make this expression to have more sense ( this is STM32 microcontroller specific example)
volatile uint32_t *GPIOA_CRL = (volatile uint32_t *)0x40010800UL;
I declare the volatile pointer GPIO_CLR to the uint32_t object. The assignment casts the address of this hardware register defined by the unsigned long constant to the pointer type.
0x40010800UL - address of the hardware register
(volatile uint32_t *) - converts the unsigned long address to the pointer
Then I can set or read the value of this register.
Why have I defined this pointer as volatile? Because it can be changed by the hardware and compiler will not know about it. So volatile will force the compiler to read the value stores under this address before every use (when i dereference this pointer) and store it after every change. Otherwise the compiler may optimize those reads and writes as it will see no effect of it in the normal program execution path.
Let`s analyze this line.
volatile int * p; declares a pointer to a volatile int. A volatile int is from the storage and semantics a normal int. But volatile instructs the compiler, that its value could change anytime or has other side effects.
On the right side of the assignment you have (int *) 0x0. Here you tell the compiler, that it should assume a pointer to int which points to the address 0x0.
The full assignment volatile int * p = (int *) 0x0; assigns p the value 0x0. So in total you told the compiler, that at address 0x0 is an integer value which has side effects. It can be access by *p.
volatile
You seem to be unclear what volatile means. Take a look at this code:
int * ptr = (int *) 0x0BADC0DE;
*ptr = 0;
*ptr = 1;
An optimizing compiler would take a short look on this code and say: Setting *ptr to 0 has no effect. So we will skip this line and will only assign 1 immediately to safe some execution time and shrink the binary at the same time.
So effectively the compiler would only compile the following code:
int * ptr = (int *) 0x0BADC0DE;
*ptr = 1;
Normally this is OK, but when we are talking about memory mapped IOs, things get different.
A memory mapped IO is some hardware that can be manipulated by accessing special RAM addresses. A very simple example would be an output -- a simple wire coming out of your processor.
So let's assume, that at the address 0x0BADC0DE is a memory mapped output. And when we write 1 to it, this output is set to high and when we write 0 the output is set to low.
When the compiler skips the first assignment, the output is not changed. But we want to signalize another component something with a rising edge. In this case we want to get rid of the optimization. And one common way to do this, is to use the volatile keyword. It instructs the compiler that it can't check every aspect of read or write accesses to this register.
volatile int * ptr = (int *) 0x0BADC0DE;
*ptr = 0;
*ptr = 1;
Now the compiler will not optimize the accesses to *ptr and we are able to signalize a rising edge to an outside component.
Memory mapped IOs are important in programming embedded systems, operating systems and drivers. Another use case for the volatile keyword would be shared variables in parallel computing (that in addition to the volatile keyword would need some kind of mutex of semaphore to restrict simultaneous access to these variables).

Can't align "pointer targets signedness"

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";

Pointer array of pointers with C?

I want an array of pointers and I want to set byte values in the memory addresses where the pointers (of the array) are pointing.
Would this work:
unsigned int *pointer[4] = {(unsigned int *) 0xFF200020, (unsigned int *) 0xFF20001C, (unsigned int *) 0xFF200018, (unsigned int *) 0xFF200014};
*pointer[0] = 0b0111111; // the value is correct for the address
Or is the syntax somehow different?
EDIT:
I'm coding for an SOC board and these are memory addresses that contain the case of some UI elements.
unsigned int *element1 = (unsigned int *) 0xFF200020;
*element1 = 0b0111111;
works so I'm just interested about the C syntax of this.
EDIT2: There was one 0 too much in ... = 0b0...
Short answer:
Everything you've written is fine.
Thoughts:
I'm a big fan of using the types from stdint.h. This would let you write uint32_t which is more clearly a 32 bit unsigned number than unsigned long.
You'll often see people write macros to refer to these registers:
#define REG_IRQ (*(volatile uint32_t *)(0xFF200020))
REG_IRQ = 0x42;
It's possible that you actually want these pointers to be to volatile integers. You want it to be volatile if the value can change outside of the execution of your program. That is, if that memory position doesn't act strictly like a piece of memory. (For example, it's a register that stores the interrupt flags).
With most compilers I've used on embedded platforms, you'll have problems from ignoring volatile once optimizations have been enabled.
0b00111111 is, sadly, non-standard. You can use octal, decimal, or hexadecimal.
Sure, this should work, providing you can find addresses in your own segment.
Most probably, you'll have a segmentation fault when running this code, because 0xFF200020 have really few chances to be in your program segment.
This will not throw any error and will work fine but hard-coding memory address the pointer is pointing to is not a good idea. De-referencing some unknown/non-existing memory location will cause segmentation fault but if you are sure about the memory location and hard-coding values to them as done here is totally fine.

How do I decide where to put the Asterisk?

will these lines do the same? If not, what's the difference? How do I decide where to put the asterisk?
#define OUT1 *((portptr ) SIGDATA_ADR)
#define OUT1 ((portptr *) SIGDATA_ADR)
Ok, sorry for the vague problem description.
What I'm trying to do is a function that continuously reads the value of two switches, makes a XOR, and puts it on a LED ramp.
My program looks like this; and it should work.
typedef unsigned char *port8ptr;
#define OUT *((port8ptr) 0x400)
#define IN1 *((port8ptr) 0x600)
#define IN2 *((port8ptr) 0x601)
void DipSwitchEor( void )
{
while( 1 )
{
OUT = IN1 ^ IN2;
}
}
So I'm just curious if I could have written #define OUT ((port8ptr *) 0x400) instead. I'm getting mixed answers.
There is a huge difference between these two macro definitions
#define OUT *((port8ptr) 0x400)
#define OUT ((port8ptr*) 0x400)
The first one first makes a port8ptr (cast) that points at memory address 0x400, then it dereferences this pointer (* operator outside of parentheses) to yield the unsigned char that is located at memory address 0x400.
The second one makes a pointer to a port8ptr that points at memory address 0x400. The result has the same type as a variable foo declared with port8ptr* foo;. That is, the result is a double pointer to an unsigned char, the char being located in memory wherever the pointer stored at memory address 0x400 is pointing at.
If all you need is to tell what various C declaration constructs mean, I think that you should try http://cdecl.org. It is also a utility that you can install on your computer. Probably what you want with your example is the code below, assuming that 0x600, 0x601 and 0x400 are the addresses of your registers:
void dip_switch() {
unsigned char *in1 = 0x600;
unsigned char *in2 = 0x601;
unsigned char *out = 0x400;
*out = (*in1) ^ (*in2);
}
Using #defines will only bite you in a situation like this. You should probably steer away from it.
The definitions of OUT1 and OUT2 are not semantically equivalent.
In the first case SIGDATA_ADR is cast to a pointer type portptr, and then dereferenced, so the argument to OUT1() in the first case is the data pointed to by SIGDATA_ADR. This makes sense and is likely the correct semantics - given you subsequent example of the use case, it is certainly correct.
In the second case, (portptr*) is a pointer-to-pointer, and the argument to OUT1() in the second case SIGDATA_ADR cast to a pointer-to-pointer - which seems unlikely.
Note that in the first case the * is the dereference operator, and the second it is not an operator but a data type modifier. They are not the same thing - they just happen to be represented by the same character - context is everything; understanding that probably makes determining which is correct far simpler.

How to read and write memory mapped registers using keyword volatile?

I met this question in an interview. I have no such experience.
So if we have two registers. One with address 0x11111111 and the other 0x22222222. We want to read and write it. The first one is a 32-bit register while the second one is 64-bit. How do we do it in C? Can anyone just give me an example?
Thanks,
You can use some kind of pointer or other, for example:
#include <stdint.h>
uint32_t volatile * p = (uint32_t volatile *) 0x11111111;
uint64_t volatile * q = (uint64_t volatile *) 0x22222222;
++*p; // read-modify-write
(Note that this specific example is almost certainly bogus, since neither address seems to be aligned properly for the respective type.)
As you say, qualifying the pointers as volatile is necessary if the values stored at those addresses can change from outside your program; with volatile you tell the compiler that no assumptions may be made about the value (e.g. constant propagation or common subexpression elimination may not be done for volatile values).

Resources