Go Down

Topic: What does the F() do exactly? (Read 8405 times) previous topic - next topic


mkwired

It seems you found a bug in the Arduino code.  Here's the fix.  Make the following change to WString.h.

Code: [Select]

class __FlashStringHelper;
//#define F(string_literal) (reinterpret_cast<__FlashStringHelper *>(PSTR(string_literal)))
#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))

kb3dow

Yes, that appears to fix it. It compiles and I'll test it at home later tonight.

Thank you very much.

mkwired

I have posted a bug report to the Arduino team.

http://code.google.com/p/arduino/issues/detail?id=866

kb3dow

Another question with the F() macro, now that I have it working. The following code fails to compile

struct some_table{
    char *name;
    int val;
} arrary[] = {
    { F("a"), 0},
    { "b", 1}
};

The compiler says
  tst.cpp:31:7: error: statement-expressions are not allowed outside functions nor in template-argument lists
Maybe I should try using the flash library and use a variable to hold that string in PROGMEM

mkwired

Do you really need to store data in FLASH?  Doing so isn't "free."  You will pay a performance penalty in terms of the time it takes to read from FLASH as well as the complexity in terms of the code necessary to access FLASH.

Nick Gammon



Serial << F("This is a test string");


Try
Serial.print( F("This is a test string") );
or
Serial.println( F("This is a test string") );


On my copy of the Arduino 1.0 IDE this code:

Code: [Select]
#include <Streaming.h>

void setup ()
{
  Serial << F("This is a test string");
  Serial.println( F("This is a test string") );
}
void loop () {}


Gives no errors:

Code: [Select]
Binary sketch size: 1716 bytes (of a 32256 byte maximum)

Works on both OS/X and Windows XP versions.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

mkwired

Nick, he's not using the same compiler.

Nick Gammon


Do you really need to store data in FLASH?  Doing so isn't "free."  You will pay a performance penalty in terms of the time it takes to read from FLASH as well as the complexity in terms of the code necessary to access FLASH.


It's not that bad. In terms of time, the processor can read flash memory quickly. After all, it is getting instructions from it at the rate of a byte every clock cycle. Compare:

Flash "strcpy":

Code: [Select]
000000be <strcpy_P>:
  be: fb 01        movw r30, r22
  c0: dc 01        movw r26, r24
  c2: 05 90        lpm r0, Z+
  c4: 0d 92        st X+, r0
  c6: 00 20        and r0, r0
  c8: e1 f7        brne .-8      ; 0xc2 <strcpy_P+0x4>
  ca: 08 95        ret


To normal "strcpy":

Code: [Select]
000000cc <strcpy>:
  cc: fb 01        movw r30, r22
  ce: dc 01        movw r26, r24
  d0: 01 90        ld r0, Z+
  d2: 0d 92        st X+, r0
  d4: 00 20        and r0, r0
  d6: e1 f7        brne .-8      ; 0xd0 <strcpy+0x4>
  d8: 08 95        ret


The only difference is changing "ld" to "lpm". The LPM instruction takes 3 clock cycles compared to 2 for LD. So, you lose one clock cycle (62.5 nS) per byte copied.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

ninja2

Nick, How did you reveal that assembler code?

Nick Gammon

Get verbose output from the compiler (check box in Preferences under Arduino 1.0).

About the second last line will be a .elf file. Copy its entire filename.

Go to a command / console window and type:

Code: [Select]
avr-objdump -S whatever.elf > foo.txt

The output file (foo.txt) will have the disassembly in it.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

ninja2


nicocarv

Hi everybody,

I'm trying to copy a string from the flash memory to a char[] variable. But because of the __FlashStringHelper * type I don't know how to do it.

Any idea?

I'm working on a Web Server with a table which I have to construct on each iteration (see code below). But I don't want to send the string and numerical information separately because of the TCP overhead. So instead, I would like to store and concatenate the info in a fixed size buffer and when full, send it.

I already posted a thread about it (without flash memory) http://arduino.cc/forum/index.php/topic,103110.0.html and I have good performance for a buffer of 60 bytes. But because I'm running out of memory I need to store the HTML code in the flash memory.

I'm having error because of the different types. I need a way to copy the flash values to RAM values.

Tnx!!

Code: [Select]
const int Buffer_length = 90;
char buffer[Buffer_length];
int TempTable[5][5];

void SecondTable(EthernetClient client)
{
for (int i = 1; i < 5; i++) {
  int i=1;
  printI(i,client);
  printC(F("</td><td align='center'><input type='text' name='Block"),client);
  printI(i,client);
  printC(F("1' value='"),client);
  printI(TempTable[i-1][0],client);
  printC(F("' size='2' maxlength='2'/>: <input type='text' name='Block"),client);
  printI(i,client);
  printC(F("2' value='"),client);
  printI(TempTable[i-1][1],client);
  printC(F("' size='2' maxlength='2'/></td><td align='center'><input type='text' name='Block"),client);
  printI(i,client);
  printC(F("3' value='"),client);
  printI(TempTable[i-1][2],client);
  printC(F("' size='2' maxlength='2'/>: <input type='text' name='Block"),client);
  printI(i,client);
  printC(F("4' value='"),client);
  printI(TempTable[i-1][3],client);
  printC(F("' size='2' maxlength='2'/></td><td align='center'><input type='text' name='Block"),client);
  printI(i,client);
  printC(F("5' value='"),client);
  printI(TempTable[i-1][4],client);
  printC(F("' size='2' maxlength='2'/></td></tr>"),client);
  }

void printI(int num, EthernetClient client){
  if (strlen(buffer)<Buffer_length-6)      //we add the int value only if we have enough space!
  {
    sprintf(buffer,"%s%d",buffer,num); //we add the int value to the buffer
  }
  else {
    client.println(buffer); //we send the buffer though the net
    buffer[0]='\0'; //we reset the buffer
    sprintf(buffer,"%s%d",buffer,num);
  }
}
void printC(const __FlashStringHelper * info, EthernetClient client){
  int length_array1=strlen(buffer);
  int length_array2=strlen(info);
  if (Buffer_length-1>length_array1+length_array2)
  {
    strcat(buffer,info);
  }
  else {
    client.println(buffer);
    buffer[0]='\0';
    strcat(buffer,info);
  }
}

Coding Badly

Code: [Select]
strcat_P( buffer, (PGM_P)(info) );

...may work.  Otherwise, you will have to use static_cast...

Code: [Select]
strcat_P( buffer, static_cast<PGM_P>(info) );

liudr

nicocarv,

I suggest you learn the way to do PROGMEM way instead of F(). F() doesn't optimize duplicate strings. If you do PROGMEM, you only define the string once and use it any time you want. I'll write some tutorial on my blog and remember to post back here.

Go Up