MC9S12XDT256: Flash error possibly caused by bootloader

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

MC9S12XDT256: Flash error possibly caused by bootloader

3,303 Views
dwhite
Contributor I
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 */
}

Labels (1)
0 Kudos
Reply
4 Replies

780 Views
kef
Specialist I
FCLKDIV is write once register. So first write is granted

  FCLKDIV_PRDIV8 = TRUE;

but second write is ignored


  FCLKDIV_FDIV = 10;   //results in 181kHz

 
So resulting oscilator clock divider is probably 8 (instead of 88) and as a result you have too fast flash module clock and too short programming time.
 
0 Kudos
Reply

780 Views
dwhite
Contributor I
Good catch, kef.
 
Now that I got my heart beating again, I see that this is a write once register. This would mean that my clock is 2MHz instead of 181kHz so I'm suprised that it ever worked.
 
I just tested this in my emulator and it looks like the FCLKDIV register is 0xCA (I also have the exact same issue with me EE init and the ECLKDIV is also 0xCA). As I step through the code, it sets the PRDIV8 bit first and then sets the remaining bits. So, either my True-Time Simulator is wrong or the register actually allows multiple writes.
 
Or, do write once registers show the results of the second write when read back but the data isn't actually clocked into the module?
 
I will fix this and repeat our failing test and post the results. At this point, I'm not 100% convinced that this is the problem.
 
0 Kudos
Reply

780 Views
kef
Specialist I
Not sure about FCLKDIV, but the most of other write once registers are write once only in normal modes. In special modes (normal, not hotplug BDM debugging) the most of write once registers are write many times, write once restriction is removed. Emulators are using special modes I think.
0 Kudos
Reply

780 Views
JimDon
Senior Contributor III

Oh, it's a write once register for sure. When it comes to that sort of thing, don't believe the simulator.

0 Kudos
Reply