Pointer increment problem

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

After i load OCR1a i need lcg_ptr to inc and point to next address, but i can't do it. The *.lss code shows beginning address of ptr[], NOT lcg_ptr. It would work on 1st pass, but wouldn't index thru the ptr array on further looping passes. I also don't get why the compiler's not using the address for lcg_ptr.

I'm using winavr 20090313

#define   big   50

uint8_t   ptr[big], *lcg_ptr;
void   main ( void )
{

lcg_ptr = ptr;
.
.
.

OCR1A = *(uint16_t *)lcg_ptr++;

.
.
.

}

*.LSS
{ OCR1A = *lcg_ptr++;}
 1ce:	80 91 67 00 	lds	r24, 0x0067
 1d2:	90 e0       	ldi	r25, 0x00	; 0
 1d4:	9b bd       	out	0x2b, r25	; 43
 1d6:	8a bd       	out	0x2a, r24	;

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are seriously unwise mixing datatypes.

I am guessing that you have a table of 8 bit values:

uint8_t ptr[big] = { 1, 2, 3, 4, ... };

and that you want to set the 16bit wide OCR1A to each value in turn.

OCR1A = *lcg_ptr++;

The compiler will look after the proper setting of OCR1AH and OCR1AL. And your pointer will be ready for the next pass.
Remember that compilers are clever. If you have an ambiguous looking expression. Split into individual statements. The optimiser will re-create an efficient sequence.

If your table is actually 16bit wide, say so:

uint16_t *lcg_16, ptr16[big] = { 1234, 2345, 3456, 7890, ... };
...
OCR1A = *lcg_16++;

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry, the previous *.lss was from trying a differnet code snip. Correct code's below. The table has 8 bit pseudo random numbers.

 *.lss
OCR1A = *(uint16_t *)lcg_ptr++;
 20c:	80 91 65 00 	lds	r24, 0x0065
 210:	90 91 66 00 	lds	r25, 0x0066
 214:	9b bd       	out	0x2b, r25	; 43
 216:	8a bd       	out	0x2a, r24

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

dear Indiana,

I have no idea what your *.lss means. You do not even bother to say which AVR you are using.

Perhaps if you say what you want to do, I can be of more assistance.

Your current C is going to load 0x0201, 0x0302, 0x403 for each pass. Is this what you want?

Again. Why not write unambiguous C:

OCR1A = ptr[index++];  // fetch each uint8_t from the array

Once you make it clear what you want to do, you may re-arrange with the use of a static pointer.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I generate 50 8 bit PRNs and then load adjacent pairs into OCR1A. I'm using a tiny2313, and the *.lss is loading the 1st pair of #s from RAM address $65 - $66
( but w/o the needed increment ).

I guess I'll have to declare lcg_ptr as 16 bit ptr, but the 'cast I used should've worked ( incremented after each load ), if it's a correct typecast right?

Summarizing:

1) address for ptr[]( 0x65 ) is used, when it should be lcg_ptr's address ( 0x9B ) ( see 1st post. ).

2) No increment when it should.

Quote:
Your current C is going to load 0x0201, 0x0302, 0x403 for each pass. Is this what you want?
Nope, and it will NOT generate those #s.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So you seriously do have an array of uint8_t
And you want to access element 1,0 then 2,1 then 3,2 ... into the 16 bit OCR1A. e.g.

OCR1AH = ptr[index+1];   // high byte
OCR1AL = ptr
; // low byte index++; // ready for next pass.

Yes you can do the same thing with a pointer that is:

lpc_ptr = &ptr
; // initialise at some stage ... OCR1A = *((uint16_t *)lpc_ptr); //read 16 bits from here lpc_ptr++; // increment 8 bit pointer

Completely untested by me. But you can write the first version and see what the compiler produces. Then verify that the second version has the same effect.

The Simulator will count the clock cycles for you. I would guess that you may get swifter code from the second version. But I would be very surprised if it makes any difference if you put all your operations in one single unholy C expression:

OCR1A = *((uint16_t *)lpc_ptr++);

I can see no reason for using complicated expressions unless you just want to impress your colleagues.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
After i load OCR1a i need lcg_ptr to inc and point to next address, but i can't do it. The *.lss code shows beginning address of ptr[], NOT lcg_ptr. It would work on 1st pass, but wouldn't index thru the ptr array on further looping passes. I also don't get why the compiler's not using the address for lcg_ptr.

I'm using winavr 20090313

#define   big   50

uint8_t   ptr[big], *lcg_ptr;
void   main ( void )
{

lcg_ptr = ptr;
.
.
.

OCR1A = *(uint16_t *)lcg_ptr++;

We haven't seen enough of your code or its results
to know what should have happened or what did.
We can't even tell if the second assignment was in a loop.
The indentation level suggests not.
Note that you are using post increment.
lcg_ptr does get incremented,
but its new value does not affect the value of the assignment.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

lcg_ptr does get incremented

Michael,

I think his issue was that (because the pointer is fundamentally defined as pointer to unsigned char) that it was only incremented by 1 byte and not the 2 the OP had hoped for by the (uint16_t*) cast (as we know this only affects the read through the pointer, not the increment the OP had hoped).

But I think David hit the nail on the head when he said:

Quote:
I can see no reason for using complicated expressions unless you just want to impress your colleagues.

This kind of attempted "cleverness" aggravates code maintainers!

If the intention is to increase a byte pointer by 2 bytes I don't see what's wrong with:

lgc_ptr += 2; // step on a whole word

But one mystery here is that if this data is always to be used in 16bit chunks why isn't it a unit16_t array in the first place and the pointer (if access is to be by pointer rather than array index) isn't a uint16_t* ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Quote:

lcg_ptr does get incremented
I think his issue was that (because the pointer is fundamentally defined as pointer to unsigned char) that it was only incremented by 1 byte and not the 2 the OP had hoped for by the (uint16_t*) cast (as we know this only affects the read through the pointer, not the increment the OP had hoped).
The claim was that it wasn't incremented at all.
Quote:
But I think David hit the nail on the head when he said:
Quote:
I can see no reason for using complicated expressions unless you just want to impress your colleagues.

This kind of attempted "cleverness" aggravates code maintainers!
I agree, but others had already written it.
Such cleverness, even when useful, should at least be commented.
Quote:
If the intention is to increase a byte pointer by 2 bytes I don't see what's wrong with:

lgc_ptr += 2; // step on a whole word

But one mystery here is that if this data is always to be used in 16bit chunks why isn't it a unit16_t array in the first place and the pointer (if access is to be by pointer rather than array index) isn't a uint16_t* ?

I think the intent was to use most bytes twice,
once as a high byte and once as a low byte.
The OP has not been terribly clear.
Another mystery is why he named an array "ptr".
I'd do something less clever.
for(j=...; ++j) {
    ...
    OCR1A=array[j]+0x100*array[j+1];
    ...
} // j

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I learned that,

OCR1A = *lcg_ptr++; // Declared as a 16 bit ptr.

Is equal to :

*(uint16_t *)lcg_ptr; lcg_ptr += 2;

For this app., I can use the 16 ptr. version as the array values are only used in above manner. But what if the app. needed to access the 8 bit values at another stage ( so needing an 8 bitter )? Casting 16bit ptr down to an 8 bitter would work, but i wanted to see if it could be done casting up ( i'm a rookie at using pointers and it was a good learning exercise, w/ all your help ). The array has to be 8 bit ( A 16 bit LCG to get my PRNs gives 32 bit result generally, and i anticipate getting close enough to the program memory edge already).

Quote:
We haven't seen enough of your code or its results to know what should have happened or what did.

These are the only places where it's used, and I see that there IS an "increment" as 0x66 gets read from via the cast ( so my post-inc is redundant ). Thanks for showing me that. When i thought it wasn't inc. by 1, i saw no reason to try for the needed increment by 2 ( Have mercy :roll: ).

Quote:
...not the 2 the OP had hoped for by the (uint16_t*) cast (as we know this only affects the read through the pointer, not the increment the OP had hoped).

I know the cast only affects the read.. I'm not that big of a rookie. On the aggravation / cleverness issue, if more experienced programmers say such expressions aren't good practice, then that's the 2nd thing I learned from this.

thank you.

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
uint8_t table[BIG];             // for some obscure reason
uint16_t *lpc_ptr;              // but we access as 16bit

lpc_ptr = (uint16_t *)table;    // initialise at some stage
...
OCR1A = *lpc_ptr++;             //read 16 bits from here

The obvious question is: "Why not call the table a table of uint16_t's in the first place ?"

uint8_t *lpc8_ptr;              // but we access as 8bit
lpc8_ptr = table;                // initialise at some stage

Surely these two examples are fairly clear and straightforward?

C allows you to perform all sorts of monstrosities. And sometimes they may be justified. But it is wise to COMMENT exactly what you are trying to achieve. And if you use array notation, that is fine. Humans find array access easier to understand than dereferenced pointers.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why it's an 8 bit array instead of 16: I'd have to do a 16 x 16 = 32 bit ( generally, depending on seed value ),
then I'd have to cast down result to 16 bits ( I'd be using program memory that i need for other things, including near future feature additions ).

Quote:
Humans find array access easier to understand than dereferenced pointers.
Yeah, that's why I've put off using that stuff for so long. But i hear it's more efficient, so I'm suffering the slings and arrrows of it.

jerome

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:
For this app., I can use the 16 ptr. version as the array values are only used in above manner. But what if the app. needed to access the 8 bit values at another stage ( so needing an 8 bitter )?
Read your data as bytes and do the math.
Quote:
Quote:
We haven't seen enough of your code or its results to know what should have happened or what did.

These are the only places where it's used, and I see that there IS an "increment" as 0x66 gets read from via the cast ( so my post-inc is redundant ).
The only places where what gets used?
I got the impression that some of the posted code was inside a loop.
We never saw the loop.

Iluvatar is the better part of Valar.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

indianajones11 wrote:

Quote:
Humans find array access easier to understand than dereferenced pointers.
Yeah, that's why I've put off using that stuff for so long. But i hear it's more efficient, so I'm suffering the slings and arrrows of it.

jerome


You should have more confidence in your compiler. If you write unambiguous code, it will generate efficient ASM.

It is also handy to realise that writing ptr[0] is exactly the same as *ptr. So write your C in as humanly understandable language in the first place.

By all means inspect the generated code for size. This just means noting the report at the end of a build.

If you were unsure of your gobbledygook expression, then you cannot be sure what the compiler will make of it. The compiler will just do what you ask, not what you intend.

Yes. There are occasions when dereferencing is needed. I put them in macros.

#define eeprom_read_byte(ads)	(*((uint8_t eeprom *)(ads)))
#define eeprom_write_byte(ads,x) (*((uint8_t eeprom *)(ads))) = x
#define eeprom_write_word(ads,x) (*((uint16_t eeprom *)(ads))) = x

Once you discover that you need a cast to stop a Compiler whinging, it is time to look to see what you are doing wrong in the first place.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But i hear it's more efficient, so I'm suffering the slings and arrrows of it.

You think so do you? Consider:

#include 

uint8_t vals1[] = { 1, 29, 54, 86, 217, 38, 2, 176 };
uint8_t vals2[] = { 8, 96, 144, 12, 19, 207, 48, 3 };

int main(void) {
	uint8_t i;
	uint8_t *ptr;
	for (i=0; i<8; i++) {
		PORTB = vals1[i];
	}
	ptr = vals2;
	for (i=0; i<8; i++) {
		PORTB = *ptr++;
	}
}

The first loop:

  82:	e4 e6       	ldi	r30, 0x64	; 100
  84:	f0 e0       	ldi	r31, 0x00	; 0
  86:	81 91       	ld	r24, Z+
  88:	88 bb       	out	0x18, r24	; 24
  8a:	80 e0       	ldi	r24, 0x00	; 0
  8c:	ec 36       	cpi	r30, 0x6C	; 108
  8e:	f8 07       	cpc	r31, r24
  90:	d1 f7       	brne	.-12     	; 0x86 

the second loop:

  92:	ec e6       	ldi	r30, 0x6C	; 108
  94:	f0 e0       	ldi	r31, 0x00	; 0
  96:	81 91       	ld	r24, Z+
  98:	88 bb       	out	0x18, r24	; 24
  9a:	80 e0       	ldi	r24, 0x00	; 0
  9c:	e4 37       	cpi	r30, 0x74	; 116
  9e:	f8 07       	cpc	r31, r24
  a0:	d1 f7       	brne	.-12     	; 0x96 

This looks like one of those "spot the difference" competitions.

(I only used two data arrays because otherwise the second loop just relied on the setup from the first (it just subtracted 8 from Z to return to the start of the data)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

But i hear it's more efficient

Please note that array notation is only syntactic sugar for pointer arithmetic anyway. It's late and I'm kind'a tired so there might be some slip in the details but it goes like this:

Doing an access with array notation like so

a[i]

is actually just another notation for

*(a+i)

The fun part, and also a bit of a proof that the array notation is only syntactic sugar is that

i) for the pointer notation the commutative law of-course holds so you could just as well write

*(i+a)

but ii) this actually leads to that you can use the array notation like so

i[a]

and actually get the same result as from a[i]. (I've pointed [1] this out before here on 'freaks, but I fint this both fun and enlightening, so when the subject comes up I'll iterate...)

So... I'd be surprised if pointer arithmetic notation would be more efficient than array notation.

[1] Lovely pun, ehhhh?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
The only places where what gets used?
I got the impression that some of the posted code was inside a loop. We never saw the loop.

I had no issue w/ the rest of the loop and I don't like wasting freaky peoples' valuable time going thru code that's good.I've always READ about pointers over array notation, but just shows you can't believe everything you read.

Here's an example of where I get this pointer supremacy from: http://www.bores.com/courses/int...

thanks for the real deal schoolin'.

jerome

1) Studio 4.18 build 716 (SP3)
2) WinAvr 20100110
3) PN, all on Doze XP... For Now
A) Avr Dragon ver. 1
B) Avr MKII ISP, 2009 model
C) MKII JTAGICE ver. 1

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But the example on that page is more complex than what you are doing. The compiler is far more likely to have to calculate the address of the element each loop. In your code it is easy for the optimizer to see that sequential elements are being accessed.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To Johan Ekdahl :
I guess that I should add that i has to be of same type as *a ! (else some need for type casting)