Microchip pic access registers by address - pic

Is it possible to access a PIC register by address?
Why I'd want to do that? because I need to compute it beforehand (for ports). If a function receives PORTX, it can figure out TRISX, LATX and ANSELX by adding an offset.
The include files use the __at macro to define registers
extern volatile PORTAbits_t PORTAbits __at(0x00C);
#define __at(x) __attribute__((address(x)))
I'm assuming __attribute__ and address are compiler specific?
Can I use that with memory map to access the computed address?

I managed to get it working (at least for what I want to achieve) by using pointers and offsets.
As an example PIC12F1571, has:
PORTA # 0x00C
TRISA # 0x08C
ANSELA # 0x18C
To set the port to digital output:
volatile unsigned char *direction = &PORTA + 0x080;
volatile unsigned char *mode = &PORTA + 0x180;
*mode = 0;
*direction = 0;

Related

__eeprom and EEMEM

I am trying to port a code base from iar to avr-gcc. Amongst other things that have to replaced, the iar eeprom memory attribute __eeprom has to replaced with a avr-gcc friendly attribute. AFAIK the replacement for that is EEMEM, but the usage differs and I am not able to figure out how to replace __eeprom in the cleanest manner.
../src/myfunc.h:35:46: error: section attribute not allowed for 'src'
UBYTE *strcpye(UBYTE *dest, UBYTE EEMEM *src);
This error is not limited to pointers, but to all variables in general. IMO the usage of EEMEM is correct, where am I going wrong?
In the avr-gcc toolchain, avr-libc defines macro EEMEM in avr/eeprom.h:
#define EEMEM __attribute__((section(".eeprom")))
This means it's just an attribute that determines the section in which an object with this attribute will be located. In particular, EEMEM only makes sense for variables in static storage. Moreover, accesses to objects located in EEMEM have to be done by hand using functions / macros supplied by avr/eeprom.h like
void eeprom_read_block (void *dst, const void *src, size_t n);
void eeprom_write_byte (uint8_t *p, uint8_t value);
void eeprom_update_word (uint16_t *p, uint16_t value);
etc. Also notice that EEMEM is just an attribute and not a qualifier (like __flash for example). This means that even though you can tag a pointer (target) using attributes, that won't change the access in any way. To be more specific, any access through a pointer that's attributed EEMEM will be to RAM and not to eeprom.
In your case, the prototype of strcpye would read
char* strcpye (char *dest, const char *src);
and the implementation of that function would apply eeprom_read_byte on src++ and write to dest++ until it reads a terminal \0. Notice that you might need an explicit pointer cast as eeprom_read_byte expects [const] uint8_t*, and that char, signed char and unsigned char are 3 distinct types in C.

What is the modern C++ way of having a constexpr const pointer to a volatile memory location for embedded applications?

In building libraries for controlling hardware on embedded microprocessors, a common task is manipulating bits at specific memory locations for controlling hardware features.
In AVR processors, Atmel (now Microchip) provides macros that expand to something like this:
#define PORTA (*(volatile uint8_t *)(0x25))
Which enables things like:
PORTA |= 1;
Now in C++11 (and newer), it is desirable to replace almost any usage of #define with constexpr.
In older versions of the GCC C++ compiler (4.9.2), the following compiled:
#include <avr/io.h>
constexpr volatile uint8_t *const PortA = &PORTA;
In version 8.2.0, the above does not compile and gives errors:
error: 'reinterpret_cast<volatile uint8_t* {aka volatile unsigned char*}>(37)' is not a constant expression
I'm not looking for explanations of why you cannot use reinterpret_cast inside a constexpr context or why integer to pointer conversion is illegal.
What is the correct way to have a constexpr pointer to volatile memory in modern C++?
I've seen suggestions of storing the memory address of PORTA in a constexpr uintptr_t and then reinterprect_casting that to volatile uint8_t * const at runtime for bit manipulation.
For instance, this works and even compiles to a single sbi instruction in avr-gcc as expected.
#include <stdint.h>
constexpr uintptr_t PortA = 0x25;
void set() { *((volatile uint8_t *)(PortA)) |= 1; }
However it takes a decent amount of ugly boilerplate to use PortA as the pointer it is intended to be.
This also has the problem that it seem to be impossible to use the PORTA macro directly. We're instead forced to hard-code the memory address 0x25 which breaks certain desirable portability features.
It feels like I'm missing something obvious buy my searches have not yielded anything fruitful.
For instance, this feels like an "address constant expression", but that seems to relate to referring to statically allocated const values like which is not quite what I want.
const char str[] = "FooBar";
constexpr const char * x = str + 2;
You can't create a constexpr pointer initialized by a non-constant expression. However, you can create a static const pointer:
static uint8_t volatile* const PortA = &PORTA;
Or, even better, a static reference:
static uint8_t volatile& PortA = PORTA;

How to use arrays in program (global) scope in OpenCL

AMD OpenCL Programming Guide, Section 6.3 Constant Memory Optimization:
Globally scoped constant arrays. These arrays are initialized,
globally scoped, and in the constant address space (as specified in
section 6.5.3 of the OpenCL specification). If the size of an array is
below 64 kB, it is placed in hardware constant buffers; otherwise, it
uses global memory. An example of this is a lookup table for math
functions.
I want to use this "globally scoped constant array". I have such code in pure C
#define SIZE 101
int *reciprocal_table;
int reciprocal(int number){
return reciprocal_table[number];
}
void kernel(int *output)
{
for(int i=0; i < SIZE; i+)
output[i] = reciprocal(i);
}
I want to port it into OpenCL
__kernel void kernel(__global int *output){
int gid = get_global_id(0);
output[gid] = reciprocal(gid);
}
int reciprocal(int number){
return reciprocal_table[number];
}
What should I do with global variable reciprocal_table? If I try to add __global or __constant to it I get an error:
global variable must be declared in addrSpace constant
I don't want to pass __constant int *reciprocal_table from kernel to reciprocal. Is it possible to initialize global variable somehow? I know that I can write it down into code, but does other way exist?
P.S. I'm using AMD OpenCL
UPD Above code is just an example. I have real much more complex code with a lot of functions. So I want to make array in program scope to use it in all functions.
UPD2 Changed example code and added citation from Programming Guide
#define SIZE 2
int constant array[SIZE] = {0, 1};
kernel void
foo (global int* input,
global int* output)
{
const uint id = get_global_id (0);
output[id] = input[id] + array[id];
}
I can get the above to compile with Intel as well as AMD. It also works without the initialization of the array but then you would not know what's in the array and since it's in the constant address space, you could not assign any values.
Program global variables have to be in the __constant address space, as stated by section 6.5.3 in the standard.
UPDATE Now, that I fully understood the question:
One thing that worked for me is to define the array in the constant space and then overwrite it by passing a kernel parameter constant int* array which overwrites the array.
That produced correct results only on the GPU Device. The AMD CPU Device and the Intel CPU Device did not overwrite the arrays address. It also is probably not compliant to the standard.
Here's how it looks:
#define SIZE 2
int constant foo[SIZE] = {100, 100};
int
baz (int i)
{
return foo[i];
}
kernel void
bar (global int* input,
global int* output,
constant int* foo)
{
const uint id = get_global_id (0);
output[id] = input[id] + baz (id);
}
For input = {2, 3} and foo = {0, 1} this produces {2, 4} on my HD 7850 Device (Ubuntu 12.10, Catalyst 9.0.2). But on the CPU I get {102, 103} with either OCL Implementation (AMD, Intel). So I can not stress, how much I personally would NOT do this, because it's only a matter of time, before this breaks.
Another way to achieve this is would be to compute .h files with the host during runtime with the definition of the array (or predefine them) and pass them to the kernel upon compilation via a compiler option. This, of course, requires recompilation of the clProgram/clKernel for every different LUT.
I struggled to get this work in my own program some time ago.
I did not find any way to initialize a constant or global scope array from the host via some clEnqueueWriteBuffer or so. The only way is to write it explicitely in your .cl source file.
So here my trick to initialize it from the host is to use the fact that you are actually compiling your source from the host, which also means you can alter your src.cl file before compiling it.
First my src.cl file reads:
__constant double lookup[SIZE] = { LOOKUP }; // precomputed table (in constant memory).
double func(int idx) {
return(lookup[idx])
}
__kernel void ker1(__global double *in, __global double *out)
{
... do something ...
double t = func(i)
...
}
notice the lookup table is initialized with LOOKUP.
Then, in the host program, before compiling your OpenCL code:
compute the values of my lookup table in host_values[]
on your host, run something like:
char *buf = (char*) malloc( 10000 );
int count = sprintf(buf, "#define LOOKUP "); // actual source generation !
for (int i=0;i<SIZE;i++) count += sprintf(buf+count, "%g, ",host_values[i]);
count += sprintf(buf+count,"\n");
then read the content of your source file src.cl and place it right at buf+count.
you now have a source file with an explicitely defined lookup table that you just computed from the host.
compile your buffer with something like clCreateProgramWithSource(context, 1, (const char **) &buf, &src_sz, err);
voilĂ  !
It looks like "array" is a look-up table of sorts. You'll need to clCreateBuffer and clEnqueueWriteBuffer so the GPU has a copy of it to use.

atomic_inc and atomic_xchg in gcc assembly

I have written the following user-level code snippet to test two sub functions, atomic inc and xchg (refer to Linux code).
What I need is just try to perform operations on 32-bit integer, and that's why I explicitly use int32_t.
I assume global_counter will be raced by different threads, while tmp_counter is fine.
#include <stdio.h>
#include <stdint.h>
int32_t global_counter = 10;
/* Increment the value pointed by ptr */
void atomic_inc(int32_t *ptr)
{
__asm__("incl %0;\n"
: "+m"(*ptr));
}
/*
* Atomically exchange the val with *ptr.
* Return the value previously stored in *ptr before the exchange
*/
int32_t atomic_xchg(uint32_t *ptr, uint32_t val)
{
uint32_t tmp = val;
__asm__(
"xchgl %0, %1;\n"
: "=r"(tmp), "+m"(*ptr)
: "0"(tmp)
:"memory");
return tmp;
}
int main()
{
int32_t tmp_counter = 0;
printf("Init global=%d, tmp=%d\n", global_counter, tmp_counter);
atomic_inc(&tmp_counter);
atomic_inc(&global_counter);
printf("After inc, global=%d, tmp=%d\n", global_counter, tmp_counter);
tmp_counter = atomic_xchg(&global_counter, tmp_counter);
printf("After xchg, global=%d, tmp=%d\n", global_counter, tmp_counter);
return 0;
}
My 2 questions are:
Are these two subfunctions written properly?
Will this behave the same when I compile this on 32-bit or
64-bit platform? For example, could the pointer address have a different
length. or could incl and xchgl will conflict with the operand?
My understanding of this question is below, please correct me if I'm wrong.
All the read-modify-write instructions (ex: incl, add, xchg) need a lock prefix. The lock instruction is to lock the memory accessed by other CPUs by asserting LOCK# signal on the memory bus.
The __xchg function in Linux kernel implies no "lock" prefix because xchg always implies lock anyway. http://lxr.linux.no/linux+v2.6.38/arch/x86/include/asm/cmpxchg_64.h#L15
However, the incl used in atomic_inc does not have this assumption so a lock_prefix is needed.
http://lxr.linux.no/linux+v2.6.38/arch/x86/include/asm/atomic.h#L105
btw, I think you need to copy the *ptr to a volatile variable to avoid gcc optimization.
William

Setting register values in PIC16F876 using Hi Tech PICC

I am using MPLABx and the HI Tech PICC compiler. My target chip is a PIC16F876. By looking at the pic16f876.h include file, it appears that it should be possible to set the system registers of the chip by referring to them by name.
For example, within the CCP1CON register, bits 0 to 3 set how the CCP and PWM modules work. By looking at the pic16f876.h file, it looks like it should be possible to refer to these 4 bits alone, without change the value of the rest of the CCP1CON register.
However, I have tried to refer to these 4 bits in a variety of ways with no success.
I have tried;
CCP1CON.CCP1M=0xC0; this results in "error: struct/union required
CCP1CON:CCP1M=0xC0; this results in "error: undefined identifier "CCP1M"
but both have failed. I have read through the Hi Tech PICC compiler manual, but cannot see how to do this.
From the pic16f876.h file, it looks to me as though I should be able to refer to these subsets within the system registers by name, as they are defined in the .h file.
Does anyone know how to accomplish this?
Excerpt from pic16f876.h
// Register: CCP1CON
volatile unsigned char CCP1CON # 0x017;
// bit and bitfield definitions
volatile bit CCP1Y # ((unsigned)&CCP1CON*8)+4;
volatile bit CCP1X # ((unsigned)&CCP1CON*8)+5;
volatile bit CCP1M0 # ((unsigned)&CCP1CON*8)+0;
volatile bit CCP1M1 # ((unsigned)&CCP1CON*8)+1;
volatile bit CCP1M2 # ((unsigned)&CCP1CON*8)+2;
volatile bit CCP1M3 # ((unsigned)&CCP1CON*8)+3;
#ifndef _LIB_BUILD
volatile union {
struct {
unsigned CCP1M : 4;
unsigned CCP1Y : 1;
unsigned CCP1X : 1;
};
struct {
unsigned CCP1M0 : 1;
unsigned CCP1M1 : 1;
unsigned CCP1M2 : 1;
unsigned CCP1M3 : 1;
};
} CCP1CONbits # 0x017;
#endif
You need to access the bitfield members through an instance of a struct. In this case, that is CCP1CONbits. Because it is a bitfield, you only need to have the number of significant bits as defined in the bitfield, not the full eight bits in your code.
So:
CCP1CONbits.CCP1M = 0x0c;
Should be the equivalent of what you are trying to do. If you want to set all eight bits at once you can use CCP1CON = 0xc0. That would set the CCP1M bits to 0x0c and all the other bits to zero.
The header you gave also has individual bit symbols, so you could do this too:
CCP1M0 = 1;
CCP1M1 = 1;
CCP1M2 = 0;
CCP1M3 = 0;
Although the bitfield approach is cleaner.

Resources