Daniel White

MC9S12XDT256: Flash error possibly caused by bootloader

Discussion created by Daniel White on Sep 8, 2008
Latest reply on Sep 10, 2008 by kef
MC9S12XDT256VAL Mask: 1L15Y Xtal: 16MHz Bus:40MHz
Codewarrior v4.5 for HCS12(X)
P&E Cyclone Pro using algorithm Freescale_MC9S12XDT256_1x16x128k_Linear_16k_page.12P
 
Sorry for the very long post but I really need some help.
 
We have one module with a specific bit in flash that should be programmed (0) and sometimes is read as erased (1). Of course, we can't be sure that the error doesn't occur when the value is moved to the stack and back but it seems to be a flash memory programming error.
 
What we do know:
1. The error is always the same. An address (0x4014) is passed to a function but sometimes the function gets the correct address and sometimes it starts at 0x401C instead. This occurs nearly 50% of the time.
2. The error only occurs if the application is programmed into flash using our bootloader.
3. The error does not occur if the same application is programmed into flash using the P&E Cyclone Pro
4. The application has been rebuit with minor unrelated changes and the error still occurs if programmed with the bootloader but does not occur if programmed with the Cyclone Pro.
5. We have used this bootloader hundreds of times with no errors.
 
So, I am suspecting a problem with my bootloader that leaves the bit not fully programmed. I also suspect that it is a hardware problem with this particular module but why would the Cyclone Pro algorithm be superior? If there is a problem with our bootloader, I need to find it now.
 
Our bootloader is made up of functions that are loaded into RAM and executed from there with interrupts disabled. The functions poll for new incoming bytes on the UART and strobe the watchdog during long wait periods.
 
Could someone please check the following for any possible errors?
 
The PLL is set to produce a 40MHz bus clock from a 16MHz xtal:
SYNR = 4:
REFDV = 1:
 
The NVM flash is set for a 181.8kHz FCLK with the following:
void LRAE_Init_Flash(uByte *ret_ptr, uByte *data_buffer )
{

  /* set the clock according to MC9S12XDP512_V2.pdf Rev2.13 page 213-214 */
  FCLKDIV_PRDIV8 = TRUE;
  FCLKDIV_FDIV = 10;   //results in 181kHz
  /* configure interrupts */
  FCNFG = 0;  // not enabled

} /* end LRAE_Init_Flash */
 
The Flash is programmed with the following algorithm. The first function is used to erase a sector and program the first buffer in that sector. The second function is for programming sucessive buffers in a sector.
#define FCMD_WORD_PROGRAM 0x20
#define FCMD_SECTOR_ERASE  0x40
//*****************************************************************************
//* Function Name : LRAE_Flash_Erase_and_Write
//* Description  : Erases a given Flash sector using address
//*          passed in via data buffer then writes first buffer at that location
//*
//*****************************************************************************
void LRAE_Flash_Erase_and_Write(uByte *ret_ptr, uByte *data_buffer )
{
uByte num_bytes; //supports up to 256 bytes
long_word_byte_t address;
unsigned int *far far_address;
uWord data_word;
uByte i;
uWord rx_data_idx;
uByte buf_cnt=0;

 
 
  rx_data_idx = RET_DATA_START;
  ret_ptr[NUM_REC_BYTES_IDX] = 0;
 
  ret_ptr[RET_CODE_IDX] = LRAE_RET_DONE;
 
  //1st byte is num bytes
  num_bytes = data_buffer[buf_cnt++];
  address.ul = 0;
  //3 bytes of address
  address.ub.b2 = data_buffer[buf_cnt++];
  address.ub.b1 = data_buffer[buf_cnt++];
  address.ub.b0 = data_buffer[buf_cnt++];
  
    far_address = (unsigned int *far)address.ul;
   
   FSTAT = (FSTAT_ACCERR_MASK | FSTAT_PVIOL_MASK);               //   clear errors
   (*far_address) = 0xFFFF; /* Dummy store to page to be erased */
   FCMD = FCMD_SECTOR_ERASE;
 
      FSTAT_CBEIF = TRUE;
  __asm nop;
  __asm nop;
  __asm nop;
      do{
        WDOG_STROBE_PORT ^= BIT(WDOG_STROBE_PIN); //toggle wdog
        i=0;
        do{
          //check for any new SCI data that needs to be recd
          if(SCI0SR1_RDRF)
          {
            /* check for framing errors and space in buffer */
            if ((SCI0SR1_FE == 0) && (rx_data_idx < LRAE_RETURN_DATA_BUFFER_SIZE))
            {
              ret_ptr[rx_data_idx++] = SCI0DRL;
              ret_ptr[NUM_REC_BYTES_IDX]++;
            }
         
          }
        }    while(++i<255); 
      }  while(!FSTAT_CCIF);
  

   if(FSTAT_ACCERR)
   {
     ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
      ret_ptr[RET_ERROR_IDX] = Access_Error;
   }
   else if (FSTAT_PVIOL)
   {
     ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
      ret_ptr[RET_ERROR_IDX] = Protection_Error;
   }
  
  
   /* now program first buffer of data into new sector */
    i=0;     
    /* loop until all bytes programmed or error */
    while((buf_cnt < num_bytes) &&
          (i++ < BURST_BUFFER_SIZE_IN_WORDS) &&
          (ret_ptr[RET_CODE_IDX] == LRAE_RET_DONE))
    {
   
     FSTAT = (FSTAT_ACCERR_MASK | FSTAT_PVIOL_MASK);               //   clear errors
    
     data_word = *(uWord*)&data_buffer[buf_cnt];
     buf_cnt += 2; //2 bytes at a time
     (*far_address) = data_word;  // Store desired data to address being programmed 
    
     FCMD = FCMD_WORD_PROGRAM;                  // Store programming command in FCMD
      FSTAT_CBEIF = TRUE; //start command
      while(!FSTAT_CCIF); //wait here for command to complete
      far_address++; //advance to next word

     if (FSTAT_ACCERR)
     {
       ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
       ret_ptr[RET_ERROR_IDX] = Access_Error;
     }
     else if (FSTAT_PVIOL)
     {
       ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
       ret_ptr[RET_ERROR_IDX] = Protection_Error;
     }
      //check for any new SCI data that needs to be recd
      if(SCI0SR1_RDRF)
      {
        /* check for framing errors and space in buffer */
        if ((SCI0SR1_FE == 0) && (rx_data_idx < LRAE_RETURN_DATA_BUFFER_SIZE))
        {
          ret_ptr[rx_data_idx++] = SCI0DRL;
          ret_ptr[NUM_REC_BYTES_IDX]++;
        }
      }
 
   } /* end while loop */
  
//  } /* end if address checks */

} /* end LRAE_Flash_Erase_and_Write */
//*****************************************************************************
//* Function Name : LRAE_Flash_Write
//* Description  : Write to flash using address and data
//*          passed in via data buffer.
//*
//*****************************************************************************
void LRAE_Flash_Write(uByte *ret_ptr, uByte *data_buffer )
{
uByte i; // supports up to 256 words
uByte num_bytes; //supports up to 256 bytes
long_word_byte_t address;
unsigned int *far far_address;
uWord data_word;
uWord rx_data_idx;
uByte buf_cnt=0;

  rx_data_idx = RET_DATA_START;
  ret_ptr[NUM_REC_BYTES_IDX] = 0;
 
  ret_ptr[RET_CODE_IDX] = LRAE_RET_DONE;
 
  num_bytes = data_buffer[buf_cnt++];
  address.ul = 0;
  address.ub.b2 = data_buffer[buf_cnt++];
  address.ub.b1 = data_buffer[buf_cnt++];
  address.ub.b0 = data_buffer[buf_cnt++];
  far_address = (unsigned int *far)address.ul;
  i=0;
  /* loop until all bytes programmed or error */
  while((buf_cnt < num_bytes) &&
        (i++ < BURST_BUFFER_SIZE_IN_WORDS) &&
        (ret_ptr[RET_CODE_IDX] == LRAE_RET_DONE))
  {
 
   FSTAT = (FSTAT_ACCERR_MASK | FSTAT_PVIOL_MASK);               //   clear errors
   if(address.ub.b0 & 0x0001)  // Aligned word?
   {
     ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
      ret_ptr[RET_ERROR_IDX] = Flash_Odd_Access;
   }
   else if(*far_address != 0xFFFF)          // Is it erased?
   {
     ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
     ret_ptr[RET_ERROR_IDX] = Flash_Not_Erased;
   }
   else
   {
  
     data_word = *(uWord*)&data_buffer[buf_cnt];
     buf_cnt += 2; //2 bytes at a time
     (*far_address) = data_word;  // Store desired data to address being programmed 
  
     FCMD = FCMD_WORD_PROGRAM;                  // Store programming command in FCMD

  FSTAT_CBEIF = TRUE; //start command
  while(!FSTAT_CCIF); //wait here for command to complete
  far_address++; //advance to next word
     if (FSTAT_ACCERR)
     {
       ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
       ret_ptr[RET_ERROR_IDX] = Access_Error;
     }
     else if (FSTAT_PVIOL)
     {
       ret_ptr[RET_CODE_IDX] = LRAE_RET_FAIL;
       ret_ptr[RET_ERROR_IDX] = Protection_Error;
     }
    } /* end if error */

    //check for any new SCI data that needs to be recd
    if(SCI0SR1_RDRF)
    {
      /* check for framing errors and space in buffer */
      if ((SCI0SR1_FE == 0) && (rx_data_idx < LRAE_RETURN_DATA_BUFFER_SIZE))
      {
        ret_ptr[rx_data_idx++] = SCI0DRL;
        ret_ptr[NUM_REC_BYTES_IDX]++;
      }
    }
 
 } /* end while loop */
}

Outcomes