WORD read_freq(void) { WORD offset; TBLPAG = __builtin_tblpage(&dat); offset = __builtin_tbloffset(&dat); return(__builtin_tblrdl(offset)); }
DWORD FlashReadDWORD(DWORD address) { DWORD_VAL a = { address }; DWORD_VAL res; TBLPAG = a.word.HW; res.word.HW = __builtin_tblrdh(a.word.LW); res.word.LW = __builtin_tblrdl(a.word.LW); return res.Val; }
/********************************************************************* * Function: static DWORD ReadProgramMemory(DWORD address) * * PreCondition: None * * Input: Program memory address to read from. Should be * an even number. * * Output: Program word at the specified address. For the * PIC24, dsPIC, etc. which have a 24 bit program * word size, the upper byte is 0x00. * * Side Effects: None * * Overview: Modifies and restores TBLPAG. Make sure that if * using interrupts and the PSV feature of the CPU * in an ISR that the TBLPAG register is preloaded * with the correct value (rather than assuming * TBLPAG is always pointing to the .const section. * * Note: None ********************************************************************/ static DWORD ReadProgramMemory(DWORD address) { DWORD dwResult; WORD wTBLPAGSave; wTBLPAGSave = TBLPAG; TBLPAG = ((WORD*)&address)[1]; ((WORD*)&dwResult)[1] = __builtin_tblrdh((WORD)address); ((WORD*)&dwResult)[0] = __builtin_tblrdl((WORD)address); TBLPAG = wTBLPAGSave; return dwResult; }
/******************************************************************** * Function: ValidAppPresent() ********************************************************************/ BOOL ValidAppPresent(void) { volatile DWORD AppPtr; TBLPAG = 0x00; AppPtr = ((DWORD)__builtin_tblrdh(0) << 16); AppPtr = AppPtr | ((DWORD)__builtin_tblrdl(0)); if(AppPtr == 0xFFFFFF) return FALSE; else return TRUE; }
DWORD ReadProgramMemory(DWORD address) { DWORD_VAL dwvResult; WORD wTBLPAGSave; wTBLPAGSave = TBLPAG; TBLPAG = ((DWORD_VAL*)&address)->w[1]; dwvResult.w[1] = __builtin_tblrdh((WORD)address); dwvResult.w[0] = __builtin_tblrdl((WORD)address); TBLPAG = wTBLPAGSave; return dwvResult.Val; }
u32 flashRead1Instruction ( u32 * wordAddress ) { 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.word.LW = __builtin_tblrdl( offset ); value.word.HW = __builtin_tblrdh( offset ); return value.Val; }
BYTE MDD_IntFlash_SectorRead(DWORD sector_addr, BYTE* buffer) { WORD i; DWORD flashAddress; BYTE TBLPAGSave; WORD_VAL temp; //Error check. Make sure the host is trying to read from a legitimate //address, which corresponds to the MSD volume (and not some other program //memory region beyond the end of the MSD volume). if(sector_addr >= MDD_INTERNAL_FLASH_TOTAL_DISK_SIZE) { return FALSE; } //Save TBLPAG register TBLPAGSave = TBLPAG; //Compute the 24 bit starting address. Note: this is a word address, but we //only store data in and read from the lower word (even LSB). //Starting address will always be even, since MasterBootRecord[] uses aligned attribute in declaration. flashAddress = (DWORD)FILES_ADDRESS + (DWORD)(sector_addr*(WORD)MEDIA_SECTOR_SIZE); //Read a sector worth of data from the flash, and copy to the user specified "buffer". for(i = 0; i < (MEDIA_SECTOR_SIZE / 2u); i++) { TBLPAG = (BYTE)(flashAddress >> 16); //Load TBLPAG pointer (upper 8 bits of total address. A sector could get split at //a 16-bit address boundary, and therefore could exist on two TBLPAG pages. //Therefore, need to reload TBLPAG every iteration of the for() loop temp.Val = __builtin_tblrdl((WORD)flashAddress); *buffer++ = temp.v[0]; *buffer++ = temp.v[1]; flashAddress += 2u; //Increment address by 2. No MSD data stored in the upper WORD (which only has one implemented byte anyway). } //Restore TBLPAG register to original value TBLPAG = TBLPAGSave; return TRUE; }
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; } }
} asm("DISI #5"); __builtin_write_NVM(); while (NVMCONbits.WR == 1) ; } /* Read an instruction from flash. word_addr is the word address, not * the byte address. */ static void read_flash(uint32_t word_addr, uint16_t *low, uint16_t *high) { TBLPAG = word_addr >> 16 & 0xff; *high = __builtin_tblrdh(word_addr & 0xffff); *low = __builtin_tblrdl(word_addr & 0xffff); } /* Read data starting at prog_addr into the global prog_buf. prog_addr * and len are in words, not bytes. */ static void read_prog_data(uint32_t prog_addr, uint32_t len/*words*/) { int i; for (i = 0; i < len; i += 2) { read_flash(prog_addr + i, &prog_buf[i] /*low*/, &prog_buf[i+1] /*high*/); } } int main(void)