Further question with memory mapped interface - c

I still have some issues with my c code that deals with an memory mapped device.
At the moment I declare the address space for the registers I write as volatile
pointer and I write data to them as shown below:
volatile unsigned int *wr_register = (int *) 0x40000000;
volatile unsigned int *c_register = (int *) 0x40000100;
...
main{
*wr_register = 0x01234567;
*c_register = 0x01234567;
*(c_register+1) = 0x89abcdef;
}
This works more or less fine. However, I would like to have specific read and
write functions that interact with the memory mapped registers. So ideally,
it would look something like this:
const unsigned int wr_register = 0x40000000;
const unsigned int c_register = 0x40000100;
function write_REG(unsigned int address, int offset, int data)
{
(unsigned int*) (address + offset) = data;
}
main{
*write_REG(0x40000000, 0, 0x01234567);
*write_REG(0x40000100, 0, 0x01234567);
*write_REG(0x40000100, 1, 0x89abcdef);
}
I have not tried it out yet to be honest, but I am wondering if somebody could
tell me if this is a proper way to do it?
EDIT: Maybe it is of use for someone else, here I have my function and they seem to work. Many thanks for the helpful comments!
void reg_write(unsigned int address, int offset, int data)
{
*((volatile unsigned int*)address + offset) = data;
}
int reg_read(unsigned int address, int offset)
{
return(*((volatile unsigned int*)address + offset));
}
Many thanks

There are quite a few problems with your code:
I assume you meant void where you wrote function.
You should make the pointer inside the function to be volatile as well.
You should dereference the pointer before writing the data. The * should be inside the function, not at the call site (*write_REG) as it is now - that would be a compile error.
You should add the offset to the pointer, not the address. This is because an offset of 1 is meant to be the next int which could be, say, 4 bytes away, but adding it to the address will only add 1 byte.
Your corrected function should look like this:
void write_REG(unsigned int address, int offset, int data)
{
*((volatile unsigned int*)address + offset) = data;
}
and you would call it like:
write_REG(0x40000000, 0, 0x01234567);

That would be just fine IMHO. I sometimes use macros like:
#define WR_REG *(volatile unsigned int*)0x40000000
This allows the registers to be used sort of like variables:
WR_REG = 0x12345678;

Related

C vs C++ placing structs in unsigned char buffer

Does C have anything similar to C++ where one can place structs in an unsigned char buffer as is done in C++ as shown in the standard sec. 6.7.2
template<typename ...T>
struct AlignedUnion {
alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f() {
AlignedUnion<int, char> au;
int *p = new (au.data) int; // OK, au.data provides storage
char *c = new (au.data) char(); // OK, ends lifetime of *p
char *d = new (au.data + 1) char();
return *c + *d; // OK
}
In C I can certainly memcpy a struct of things(or int as shown above) into an unsigned char buffer, but then using a pointer to this struct one runs into strict aliasing violations; the buffer has different declared type.
So suppose one would want to replicate the second line in f the C++ above in C. One would do something like this
#include<string.h>
#include<stdio.h>
struct Buffer {
unsigned char data[sizeof(int)];
};
int main()
{
struct Buffer b;
int n = 5;
int* p = memcpy(&b.data,&n,sizeof(int));
printf("%d",*p); // aliasing violation here as unsigned char is accessed as int
return 0;
}
Unions are often suggested i.e. union Buffer {int i;unsigned char b[sizeof(int)]}; but this is not quite as nice if the aim of the buffer is to act as storage (i.e. placing different sized types in there, by advancing a pointer into the buffer to the free part + potenially some more for proper alignment).
Have you tried using a union?
#include <string.h>
#include <stdio.h>
union Buffer {
int int_;
double double_;
long double long_double_;
unsigned char data[1];
};
int main() {
union Buffer b;
int n = 5;
int *p = memcpy(&b.data, &n, sizeof(int));
printf("%d", *p); // aliasing violation here as unsigned char is accessed as int
return 0;
}
The Buffer aligns data member according the type with the greatest alignment requirement.
Yes, because of strict aliasing rule it is just not possible. As it is not possible to write a standard compliant malloc().
Your buffer is not aligned - alignas(int) from stdalign.h needs to be added.
If you want to protect against compiler optimizations, either:
just cast the pointer and access it and compile with -fno-strict-aliasing, or use volatile
or move the accessor to the buffer to another file that is compiled without LTO so that compiler just is not able to optimize it.
// mybuffer.c
#include <stdalign.h>
alignas(int) unsigned char buffer[sizeof(int)];
void *getbuffer() { return buffer; }
// main.c
#include <string.h>
#include <stdio.h>
#include "mybuffer.h"
int main() {
void *data = getbuffer();
// int *p = new (au.data) int; // OK, au.data provides storage
int *p = data;
// char *c = new (au.data) char(); // OK, ends lifetime of *p
char *c = data;
*c = 0;
// char *d = new (au.data + 1) char();
char *d = (char*)data + 1;
*d = 0;
return *c + *d;
}
The way the definition of Effective Type in 6.5p6 is written, it's unclear what it's supposed to mean in all corner cases--likely because there was never a consensus among Committee Members as to how all corner cases should be handled. Defect reports often add more confusion than clarity, since they use terms like the "active member" of a union when neither the Standard nor the defect reports specify what actions would set or change it.
If one wants to use an object of static or automatic duration as though it were a buffer without a declared type, a safe way of doing that should be to do something like the following:
void volatile *volatile dummy_vp;
void test(void)
{
union {
char dat[1000];
unsigned long force_alignment;
} buffer;
void *volatile launder = buffer.dat;
dummy_vp = &launder;
void *storage_blob = launder;
...
}
Unless an implementation goes out of its way to test whether the read of
launder happened to yield an address matching buffer.dat, it would have no way of knowing whether the object at that address had a declared type. Nothing in the Standard would forbid an implementation from behaving nonsensically if the address happened to match that of buffer.dat, but situations where performance improvements would justify the cost of the check aren't likely to be common enough for compilers to attempt such "optimization".

Converting any variable from big to little endian - how to avoid void pointers?

I'm working on an application that needs to convert any type of the variable from big to little-endian.
My system works with different variable types (16, 32, and 64 bits wide), and I need to be able to change the endianness with a single function. I wrote a function that manages to swap bytes in any variable however, I'm not happy with it. It works, but it requires dereferencing void pointers, which are prone to error with the double star...
Is there any better way to approach the problem?
Is there any way to avoid void pointers as return value? I was thinking about switch-case loop (eg. case 4 bytes -> return int32) however, I don't know how to write a function prototype for a function that returns different values.
My function:
void* swapBytes(void* number, int bytes_num){
void* swapped;
unsigned __int8* single_byte_ptr;
swapped = malloc(bytes_num * sizeof(__int8));
for (int i = 0; i<bytes_num; i++){
single_byte_ptr =((unsigned __int8*)number)+i; //get current byte
*( (__int8*)(swapped)+((bytes_num-1)-i)) = (unsigned __int8)*single_byte_ptr; //save the byte in new position
}
return swapped;
}
the way I call this function
__int64 big_number = 35169804487071;
big_number = *(__int64*)(swapBytes(&big_number, 8));
One problem you have is that you're leaking memory. You return a pointer to malloc'ed memory, but you're not saving the pointer when you return.
Given that you're assigning the result back to the same value, you're better off updating the existing variable, swapping the current byte with a byte on the "opposite" side.
You also don't need to use a void * anyplace other than the parameter type. Inside of the function, just use a pointer to an unsigned char or unsigned __int8 to work through the bytes.
void swapBytes(void* number, int bytes_num)
{
unsigned __int8* ptr = number;
for (int i = 0; i<bytes_num/2; i++) {
unsigned __int8 tmp = ptr[i];
ptr[i] = ptr[bytes_num-1-i];
ptr[bytes_num-1-i] = tmp;
}
}
Then call it like this:
swapBytes(&big_number, sizeof(big_number));
Your solution is very over-engineered and also entirely unsuitable for embedded systems such as MPC57xx.
Any integer type can get safely iterated across using a pointer to character. Assuming uint8_t* is a character type for your compiler, it's as simple as this:
void little_to_big16 (uint8_t big [sizeof(uint16_t)],
const uint8_t little [sizeof(uint16_t)])
{
big[0] = little[1];
big[1] = little[0];
}
Then write big_to_little16, big_to_little32 etc etc as needed. Such functions can and should probably be inlined too.
Example of use:
#include <stdio.h>
#include <inttypes.h>
void little_to_big16 (uint8_t big [sizeof(uint16_t)],
const uint8_t little [sizeof(uint16_t)])
{
big[0] = little[1];
big[1] = little[0];
}
int main (void)
{
uint16_t little = 0xAABB;
uint16_t big;
little_to_big16((uint8_t*)&big, (uint8_t*)&little);
printf("%"PRIx16, big);
}
Output on x86 little endian:
bbaa

How to set a static array in a specific memory location

I am running this c program in gcc.
The below works for one variable.
#define dataBlk_tx0 ((volatile unsigned int *) 0x20000ACB)
But if I want to create an array and write to it how would I do this, this array needs to be defined before main?
#define dataBlk_tx0 ((volatile unsigned int * x[8]) 0x20000ACB)
main{
dataBlk_tx0[0] = 5;
}
If you want to read or write directly to that address and memory, you can do it like this:
Initialize dataBlk_tx0 as a pointer to the specific memory location
Access that memory through the pointer.
volatile unsigned int * dataBlk_tx0 = (unsigned int *)0x20000ACB;
int main () {
dataBlk_tx0[0] = 5;
return 0;
}
If you want to create an array in a specific memory region (like Flash vs RAM on a micocontroller), then you'll need to look into linker scripts.

How do I send an array of over the RPC?

I have a bit of a difficulty sending arrays over the RPC using the libtirpc library. Sending primitives during a client-server session is as easy as:
// Client-side boilerplate
struct timeval tout = { 1, 0 };
int in = 42;
clnt_call (cln, 1, (xdrproc_t)xdr_int, (char*)&in,
(xdrproc_t)xdr_void, NULL, tout);
// Server-side boilerplate
int in;
svc_getargs (xprt, (xdrproc_t)xdr_int, (char*)&in);
assert (in == 42);
The xdrproc_t function signature is bool_t (*xdrproc_t) (XDR *, void *, ...);. The xdr_int(3), xdr_long(3) and other primitive serializers have no variable arguments and so they can be used directly using the clnt_call(3) and svc_getargs(3) functions. The xdr_array(3) function used to serialize variable length arrays, however, takes much more arguments:
bool_t xdr_array(XDR *xdrs, char **arrp, unsigned int *sizep,
unsigned int maxsize, unsigned int elsize,
xdrproc_t elproc);
The clnt_call(3) and svc_getargs(3) functions can't really pass these arguments to the functions, so creating wrapper functions seemed like the cleanest solution to the problem:
// Client-side boilerplate
long a = 1, b = 2;
long * arr[] = { &a, &b };
unsigned int amount = sizeof(arr) / sizeof(long*);
bool_t xdr_array_wrapper (XDR * xdr, void * ptr) {
return xdr_array (xdr, ptr, &amount, amount,
sizeof(long), (xdrproc_t)xdr_long);
}
struct timeval tout = { 1, 0 };
long out;
clnt_call (cln, 1, (xdrproc_t)xdr_array_wrapper,
(char*)arr, (xdrproc_t)xdr_long, (char*)&out, tout);
// Server-side boilerplate
long * arr[2];
unsigned int amount = sizeof(arr) / sizeof(long*);
bool_t xdr_array_wrapper (XDR * xdr, void * ptr) {
return xdr_array (xdr, ptr, &amount, amount,
sizeof(long), (xdrproc_t)xdr_long);
}
svc_getargs (xprt, (xdrproc_t)xdr_array_wrapper, (char*)arr);
long a = *arr[0], b = *arr[1];
However, for some unknown reason, only the first element of the array (the variable a) is transferred and the other one contains garbage. What am I doing wrong?
You are using xdr_array incorrectly for two reasons.
It can only handle dynamically allocated arrays.
You are trying to send an array of int* as if it were an array of int.
The correct way of using it goes like this (stolen from IBM and simplified, refer to the link for a more complete treatment):
typedef struct xarray
{
int size;
int *p_array;
} xarray ;
bool_t xdr_xarray(XDR *xdrs, xarray *p_xarray )
{
return xdr_array(
xdrs,
(char**)(&(p_xarray->p_array)),
&(p_xarray->size),
MAX_INT,
sizeof(int),
(xdrproc_t)xdr_int))
}
Note these thinsg:
p_array is a pointer to a dynamically allocated array.
It is an array of int, not of pointers.
We are passing an address of p_array to xdr_array so that on decoding it can allocate an array of the required size and assign it to p_array.
If you want fixed-size arrays you need to use xdr_vector.
typedef struct xvector
{
int vector[42];
} xarray ;
bool_t xdr_xvector(XDR *xdrs, xarray *p_xvector )
{
return xdr_vector(
xdrs,
(char*)p_xvector->vector,
42,
sizeof(int),
(xdrproc_t)xdr_int))
}
Note you still should not use an array of pointers here.
An RPC compiler generates XDR procedures automatically from your data structures, so consider using one.

Reading audio rlp

I am tring to get sound samples from microphone through Fez Panda 2. I am using rlp to accomplish that. Here is my code:
int GHAL_AnalogIn_Read(unsigned char channel)
{
return ((*((int*)(ADC_DATA_BASE_ADDRESS) + channel)) >>8) & 0x3FF;
}
int ReadAudio(unsigned int *generalArray, void **args, unsigned int argsCount ,unsigned int *argSize)
{
unsigned char *buffer = (unsigned char*)args[0];
int buffer_lengh = argSize[0];
unsigned char channel = *(unsigned char*)args[1];
int i=0;
while(i<buffer_lengh)
{
buffer[i] = GHAL_AnalogIn_Read(channel);
i++;
RLPext->Delay(100);
}
return 0;
}
The problem is that I need float values not unsigned char because I'm performing fft on these sound samples. So I need modification that will provide me float values. Any ideas?
Have you got experience with C? Especially with the meaning of * and &? * means: get the value pointed by address. So void ** args says someting like 'get the value pointed by the value obtained from address'. void is used to freely input anything you like. As you can not put whole structures or objects in an argument, you provide the pointer (an address) to a structure or object. By using the * you obtain the value on the address of the argument.
In C you do not pass whole arrays in an argument, you pass on the address of the first index.
Now you could simply re-factor your function to be something like:
int ReadAudio(unsigned int *generalArray, float arg, unsigned int argsCount ,unsigned int *argSize)
But as void **args is pointing to a buffer now, I think you should know what operation you want to perform on the data collected. An analog read will always provide you with an integer, most ADC (analog - digital - converter) are 10-bit or so.
If a float is 4 bytes on a 32-bit system, you want to mangle your data (unsigned char *buffer) in a 4-byte boundary.
EDIT: I have overlooked this in the documentatio: Note: Parameter of all function in RLP code file must have format follow this:Note: Parameter of all function in RLP code file must have format follow this:. Just cast the buffer bytes to a float by 4 byte boundary and I think you will do fine.

Resources