Pages: 1 2 [3]   Go Down
Author Topic: What does the F() do exactly?  (Read 4842 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

avr-gcc-4.5.1
Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 235
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

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

Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

Thank you very much.
Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 235
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have posted a bug report to the Arduino team.

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

Offline Offline
Newbie
*
Karma: 0
Posts: 13
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 235
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#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:
Binary sketch size: 1716 bytes (of a 32256 byte maximum)

Works on both OS/X and Windows XP versions.
Logged

USA
Offline Offline
Full Member
***
Karma: 0
Posts: 235
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick, he's not using the same compiler.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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:
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.
Logged

Adelaide, South Australia
Offline Offline
Full Member
***
Karma: 0
Posts: 139
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick, How did you reveal that assembler code?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 452
Posts: 18694
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
avr-objdump -S whatever.elf > foo.txt

The output file (foo.txt) will have the disassembly in it.
Logged

Adelaide, South Australia
Offline Offline
Full Member
***
Karma: 0
Posts: 139
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

excellent, thanks
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
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);
  }
}
Logged

Global Moderator
Dallas
Offline Offline
Shannon Member
*****
Karma: 178
Posts: 12290
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
strcat_P( buffer, (PGM_P)(info) );

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

Code:
strcat_P( buffer, static_cast<PGM_P>(info) );
Logged

Central MN, USA
Online Online
Tesla Member
***
Karma: 65
Posts: 6939
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged


Pages: 1 2 [3]   Go Up
Jump to: