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.
Hi
What kind of external flash device do you want to connect?
Are you planning to use a file system, or will you just access the flash using low level read/write/erase commands?
The usbd_msc example in the SDK allows you to access SD cards over the SPI interface, if you compile the example with the USE_SD_CARD define set to 1 (located on line 106 of main.c).
Unfortunately this example is designed for the nRF52840 only, since it uses the USB interface in the nRF52840 to enumerate the connected SD card as a flash drive when connected to a PC.
Best regards
Torbjørn
I want to interface MX25R1635F FLASH memory with nrf52832. And no file system but want to access its read,write and erase commands. I have seen the qspi example but got confused with it as my I have nrf52832 that does not support QSPI.
Hi
Did you really need a 100ms delay after chip select to make it work?
Did you try to measure how long the status is busy after issuing an erase command?
According to the specification this can take several seconds, depending on how much you are erasing.
I realized you're using a similar flash device to the one used on the nRF52840DK, which allows me to do some testing myself.
Are you able to send me both your source and header files so I can try to run your code?
The code you sent is referencing some includes and defines that I don't have.
Best regards
Torbjørn
Did you really need a 100ms delay after chip select to make it work? - No but to try to get the chip erase working I added that delay . But now when I removed it it is working. But I am not sure enough that whether it will work always or not.
I realized you're using a similar flash device to the one used on the nRF52840DK- Yes its a similar flash with difference in its storage capacity .(16 MB)
I have made removed that 100ms delay after CS and also removed the flash busy and wait status which I think is necessary but after doing that I am able to get the results sometimes. So I think it still needs some modifications for its proper functioning. I am attaching my source code for your reference.I am using SDK 15.3.0ble_app_uart_pdm_extflash.rar
Hi
Thanks for sharing your project. It mostly seems to work fine, except the external_flash.c/h files appear to be missing.
Most likely you put these in one of the SDK folders.
Are you able to share these files also?
Best regards
Torbjørn
Opps, Sorry for the inconvience. I am sharing these two files. One more thing I have doubt is that I am not able to write more than 16 bytes and also do not know the what the
///** // ****************************************************************************** // * @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]; //int16_t pcm_data_buffer[MEM_SIZE_15KB] = {0}; static uint16_t pcm_data_buffer[MEM_SIZE_15KB]; //static uint8_t m_data_send[256]; static uint8_t m_data_receive[256]; static uint8_t m_data_send[225] = {[0 ... 224] = 0xcd}; 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); nrf_gpio_pin_clear(SPI_SS_PIN); } void cs_high(void) { // nrf_gpio_pin_clear(SPI_SS_PIN); nrf_gpio_pin_set(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, uint16_t *target_address, uint32_t byte_length ) { uint32_t index; // Check flash address if( flash_address > FlashSize ) return FlashAddressInvalid; // cmd_wrdis(); // nrf_delay_ms(100); // Chip select go low to start a flash command cs_low(); // nrf_delay_ms(50); // Write READ command and address memset(m_buffer_tx,0x00,sizeof(m_buffer_tx)); 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); nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,FLASH_CMD_READ_LENGHT,m_data_receive,FLASH_CMD_READ_LENGHT+byte_length); // 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(50); cs_high(); return true; } void read_data_ext_flash(void) { uint8_t i; static uint32_t flash_address = FLASH_TARGET_ADDR; static counter=0; for(i=0;i<16;i++) // for(i=0;i<2;i++) { // for(j=0;j<256;j=j+2) { cmd_read(flash_address,pcm_data_buffer,225); uint16_t index; nrf_delay_ms(5); // for( index=0; index < 102400; index++ ) for( index=0; index < 225; index++ ) { // Read data one byte at a time printf("\r\n%2.2X%2.2X",pcm_data_buffer[index],pcm_data_buffer[index+1]); index = index+1; } // nrf_delay_ms(10); } flash_address = flash_address + 0x000100; // counter ++; } // uint32_t flash_address = FLASH_TARGET_ADDR; //// cmd_read(flash_address,pcm_data_buffer,102400); // cmd_read(flash_address,pcm_data_buffer,3584); //256*16 3584 bytes // for( index=0; index < 102400; index++ ) // for( index=0; index < MEM_SIZE_15KB; index++ ) // { // // Read data one byte at a time // // printf("\r\n%2.2X%2.2X",pcm_data_buffer[index],pcm_data_buffer[index+1]); // index = index+1; // // } // // for( index=0; index < MEM_SIZE_15KB; index++ ) //// { //// // Read data one byte at a time //// // printf("\r\n%2.2X%",pcm_data_buffer[index]); // index = index+1; // // } } /* * 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 \n",m_buffer_rx[4]); cs_high(); break; case 2: instruction[0] = FLASH_CMD_REMS ; instruction[1]= 0x01; instruction[2] = 0x02; instruction[3]= 0x00; printf("\rValue is 2:"); memset(m_buffer_rx,0x00,sizeof(m_buffer_rx)); 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]); // printf("%d,%d,%d,%d,%d,%d\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_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,1,m_buffer_rx,4); 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]); // printf("%d,%d,%d \n",m_buffer_rx[1],m_buffer_rx[2],m_buffer_rx[3]); 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(); memset(m_buffer_tx,0x00,sizeof(m_buffer_tx)); // 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,0); // 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, uint16_t *source_address, uint32_t byte_length ) { // printf("cmd_pp \n"); uint32_t index; // Check flash address if( flash_address > FLASH_SIZE ) return FlashAddressInvalid; // // // Check flash is busy or not // if( IsFlashBusy() ) return FlashIsBusy; nrf_delay_ms(10); // Chip select go low to start a flash command cs_low(); // Setting Write Enable Latch bit cmd_wren(); nrf_delay_ms(3); // 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 < byte_length; index++ ) { m_buffer_tx[index] = (uint8_t) source_address[index];//0xaa; } printf("\r data transmitted: "); for( index=0; index < 30; 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,0); nrf_drv_spi_transfer(&spi,(uint8_t const *)m_buffer_tx,251,m_data_receive,0); // Chip select go high to end a flash command nrf_delay_ms(50); cs_high(); nrf_delay_ms(20); 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; // Chip select go low to start a flash command cs_low(); // Setting Write Enable Latch bit cmd_wren(); nrf_delay_ms(3); // nrf_delay_ms(100); //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,0); // Chip select go high to end a flash command nrf_delay_ms(50); cs_high(); nrf_delay_ms(240); printf("sector esrsed \n"); // if( WaitFlashReady( SectorEraseCycleTime ) ) // if( WaitFlashReady( 240000000 )) // cmd_rdsr(StatusReg); 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; // Chip select go low to start a flash command cs_low(); // Setting Write Enable Latch bit cmd_wren(); nrf_delay_ms(3); //Write Sector Erase command = 0x20; uint8_t instruction; instruction= FLASH_CMD_BE; // 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,0); // Chip select go high to end a flash command nrf_delay_ms(100); cs_high(); nrf_delay_ms(4000); printf("block earsed \n"); // 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; // Chip select go low to start a flash command cs_low(); // Setting Write Enable Latch bit cmd_wren(); nrf_delay_ms(3); // 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 nrf_delay_ms(100); cs_high(); // cmd_rdsr(StatusReg); // printf("StatusReg= %d \n",StatusReg); //if( WaitFlashReady( 60000 ) ) nrf_delay_ms(60000); printf("chip esrsed \n"); return FlashOperationSuccess; // else // return FlashTimeOut; //return FlashOperationSuccess; } ReturnMsg full_sector_erase(void) { uint8_t i=0; uint32_t flash_address = FLASH_TARGET_ADDR; for(i=0;i<5;i++) { cmd_se(flash_address); nrf_delay_ms(240); flash_address = flash_address + FLASH_SECTORSIZE; } } /* * 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_se( flash_addr ); //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,256 ); //TRANS_LENGTH // nrf_delay_ms(500); /* Read flash memory data to memory buffer */ // cmd_read( flash_addr, m_data_receive, 256 ); //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 < 256; i++ ) { printf(" %.02x ",m_data_receive[i]); nrf_delay_ms(10); } printf("\n"); // } // } /* Erase 4K sector of flash memory */ // cmd_se( flash_addr ); //cmd_ce();//cmd_block_erase(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); // nrf_gpio_pin_clear(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(3); /* read and verify manufacturer and device id from external flash to ensure external flash is working */ if(flash_ID_test(3) == true) { // flash_read_write_test(); // return true; } // cmd_wren(); // cmd_wrsr(2); // cmd_rdsr(StatusReg); // cmd_rdcr(ConfigReg); //nrf_delay_ms(500); ////cmd_ce(); //// cmd_se(0x000000); //// nrf_delay_ms(500); //printf("finish \n"); // cmd_read( 0x000000, m_data_receive, TRANS_LENGTH ); // uint8_t i; // printf("\r data after chip erase at 0x000000: "); // for( i=4; i < 20; i++ ) // { // printf(" %.02x ",m_data_receive[i]); // nrf_delay_ms(10); // } // printf("\n"); // cmd_se(0x008000); // cmd_read( 0x008000, m_data_receive, TRANS_LENGTH ); // // // printf("\r data after chip erase at 0x008000: "); // for( i=4; i < 20; i++ ) // { // printf(" %.02x ",m_data_receive[i]); // nrf_delay_ms(10); // } // printf("\n"); return retval; }
Hi
Thanks. Adding those files I realize that ext_flash.h is also missing ;)
Either way, I will start doing some testing on my own in the mean time, and set up a quick test based on the ble_app_uart example.
Getting 3-4 of the core functions running should not be very time consuming.
Best regards
Torbjørn
Hi
Thanks. Adding those files I realize that ext_flash.h is also missing ;)
Either way, I will start doing some testing on my own in the mean time, and set up a quick test based on the ble_app_uart example.
Getting 3-4 of the core functions running should not be very time consuming.
Best regards
Torbjørn
Ext_flash.h you can remove it and instead of it add external_flash.h
Hi
I set up my own little test based no ble_app_uart, and it seems to work fine.
I have tested most of the core commands, including Sector Erase, Chip Erase, Program, Read, Write Enable and RDSR.
I set up a small state machine that runs through a read - erase - read - program - read loop every time I reset the code, and the results look OK.
When I run this on an nRF52840 DK I get the following UART output:
UART started.
Reading REMS. Man id: c2, Dev id: 17
Status: 0
Config: 0
Reading address 00001000: FF-FF-FF-FF-00-01-02-03-04-05-06-07-08-09-0A-0B-
Running write enable
Running sector erase at address 0x1000
Status: 0
Reading address 00001000: FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-FF-
Running write enable
Programming data at address 00001004
Status: 0
Reading address 00001000: FF-FF-FF-FF-00-01-02-03-04-05-06-07-08-09-0A-0B-
I have updated the nRF52832 project also. It compiles and runs nicely, but doesn't show any output since I don't have a flash device connected.
Can you take a look at my code and see what might be different?
I put all the flash functionality in the spi_flash.c/h files, and the test state machine can be found towards the bottom of main.c
Best regards
Torbjørn
Thank you soo much Torbjorn.
U really made my work easier and also cleared my few doubts.
I tested your code with my flash device and its working properly. But now when I want to write the full page what which is 256 bytes I am not able to do it. I tested first by sending sector erase and the if I read 256 bytes I get the following results which is wrong. ryt?? for full sector earse and fullpage write for 256 what should i add?
I need this because I want to write and read full sectors.
Reading address 00001000: 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-000000000000000000000000000
One more thing and if I want to erase :
sector 0 do i have to give address as 0x000000,
sector 1 as 0x008000
sector 2 as 0x010000 ????
Hi
It seems there are a couple of problems here. First off the UART TX buffer should be increased to allow the longer log messages to be buffered properly (I increased it from 256 to 1024 bytes), but more importantly the SPI driver is limited to 255 byte transactions, which makes it fail when you try to send 256 bytes in one go.
I made a slight change to the driver to split transactions longer than 255 bytes into multiple transactions:
Please note that the sensor has it's own limitations. If I remember correctly you can't write more than 256 bytes in one go (but I am sure you can read more).
Regarding erase I think it is sufficient to specify any address within the block to erase the whole block, but specifying the start address of the block seems the most logical.
Best regards
Torbjørn