This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Trying to use Main Flash as Data storage in the MSP420f22x74

Other Parts Discussed in Thread: MSP430F2274, MSP430F1611




Hola All,

I'm trying to make a program that takes ADC readings twice a second for a hour and stores these values
in the Main flash memory of the MSP430x2274.Later this data will be sent to a computer and
then graphed using MatLab.

I've drawn out a general flow chart of how this program will function, and I've made and tested
functions to take care of the timing and the voltage readings with success. However, I've hit a
bump. I made functions that erase, write too, and get data from the information memory, but there
isn't enough room in information memory. I then tried to alter these functions so they would instead
write, read, and erase segments of main memory. Its this part that I'm stuck on.

I've made some code below that uses the functions i'm trying to use to accomplish reading and
writing to FLASH. Unlike the info memory, all the memory in the main section, when viewed in the Memory
window, are 0, and since bits in Flash memory can only be changed from 1 to 0 I
created an erase function, but it doesn't work and I don't know why. Sorry about that run on sentence.
There are also sections in the main memory that all have the same "random" value and are spaced the same
distance apart. I have no idea what these are or do, but they do change every time I step through the code.


So let me sum up my questions concisely.

1) In the code below, why don't the functions work as intended?


2) Can I use Flash memory as data storage, without moving or altering the code memory?

Thanks for looking over my code ,and any help you can offer.

Triston







____________________________________ CODE __________________________________________________

     #include'msp430x22x4';

//******************************* Function declarations ****************
     void Data_Erase_Main(void);

//******************************* Global Variables *********************
     volatile unsigned int ADC, i, Temp;

//******************************* Main Program Start *******************
     void main(void)
     {
    WDTCTL = WDTPW + WDTHOLD;                  // Turn off WDT
    
    // Clock Set Up
    DCOCTL = CALDCO_1MHZ;        
    BCSCTL1 = CALBC1_1MHZ;
    BCSCTL2 = SELM_0 | DIVM_0|DIVS_3;    // Selects DCo as masterclock, Division
                                                                              // for  master clock and submaster clock
                                                                              // (1, and 8, respectively)


    for(;;)
    {
        Data_Erase_Main();        // supposed to erase a segment of main memory.
        
        for( i = 1; i< 4 ;i++)        // For loop places 1 - 3 in main memory
        {
            ADC = i;
            Data_In_Main(i);
        }

        for( i = 1; i < 4; i++)        // Using CCE Debug the values 1 - 3 are checked
        {             

            Temp = Data_Out_Main();
        }

    }
}

//****************************** Function Definitions ************************************

     //------------------------------ Data_Erase_Main -----------------------------------
      void Data_Erase_Main(void)
       {
      int *P_int;
    FCTL2 = FWKEY + FSSEL0 + FN1;
    FCTL3 = FWKEY;                              // clr LOCK bit
    FCTL1 = FWKEY + ERASE;            // activate segment erase mode
        
    P_int = (int*)0x4A00;
    *P_int = 0;                                          // Dummy write to erase.
       }
     // ----------------------------- Data_In_Main -----------------------------------------
     void Data_In_Main(int n)
       {
    int *P_int;
        
    FCTL2 = FWKEY + FSSEL0 + FN1;
    FCTL3 = FWKEY;                         // CLR LOCK Bit
        
    FCTL1 = FWKEY + WRT;            // Set WRT bit to enable WRT mode
        
    n--;                                                   // setting n to one will ensure a write to the
                                                             // original pointer location (i.e. 0x4A00).

    P_int = (int*)0x4A00;                     // Intiate pointer to selected location
    P_int = P_int - n;            
    *P_int = ADC;
        
    FCTL1 = FWKEY;
    FCTL3 = FWKEY + LOCK;

    }

    //--------------------------- Data_Out_Main ------------------------------------------
    unsigned int Data_Out_Main(int n)
    {
        volatile unsigned int x2 = 0;
        int *P_int;
        
        FCTL2 = FWKEY + FSSEL0 + FN1;
        FCTL3 = FWKEY;            // CLR LOCK bit
        
        n--;
        P_int = (int*)0x4A00;        // Set pointer to reference location
        P_int = P_int - n;               // Go to location n away from reference
        x2 = *P_int;                        // Store value in x2
        return x2;                            // return x2 value to main function
    }

  • Hi Triston,

    yes, you can use main flash for data storage, but be shure to keep it separated from your application. Have a look at this post here (http://e2e.ti.com/forums/p/8918/34816.aspx#34816); it will give you some more information and has a link to a 'how to' guide for IAR.

    Rgds
    aBUGSworstnightmare 

  • Thanks for the help aBUGSworstnightmare. I'm a bit of a noob when it comes to embedded programming, so please bare with me. 

     

    I looked over the the links you gave me, and I must say they made me even more confused. G**kBuster and Stephans code issues seem very close to mine, but I'm still unclear as to why my code doesn't work. Unlike G**kBuster I was able to write to and erase the info segments without any difficulty, which ended up giving me some false hope. Stephans'  problems seems the closets to mine, and perhaps it is just a matter of me using assembly at the right times in the code (I'll try this and report back), but this seems a bit doubtful since it worked fine in the INFO section.

     

    I used the code below to write to , and erase Flash memory.  I added the "while(FCTL3 & BUSY);" lines after viewing Stephans' code. The Info code that I've been working with always starts up clear of data, or rather, its writable. However, the main memory sections i'm trying to write to aren't as nice - they always show registers full of zeroes, and thus I need to erase these segments before I write to them. At least, that is my current understanding. I made an Erase function that should do just this, but does zip when I view it through the Debug program , and still zip when I just run my program.

     

     I made erase, write, and read functions which should do just what their name imply when used, and they do just this for the Flash Info sections. However, when i altered these functions to write to Main Flash sections they no longer function,and my plans for glorious embedded happiness are destroyed. 

     

    Below is my original Erase_Info() function, and the altered one that is suppose to just erase a segment in the Main Flash section. Note that the Info function has a case statement to choose which segment one wants to write to (A-D).

    Again thank you and anyone else looking at this.

    ___________________________________________________________________________________________________________________

    **************** Info erase ***************************

    void Erase_Info(char seg)
    {
        int *P_int;
        FCTL2 = FWKEY + FSSEL0 + FN1;        // Set Flash clk
       
       
        switch(seg)
        {
            case 'A':
                        P_int = (int*)0x10FF;    // need to clr LOCKA bit ?
                        FCTL3 = FWKEY + LOCKA;        //clr LOCKA bit
                        Temp4 = 1;
                        break;
            case 'B':
                        P_int = (int*)0x10BF;
                        break;
            case 'C':   
                        P_int = (int*)0x1074;
                        break;
            case 'D':   
                        P_int = (int*)0x103F;
                        break;
        }

    FCTL3 = FWKEY;                    //CLR LOCK bit
        while(FCTL3 & BUSY);
        FCTL1 = FWKEY + ERASE;            //enable erase
        *P_int= 0;                        //Dummy Erase
        while(FCTL3 & BUSY);
        FCTL3 = FWKEY + LOCK;                // Set Lock Bit

    }

      ************************* Data_Erase_Main ******************************

          void Data_Erase_Main(void)
           {
          int *P_int;
          P_int = (int*)0x4A00;
        FCTL2 = FWKEY + FSSEL0 + FN1;
        FCTL3 = FWKEY;                               // clr LOCK bit
        while(FCTL3 & BUSY);
        FCTL1 = FWKEY + ERASE;            // activate segment erase mode
           
       
        *P_int = 0;                                           // Dummy write to erase.
        while(FCTL3 & BUSY);
        FCTL3 = FWKEY + LOCK;                // Set Lock Bit
           }
  • Also, I'm using CCE not IAR, but if you think using IAR would gt rid of my current troubles I've already downloaded it and am ready to trudge through the intro. However, I'd rather not get acquainted with a new IDE just yet.

     

    Again thanks for the help.

  • Hi Triston,

    if you erase INFOA you will loose your calibration constants; because of that the code below will no longer work as expected:

    // Clock Set Up
        DCOCTL = CALDCO_1MHZ;       
        BCSCTL1 = CALBC1_1MHZ;
        BCSCTL2 = SELM_0 | DIVM_0|DIVS_3;    // Selects DCo as masterclock, Division
                                                                                  // for  master clock and submaster clock
                                                                                  // (1, and 8, respectively)

     

    First of all, you will need to modify your .cmd file. Open the file and search for the lines below:

    /****************************************************************************/
    /* SPECIFY THE SYSTEM MEMORY MAP                                            */
    /****************************************************************************/

    MEMORY
    {
        SFR                     : origin = 0x0000, length = 0x0010
        PERIPHERALS_8BIT        : origin = 0x0010, length = 0x00F0
        PERIPHERALS_16BIT       : origin = 0x0100, length = 0x0100
        ADCSAMPLE    : origin = 0x0200, length = 0x0014
        RAM                     : origin = 0x0214, length = 0x03E8
        INFOA                   : origin = 0x10C0, length = 0x0040
        INFOB                   : origin = 0x1080, length = 0x0040
        INFOC                   : origin = 0x1040, length = 0x0040
        INFOD                   : origin = 0x1000, length = 0x0040
       
        /* old line; keep it for reference */
        /* FLASH                   : origin = 0x8000, length = 0x7FDE */

        /* add the next two lines */
        /* first one will create a new segment in flash for your own data, size is 512bytes */
        MYDATA      : origin = 0x8000, length = 0x0200
        FLASH                   : origin = 0x8200, length = 0x7DDE

        /* rest remains unchanged */
        INT00                   : origin = 0xFFE0, length = 0x0002
       ...

    /****************************************************************************/
    /* SPECIFY THE SECTIONS ALLOCATION INTO MEMORY                              */
    /****************************************************************************/

    SECTIONS
    {
        .bss       : {} > RAM                /* GLOBAL & STATIC VARS              */
        .sysmem    : {} > RAM                /* DYNAMIC MEMORY ALLOCATION AREA    */
        .stack     : {} > RAM (HIGH)         /* SOFTWARE SYSTEM STACK             */
        .adcsample : {} > ADCSAMPLE    /* RESERVED FOR SPECIAL VARIABLES    */

        .text      : {} > FLASH              /* CODE                              */
        .cinit     : {} > FLASH              /* INITIALIZATION TABLES             */
        .const     : {} > FLASH              /* CONSTANT DATA                     */
        .cio       : {} > RAM                /* C I/O BUFFER                      */

        .pinit     : {} > FLASH              /* C++ CONSTRUCTOR TABLES            */

        .infoA     : {} > INFOA              /* MSP430 INFO FLASH MEMORY SEGMENTS */
        .infoB     : {} > INFOB
        .infoC     : {} > INFOC
        .infoD     : {} > INFOD

        /* add the next line here */
       
        .mydata : {} > MYDATA    /* my own segment in flash     */

        /* rest remains unchanged

        .int00   : {} > INT00                /* MSP430 INTERRUPT VECTORS          */
     ...

    Now, save the file.
    Next, add this to your application:

    /*-------------------------------------------------------------
     *                       Macros
     * ------------------------------------------------------------*/
    #define FLASH_UNLOCK    FCTL3 = FWKEY; FCTL1 = FWKEY + WRT;
    #define FLASH_LOCK      FCTL1 = FWKEY; FCTL3 = FWKEY +  LOCK;

    //-- user defined data stored in segment MYDATA in MSP430 Flash --
    #pragma DATA_SECTION(variable1, ".mydata");
    #pragma DATA_SECTION(variable2, ".mydata");
    #pragma DATA_SECTION(variable3, ".mydata");
    #pragma DATA_SECTION(variable4, ".mydata");
    #pragma DATA_SECTION(variable5, ".mydata");
    #pragma DATA_SECTION(variable6, ".mydata");
    #pragma DATA_SECTION(variable7, ".mydata");
    #pragma DATA_SECTION(variable8, ".mydata");
    #pragma DATA_SECTION(variable9, ".mydata");


    #pragma DATA_ALIGN(variable1, 1);
    #pragma DATA_ALIGN(variable2, 1);
    #pragma DATA_ALIGN(variable3, 2);
    #pragma DATA_ALIGN(variable4, 1);
    #pragma DATA_ALIGN(variable5, 1);
    #pragma DATA_ALIGN(variable6, 2);
    #pragma DATA_ALIGN(variable7, 1);
    #pragma DATA_ALIGN(variable8, 1);
    #pragma DATA_ALIGN(variable9, 2);

    unsigned char variable1;
    unsigned char variable2;
    int variable3;
    unsigned char variable4;
    unsigned char variable5;
    int variable6;
    unsigned char variable7;
    unsigned char variable8;
    int  variable9;

    // -- local variable set --
    unsigned char variable1LOCAL = 0;
    unsigned char variable2LOCAL = 0;
    int variable3LOCAL = 0;
    unsigned char variable4LOCAL = 0;
    unsigned char variable5LOCAL = 0;
    int variable6LOCAL = 0;
    unsigned char variable7LOCAL = 0;
    unsigned char variable8LOCAL = 0;
    int  variable9LOCAL = 0;

     

    /**********************************************************************//**
     * @brief  Erases a single segment of memory containing the address FarPtr.
     *
     * @param  FarPtr The address location within the segment of memory to be
     *                erased.
     *
     * @return none
     **************************************************************************/
    void flashEraseSegment(unsigned long FarPtr)
    {
      unsigned long *Flash_ptr;                         // local Flash pointer
     
      Flash_ptr = (unsigned long *) FarPtr;             // Initialize Flash pointer
     
      FCTL3 = FWKEY;
      FCTL1 = FWKEY + ERASE;
     
      *Flash_ptr = 0;                         // dummy write to start erase
     
      while (FCTL3 & BUSY );
      FCTL1 = FWKEY;               
      FCTL3 = FWKEY +  LOCK;
    }


    /**********************************************************************//**
     * @brief  Stores calibration and user-config data into flash segment
     *
     * @param  none
     *
     * @return none
     *************************************************************************/
    void saveSettings(void)

      flashEraseSegment((unsigned long)&variable1);
      FLASH_UNLOCK;
      variable1 = variable1LOCAL ;
      variable2 = variable2LOCAL ;
      variable3 = variable3LOCAL ;
      variable4 = variable4LOCAL ;
      variable5 = variable5LOCAL; 
      variable6 = variable6LOCAL ;
      variable7 = variable7LOCAL;
      variable8 = variable8LOCAL; 
      variable9 = variable9LOCAL; 
      FLASH_LOCK; 
    }

    /**********************************************************************//**
     * @brief  Loads calibration and user-config data from flash segment.
     *
     * @param  none
     *
     * @return none
     *************************************************************************/
    void loadSettings(void)

      variable1LOCAL = variable1;
      variable2LOCAL = variable2;
      variable3LOCAL = variable3;
      variable4LOCAL = variable4;
      variable5LOCAL = variable5;
      variable6LOCAL = variable6;
      variable7LOCAL = variable7;
      variable8LOCAL = variable8;
      variable9LOCAL = variable9;
    }

    void main(void)
    {
      // some initialization for your MSP430F2274  
      // disable watchdog timer
      //------------------------
      WDTCTL = WDTPW + WDTHOLD;               // Stop WDT

      // clock setting
      //------------------------
      DCOCTL = CALDCO_16MHZ;                  // Set DCO to 16MHz
      BCSCTL1 = CALBC1_16MHZ;                 // MCLC = SMCLK = DCOCLK = 16MHz
      BCSCTL1 |= DIVA_0;                      // ACLK = ACLK/1
      BCSCTL3 = LFXT1S_2;                     // LFXT1 = ACLK = VLO = ~12kHz
      BCSCTL3 &= ~LFXT1OF;                    // clear LFXT1OF flag, 0

      // flash memory controller
      FCTL2 = FWKEY + FSSEL_2 + FN5 + FN3;
                                              // SMCLK/40 for flash timing
                                              // generator

      P1DIR |= 0x01;                            // Set P1.0 to output direction

      for (;;)
      {
        volatile unsigned int i;

        P1OUT ^= 0x01;                          // Toggle P1.0 using exclusive-OR
       
        loadSettings(); // load settings from flash

        i = 50000;                              // Delay
        do (i--);
        while (i != 0);
       
        variable1LOCAL++;
        variable2LOCAL--;
       
       
        saveSettings(); // save settings to flash
        P1OUT ^= 0x01;                          // Toggle P1.0 using exclusive-OR
        __NOP(); // place a breakpoint here to prevent damaging the flash because of continous writes!!!
      }
    }


    Be shure to ckeck your FET Debugger settings; by default code and info memory will be erased when you download your application!
    Have a look at PROJECT-->FET DEBUGGER-->DOWNLOAD and select the option ERASE MAIN MEMORY to prevent erasing of your info memory (if you want to!).


    Now you can start using the code. Have a look on SLAU157H - MSP-FET430 Flash Emulation Tool (..) User's Guide; there are some explainations on the above.
    Rgds
    aBUGSworstnightmare

  • Thank you for the explanation. I'll try this .

     

    Triston

  • Hola.

     

    I apologize for responding so late. I altered the .cmd file like you showed me and my program now works exactly as intended. I appreciated the tutorial on how to save the Data in INFO_A, but I knew about the calibration settings being stored in that segment, so I had no intention of using it. However, this no doubt will be useful later, so thanks again.

     

    Now, I only have one problem left. I intend to gather the data, store it and then the micro controller is disconnected from its power supply, until it is hooked up to a USB to transfer the data via hyperlink or putty. When i leave the device hooked up for data collection and data sending, everything works great. When I power it it down after it collects data and then turn it on nothing happens. I'm thinking it has something to do with the reset vector of the MSP430, but I haven't really looked into this just yet. Does this sound valid?

     

    Thanks again for your explanation/ tutorial. It was a life saver.

     

    Triston

    one more step away from newb.

     

  • i want to put a char table on the flash ROM

    how can modify the code to use a char T[20] rather variable1..2..3.....

  • Hi chouban,

    that's quite simple! Pls refer to the codelines below:

    // in case of variables of type unsigned int
    #pragma DATA_SECTION (T, ".mydata");
    #pragma DATA_ALIGN (T, 2); // reserve 2 bytes for each variable
    unsigned int T[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    // in case of variables of type unsigned char
    #pragma DATA_SECTION (T, ".mydata");
    #pragma DATA_ALIGN (T, 1); // resreve one byte for each variable
    unsigned int T[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    I hope this answers your question.

    Pls note that you can place your code into a new custom section too. Refer to my postings above and have a look on my explanations how to define custom segments.

    Rgds
    aBUGSworstnightmare

  • Dear aBUGSworstnightmare,

                                                              I need to store a character array of size 15KB in Flash memory.  I m using MSP430F1611 in which Flash is 48KB and RAM is 10KB. I use IAR embedded workbench 5.3 for programming. I have gone through previous threads regarding the same i have few queires.

    What is .cmd file is it for Code composer studio or IAR compiler????? and if IAR wer to find it???

    The above mentioned 15KB data is to store Fonts used in LCD as the RAM of MSP430F1611 doesn't support i want to make use of Flash for regular access.

    Also I have tried implementing your suggestions from previous threads and present, yet din't succeed

     

    // in case of variables of type unsigned char
    #pragma DATA_SECTION (T, ".mydata");
    #pragma DATA_ALIGN (T, 1); // resreve one byte for each variable
    unsigned int T[8] = {0, 0, 0, 0, 0, 0, 0, 0};

    I implemented the above as follows

    // in case of variables of type unsigned char
    #pragma DATA_SECTION (English_font, ".mydata");
    #pragma DATA_ALIGN (English_font, 1); // resreve one byte for each variable

    const unsigned char  English_font[] = { 15KB of LCD font};

    for which i get error as 1. Unrecognised # Pragma, 2. Variable "English_font[]" has already been declared.

    I also tried in the following way from other thread

    /* IAR C Code */
    __no_init char alpha @ 0x0200; /* Place ‘alpha' at address 0x200 */
    #pragma location = 0x0202 const int beta;

    as follows

    #pragma location = 0xFE00 unsigned char const English_font[97][16];         // start storage from seg1 of flash

    __no_init const unsigned char  English_font[] @ 0xFE00;

    const unsigned char  English_font[] = { 15KB of LCD font};

    for which the error is same :  Variable "English_font[]" has already been declared.

    Please help me out, I would be very thankful.


    Regards

    Sansu        

  • Sansu said:
    #pragma location = 0xFE00 unsigned char const English_font[97][16];         // start storage from seg1 of flash
    __no_init const unsigned char  English_font[] @ 0xFE00;
    const unsigned char  English_font[] = { 15KB of LCD font};
    for which the error is same
    :  Variable "English_font[]" has already been declared.


    Indeed, you're declaring teh constant several times.

    the __no_init const... declares that there is a constant at 0xfe00. Then you define a (new!) variable of the same value with initialization data. And finally, in the pragma, you define a third constant of the same name with a given size. Only one can be used and it depends on what you want todo.
    Also, palcing something of the size of 15k on 0xfe00 will surely not work, as above fe00 is the interrupt vector table. Unless your array is smaller than a few 100 bytes (which is isn't by your diefinition), it won't fit between 0xfe00 and the vector table :)

    After all, there is no need for all this. It should be sufficient to just define a cosntant array.

    const unsigned char English_font[97][16] = { {,...},{,...},...};

    The compile rshould put this automatically into flash instead of any ram area
    (note that even if this data would fit into ram and would be placed there as a non-constant variable, the init data would still be placed in flash and copied over at program start - slowly, by this size)

    Since it is constant, it will be never written to, so it will simply reside in flash, because the MSP cpu does not differentiate between ram and flash address space (von-Neumann architecture) while others like the ATMega do (Harvard-architecture).

    So just define the font as a two-dimensional constant array and be happy. It's not even necessary to define a fixed address. The linker will adjust all parts of the code where you refer to the array. Unless you do some fancy things in self-written assembly functions, all should be well.

    No need for changing any cmd files too. It's plain C language and default compiler behavior.

     

  • Dear Jens-Michael Gross

            The above problem has been solved after defining as suggested above, Thanks a lot.

            Also I have a data coming from an Image sensor(around 150KB) which i have to display on LCD with regular time intervals. The above data is not dumped directly
    but in chunks of 25KB(6 times =a50KB). For this 25KB, apart from English_font()  I have defiined one more

         const unsigned char pic { .........};

         I am using IAR embedded workbench, till compiling its fine and the software gets struck while dumping the code into MSP comtroller. I din't get the problem.
    Is it because the code size is 30KB(this i have seen from  filename.d43) but program mem. inside the MSP is mentioned as 48KB + 10KB RAM???

         Emulator also shows Download completed and verification successful. loaded debugee.

         Please suggest me some solution on its strucking in the mid way.

    Regards
    sansu

  • Sansu said:
    const unsigned char pic { .........};

    This doesn't look like valid C code. What exactly did you define?

    Anyway, if the image data is read from a sensor, it doesn't make much sense to write it into flash. Also, of course it is way more than this particular MSP can handle. It has only 48k flash, that means with 30k code, there's only 10k flash and less than 10k ram left for this data. No space for 25k, let alone 150k.
    Or does this 30k code include the 25k data? Sorry, but somehow I don't get a grip on what you're trying to do.

    Usually, the linker would complain if something won't fit into the device. And if it fits, it should be no problem dumping the result into the MSP (which does not mean that it will run). The flashing function should be able to dump any code size properly. Do you get any error message? What is happening (or not)?

  • The above mentioned syntax is wrong and i dint code it in program like that, Its mistyped here.

    Now that I have solved the problem, Earlier I stored the data in a seperate .h file. Because of above problem I removed entire .h file and pasted the data in Main( ) function. I donno the reason but it started working and program is being executed.

    The code 30K itself include 25K of data.

     

    Regards

    Sansu

  • One stupid question... I'm still learning :) Where in Code Composer studio do you add macros? Complier returns: badly formed pragma

    Thank you in advance

  • Matja�� Behek said:
    Where in Code Composer studio do you add macros

    The source code input window?

    Macros are jsut part of the source code, whether directly written or included from header files.

    Matja�� Behek said:
    Complier returns: badly formed pragma

    A macro is no pragma.

    A macro definition begins with

    #define

    and a pragma begins with

    #pragma

    To learn what may happen if you start a sourcecode line with a '#', you shoudl do a google search for 'C++ preprocessor directives'.

    p.s.: macros contain valid c++ code, expressions or just tokens, pragmas contain compiler-specific instructions outside the C language.

    or in other words, macros define a 'replace macro name by this text' instruction, while pragmas contain a 'dear compiler, please do something special and compiler specific right now at this point' instruction. Macros will become part of the code, while pragmas tell the compiler how to handle the code.

  • at the beginning of the program you must type #define replacement-text for example: #define LED1 BIT3 or #define forever for(;;)

**Attention** This is a public forum