const struct in program memory

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

const struct in program memory

avr-libc-devel
Hello friends.
Tell me, please, can I use constant structures located in the program
memory, as usual, which are located in the RAM?
I tried to use the structure with the PROGMEM modifier, the program is
compiled, but it seems to work incorrectly.

Thank you.

_______________________________________________
AVR-libc-dev mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
Reply | Threaded
Open this post in threaded view
|

Re: const struct in program memory

David Brown-4
You certainly can use PROGMEM (or the newer __flash) on structs in
program memory.  But you need to use the right methods to access the
data.  Can you post a short sample code that you tried but which did not
work?



On 17/06/2019 07:08, avr-libc-devel wrote:

> Hello friends.
> Tell me, please, can I use constant structures located in the program
> memory, as usual, which are located in the RAM?
> I tried to use the structure with the PROGMEM modifier, the program is
> compiled, but it seems to work incorrectly.
>
> Thank you.
>
> _______________________________________________
> AVR-libc-dev mailing list
> [hidden email]
> https://lists.nongnu.org/mailman/listinfo/avr-libc-dev

_______________________________________________
AVR-libc-dev mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
Reply | Threaded
Open this post in threaded view
|

Re: const struct in program memory

avr-libc-devel
> You certainly can use PROGMEM (or the newer __flash) on structs in
> program memory.  But you need to use the right methods to access the
> data.  Can you post a short sample code that you tried but which did not
> work?

typedef struct {
         uint16_t int_part;
         uint8_t frac_part;
         float fl_part;
} __attribute__ ((packed)) bw_data;

const bw_data bw_tab[] PROGMEM;

const bw_data bw_tab[] PROGMEM = {
         [BW_7_8] = { //7.81
                 .int_part = 7,
                 .frac_part = 81,
                 .fl_part = 7.81f,
         },
         .... skip ....
     }

float symbols_time_ms(const param_t *const par, const uint8_t symbols_num){
         float temp;
         temp = 1 << (par->sf + 6); //2^SF
         temp = (float) temp * (float) symbols_num /
bw_tab[par->bw].fl_part;
         return temp;
}

------------------

When I call the function symbols_time_ms (), the result is incorrect if
the PROGMEM modifier is uncommented.
Thank you very much for your answer and attention to my question.

_______________________________________________
AVR-libc-dev mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
Reply | Threaded
Open this post in threaded view
|

Re: const struct in program memory

David Brown-4

On 17/06/2019 09:38, avr-libc-devel wrote:

>> You certainly can use PROGMEM (or the newer __flash) on structs in
>> program memory.  But you need to use the right methods to access the
>> data.  Can you post a short sample code that you tried but which did
>> not work?
>
> typedef struct {
>          uint16_t int_part;
>          uint8_t frac_part;
>          float fl_part;
> } __attribute__ ((packed)) bw_data;


(This is just incidental advice, and not related to you problem.

I recommend never using the "packed" attribute.  It rarely helps (and
should make no difference on the AVR), and can often result in
significantly less efficient code.  Only use it if you /really/ need it,
and need to be sure on identical layouts on widely different target
processors.  Even in such cases, I would prefer to manually add dummy
padding members to make everything naturally aligned (here that would be
a "uint8_t dummy" after "frac_part") and use gcc's "-Wpadded" warning to
let you know if you've got things wrong.)

>
> const bw_data bw_tab[] PROGMEM;
>
> const bw_data bw_tab[] PROGMEM = {
>          [BW_7_8] = { //7.81
>                  .int_part = 7,
>                  .frac_part = 81,
>                  .fl_part = 7.81f,
>          },
>          .... skip ....
>      }
>
> float symbols_time_ms(const param_t *const par, const uint8_t symbols_num){
>          float temp;
>          temp = 1 << (par->sf + 6); //2^SF
>          temp = (float) temp * (float) symbols_num /
> bw_tab[par->bw].fl_part;
>          return temp;
> }
>

When giving sample code for a problem like this, try to keep it short
and valid - this function is too complicated, and involves different
variables and types.

Let's just use the simplified function :

float get_fl_part(const bw_data * par) {
        float temp = par->fl_part;
        return temp;
}


This is wrong.

PROGMEM tells the compiler to put the data (bw_tab here) in flash
memory.  On the AVR, flash is accessed with different instructions from
ram (and IO registers).  So if you have told the compiler to put the
data in flash, you have to tell it to read the data from flash:

float get_fl_part(const bw_data * par){
          float temp = pgm_read_float(&par->fl_part);
          return temp;
}

Yes, this is a little awkward and inconvenient.  But you have to do it.

The reason the program worked when you omitted the PROGMEM on bw_tab is
that the table is then allocated in ram, and initialised at startup.
For smaller tables, or if you are not using the ram for anything else,
this is the most convenient and efficient method.  But you must be
consistent - either PROGMEM on definitions and "pgm_read_" functions in
use, or omit both.


Newer gcc versions also support the "__flash" address space.  This lets
you write:

const __flash bw_data bw_tab[] = {
          [BW_7_8] = { //7.81
                   .int_part = 7,
                   .frac_part = 81,
                   .fl_part = 7.81f,
           },
           .... skip ....
       }

float get_fl_part(const __flash bw_data * par){
          float temp = par->fl_part;
          return temp;
}

Much nicer.  But again, be consistent!


> ------------------
>
> When I call the function symbols_time_ms (), the result is incorrect if
> the PROGMEM modifier is uncommented.
> Thank you very much for your answer and attention to my question.
>

No problem.


_______________________________________________
AVR-libc-dev mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev
Reply | Threaded
Open this post in threaded view
|

Re: const struct in program memory

avr-libc-devel
> I recommend never using the "packed" attribute.  It rarely helps (and
Thanks, I will consider it. In general, I know this, I'm just
experimenting :)

> PROGMEM tells the compiler to put the data (bw_tab here) in flash
> memory.  On the AVR, flash is accessed with different instructions from
> ram (and IO registers).  So if you have told the compiler to put the
> data in flash, you have to tell it to read the data from flash:

> Newer gcc versions also support the "__flash" address space.  This lets
Thank :)
I have an understanding of the features of addressing memory in the AVR
family and access to them, but thanks anyway for an explanation - I was
not mistaken :) I was wondering if the compiler for AVR microcontrollers
can address the elements in the program memory without a significant
change in the code semantics . Thanks to your explanation about the
__flash modifier, I saw that yes, it could. It really works.

Thank you very much for your attention and time spent, have a nice day!

_______________________________________________
AVR-libc-dev mailing list
[hidden email]
https://lists.nongnu.org/mailman/listinfo/avr-libc-dev