Internal Flash accesses

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

Hi all,
i'm converting CodevisionAVR project to AVR Studio + WinAVR one.
My current problem is to convert internal flash accesses with a different syntax.

I defined the variable:
__flash unsigned char qn10[]= { 0, 10, 10,
0x03,0xFF, ....... };

I defined __flash as
#define __flash PROGMEM

I see the variable in *.lss file as:
*(.progmem*)
.progmem.data 0x000000b2 0x2ba main.o
0x000000b2 img
0x00000355 qn10

I make accesses as:
debug_hex(pgm_read_byte(image[0]));
debug_hex(pgm_read_byte(image[1]));
in a function that receives 'qn10' into 'image'.

but i read wrong values.
Printing &image i see 0x0355, confirming *.lss data.

How must i define 'image'? Right now is '(unsigned char const image[])'.

Where is my error(s)?

Thanks a lot!
Regards.

SteM

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

pgm_read_byte(&image[0])

instead of

pgm_read_byte(image[0])

just a quick guess (although I'm not sure I understand exactly what you are asking- I'm unsure of how qn10[]->image[])

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

yes !!
what a dummy :oops:
image[0] is no more a pointer !

now i use
pgm_read_byte(image+0)
pgm_read_byte(image+1)
pgm_read_byte(image+2)

and it works as expected.

Thanks!

SteM

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

Pointer arithmetic is usually frowned upon, I think you'll find. curtvm's example of just grabbing the address of the array element is stylistically more appropriate.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

abcminiuser wrote:
Pointer arithmetic is usually frowned upon,

On which planet is it frowned upon exactly?

Personally I think:

pgm_read_byte(image+0) 
pgm_read_byte(image+1) 
pgm_read_byte(image+2)

looks more "stylish" than:

pgm_read_byte(&image[0]) 
pgm_read_byte(&image[1]) 
pgm_read_byte(&image[2])

(don't ask why I'm using this ID ;) )

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

Quote:

On which planet is it frowned upon exactly?

Cliff,

I think that using C's array features are a good thing, and pointer arithmetic should only be used when necessary. My personal reasoning is that by using the array method you make your code independent of the size of each array method, unlike the arithmetic code. I realize that it's moot-point with the read_byte command, but I like to stick to what I think is "good practice".

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I'm not quite sure what you mean by

Quote:
My personal reasoning is that by using the array method you make your code independent of the size of each array method, unlike the arithmetic code.

But as far as the C-compiler is concerned the two methods are ident.
You do have a point once you move to C++ and away from C-arrays, where you could overwrite operator[] for a given class. But for a regular arrays - there is no difference (literally). In fact, that's the reason why there is pointer arithmetic.
I say: as long as you don't cast your pointers, you can use pointer arithmetic all you want.

Have fun,
Markus

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

Quote:

I'm not quite sure what you mean by

Whoops, that should have read "...of the size of each array element...". What I was getting at is that say you have a ringbuffer with the following globals:

int Index
char BuffData[20]

And the store code is like the following:

void StoreData(char Data)
{
   // ...
   BuffData[Index++] = Data;
   // ...
}

That works fine, even when you later decide you need to expand the size of the data being stored to a long (for instance). However, the same is not true for pointer arithmetic - you loose the implicit "sizeof(BuffData[0])" multiplier on the index, and so you'll be storing to the incorrect locations. The alternative would be to include the sizeof yourself:

void StoreData(char Data)
{
   // ...
   *(BuffData + (sizeof(BuffData[0]) * Index++) = Data;
   // ...
}

But that makes it harder to read than the array version, and you gain nothing.

Pointer arithmetic most certainly has its place, I'm not arguing against that. I'm arguing against its use to access array elements when a the more robust (as far as code refactoring is concerned) array version above would suffice.

- Dean :twisted:

PS: This comes down to a matter of style, and everyone will have a different opinion. Sorry I brought it up and took the thread off-topic!

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

I do not want to upset the applecart but:

if you alter the type of BuffData to an array of longs, then saying BuffData{index++] = longvalue; will work correctly.

If you want to store a long in a char array, then you have to cast appropriately and calculate the correct place in the char array. And preferably comment your code for reference.

Since this thread started with how to access flash, you have the CodeVision approach where the array is accessed in sourcecode as if it was regular memory.

With the avr-gcc approach with the PROGMEM macro you have to calculate yourself. Just horses for courses.

David.

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

I tend to blow with the wind on this one. Sometimes I access array data by index and sometimes by pointer. Would you concede, for example that strcpy() is better implemented as:

void strcpy(char *dest, char *src) {
  while (*src) {
    *dest++ = *src++;
  }
}

rather than the array index version:

void strcpy(char dest[], char src[]) {
  uint16_t i;
  for (i=0; i<(strlen(src)+1); i++) {
    dest[i] = src[i];
  }
}

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

Dean,

Quote:
That works fine, even when you later decide you need to expand the size of the data being stored to a long (for instance). However, the same is not true for pointer arithmetic - you loose the implicit "sizeof(BuffData[0])" multiplier on the index, and so you'll be storing to the incorrect locations.

But that's not how pointer arithmetic works. The two operands:

BufferArray[ Index++ ]
*(BufferArray + Index++)

Are exactly the same, no matter what the element type BufferArray has. Give it a shot, compile the following code and check the assembler output for different types:

int Index1, Index2;
char BufferArray[20];


void StoreData1( char Data) {
  BufferArray[Index1++] = Data;
}

void StoreData2( char Data) {
  *(BufferArray + Index2++) = Data;
}

Have fun,
Markus

PS: Once you opened the can ... ;)

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

Markus,

Quote:
Are exactly the same, no matter what the element type BufferArray has. Give it a shot, compile the following code and check the assembler output for different types:

I was quite ready to proove you wrong, and even wrote up a simple test. Well bugger - seems you're quite correct! I never knew that C would take care of the size of the array type when dealing with pointer arithmetic.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

From wikipedia (I know, I know...)

"Adding or subtracting from a pointer moves it by a multiple of the size of the datatype it points to. For example, adding 1 to a pointer to 4-byte integer values will increment the pointer by 4. This has the effect of incrementing the pointer to point at the next element in a contiguous array of integers -- which is often the intended result."

"In particular, the C definition explicitly declares that the syntax a[n], which is the n-th element of the array a, is equivalent to *(a+n), which is the content of the element pointed by a+n."

Winner of the "Least Original Post" award.

- jason

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

Dean,

You want to be careful, a fairly common job interview question is:

uint32_t *ptr = (uint32_t *) 0x14FC;
ptr += 3;
what is the value in 'ptr' now?

If you answer 0x14FF you don't get the job :(

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

Quote:
Jason, Cliff

Yes yes, I see now - brain fart! I was thinking of when you play with offsets from the address of a variable, which I believe is different. I've seen your example Cliff and my silly mistake above indicates why I'm still at uni learning and not out in the field just yet ;). Thanks for the standards references.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

clawson wrote:

question is:
uint32_t *ptr = (uint32_t *) 0x14FC;

If you had written uint32_t *ptr = (uint32_t *) 0x14FB;

I might have answered "Alignment error" , on many cpu's :-)

/Bingo

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

Bingo,

Ah yes, I was very careful about picking my example to be a multiple of 4 as I spend a lot of my life working with ARMs and MIPS4000. (you get alignment exceptions quite often during development if you get your pointer maths incorrect!)

Cliff

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

So really, pointer arithmetic is not so much "frowned upon", as it is "you had better know what you're doing". :)