I want to interface a 16MB external flash (SPI) with nrf52832 on the development board.Suggest me how should I start with and if there is an example for external flash then let me know.
I want to interface a 16MB external flash (SPI) with nrf52832 on the development board.Suggest me how should I start with and if there is an example for external flash then let me know.
I am able to see only a high pulse on MISO line on logic analyser. I did try RDID command I am getting correct values but data which I get is always 0XFF.
Hi Torbjorn,
I am able to read the data now.It was due to some hardware issues that I was not able to read on MISO line.But now I am facing issue in erasing the chip.what else do I need to send to erase chip/ sector/block with it's instruction command?
Hi
This should be described in the datasheet of your flash device.
If you can't find it there please share the datasheet with me, and I will have a look.
Best regards
Torbjørn
Ok sharing with you the datasheet and the code which I am using. I added delay after CS_LOW so I am able to get the chip erase done. but still the issue is that after sending chip erase function I am not abl to write it. Also sector earse is not working ,I think I am struggling with the timing issues. I will be grateful if you can help me with these issues and make my flash running propelry.MX25R1635F, Wide Range, 16Mb, v1.6.pdf
and the code as below
///** // ****************************************************************************** // * @file ext_flash.c // * This source file provides external flash memory related functionalities. // * // * @author Glide Embedded Technology <www.glidemtech.com> // * @date 7, August, 2019 // ****************************************************************************** // */ // ///* Includes ------------------------------------------------------------------*/ ///* Includes ------------------------------------------------------------------*/ #include <stdio.h> #include <string.h> #include <stdint.h> // #include "external_flash.h" #include <hal/nrf_gpio.h> #include <hal/nrf_spi.h> #include "nrf_drv_spi.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "nrf_delay.h" uint8_t print = 1; #define SPI_INSTANCE 0 /**< SPI instance index. */ static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); #define WAIT_FOR_PERIPH() do { \ while (!m_finished) {} \ m_finished = false; \ } while (0) static volatile bool m_finished = false; static uint8_t m_buffer_tx[256]; static uint8_t m_buffer_rx[256]; //static uint8_t m_data_send[256]; static uint8_t m_data_receive[256]; #define TEST_STRING "Z" //"Nordic" static uint8_t m_tx_buf[] = TEST_STRING; /**< TX buffer. */ static uint8_t m_rx_buf[sizeof(TEST_STRING) + 1]; /**< RX buffer. */ static const uint8_t m_length = sizeof(m_tx_buf); static uint8_t m_buffer_tx[256]; static uint8_t m_buffer_rx[256]; //static uint8_t m_data_send[256]; static uint8_t m_data_receive[256]; static uint8_t m_data_send[256] = {[0 ... 255] = 0xbb}; uint8_t StatusReg; uint8_t ConfigReg; uint8_t SecurityReg; /** * @brief SPI user event handler. * @param event */ void spi_event_handler(nrf_drv_spi_evt_t const * p_event, void * p_context) { m_finished = true; uint16_t i ; //printf("\n\rTransfer completed."); if (m_buffer_rx[0] != 0) { // printf(" Received:"); for(i=0;i<8;i++) { // printf("m_buffer_rx[%d] = %x ",i,m_buffer_rx[i]); } NRF_LOG_HEXDUMP_INFO(m_buffer_rx, strlen((const char *)m_buffer_rx)); } // nrf_gpio_pin_set(SPI_SS_PIN); } void cs_low(void) { nrf_gpio_pin_set(SPI_SS_PIN); } void cs_high(void) { nrf_gpio_pin_clear(SPI_SS_PIN); } /* * Reset setting Command */ /* * Function: CMD_RSTEN * Arguments: None. * Description: Enable RST command * Return Message: FlashOperationSuccess */ ReturnMsg cmd_rsten( void ) { // Chip select go low to start a flash command cs_low(); // Write RSTEN command uint8_t instruction = FLASH_CMD_RSTEN; m_buffer_tx[0] = instruction; nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,1); // Chip select go high to end a flash command cs_high(); return FlashOperationSuccess; } /* * Function: CMD_RST * Arguments: fsptr, pointer of flash status structure * Description: The RST instruction is used as a system (software) reset that * puts the device in normal operating Ready mode. * Return Message: FlashOperationSuccess */ ReturnMsg cmd_rst( void ) { // Chip select go low to start a flash command cs_low(); // Write RST command = 0x99 uint8_t instruction = FLASH_CMD_RST; m_buffer_tx[0] = instruction; nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,1); // Chip select go high to end a flash command cs_high(); return FlashOperationSuccess; } /* * Function: CMD_WRSR * Arguments: UpdateValue, 8/16 bit status register value to updata * Description: The WRSR instruction is for changing the values of * Status Register Bits (and configuration register) * Return Message: FlashIsBusy, FlashTimeOut, FlashOperationSuccess */ //ReturnMsg cmd_wrsr( uint8_t UpdateValue ) // //{ // // Check flash is busy or not // if( IsFlashBusy() ) return FlashIsBusy; // // // Setting Write Enable Latch bit // uint8_t err_code; // err_code = cmd_wren(); // // // Chip select go low to start a flash command //// cs_low(); // // // Send command and update value // // uint8_t instruction[9] = {0}; // instruction[0] = FLASH_CMD_WRSR; // nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,1,m_buffer_rx,3); // nrf_delay_ms(2); // printf("UPDATE VALUE = %d",UpdateValue); // instruction[1]=UpdateValue; //// memcpy(instruction[1],UpdateValue,8); // nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction[1],2,m_buffer_rx,4); // ////#ifdef SUPPORT_WRSR_CR //// SendByte( UpdateValue >> 8, SIO ); // write configuration register ////#endif // // // Chip select go high to end a flash command // cs_high(); // // // if( WaitFlashReady( WriteStatusRegCycleTime ) ) // return FlashOperationSuccess; // else // return FlashTimeOut; // //} ReturnMsg cmd_wrsr( uint8_t UpdateValue ) { // Check flash is busy or not if( IsFlashBusy() ) return FlashIsBusy; // Setting Write Enable Latch bit uint8_t err_code; uint8_t read_value; nrf_gpio_pin_clear(SPI_WP_PIN); err_code = cmd_wren(); // Chip select go low to start a flash command // cs_low(); // Send command and update value err_code = cmd_rdsr(read_value); printf("rdsr valu = %d \n",read_value); if((read_value & 2)== 1) { uint8_t instruction[9] = {0}; instruction[0] = FLASH_CMD_WRSR; nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,1,m_buffer_rx,3); nrf_delay_ms(2); printf("UPDATE VALUE = %d",UpdateValue); instruction[1]=UpdateValue; // memcpy(instruction[1],UpdateValue,8); nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction[1],2,m_buffer_rx,4); err_code = cmd_rdsr(read_value); printf("rdsr valu = %d \n",read_value); if((read_value ^ 1)==1) { printf("wep is zero \n"); } } // uint8_t instruction[9] = {0}; // instruction[0] = FLASH_CMD_WRSR; // nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,1,m_buffer_rx,3); // nrf_delay_ms(2); // printf("UPDATE VALUE = %d",UpdateValue); // instruction[1]=UpdateValue; //// memcpy(instruction[1],UpdateValue,8); // nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction[1],2,m_buffer_rx,4); //#ifdef SUPPORT_WRSR_CR // SendByte( UpdateValue >> 8, SIO ); // write configuration register //#endif // Chip select go high to end a flash command cs_high(); if( WaitFlashReady( WriteStatusRegCycleTime ) ) return FlashOperationSuccess; else return FlashTimeOut; } /* * Function: CMD_RDSCUR * Arguments: SecurityReg, 8 bit buffer to store security register value * Description: The RDSCUR instruction is for reading the value of * Security Register bits. * Return Message: FlashOperationSuccess */ ReturnMsg cmd_rdscur( uint8_t *SecurityReg ) { uint8_t gDataBuffer; // Chip select go low to start a flash command cs_low(); //Send command uint8_t instruction = FLASH_CMD_RDSCUR; nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,1,gDataBuffer,3); // Chip select go high to end a flash command cs_high(); *SecurityReg = gDataBuffer; return FlashOperationSuccess; } /* * Function: CMD_WRSCUR * Arguments: None. * Description: The WRSCUR instruction is for changing the values of * Security Register Bits. * Return Message: FlashIsBusy, FlashOperationSuccess, FlashWriteRegFailed, * FlashTimeOut */ ReturnMsg cmd_wrscur( void ) { uint8_t gDataBuffer; // Check flash is busy or not if( IsFlashBusy() ) return FlashIsBusy; // Setting Write Enable Latch bit cmd_wren(); // Chip select go low to start a flash command cs_low(); // Write WRSCUR command uint8_t instruction = FLASH_CMD_WRSCUR; nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,1,gDataBuffer,3); // Chip select go high to end a flash command cs_high(); if( WaitFlashReady( WriteSecuRegCycleTime ) ){ cmd_rdscur( &gDataBuffer ); // Check security register LDSO bit if( (gDataBuffer & FLASH_LDSO_MASK) == FLASH_LDSO_MASK ) return FlashOperationSuccess; else return FlashWriteRegFailed; } else return FlashTimeOut; } /* * Function: CMD_RDID * Arguments: Identification, 32 bit buffer to store id * Description: The RDID instruction is to read the manufacturer ID * of 1-byte and followed by Device ID of 2-byte. * Return Message: FlashOperationSuccess */ ReturnMsg cmd_rdid( uint32_t *Identification ) { uint32_t temp; uint8_t gDataBuffer[3]; // Chip select go low to start a flash command cs_low(); // Send command // SendByte( FLASH_CMD_RDID, SIO ); uint8_t instruction = FLASH_CMD_RDID; nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,1,gDataBuffer,3); // Chip select go high to end a command cs_high(); // Store identification temp = gDataBuffer[0]; temp = (temp << 8) | gDataBuffer[1]; *Identification = (temp << 8) | gDataBuffer[2]; printf("rdid = %x %x",gDataBuffer [0],gDataBuffer [1]); return FlashOperationSuccess; } /* * Function: CMD_RES * Arguments: ElectricIdentification, 8 bit buffer to store electric id * Description: The RES instruction is to read the Device * electric identification of 1-byte. * Return Message: FlashOperationSuccess */ ReturnMsg cmd_res( uint8_t *ElectricIdentification ) { printf("cmd_res \n"); // Chip select go low to start a flash command cs_low(); // Send flash command and insert dummy cycle uint8_t instruction[4]; instruction[0]= FLASH_CMD_RES; instruction[1]= 0; instruction[2]=0; instruction[3]=0; nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,4,m_buffer_rx,5); // Get electric identification *ElectricIdentification = m_buffer_rx[4]; printf(" eid = %x\n",m_buffer_rx[4]); // Chip select go high to end a flash command cs_high(); return FlashOperationSuccess; } /* * Function: CMD_REMS * Arguments: REMS_Identification, 16 bit buffer to store id * fsptr, pointer of flash status structure * Description: The REMS instruction is to read the Device * manufacturer ID and electric ID of 1-byte. * Return Message: FlashOperationSuccess */ ReturnMsg cmd_rems( uint16_t *REMS_Identification, FlashStatus *fsptr ) { uint8_t gDataBuffer[2]; // Chip select go low to start a flash command cs_low(); // Send flash command and insert dummy cycle ( if need ) // ArrangeOpt = 0x00 will output the manufacturer's ID first // = 0x01 will output electric ID first // SendByte( FLASH_CMD_REMS, SIO ); // InsertDummyCycle( 16 ); // SendByte( fsptr->ArrangeOpt, SIO ); uint8_t instruction[4]; instruction[0]= FLASH_CMD_REMS; instruction[1]= 0; instruction[2]=0; instruction[3]=0x00; nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,4,m_buffer_rx,6); // Get ID gDataBuffer[0] = m_buffer_rx[2];//GetByte( SIO ); gDataBuffer[1] = m_buffer_rx[3];//GetByte( SIO ); // Store identification informaion *REMS_Identification = (gDataBuffer[0] << 8) | gDataBuffer[1]; // Chip select go high to end a flash command cs_high(); return FlashOperationSuccess; } void cmd_read( uint32_t flash_address, uint8_t *target_address, uint32_t byte_length ) { uint32_t index; uint8_t addr_4byte_mode; // Check flash address if( flash_address > FlashSize ) return FlashAddressInvalid; nrf_delay_ms(5); // Chip select go low to start a flash command cs_low(); // Write READ command and address uint8_t instruction; instruction = FLASH_CMD_READ; m_buffer_tx[0]= instruction; m_buffer_tx[1] = flash_address >> 16; m_buffer_tx[2] = flash_address >> 8; m_buffer_tx[3] = flash_address; nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,FLASH_CMD_READ_LENGHT,m_data_receive,FLASH_CMD_READ_LENGHT+16); // for( index=0; index < 4; index++ ) // { // printf("m_buffer_tx[%d] = %.02x \n",index,m_buffer_tx[index]); // nrf_delay_ms(10); // } // for( index=0; index < 20; index++ ) // { // printf("m_data_receive[%d] = %.02x \n",index,m_data_receive[index]); // nrf_delay_ms(10); // } // Chip select go high to end a flash command nrf_delay_ms(500); cs_high(); return true; } /* * Function: Wait_Flash_WarmUp * Arguments: None. * Description: Wait some time until flash read / write enable. * Return Message: None. */ void wait_flash_warm_up() { uint32_t time_cnt = FlashFullAccessTime; while( time_cnt > 0 ) { time_cnt--; } } uint8_t flash_ID_test( uint8_t id ) { uint8_t instruction[8] = {0}; uint8_t id_read = id; switch (id_read) { case 1: instruction[0] = FLASH_CMD_RES ; instruction[1]= 0x00; instruction[2] = 0x00; instruction[3]= 0x00; cs_low(); nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,4,m_buffer_rx,5); nrf_delay_ms(1); printf("\rValue is 1:"); printf("%02x,%02x,%02x,%02x,%02x,%02x,%02x \n",m_buffer_rx[0],m_buffer_rx[1],m_buffer_rx[2],m_buffer_rx[3],m_buffer_rx[4],m_buffer_rx[5],m_buffer_rx[6]); cs_high(); break; case 2: instruction[0] = FLASH_CMD_REMS ; instruction[1]= 0x01; instruction[2] = 0x02; instruction[3]= 0x00; printf("\rValue is 2:"); nrf_drv_spi_transfer(&spi,(uint8_t const *)instruction,4,m_buffer_rx,6); nrf_delay_ms(2); printf("%02x,%02x,%02x,%02x,%02x,%02x\n",m_buffer_rx[0],m_buffer_rx[1],m_buffer_rx[2],m_buffer_rx[3],m_buffer_rx[4],m_buffer_rx[5]); break; case 3: m_buffer_tx[0] = FLASH_CMD_RDID; cs_low(); // nrf_gpio_pin_clear(SPI_SS_PIN); nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,4); //nrf_delay_ms(2); //nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,3); nrf_delay_ms(2); printf("\rValue is 3:"); printf("%02x,%02x,%02x\n",m_buffer_rx[1],m_buffer_rx[2],m_buffer_rx[3]); // nrf_gpio_pin_set(SPI_SS_PIN); cs_high(); break; default: printf("Out of range"); break; } return true; } ReturnMsg cmd_rdsr( uint8_t *StatusReg ) { uint8_t gDataBuffer; // Chip select go low to start a flash command cs_low(); // Send command nrf_drv_spi_transfer(&spi,FLASH_CMD_RDSR,1,gDataBuffer,1); // Chip select go high to end a flash command cs_high(); *StatusReg = gDataBuffer; // printf("cmd_rdsr = %d \n",gDataBuffer); return FlashOperationSuccess; } ReturnMsg cmd_rdcr( uint8_t *StatusReg ) { uint8_t gDataBuffer; // Chip select go low to start a flash command cs_low(); // Send command // SendByte( FLASH_CMD_RDSR, SIO ); // gDataBuffer = GetByte( SIO ); nrf_drv_spi_transfer(&spi,FLASH_CMD_RDCR,1,gDataBuffer,1); // Chip select go high to end a flash command cs_high(); *StatusReg = gDataBuffer; // printf("status register = %x \n",StatusReg); return FlashOperationSuccess; } bool IsFlashBusy( void ) { uint8_t gDataBuffer; cmd_rdsr( &gDataBuffer ); if( (gDataBuffer & FLASH_WIP_MASK) == FLASH_WIP_MASK ) return true; else return false; } bool WaitFlashReady( uint32_t ExpectTime ) { uint32_t temp = 0; while( IsFlashBusy() ) { if( temp > ExpectTime ) { return false; } temp = temp + 1; } return true; } ReturnMsg cmd_wren( void ) { // Chip select go low to start a flash command cs_low(); // Write Enable command = 0x06, Setting Write Enable Latch Bit uint8_t instruction = FLASH_CMD_WREN; m_buffer_tx[0] = instruction; nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,1); // Chip select go high to end a flash command cs_high(); return FlashOperationSuccess; } ReturnMsg cmd_wrdis( void ) { // Chip select go low to start a flash command cs_low(); // Write Enable command = 0x06, Setting Write Enable Latch Bit uint8_t instruction = FLASH_CMD_WRDI; m_buffer_tx[0] = instruction; nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,1); // Chip select go high to end a flash command cs_high(); return FlashOperationSuccess; } ReturnMsg cmd_pp( uint32_t flash_address, uint8_t *source_address, uint32_t byte_length ) { uint32_t index; // Check flash address if( flash_address > FLASH_SIZE ) return FlashAddressInvalid; // // // Check flash is busy or not if( IsFlashBusy() ) return FlashIsBusy; // Setting Write Enable Latch bit cmd_wren(); nrf_delay_ms(5); // Chip select go low to start a flash command cs_low(); nrf_delay_ms(100); // Write Page Program command uint8_t len = 4; m_buffer_tx[0]=FLASH_CMD_PP; // memcpy(m_buffer_tx,instruction,4); // nrf_drv_spi_transfer(&spi,instruction,len,m_buffer_rx,len+1); memcpy(m_buffer_tx[4],flash_address >> 16,1); m_buffer_tx[1] = flash_address >> 16; m_buffer_tx[2] = flash_address >> 8; m_buffer_tx[3] = flash_address; for( index=4; index < 20; index++ ) { m_buffer_tx[index] = source_address[index];//0xaa; } printf("\r data transmitted: "); for( index=0; index < 20; index++ ) { printf(" %.02x ",m_buffer_tx[index]); nrf_delay_ms(10); } printf("\n"); // nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,20,m_data_receive,40); nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,20,m_data_receive,0); // Chip select go high to end a flash command cs_high(); if( WaitFlashReady( PageProgramCycleTime ) ) return FlashOperationSuccess; else return FlashTimeOut; } uint8_t cmd_se( uint32_t flash_address ) { // Check flash address if( flash_address > FLASH_SIZE ) return FlashAddressInvalid; // Check flash is busy or not if( IsFlashBusy() ) return FlashIsBusy; // Setting Write Enable Latch bit cmd_wren(); // Chip select go low to start a flash command cs_low(); //Write Sector Erase command = 0x20; m_buffer_tx[0] = FLASH_CMD_SE; m_buffer_tx[1] = flash_address >> 16; m_buffer_tx[2] = flash_address >> 8; m_buffer_tx[3] = flash_address; printf(" \r sectore esrase command : %0.2x,%0.2x,%0.2x,%0.2x\n ",m_buffer_tx[0],m_buffer_tx[1],m_buffer_tx[2],m_buffer_tx[3]); nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,4,m_buffer_rx,4); // Chip select go high to end a flash command cs_high(); // if( WaitFlashReady( SectorEraseCycleTime ) ) if( WaitFlashReady( 240000000 )) { cmd_rdscur(SecurityReg); printf("SecurityReg %d \n ",SecurityReg); return FlashOperationSuccess; } else return FlashTimeOut; } uint8_t cmd_block_erase( uint32_t flash_address ) { // Check flash address if( flash_address > FLASH_SIZE ) return FlashAddressInvalid; // Check flash is busy or not if( IsFlashBusy() ) return FlashIsBusy; // Setting Write Enable Latch bit // cmd_wren(); // Chip select go low to start a flash command cs_low(); //Write Sector Erase command = 0x20; uint8_t instruction; instruction= FLASH_CMD_SE; // instruction[1]= 0; // instruction[2] =0; // instruction[3]=0; m_buffer_tx[0] = instruction; // memcpy(m_buffer_tx,instruction,4); m_buffer_tx[1] = flash_address >> 16; m_buffer_tx[2] = flash_address >> 8; m_buffer_tx[3] = flash_address; // SendByte( FLASH_CMD_SE, SIO ); // SendFlashAddr( flash_address, SIO, addr_4byte_mode ); nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,4,m_buffer_rx,4); // Chip select go high to end a flash command cs_high(); if( WaitFlashReady( SectorEraseCycleTime ) ) return FlashOperationSuccess; else return FlashTimeOut; } /* * Function: CMD_CE * Arguments: None. * Description: The CE instruction is for erasing the data * of the whole chip to be "1". * Return Message: FlashIsBusy, FlashOperationSuccess, FlashTimeOut */ ReturnMsg cmd_ce( void ) { // Check flash is busy or not if( IsFlashBusy() ) return FlashIsBusy; // Setting Write Enable Latch bit cmd_wren(); // Chip select go low to start a flash command cs_low(); nrf_delay_ms(100); //Write Chip Erase command = 0x60; m_buffer_tx[0] = 0xC7;//FLASH_CMD_CE; nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,0); // Chip select go high to end a flash command cs_high(); // cmd_rdsr(StatusReg); // printf("StatusReg= %d \n",StatusReg); //if( WaitFlashReady( 60000 ) ) nrf_delay_ms(60000); return FlashOperationSuccess; // else // return FlashTimeOut; //return FlashOperationSuccess; } /* * Simple flash read/write test */ uint8_t flash_read_write_test( void ) { uint8_t message= 0; FlashStatus flash_state = {0}; uint32_t flash_addr; uint32_t trans_len = 0; uint16_t i=0, error_cnt = 0; uint16_t seed = 0; uint8_t st_reg = 0; /* Assign initial condition */ flash_addr = FLASH_TARGET_ADDR; trans_len = TRANS_LENGTH; seed = RANDOM_SEED; /* Erase 4K sector of flash memory Note: It needs to erase dirty sector before program */ uint8_t err_code; // err_code = cmd_ce();//cmd_block_erase(flash_addr);//cmd_se( flash_addr ); // printf("error code = %d \n",err_code); // nrf_delay_ms(300); // cmd_read( flash_addr, m_data_receive, TRANS_LENGTH ); // nrf_delay_ms(300); // // printf("\r data after chip erase: "); // for( i=4; i < 20; i++ ) // { // printf(" %.02x ",m_data_receive[i]); // nrf_delay_ms(10); // } // printf("\n"); /* Program data to flash memory */ cmd_pp( flash_addr, m_data_send, TRANS_LENGTH ); nrf_delay_ms(100); /* Read flash memory data to memory buffer */ cmd_read( flash_addr, m_data_receive, TRANS_LENGTH ); nrf_delay_ms(300); /* Compare original data and flash data */ // for( i=4; i < (trans_len); i=i+1 ) // { // if( m_data_send[i] != m_data_receive[i] ) // { // printf("wrong data \n"); // Error_inc( error_cnt ); // } // else // { printf("\r data received: "); for( i=4; i < 20; i++ ) { printf(" %.02x ",m_data_receive[i]); nrf_delay_ms(10); } printf("\n"); // } // } /* Erase 4K sector of flash memory */ cmd_ce();//cmd_block_erase(flash_addr); //cmd_se( flash_addr ); nrf_delay_ms(240); //240 60000 if( error_cnt != 0 ) return false; else return true; } uint8_t ext_flash_init(void) { uint8_t retval = false; /* Configure SPI pins */ nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; spi_config.ss_pin = SPI_SS_PIN; spi_config.miso_pin = SPI_MISO_PIN; spi_config.mosi_pin = SPI_MOSI_PIN; spi_config.sck_pin = SPI_SCK_PIN; spi_config.mode = NRF_DRV_SPI_MODE_0; spi_config.frequency= NRF_DRV_SPI_FREQ_125K; APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL)); nrf_gpio_pin_set(SPI_WP_PIN); uint8_t err_code; cmd_rsten(); cmd_rst(); err_code = cmd_wrdis(); /* Set CS pin to High*/ // cs_high(); wait_flash_warm_up(); nrf_delay_ms(100); flash_ID_test(2); /* read and verify manufacturer and device id from external flash to ensure external flash is working */ if(flash_ID_test(2) == true) { return true; } return retval; }