//! \brief Launch a copy-back session //! //! \param page_addr absolute recipient page address of the block //! //! \pre <code>nf_init()</code> should have been called before. //! void nfc_copy_back_conf( U32 page_addr ) { nf_wait_busy(); nf_wr_cmd(NF_RANDOM_DATA_INPUT_CMD); nf_wr_addr( 0 ); nf_wr_addr( 0 ); nf_wr_addr( LSB0(page_addr) ); nf_wr_addr( LSB1(page_addr) ); if ( 3==G_N_ROW_CYCLES ) { nf_wr_addr( MSB1(page_addr) ); } nf_wr_cmd(NF_PAGE_PROGRAM_CMD); }
//! \brief Prepare a copy-back session //! //! \param page_addr absolute source page address of the block //! //! \pre <code>nf_init()</code> should have been called before. //! void nf_copy_back_init( U32 page_addr ) { nf_wait_busy(); nf_wr_cmd(NF_READ_CMD); nf_wr_addr( 0 ); nf_wr_addr( 0 ); nf_wr_addr( LSB0(page_addr) ); nf_wr_addr( LSB1(page_addr) ); if ( 3==G_N_ROW_CYCLES ) { nf_wr_addr( MSB1(page_addr) ); } nf_wr_cmd(NF_COPY_BACK_CMD); nf_wait_busy(); }
//! \brief Tests the Nand Flash configuration //! //! The function verifies that the connected NF is //! properly declared in conf_nf.h. //! //! \param nb_dev number of device //! //! \return The number of device connected and corresponding //! to NF identifiers. //! U8 nf_check_type( U8 nb_dev ) { U8 i_dev; //nf_init( nb_dev, 0 ); #warning Update for full support. nf_reset_nands( nb_dev ); // Reset all the NF devices // Test NF configuration // for( i_dev=0 ; i_dev<nb_dev ; i_dev++ ) { nf_select( i_dev ); nf_wait_busy(); nf_force_CE(); nf_wr_cmd(NF_READ_ID_CMD); nf_wr_addr( 0 ); if(( nf_rd_data()!=G_DEV_MAKER ) || ( nf_rd_data()!=G_DEV_ID )) { Assert( false ); return i_dev; } if( G_CE_LOW ) { // Activate CE Low if needed. This config is static // and we supposed that it is no more deactivated in firmware. nf_force_CE(); } } return nb_dev; }
//! \brief Erases a block. //! //! The erase will be done only if the block is not bad //! //! \param page_addr absolute page address of the block //! \param force_erase true forces erasing, false erases the block (if not bad) //! //! \pre <code>nf_init()</code> should have been called before. //! The device which holds the block to delete should have been selected //! before with <code>nf_select( id )</code>. //! void nf_erase_block( U32 page_addr, U8 force_erase ) { if( false==force_erase ) { nf_open_page_read( page_addr, NF_SPARE_POS + G_OFST_BLK_STATUS ); if( (nf_rd_data()!=0xFF) ) return; // The block is bad. We can not erase it } nf_wait_busy(); nf_wr_cmd(NF_BLOCK_ERASE_CMD); // Auto Block Erase Setup nf_wr_addr( LSB0(page_addr) ); nf_wr_addr( LSB1(page_addr) ); if ( 3==G_N_ROW_CYCLES ) { nf_wr_addr( MSB1(page_addr) ); } nf_wr_cmd(NF_BLOCK_ERASE_CONFIRM_CMD); // Erase command }
//! \brief Read the ID of the Nand-Flash //! //! \param read_id_cmd Read_id command (NF_READ_ID_CMD, NF_READ_ID2_CMD) //! \param nf_num Nand Flash number //! //! \return : //! MSB0(ret) (MSB) is the Maker Code, //! MSB1(ret) is the Device Id, //! MSB2(ret) is 3rd byte returned, //! MSB3(ret) (LSB) is 4th byte returned. //! //! \pre <code>nf_init()</code> should have been called before. //! U32 nf_read_id( U8 read_id_cmd, U8 nf_num ) { U32 ret; nf_select( nf_num ); nf_wait_busy(); //nf_force_CE(); nf_wr_cmd (read_id_cmd); nf_wr_addr( 0 ); MSB0(ret)= nf_rd_data(); // Maker Code MSB1(ret)= nf_rd_data(); // Device Id MSB2(ret)= nf_rd_data(); // extra MSB3(ret)= nf_rd_data(); // extra (Multi Plane Support) //Nfc_action( NFC_ACT_ASSERT_CE, NFC_EXT_NOP); return ret; }
// main function int main(void) { bool valid_block_found[NF_N_DEVICES]; U32 u32_nf_ids, i_dev, i_block; U8 maker_id, device_id; U32 i, j; // ECCHRS options. static const ecchrs_options_t ECCHRS_OPTIONS = { .typecorrect = ECCHRS_TYPECORRECT_4_BIT, .pagesize = ECCHRS_PAGESIZE_4_BIT_2112_W }; // switch to oscillator 0 pcl_switch_to_osc(PCL_OSC0, FOSC0, OSC0_STARTUP); // init debug serial interface init_dbg_rs232(FOSC0); nf_init(FOSC0); // init the nand flash driver with the correct HSB frequency nf_unprotect(); print_dbg("\r\nECCHRS example using Nand Flash.\r\n================================\r\n\r\n"); // - Simple test of the NF communication through the SMC. // - Find all bad blocks. // - Find a valid block for the remaining tests. nf_reset_nands(NF_N_DEVICES); print_dbg("\tCPU, HSB is at 12000000Mhz.\r\n"); print_dbg("\tPBA, PBB is at 12000000Mhz.\r\n"); print_dbg("\tDetecting Nand Flash device(s).\r\n"); for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ ) { // Performs some init here... valid_block_found[i_dev] = false; // Test Maker and Device ids u32_nf_ids = nf_read_id( NF_READ_ID_CMD, i_dev ); maker_id = MSB0(u32_nf_ids); device_id = MSB1(u32_nf_ids); print_dbg("\t\tNF"); print_dbg_hex(i_dev); print_dbg(" [Maker="); print_dbg_hex(maker_id); print_dbg("] [Device="); print_dbg_hex(device_id); print_dbg("]\r\n"); if( maker_id==M_ID_MICRON ) { print_dbg("\t\t Micron chip"); if( device_id==0xDA ){ print_dbg("- MT29F2G08AACWP device\r\n"); } else { print_dbg("- *** Error: unexpected chip detected. Please check the board settings and hardware.\r\n"); return -1; } } else { print_dbg("\t\t *** Error: unexpected chip detected. Please check the board settings and hardware.\r\n"); return -1; } } // Looking for valid blocks for the test. for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ ) { nf_select(i_dev); for( i_block=0 ; i_block<G_N_BLOCKS ; i_block++ ) { nf_open_page_read( nf_block_2_page(i_block), NF_SPARE_POS + G_OFST_BLK_STATUS ); if( (nf_rd_data()==0xFF) ) { // The block is valid. print_dbg("\tValid block found ("); print_dbg_ulong(i_block); print_dbg(") on NF "); print_dbg_hex(i_dev); print_dbg("\r\n"); valid_block_found[i_dev]= true; valid_block_addr[i_dev] = i_block; break; } } } for( i_dev=0 ; i_dev<NF_N_DEVICES ; i_dev++ ) if( !valid_block_found[i_dev] ) { print_dbg("Error: no valid blocks found.\r\n"); return 0; } print_dbg("\tECCHRS IP ver "); print_dbg_ulong(ecchrs->version); print_dbg("("); print_dbg_hex(ecchrs->version); print_dbg(")"); print_dbg("\r\n"); // Work with NF 0 from now... nf_select(0); // Setup the ECCHRS. ecchrs_init(&AVR32_ECCHRS, &ECCHRS_OPTIONS); // Ensures that the block is erased for the test. print_dbg("\tErasing a free block for the test.\r\n"); nf_erase_block(nf_block_2_page(valid_block_addr[0]), false); // Reset the ECCHRS state machine. ecchrs_reset(&AVR32_ECCHRS); // Program a simple patterns in the first page. print_dbg("\tProgramming the first page with a simple pattern.\r\n"); nf_open_page_write( nf_block_2_page(valid_block_addr[0]), 0); for ( i = 0; i < 2048/2; i++ ) { U16 val = i; nf_wr_data(MSB(val)); nf_wr_data(LSB(val)); } // Extract the ECCs and store them at the end of the page. // [2054; 2063]: codeword 0:9 // [2070; 2079]: codeword 10:19 // [2086; 2095]: codeword 20:29 // [2102; 2111]: codeword 30:39 // Since we use the Random Data Output command, we need to freeze // the ECCHRS in order to keep our ECC codewords unchanged. print_dbg("\tExtracting the ECCHRS codewords and store them in the page.\r\n"); ecchrs_freeze(&AVR32_ECCHRS); // not needed if ECCHRS reaches the end of page. for ( i=0 ; i<4 ; i++ ) { U16 offset = 2048+6+16*i; nf_wr_cmd(NF_RANDOM_DATA_INPUT_CMD); nf_wr_addr( LSB(offset) ); nf_wr_addr( MSB(offset) ); for ( j=0 ; j<10 ; j++ ) nf_wr_data( ecchrs_get_cw(&AVR32_ECCHRS, i*10+j) ); } ecchrs_unfreeze(&AVR32_ECCHRS); nf_wr_cmd(NF_PAGE_PROGRAM_CMD); // Now let's test the ECC verification. print_dbg("\tReading the first page.\r\n"); nf_open_page_read( nf_block_2_page(valid_block_addr[0]), 0); for( i=0 ; i<2048 ; i++ ) nf_rd_data(); print_dbg("\tChecking if the data are valid thanks to the ECCHRS codewords.\r\n"); for ( i=0 ; i<4 ; i++ ) { U16 offset = 2048+6+16*i; ecchrs_freeze(&AVR32_ECCHRS); nf_wr_cmd(NF_RANDOM_READ_CMD_C1); nf_wr_addr( LSB(offset) ); nf_wr_addr( MSB(offset) ); nf_wr_cmd(NF_RANDOM_READ_CMD_C2); ecchrs_unfreeze(&AVR32_ECCHRS); for ( j=0 ; j<10 ; j++ ) nf_rd_data(); } // Check if there is any errors after the read of the page. i = ecchrs_4bit_check_error(&AVR32_ECCHRS); print_dbg("\tSR1 is "); print_dbg_ulong(i); print_dbg("("); print_dbg_hex(i); print_dbg(")"); print_dbg("\r\n"); if(i&(15)) { print_dbg("\tERROR: ECCHRS detects some errors in the sectors 1, 2, 3 or 4\r\n"); } else print_dbg("\tNo error detected.\r\n"); // Let the block free. nf_erase_block(nf_block_2_page(valid_block_addr[0]), false); return 0; }