Reputation: 1266
For low-level programming, sometimes it's necessary to say, at a given memory location, this is where my address is. For this post, the example is the PIR1
register in the PIC16F886 and related microcontrollers. It's always found at address 0x000C.
I've taken this approach:
#define pir1 (*(uint8_t*)0xc)
now I can assign to the variable with something like pir1 |= 0x40
(okay, I'd use a #defined constant instead of magic numbers but you get my drift). This compiles just fine on GCC, with no warnings even when I use -Wextra -Wall
. To check my assumptions, GCC spits out the following x86_64:
movl $12, %eax
movb $64, (%rax)
Exactly what I wanted (okay, I'm not sure why it's eax
one moment and rax
another, that's probably yet another stupid x86 quirk, but irrelevant since I want PIC14 code anyway)
Now, to target the PIC14, I'm actually using the SDCC compiler. I am invoking it like this
sdcc --std-c99 -mpic14 -p16f886 --use-non-free source.c
The above code starting with #define
gives the following warning:
source.c:412: warning 88: cast of LITERAL value to 'generic' pointer
from type 'const-int literal'
to type 'unsigned-char generic* fixed'
I've tried doing this instead:
__code __at (0xc) uint8_t PIR1;
but that results in an error message
error 33: Attempt to assign value to a constant variable (=)
when I try to make an assignment.
So my question is if I'm missing an idiomatic way to do this in C? Why is SDCC warning me? Is there's some particular SDCC specific funk I'm ignoring here?
Upvotes: 2
Views: 1615
Reputation: 41962
Regarding the warning it's probably a bug in the compiler. And as said, you must use (volatile uint8_t*)0xc
for memory-mapped access instead
The standard way for absolute addressing in SDCC is via compiler extensions, but you're doing it wrongly. __code __at (0xc) uint8_t PIR1;
puts the variable in the code section which isn't writable. That's why you see the error error 33: Attempt to assign value to a constant variable (=)
. Remember PIC14 uses Harvard architecture. If the address is in RAM then use
volatile __data __at (0xc) uint8_t PIR1;
If it's in xdata then use
volatile __xdata __at (0xc) uint8_t PIR1;
See Absolute Addressing in the documentation
Upvotes: 4
Reputation: 214780
"warning 88: cast of LITERAL value to 'generic' pointer" appears to be a false positive. There is nothing wrong syntax-wise or language-wise with your macro. The C standard explicitly allows such conversions, see C17 6.3.2.3/5:
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
(Alignment & traps are of no concern in this case.)
Embedded systems compilers in general and PIC compilers in particular, have a bad reputation of non-compliance to standard C. So you either have to figure out how to disable the broken warning or consider using a different compiler.
Unrelated to the warning, you also have a severe bug, namely the missing volatile
. I would recommend to study this: How to access a hardware register from firmware?
Upvotes: 1