C pointers help

Hi,

I am communicating with a stack of 3 SPI boards in a daisy-chain configuration. Most of it is working but sending more than single byte commands is loosing the following data bytes. Some debugging has shown that I'm stamping on the tx buffer with writing to the rx buffer.

Looks like I messed up some pointer arithmetic in setting up the buffers.

// combine Tx and Rx arrays, set Rx pointer half way. 

#define BYTES  (4)

uint8_t spiTxBuffer[2*SPI_BYTES][3];
uint8_t ( *spiRxBuffer ) [3] = spiTxBuffer +2;

Initially I had two separate buffers but I attempted to combine them in order to zero both buffers with a single memset(). There were many places where this was done some of which were in a critical code path. It also saved quite a bit of code space in an arduino that is full to the brim.

 memset(spiTxBuffer,0,sizeof(spiTxBuffer));

I am not looking for comments like I should not be doing it anyway. There may be other solutions. What I need to understand is how to use pointers in C which I find totally arcane. Despite lots of searching and reading, just about everything I thought was valid refused to compile. Thus compiles but apparently does not do what I intended.

The object was to have one contiguous buffer. The first half of which serves as tx buffer, the latter half as rx buffer. I need a pointer to the half way point that I can use to access the rx buffer , byte by byte.

uint8_t spiTxBuffer[2*SPI_BYTES][3];             // An 2D array with 8 rows, 3 columns of uint8_t
uint8_t ( *spiRxBuffer ) [3] = spiTxBuffer +2;  // An array of 3 pointers to uint8_t, with a bogus initializer
uint8_t buffer[2][SPI_BYTES];    // A 2D array with 2 rows, SPI_BYTES columns
uint8_t *spiTxBuffer = Buffer[0];   // Pointer to Tx buffer
uint8_t *spiRxBuffer = Buffer[1];   // Pointer to Rx buffer

// Clear both buffers to zeroes
for (uint8_t i=0; i<SPI_BYTES; i++)
{
    spiTxBuffer[i] = 0;
    spiRxBuffer[i] = 0;
}

Regards,
Ray L.

but I attempted to combine them in order to zero both buffers with a single memset().

That's a pretty lame reason.

Making the buffer twice as long would have been a much better idea that making it 2D.

The object was to have one contiguous buffer. The first half of which serves as tx buffer, the latter half as rx buffer.

You need to understand how arrays are arranged in memory before you can think of what "half a buffer" is. As I mentioned above, what you are trying to do is so much simpler with two arrays. Second would be one array twice as long.

uint8_t spiTxBuffer[2*SPI_BYTES][3];             // An 2D array with 8 rows, 3 columns of uint8_t

Thanks Ray but you've lost one dimension of the arrays. I need two buff [4][3] arrays.

Making the buffer twice as long would have been a much better idea that making it 2D.

That's what I did !

As I mentioned above, what you are trying to do is so much simpler with two arrays.

It is so much simpler that is the way I originally did it. But I need to save space and minimise executions time as I explained.

Now do you have anything that relates to understanding pointers and a solution.

Ray , I assume that buffer and Buffer was a typo but having corrected that it fails to compile the lines defining the pointers

error: conflicting types for 'spiTxBuffer'

Untested.

uint8_t spiTxBuffer[2*SPI_BYTES][3];
uint8_t *spiRxBuffer = &spiTxBuffer[SPI_BYTES][3];

aarg: Untested.

uint8_t spiTxBuffer[2*SPI_BYTES][3];
uint8_t *spiRxBuffer = &spiTxBuffer[SPI_BYTES][3];

Thanks, arrg. Same error.

Okay, try this.

uint8_t spiTxBuffer[2*SPI_BYTES][3];
uint8_t *spiRxBuffer[][] = &spiTxBuffer[SPI_BYTES][3];

By the way, if you include memset(), only one copy is loaded and calling it multiple times will consume only a few bytes of memory each time.

error: array type has incomplete element type

:(

define BYTES (4)

did you mean:

define SPI_BYTES (4)

and I messed up another thing, so:

uint8_t spiTxBuffer[2*SPI_BYTES][3];
uint8_t *spiRxBuffer[][] = &spiTxBuffer[SPI_BYTES][0];

I hate pointers.

#define SPI_BYTES  (4)
uint8_t spiTxBuffer[2*SPI_BYTES][3];
uint8_t* spiRxBuffer = &spiTxBuffer[SPI_BYTES][0];

Hey, I'm on my first coffee.

error: conflicting types for 'spiRxBuffer'

Me too. This is the game I went through when I did this.

It seems that the "&" operator is unnecessary since the compiler guesses what you probably wanted to do if you leave it out. Even though that is syntactically inconsistent.

C pointers are obtuse to start with. Inconsistent syntax does not help.

Sorry arrg, those errors were because I had the old delcarations in the .h file too. Adding the extra dimension to Ray's suggested format does at least compile. Though it is now throwing errors in the rest of the code. I'll see whether I can chase those out now.

uint8_t buffer[2][SPI_BYTES][3];    // 
uint8_t *spiTxBuffer = buffer[0][0];   // Pointer to Tx buffer
uint8_t *spiRxBuffer = buffer[1][0];   // Pointer to Rx buffer

ardnut: But I need to save space and minimise executions time as I explained.

Try to understand that just because it takes you less lines to write doesn't necessarily make it shorter or more efficient code. If you want to talk about shorter or more efficient then you have to understand exactly what the code you are writing compiles to. In this case, I doubt calling memset twice vs once is creating any substantial extra overhead. It's really just an extra line of typing. Those don't cost anything.

error: conflicting types for ‘spiRxBuffer’

Check again, it compiled with no errors here. I believe it is mandatory to use the “&” in this case, or you are referencing a uint_t8 element of the array, instead of the address. The compiler can’t read your mind.

Delta_G: Try to understand that just because it takes you less lines to write doesn't necessarily make it shorter or more efficient code. If you want to talk about shorter or more efficient then you have to understand exactly what the code you are writing compiles to. In this case, I doubt calling memset twice vs once is creating any substantial extra overhead. It's really just an extra line of typing. Those don't cost anything.

+1, and straightforward methods are less error prone.

Sound advice Delta.

I did look at compiled object size. I got 90 bytes down to about 27 IIRC. ( more than the saving in typed source code ;) ).

The compiler did not seem able to merge the two calls to memset() and I did not expect it too. These are global variables and using two different pointers probably means a lot of messing around. I did not bother looking at the disassemble to find out exactly why but the saving was useful.

Check again, it compiled with no errors here. I believe it is mandatory to use the "&" in this case, or you are referencing a uint_t8 element of the array, instead of the address. The compiler can't read your mind.

Indeed, it can't . It just sometimes tries to. This kind of pointless inconsistency just makes the whole thing more opaque.

I'm not sure which "it" you managed to compile. Check my most recent posts. I added an extra dimension to Ray's suggestion and it compiled.

The problem now is that I no longer have pointers to a 2D [4][3] array of int but pointers to a simple int.

spiTxBuffer[1] = (uint8_t)(value >> 16); ``` error: subscripted value is neither array nor pointer nor vector ``` What I need is pointers to two 2D arrays, not int pointers.

The "it" that compiled (and I believe should work), is reply #11.