0

So I'm trying to ORR some bits in a register on a micro controller. Up until now I've been using Assembly, now I'm using C I'm hitting some walls.

So in ASM if I wanted to access a register with an offset such as. GPIO_PORT_F and offset GPIO_DATA I would use the following code.

LDR R0,=GPIO_PORT_F ;load the base
LDR R1, [R0, #GPIO_DATA] ;load the offset
ORR R1, 0x1 ;ORR it with a value
STR R1, [R0, #GPIO_DATA] ;store back

This is the exact operation I want to perform but in C. This is what I have.

GPIO_PORT_F is defined like #define GPIO_PORT_F (*((unsigned long *)0x40025000))

(GPIO_PORT_F+GPIO_DATA) = (GPIO_PORT_F+GPIO_DATA) | inMask;

I get an error "expression must be a modifiable lvalue"

What am I doing wrong here, I'm using it's my attempt at offsetting.

Byte Me
  • 27
  • 1
  • 7
  • 1
    Well you haven't explained your C code very well. Is `PORTA` the same thing as `GPIO_PORT_F`? Is `GPIO_DIR` an integer offset? If so, try this: `*(PORTA+GPIO_DIR) |= inMask;` – r3mainer Oct 03 '14 at 08:01
  • 1
    @squeamish, I believe you want to write *(PORTA+GPIO_DIR) |= inMask; . I agree with your "approach", it could be the solution "Byte Me" is looking for – Stefano Buora Oct 03 '14 at 08:05
  • 1
    If `PORTA` is a pointer and `GPIO_DIR` is an integer offset then `PORTA[GPIO_DIR]` can be used to get or set the value at that offset from the pointer. – Will Oct 03 '14 at 08:08
  • Sorry for the mix up in example and actual vars I'm using. I've updated the question. I've attempted to use PORTA[GPIO_DIR] |= inMask; and receive another error "expression must have pointer-to-object type" *(PORTA+GPIO_DATA) |= inMask; gives the error "operand of "*" must be a pointer" – Byte Me Oct 03 '14 at 08:55

2 Answers2

1

An assignment operation generally can't have the result of another operation on the left side. Without going too deeply into the difference between an lvalue and an rvalue, the value on the left side of the assignment operator must be modifyable, which the result of an addition operator is not (more on lvalues v rvalues in the answer to this question). I presume PORTA+GPIO_DIR is pointer arithmetic, so perhaps something like:

PORTA[GPIO_DIR] = *(PORTA+GPIO_DIR)|inMask; 

PORTA[GPIO_DIR] and *(PORTA+GPIO_DIR) both result in the same lvalue, that is the element at index GPIO_DIR in array PORTA. I've included both so you can decide which you prefer, though usually the left one is used.

Community
  • 1
  • 1
IllusiveBrian
  • 3,105
  • 2
  • 14
  • 17
0

If I see it correctly you want to load a value from memory, ORR it with some value and then write it back to the same place.

Once you have correctly declared a pointer variable porta with the correct pointer type (probably something like uint32_t volatile* or so) you'd do

porta = (uint32_t*)GPIO_PORT_F; // convert the base
porta[GPIO_DATA] |= MASK;       // ORR it and store it back

The only thing that you'd have to worry is if the GPIO_DATA offset is accounted in bytes or words. If it is in bytes replace the second line by

porta[GPIO_DATA/sizeof *porta] |= MASK;       // ORR it and store it back
Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177