Beispiel #1
0
void write_flash_row()
{
	size_t offset;
	uint8_t i;
	uint32_t prog_addr = write_address;

	NVMCON = 0x4001;
	TBLPAG = prog_addr >> 16;
	offset = prog_addr & 0xffff;

	/* Write the data provided */
	for (i = 0; i < write_length; i++) {
		__builtin_tblwtl(offset, prog_buf[i]);
		__builtin_tblwth(offset, prog_buf[++i]);
		offset += 2;
	}

	/* Pad the rest of the row out with 0xff */
	for (; i < BUFFER_LENGTH; i += 2) {
		__builtin_tblwtl(offset, 0xffff);
		__builtin_tblwth(offset, 0xffff);
		offset += 2;
	}

	asm("DISI #5");
	__builtin_write_NVM();

	while (NVMCONbits.WR == 1)
		;
}
Beispiel #2
0
void flashProgramInstructionRow ( u32 * wordAddress, const u32 * instructions )
{
    s16 i;
    u32 temp = *wordAddress;
    u32 offset;
    DWORD_VAL value;
    temp = FLASH_ROW( temp ); /* normalize to beginning of row */
    offset = temp & FLASH_TABLE_PAGE_SIZE_MASK; /* offset into table page */
    TBLPAG = temp >> FLASH_TABLE_PAGE_SIZE_SHIFT; /* select table page */

    /* a complete row is written -> update wordAddress */
    *wordAddress = temp + FLASH_ROW_SIZE_IN_WORDS; 

    /* perform write of complete row */
    for ( i = 0; i < FLASH_ROW_SIZE_IN_BYTES; i += 4, instructions++, offset += 2 )
    {
	  value.Val = *instructions;

	__builtin_tblwtl( offset, value.word.LW );
	__builtin_tblwth( offset, value.word.HW );
    }

    NVMCON = FLASH_ACCESS_ROW_PROGRAM;
    asm("DISI #5");
    __builtin_write_NVM();
    while(NVMCONbits.WR == 1);
}
void WriteFlashSubBlock(void)		//Use word writes to write code chunks less than a full 64 byte block size.
{
	unsigned int i = 0;
	DWORD_VAL Address;

	NVMCON = 0x4003;		//Perform WORD write next time WR gets set = 1.

	while(BufferedDataIndex > 0)		//While data is still in the buffer.
	{
		Address.Val = ProgrammedPointer - BufferedDataIndex;
		TBLPAG = Address.word.HW;

		__builtin_tblwtl(Address.word.LW, ProgrammingBuffer[i]);		//Write the low word to the latch
		__builtin_tblwth(Address.word.LW, ProgrammingBuffer[i + 1]);	//Write the high word to the latch (8 bits of data + 8 bits of "phantom data")
		i = i + 2;

		asm("DISI #16");					//Disable interrupts for next few instructions for unlock sequence
		__builtin_write_NVM();
        while(NVMCONbits.WR == 1){}

		BufferedDataIndex = BufferedDataIndex - 2;		//Used up 2 (16-bit) words from the buffer.
	
        }

	NVMCONbits.WREN = 0;		//Good practice to clear WREN bit anytime we are not expecting to do erase/write operations, further reducing probability of accidental activation.
        

}
Beispiel #4
0
void flashErasePage ( u32 wordAddress )
{
    u32 offset = wordAddress & FLASH_TABLE_PAGE_SIZE_MASK; /* offset into table page */
    TBLPAG = wordAddress >> FLASH_TABLE_PAGE_SIZE_SHIFT; /* select table page */

    __builtin_tblwtl( offset, 0x0000 /* value is don't care */ );

    NVMCON = FLASH_ACCESS_PAGE_ERASE;
    asm volatile ( "disi #5" );
    __builtin_write_NVM(); /* unlock sequence + start erase cycle */
    while(NVMCONbits.WR == 1);
}
Beispiel #5
0
/*********************************************************************
 * Function:        unsigned int NVMWriteWord(UINT32 address, UINT32 data)
 *
 * Description:     The word at the location pointed to by NVMADDR is programmed.
 *
 * PreCondition:    None
 *
 * Inputs:          address:   Destination address to write.
 *                  data:      Word to write.
 *
 * Output:          '0' if operation completed successfully.
 *
 * Example:         NVMWriteWord(0xBD000000, 0x12345678)
 ********************************************************************/
UINT NVMemWriteWord(UINT32 address, UINT32 data)
{
	DWORD_VAL writeAddress;
	DWORD_VAL writeData;

	writeAddress.Val = address;
	writeData.Val = data;

	NVMCON = 0x4001;                            // Perform WORD write next time WR gets set = 1.
	NVMADRU = writeAddress.word.HW;
	NVMADR = writeAddress.word.LW;

	// Set the table address of "Latch". The data is programmed into the FLASH from a temporary latch. 
	TBLPAG = 0xFA;
	// The smallest block of data that can be programmed in
	// a single operation is 2 instruction words (6 Bytes + 2 Phantom Bytes).
	// Mask the high or low instruction words depending on the address and write either high or low instruction word.
	if (address % 4)
	{
		__builtin_tblwtl(0, 0xFFFF);            // Mask the low word of 1-st instruction into the latch.
		__builtin_tblwth(1, 0x00FF);            // Mask the high word of 1-st instruction into the latch. (8 bits of data + 8 bits of "phantom data" (phantom byte is always 0))

		__builtin_tblwtl(2, writeData.word.LW);	// Write the low word of 2-nd instruction into the latch
		__builtin_tblwth(3, writeData.word.HW);	// Write the high word of 2-nd instruction into the latch 		
	}
	else
	{
		__builtin_tblwtl(0, writeData.word.LW); // Write the low word of 1-st instruction into the latch
		__builtin_tblwth(1, writeData.word.HW); // Write the high word of 1-st instruction into the latch 
		__builtin_tblwtl(2, 0xFFFF);            // Mask the low word of 2-nd instruction into the latch.
		__builtin_tblwth(3, 0x00FF);            // Mask the high word of 2-nd instruction into the latch. (8 bits of data + 8 bits of "phantom data" (phantom byte is always 0))
	}

	INTCON2bits.GIE = 0;                        // Disable interrupts for next few instructions for unlock sequence
	__builtin_write_NVM();
	while(NVMCONbits.WR == 1){}
	INTCON2bits.GIE = 1;                        // Re-enable the interrupts (if required).

	return NVMCONbits.WRERR;                    // Return WRERR state.
}
Beispiel #6
0
void write_freq(WORD newData)
{
  WORD offset;

  NVMCON = 0x4058;

  TBLPAG = __builtin_tblpage(&dat);
  offset = __builtin_tbloffset(&dat);
  __builtin_tblwtl(offset,0);

  asm volatile("disi #5");
  __builtin_write_NVM();
  while(NVMCONbits.WR == 1);

  NVMCON = 0x4004;

  TBLPAG = __builtin_tblpage(&dat);
  offset = __builtin_tbloffset(&dat);
  __builtin_tblwtl(offset,newData);

  asm volatile("disi #5");
  __builtin_write_NVM();
  while(NVMCONbits.WR == 1);
}
Beispiel #7
0
BOOL FlashErasePage(DWORD address) {
  assert((address & 0x3FF) == 0);
  DWORD_VAL a = { address };

  NVMCON = 0x4042;  // Erase page

  TBLPAG = a.byte.UB;
  __builtin_tblwtl(a.word.LW, 0xFFFF);

  asm("DISI #5");
  __builtin_write_NVM();
  while(NVMCONbits.WR);
  NVMCONbits.WREN = 0;
  return NVMCONbits.WRERR == 0;
}	
void EraseFlash(void)
{
	DWORD_VAL MemAddressToErase = {0x00000000};
	MemAddressToErase.Val = (((DWORD)ErasePageTracker) << 10);

	NVMCON = 0x4042;				//Erase page on next WR

	TBLPAG = MemAddressToErase.byte.UB;
	__builtin_tblwtl(MemAddressToErase.word.LW, 0xFFFF);

	asm("DISI #16");					//Disable interrupts for next few instructions for unlock sequence
	__builtin_write_NVM();
    while(NVMCONbits.WR == 1){}

//	EECON1bits.WREN = 0;  //Good practice now to clear the WREN bit, as further protection against any future accidental activation of self write/erase operations.
}
Beispiel #9
0
BOOL FlashWriteDWORD(DWORD address, DWORD value)	{
  assert((address & 0x1) == 0);
  DWORD_VAL a = { address };
  DWORD_VAL v = { value };

  NVMCON = 0x4003;  // Word write

  TBLPAG = a.word.HW;
  __builtin_tblwtl(a.word.LW, v.word.LW);		//Write the low word to the latch
  __builtin_tblwth(a.word.LW, v.word.HW); 	//Write the high word to the latch (8 bits of data + 8 bits of "phantom data")

  asm("DISI #5");
  __builtin_write_NVM();
  while (NVMCONbits.WR);
  NVMCONbits.WREN = 0;
  return NVMCONbits.WRERR == 0;
}
Beispiel #10
0
/*********************************************************************
 * Function:        unsigned int NVMErasePage(void* address)
 *
 * Description:     A page erase will erase a single page of program flash,
 *                  which equates to 1k instructions (3KBytes). The page to
 *                  be erased is selected using NVMADDR. The lower bytes of
 *                  the address given by NVMADDR are ignored in page selection.
 *
 * PreCondition:    None
 *
 * Inputs:          address:  Destination page address to Erase.
 *
 * Output:          '0' if operation completed successfully.
 *
 * Example:         NVMemErasePage(UINT32 0xBD000000)
 ********************************************************************/
UINT NVMemErasePage(UINT32 address)
{
	DWORD_VAL eraseAddress;
	eraseAddress.Val = address;

	TBLPAG = eraseAddress.byte.UB;
	NVMADRU = eraseAddress.word.HW;
	NVMADR = eraseAddress.word.LW;
	__builtin_tblwtl(eraseAddress.word.LW, 0xFFFF);
	NVMCON = 0x4003;                // Erase page on next WR

	INTCON2bits.GIE = 0;            // Disable interrupts for next few instructions for unlock sequence
	__builtin_write_NVM();
	while(NVMCONbits.WR == 1) {}
	INTCON2bits.GIE = 1;            // Re-enable the interrupts (if required).

	return NVMCONbits.WRERR;        // Return WRERR state.
}
Beispiel #11
0
void flashProgram1Instruction ( u32 * wordAddress, u32 instruction )
{
    DWORD_VAL value;
    u32 temp = *wordAddress;
    u32 offset = temp & FLASH_TABLE_PAGE_SIZE_MASK; /* offset into table page */
    TBLPAG = temp >> FLASH_TABLE_PAGE_SIZE_SHIFT; /* select table page */

    /* a pic 24 word is 16-bits, we write 3-Bytes + phantom = 2 16-bit words */
    *wordAddress += 2;

    value.Val = instruction;

    __builtin_tblwtl( offset, value.word.LW );
    __builtin_tblwth( offset, value.word.HW );

    NVMCON = FLASH_ACCESS_WORD_PROGRAM;
    asm("DISI #5");
    __builtin_write_NVM();
    while(NVMCONbits.WR == 1);
}
Beispiel #12
0
void clear_flash()
{
	uint32_t prog_addr = USER_REGION_BASE;
	size_t offset;

	/* Clear each flash block. TBLPAG/offset is set to the
	 * base address (lowest address) of each block. */
	while (prog_addr < USER_REGION_TOP) {
		TBLPAG = prog_addr >> 16;
		offset = prog_addr & 0xffff;

		__builtin_tblwtl(offset, 0x00);
		NVMCON = 0x4042;
		asm("DISI #5");
		__builtin_write_NVM();

		while (NVMCONbits.WR == 1)
			;

		prog_addr += FLASH_BLOCK_SIZE;
	}
}
Beispiel #13
0
BOOL FlashWriteBlock(DWORD address, BYTE block[192]) {
  assert((address & 0x7F) == 0);
  unsigned int i = 0;
  DWORD_VAL a = { address };
  DWORD_VAL v;

  NVMCON = 0x4001;  // Block write

  TBLPAG = a.word.HW;
  while (i < 192) {
    v.byte.LB = block[i++];
    v.byte.HB = block[i++];
    v.byte.UB = block[i++];
    __builtin_tblwtl(a.word.LW, v.word.LW);  // Write the low word to the latch
    __builtin_tblwth(a.word.LW, v.word.HW);  // Write the high word to the latch (8 bits of data + 8 bits of "phantom data")
    a.word.LW += 2;
  }

  asm("DISI #5");
  __builtin_write_NVM();
  while (NVMCONbits.WR);
  NVMCONbits.WREN = 0;
  return NVMCONbits.WRERR == 0;
}
Beispiel #14
0
/********************************************************************
* Function: 	void HandleCommand()
*
* Precondition: data in buffer
*
* Input: 		None.
*
* Output:		None.
*
* Side Effects:	None.
*
* Overview: 	Handles commands received from host
*			
* Note:		 	None.
********************************************************************/
void HandleCommand()
{
	
	BYTE Command;
	BYTE length;

	//variables used in EE and CONFIG read/writes
	#if (defined(DEV_HAS_EEPROM) || defined(DEV_HAS_CONFIG_BITS))	
		WORD i=0;
		WORD_VAL temp;
		WORD bytesRead = 0;	
	#endif

	Command = buffer[0];	//get command from buffer
	length = buffer[1];		//get data length from buffer

	//RESET Command
	if(length == 0x00){
        UxMODEbits.UARTEN = 0;  //Disable UART
		ResetDevice(userReset.Val);
	}

	//get 24-bit address from buffer
	sourceAddr.v[0] = buffer[2];		
	sourceAddr.v[1] = buffer[3];
	sourceAddr.v[2] = buffer[4];
	sourceAddr.v[3] = 0;

	#ifdef USE_RUNAWAY_PROTECT
	writeKey1 |= (WORD)sourceAddr.Val;	// Modify keys to ensure proper program flow
	writeKey2 =  writeKey2 << 1;
	#endif

	//Handle Commands		
	switch(Command)
	{
		case RD_VER:						//Read version	
			buffer[2] = MINOR_VERSION;
			buffer[3] = MAJOR_VERSION;

			responseBytes = 4; //set length of reply
			break;
		
		case RD_FLASH:						//Read flash memory
			ReadPM(length, sourceAddr); 

				responseBytes = length*PM_INSTR_SIZE + 5; //set length of reply    									  
			break;
		
		case WT_FLASH:						//Write flash memory

			#ifdef USE_RUNAWAY_PROTECT
				writeKey1 -= length;	// Modify keys to ensure proper program flow
				writeKey2 += Command;		
			#endif

			WritePM(length, sourceAddr);	

			responseBytes = 1; //set length of reply
 			break;

		case ER_FLASH:						//Erase flash memory

			#ifdef USE_RUNAWAY_PROTECT
				writeKey1 += length;	// Modify keys to ensure proper program flow
				writeKey2 -= Command;
			#endif

			ErasePM(length, sourceAddr);	

			responseBytes = 1; //set length of reply
			break;
	
		#ifdef DEV_HAS_EEPROM
		case RD_EEDATA:						//Read EEPROM
			//if device has onboard EEPROM, allow EE reads

			//Read length words of EEPROM
			while(i < length*2){
				temp.Val = ReadLatch(sourceAddr.word.HW, 
									 sourceAddr.word.LW);
				buffer[5+i++] = temp.v[0];
				buffer[5+i++] = temp.v[1];
				sourceAddr.Val += 2;
			}

			responseBytes = length*2 + 5; //set length of reply
			break;
		
		case WT_EEDATA:						//Write EEPROM
        
			#ifdef USE_RUNAWAY_PROTECT
				writeKey1 -= length;	// Modify keys to ensure proper program flow
				writeKey2 += Command;		
			#endif
            
			//Write length words of EEPROM
			while(i < length*2){
				temp.byte.LB = buffer[5+i++];  //load data to write
				temp.byte.HB = buffer[5+i++];
	
				WriteLatch(sourceAddr.word.HW,sourceAddr.word.LW,
						   0, temp.Val);  //write data to latch

				#ifdef USE_RUNAWAY_PROTECT
					writeKey1++;
					writeKey2--;

					//setup program flow protection test keys
					keyTest1 =	(((0x0009 | (WORD)(sourceAddr.Val-i)) -
								length) + i/2) - 5;
					keyTest2 =  (((0x557F << 1) + WT_EEDATA) - i/2) + 6;

					//initiate write sequence
					WriteMem(EE_WORD_WRITE);

					writeKey1 += 5; // Modify keys to ensure proper program flow
					writeKey2 -= 6;	
				#else
					//initiate write sequence bypasssing runaway protection
					WriteMem(EE_WORD_WRITE);  
				#endif
				
				sourceAddr.Val +=2;
			}
			

			responseBytes = 1; //set length of reply
			break;
		#endif

		#ifdef DEV_HAS_CONFIG_BITS
		case RD_CONFIG:						//Read config memory

			//Read length bytes from config memory
			while(bytesRead < length)
			{
				//read flash
				temp.Val = ReadLatch(sourceAddr.word.HW, sourceAddr.word.LW);

				buffer[bytesRead+5] = temp.v[0];   	//put read data onto buffer
		
				bytesRead++; 

				sourceAddr.Val += 2;  //increment addr by 2
			}

			responseBytes = length + 5;

			break;
		case WT_CONFIG:						//Write Config mem

            //Write length  bytes of config memory
			while(i < length){
				temp.byte.LB = buffer[5+i++];  //load data to write
				temp.byte.HB = 0;
    
				#ifdef USE_RUNAWAY_PROTECT
   					writeKey1++;
   					writeKey2--;
                #endif
        	
                //Make sure that config write is inside implemented configuration space
                if(sourceAddr.Val >= CONFIG_START && sourceAddr.Val <= CONFIG_END)
                {
				
                    TBLPAG = sourceAddr.byte.UB;
                    __builtin_tblwtl(sourceAddr.word.LW,temp.Val);
    			
                    #ifdef USE_RUNAWAY_PROTECT
    					//setup program flow protection test keys
    					keyTest1 =	(((0x0009 | (WORD)(sourceAddr.Val-i*2)) -
    								length) + i) - 5;
    					keyTest2 =  (((0x557F << 1) + WT_CONFIG) - i) + 6;
    
    					//initiate write sequence
    					WriteMem(CONFIG_WORD_WRITE);
    
    					writeKey1 += 5; // Modify keys to ensure proper program flow
    					writeKey2 -= 6;	
    				#else
    					//initiate write sequence bypasssing runaway protection
    					WriteMem(CONFIG_WORD_WRITE);  
    				#endif

                }//end if(sourceAddr.Val...)

				sourceAddr.Val +=2;
			}//end while(i < length)

			responseBytes = 1; //set length of reply
			break;
		#endif
		case VERIFY_OK:

			#ifdef USE_RUNAWAY_PROTECT
				writeKey1 -= 1;		// Modify keys to ensure proper program flow
				writeKey2 += Command;		
			#endif

			WriteTimeout();
		
			responseBytes = 1; //set length of reply
			break;

		default:
			break;
	}// end switch(Command)
}//end HandleCommand()
Beispiel #15
0
BYTE MDD_IntFlash_SectorWrite(DWORD sector_addr, BYTE* buffer, BYTE allowWriteToZero)
{
#if !defined(INTERNAL_FLASH_WRITE_PROTECT)
    WORD i;
    BYTE j;
    WORD offset;
    DWORD flashAddress;
    WORD TBLPAGSave;


    //First, error check the resulting address, to make sure the MSD host isn't trying 
    //to erase/program illegal LBAs that are not part of the designated MSD volume space.
    if(sector_addr >= MDD_INTERNAL_FLASH_TOTAL_DISK_SIZE)
    {
        return FALSE;
    }  

    TBLPAGSave = TBLPAG;
    
#if defined (__dsPIC33E__) || defined (__PIC24E__)
    

    // First, save the contents of the entire erase page.  
    // To do this, we need to get a pointer to the start of the erase page.
    // AND mask 0xFFFFF800 is to clear the lower bits, 
    // so we go back to the start of the erase page.
    
    flashAddress = ((DWORD)FILES_ADDRESS + (DWORD)(sector_addr*MEDIA_SECTOR_SIZE)) 
                & (DWORD)0xFFFFF800;  
    
    //Now save all of the contents of the erase page.
    TBLPAG = (BYTE)(flashAddress >> 16);
    for(i = 0; i < ERASE_BLOCK_SIZE;i++)
    {
        file_buffer[i] = __builtin_tblrdl((WORD)flashAddress + (2 * i));
    }    

    // Now we want to overwrite the file_buffer[] contents 
    // for the sector that we are trying to write to.
    // The lower 2 bits of the helps to determine this.
   
    offset = 0x200 * (BYTE)(sector_addr & 0x3);   

    //Overwrite the file_buffer[] RAM contents for the sector that we are trying to write to.
    for(i = 0; i < MEDIA_SECTOR_SIZE; i++)
    {
        *((unsigned char *)file_buffer + offset + i) = *buffer++;
    }
#else

     //First, save the contents of the entire erase page.  To do this, we need to get a pointer to the start of the erase page.
    flashAddress = ((DWORD)FILES_ADDRESS + (DWORD)(sector_addr*MEDIA_SECTOR_SIZE)) & (DWORD)0xFFFFFC00;  //AND mask 0xFFFFFC00 is to clear the lower bits, so we go back to the start of the erase page.
    //Now save all of the contents of the erase page.
    for(i = 0; i < ERASE_BLOCK_SIZE;)
    {
        TBLPAG = (BYTE)(flashAddress >> 16);
        *(WORD*)&file_buffer[i] = __builtin_tblrdl((WORD)flashAddress);
        flashAddress += 2u;    //Skipping upper word.  Don't care about the implemented byte/don't use it when programming or reading from the sector.
        i += 2u;
    }    

    //Now we want to overwrite the file_buffer[] contents for the sector that we are trying to write to.
    //Need to figure out if the buffer[] data goes in the upper sector or the lower sector of the file_buffer[]
    if(sector_addr & 0x00000001)
    {
        //Odd sector address, must be the high file_buffer[] sector
        offset = MEDIA_SECTOR_SIZE;
    }
    else
    {
        offset = 0;
    }        

    //Overwrite the file_buffer[] RAM contents for the sector that we are trying to write to.
    for(i = 0; i < MEDIA_SECTOR_SIZE; i++)
    {
        file_buffer[offset + i] = *buffer++;
    }
    #endif
    

#if defined(__dsPIC33E__) || defined (__PIC24E__)

    INT gieBkUp;

    //Now erase the entire erase page of flash memory.  
    //First we need to calculate the actual flash memory 
    //address of the erase page. 
    
    gieBkUp = INTCON2bits.GIE;
    INTCON2bits.GIE = 0; // Disable interrupts
    NVMADRU = (WORD)(flashAddress >> 16);
    NVMADR = (WORD)(flashAddress & 0xFFFF);
    NVMCON = 0x4003;    // This value will erase a page.
    __builtin_write_NVM();
    INTCON2bits.GIE = gieBkUp; // Enable interrupts

    //Now reprogram the erase page with previously obtained contents of the file_buffer[]
    //We only write to the even flash word addresses, the odd word addresses are left blank.  
    //Therefore, we only store 2 bytes of application data for every 2 flash memory word addresses.
    //This "wastes" 1/3 of the flash memory, but it provides extra protection from accidentally executing
    //the data.  It also allows quick/convenient PSV access when reading back the flash contents.

    TBLPAG = 0xFA;
    j = 0;
    for(i = 0; i < ERASE_BLOCK_SIZE;i++)
    {

       //
        __builtin_tblwtl((j * 2), file_buffer[i]);
        __builtin_tblwth((j * 2), 0);
           
        j ++;

        //Check if we have reached a program block size boundary.  If so, program the last 128 
        //useful bytes (192 bytes total, but 64 of those are filled with '0' filler bytes).
        if(j >= 128u)
        {
            j = j - 128u;
            NVMADRU = (WORD)(flashAddress >> 16);
            NVMADR = (WORD)(flashAddress & 0xFFFF);
            NVMCON = 0x4002;
            gieBkUp = INTCON2bits.GIE;
            INTCON2bits.GIE = 0; // Disable interrupts
            __builtin_write_NVM();
            INTCON2bits.GIE = gieBkUp; // Enable interrupts
            flashAddress += 256;
        }    
    }