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.

Problem with FLASH Block Write passing arguments

Other Parts Discussed in Thread: MSP430F2410

I am having trouble passing arguments to a function that has been copied to RAM and once I have a buffer full of data, I pass a pointer to the buffer along with a Flash memory address, and then the number of bytes I want programmed.  The example code I have found works well; however, the example code uses fixed values for the buffer and address locations.  What I am seeing in my debugger is the pointers are pointing to the CPU registers instead of pointing to the address variables I am passing to the function.  I suspect when I copy the write function to RAM, this gets the pointers all out of WHACK, but I am stumped how to solve this without diving into an assembly program to solve this.(not sure this would work wither).  I have attached my compiled code. 

FYI, once the buffer is 512 bytes, I call the write routine using this

if ( !write_block_int ( &writeBuffer[0], intCurrentSegment, data_buff_index) ) { break;}

I am using an MSP430F2410; IAR EW 5.40

/*****************************************************************************
*  Filename:  flashblockwrite.c
*
*  
*  Description: Module used to perform the flash block write.
*
*  Dependencies:  
*
*  Modifications:  
*   Date      Programmer      Description
*   --------  --------------  -----------------------------------------------
*  
*****************************************************************************/
  msp430f2410.h"
 

  #include "string.h"     // included for memcpy function call

  #pragma segment="FLASHCODE"                 // Define flash segment code
  #pragma segment="RAMCODE"

     // array of received data
     extern unsigned char writeBuffer[] ;
    // writeBuffer array index pointer (and, when full, number of bytes to write to FLASH)
     extern unsigned int data_buff_index ;
    // holds the address of the start of the segment for use during flash write
     extern unsigned int intCurrentSegment ;

/******************************************************************************
*  Function Name:    copy_flash_to_RAM

*
*  Parameter: none
*  Input: none
*  Returns: none
*
*  Description:
*   This function copies the function FLASH using Block Write
*
* Change log:
* Date        Author      Description
*
*
******************************************************************************/
     
  void copy_flash_to_RAM (void)
   {
    unsigned int *flash_start_ptr;           // Initialize pointers
    unsigned int *flash_end_ptr;
    unsigned int *RAM_start_ptr;

    //Initialize flash and ram start and end address
    flash_start_ptr = (unsigned int *)__segment_begin("FLASHCODE");
    flash_end_ptr = (unsigned int *)__segment_end("FLASHCODE");
    RAM_start_ptr = (unsigned int *)__segment_begin("RAMCODE");

    //calculate function size
    unsigned long function_size = (unsigned long)(flash_end_ptr) - (unsigned long)(flash_start_ptr);

    // Copy flash function to RAM
    memcpy(RAM_start_ptr,flash_start_ptr,function_size);
   }

   
/******************************************************************************
*  Function: write_block_int()
*
*   
*  Purpose: This function is responsible for writing the contents
*           of commBuffer[] to FLASH; however, this will be done from RAM.
*           This function is copied into RAM first before writing to FLASH
*           This portion of the code is first stored in Flash and then copied
*           to RAM during initialization.  Ultimately, this function executes
*           from RAM.
*
*  Modifications:
*  Date        Name       Description
* ------      -----     -----------------------------------------------------
*
*
******************************************************************************/
 
    
#pragma location="RAMCODE"

  unsigned char write_block_int( unsigned char *ptrSource, unsigned int *ptrDest, unsigned int length )
  // BOOL write_block_int(void)
  {
    //Inputs:
    
       
    // used for counting the number of bytes being written to FLASH
    unsigned int i, u, dex;
    unsigned int numBytesToWrite, numBlocksToWrite, modBytesToWrite;
    
    // Keep local copy of initial parameters to use with memcmp
    void *Source = ptrSource;
    void *p_destination = ptrDest;
    size_t bytes = length;
   
       
    unsigned int* Flashptr;
    Flashptr = (unsigned int*)ptrDest;        // Initialize write address
    //flashptr = &intCurrentSegment;
    __disable_interrupt();                             // 5xx Workaround: Disable global
                                                                        // interrupt while erasing.
    // Erase Flash
    while(BUSY & FCTL3);                          // Check if Flash being used
    FCTL3 = FWKEY;                                    // Clear Lock bit
    FCTL1 = FWKEY+ERASE;                    // Set Erase bit
    *(unsigned char *)Flashptr = 0;           // Dummy write to erase Flash seg
    while(BUSY & FCTL3);                          // Check if Erase is done

    // get number of bytes from writeBuffer[] to write. Total can be < 512.
    // FLASH block write only writes 64 blocks at a time. The BLKWRT bit must
    // be cleared after the current block has completed its write process.
    // Then set the BLKWRT bit again to write the next block.
    
    // get number of blocks to write to segment
    // and any remaining bytes if writeBuffer[] is not a full 512 bytes.
   numBlocksToWrite = data_buff_index / 64;
   modBytesToWrite = data_buff_index % 64;
    
    
    if ( numBlocksToWrite == 0 )
      {
        numBytesToWrite = data_buff_index;
      } // end if (numBlocksToWrite == 0)
    else
      {
        numBytesToWrite = 64;
      }// end else
    
    
    // Write Flash
    FCTL1 = FWKEY+BLKWRT+WRT;               // Enable block write
    
    for (u = 0; u < numBlocksToWrite; u++)
    {
      for(i = 0; i < numBytesToWrite; i++)
        {           
          *Flashptr++ = ptrSource[dex++];            // Write contents of writeBuffer[] to Flash                     
          while(!(WAIT & FCTL3));                          // Test wait until ready for next byte
        }
      
      // on the last block of the current segment check if that block is
      // a full 64 bytes. If not, change the number of bytes to write
      if (numBlocksToWrite < 8 || ( numBlocksToWrite - u ) == 1)
      {
        numBytesToWrite = modBytesToWrite;
      } // end if (numBlocksToWrite)
    
      FCTL1 = FWKEY;                          // Clear WRT, BLKWRT
      while(BUSY & FCTL3);                    // Check for write completion
      FCTL3 = FWKEY+LOCK;                     // Set LOCK
    } // end for u
   
    
    //  verify buffer is same as segment written
    return ( memcmp ( Source, p_destination, bytes ) == 0 ? 1 : 0 );
 
  }

  • Hi Christian,

    You are using a modern version of the IAR toolchain, so you should use the "modern" way.

    Any function you want to live in RAM can be marked with the "__ramfunc" attribute.  IAR cstartup automatically copies it for you into RAM to the correct place (which is critical since the code is not position independent).

    So not only can you eliminate the copy_flash_to_RAM() routine, all the #pragma section stuff, and any customizations to the linker file, but you will automatically eliminate the linker/location problems you are now experiencing.  In short, it will "just work".

    Jeff

  • Also...

    Christian Landry said:
    unsigned char write_block_int( unsigned char *ptrSource, unsigned int *ptrDest, unsigned int length )

    This signature looks strange (different pointer types) and the function itself seems to have a few errors too.

    Did you say this came from example code somewhere?  Have you tweaked it while debugging?

    Jeff

  • Thanks for the reply Jeff,

    I will look into the __ramfunc attribute.  I have noticed in the debugger that the write_function_int is in RAM even before I start running the code; however, I still have a line of code that calls the function copy_flash_to_RAM. Not sure why I call this function a second time?

    Yes, I modified the example code from here http://www.ti.com/lit/zip/slac166 using the flashwrite_04.c file.  The example code uses no function parameters but uses a const value for the memory location.  I need to have the memory location change with every segment address as I will be writing to flash in 512 byte chunks. This is true for the source data and the length of the data.  The last chunk of data might not fill the segment. 

    What looks like is happening is the compiler is assigning CPU registers to the Flashptr instead of the passed in parameter intCurrentSegment (the memory address to write to).  For example, I can see that Flashptr is equal to the value of R11 when the code below is executed:

        unsigned int* Flashptr;
        Flashptr = (unsigned int*)ptrDest;        // Initialize write address
        //  flashptr = &intCurrentSegment;

    I tested this by writing a line of assembly code asm("MOV.W &intCurrentSegment, R11") before the write function was called and sure enough, Flashptr now equaled the value of intCurrentSegment.  There has got to be a better way to do this?

  • I modified the copy to RAM process and included the __ramfunc attribute and this solved the problem.  Thanks for the help Jeff.  You are awesome!! 8>)

    Christian

**Attention** This is a public forum