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 */
}