6 Replies Latest reply on May 6, 2020 8:56 AM by DeWa_4681626

    S25FL256S - DDR Quad I/O Read

    DeWa_4681626

      Hi

      I am using a PSOC 62 to access S25FL256S memory. PP, READ, 4QPP, 4QOR, 4QIOR all work fine (read/write within a page). However, I can't get DDR Quad I/O Read to work.
      I understand that for this particular command, I need to have mode and dummy cycles by configuring LC (My SCK is set to 1MHz) as specified in Table 23 (EDh, EEh column) of the datasheet.  

      However, I have tried all the combinations but still can't read expected data out.

      From these results so far, I think I can conclude memory content is ok, but just fail to perform a DDR Quad I/O Read (data read out is always 0xFF).

      I suspect it may be related to DLP, so I had issued a PNVDLR command to set NVDLR to 0x34, and a DLPRD command also confirmed the pattern was set correctly.

      However, I am not sure if DLP is indeed enable. I don't see a register that enable DLP in the datasheet. May I know how to enable it?

      Or as long as NVDLR is non zero, is DLP enable automatically?

      In addition, do I need to adjust mode or dummy cycles to accommodate for DLP cycles?
      Or perhaps I am missing something else?

       

      Thanks,
      Dennis

        • 1. Re: S25FL256S - DDR Quad I/O Read
          ApurvaS_36

          Hi Dennis,

           

          Is it possible for you to share your PSoC project with us?

           

          Regards,

          Apurva

          • 2. Re: S25FL256S - DDR Quad I/O Read
            DeWa_4681626

            Hi Apurva,
            Thanks for the quick reply. I am using Mbed to develop the application. It does support PSOC 62 and the QSPI API is built on top of cy_qspi_api. I extracted relevant code section below. I understand the Mbed API may look different from Cypress API, so I have added comments. If anything is not clear, please let me know. Also, let me know if you need anything from me. Thanks!

             

            // predefine section
            #define CMD_WRR   0x01
            #define CMD_PNVDLR 0x43
            #define CMD_DDR4QIOR 0xEE // 4 byte addr
            #define CMD_4QOR  0x6C // 4 byte addr
            #define CMD_4QPP  0x34 // 4 byte addr
            #define CMD_WREN  0x06
            #define ADDRESS   0x20
            
            // code section
              char tx_buf[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 };
              char cfg_buf[2];
              char rx_buf[6];
              size_t buf_len = sizeof(tx_buf);
               size_t rx_len, tx_len;
              qspi_status_t result;
            
              // instantiate a QSPI device
              QSPI qspi_device(CYBSP_QSPI_D0, CYBSP_QSPI_D1, CYBSP_QSPI_D2, CYBSP_QSPI_D3, CYBSP_QSPI_SCK, CYBSP_QSPI_SS);
            
              // set SCK = 1MHz
              qspi_device.set_frequency(1000000);
            
              // Configure bus for register related commands
              // 1st argument: (instruction bus width) single bus
              // 2nd argument: (address bus width) single bus
              // 3rd argument: address size (using 4-bye addressing)
              // 4th argument: (mode bus width) single bus (although mode is not applicable for register commands here)
              // 5th argument: mode size of 8 bits (also not applicable)
              // 6th argument: (data bus width) single bus
              // 7th argument: dummy cycle
              result = qspi_device.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_32, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
            
              // WREN before update DLP
              result = qspi_device.command_transfer(CMD_WREN, -1, nullptr, 0, nullptr, 0);
              if (result != QSPI_STATUS_OK) {
                printf("WREN failed");
              }
              cfg_buf[0] = 0x34;
              cfg_len = 1;
              result = qspi_device.command_transfer(CMD_PNVDLR, -1, cfg_buf, cfg_len, nullptr, 0);
              if (result != QSPI_STATUS_OK) {
                printf("PNVDLR failed");
              }
            
              // WREN before updating LC
              result = qspi_device.command_transfer(CMD_WREN, -1, nullptr, 0, nullptr, 0);
              if (result != QSPI_STATUS_OK) {
                printf("WREN failed");
              }
              // WRR to update LC
              // since QUAD bit has been set, use 2 bytes for WRR command
              cfg_buf[0] = 0x2;  // status register (although according to datasheet, only WREN and WRDI can change this bit)
              cfg_buf[1] = 0x2; // config reg sets LC = 0x1 & QUAD = 1
              cfg_len = 2;
              result = qspi_device.command_transfer(CMD_WRR, -1, cfg_buf, cfg_len, nullptr, 0);
              if (result != QSPI_STATUS_OK) {
                printf("WRR failed");
              }
            
              // WREN before program
              result = qspi_device.command_transfer(CMD_WREN, -1, nullptr, 0, nullptr, 0);
              if (result != QSPI_STATUS_OK) {
                printf("WREN failed");
              }
            
              // Configure bus before quad page program
              // instruction: single bus
              // address: single bus
              // 4-byte addressing
              // mode: single bus (not applicable for 4QPP)
              // mode size: 8 bits (not applicable for 4QPP)
              // data: quad bus
              // dummy cycles: 0
              result = qspi_device.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_32, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_QUAD, 0);
              if (result != QSPI_STATUS_OK) {
                  printf("Switching to Quad Page Program failed");
              }
              result = qspi_device.write(CMD_4QPP, -1, ADDRESS, tx_buf, &buf_len); // -1 indicates no value used for mode phase
              if (result != QSPI_STATUS_OK) {
                 printf("Write failed");
              }
              ThisThread::sleep_for(5000); // wait 5s for write operation to complete
            
              // Configure bus before DDR Quad I/O Read
              // instruction: single bus
              // address: quad bus
              // 4-byte addressing
              // mode: quad bus
              // mode size: 8 bits
              // data: quad bus
              // dummy cycles: 6 (since LC = 00b)
              result = qspi_device.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_ADDR_SIZE_32, QSPI_CFG_BUS_QUAD, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_QUAD, 6);
              if (result != QSPI_STATUS_OK) {
                  printf("Switching to Quad Out Read failed");
              }
              // DDR Quad I/O Read
              result = qspi_device.read(CMD_DDR4QIOR, 0xA5, ADDRESS, rx_buf, &buf_len);
              if (result != QSPI_STATUS_OK) {
                 printf("Read failed");
              }
              else {
                 printf("Read After Write Addr 0x%X len %d", ADDRESS, buf_len);
                 for (int i = 0; i < (int)buf_len; i++){
                   printf("%d data 0x%X", i, rx_buf[i]);
                 }
              }
            
              // Perform a Quad Read for comparison
              // instruction: single bus
              // address: single bus
              // 4-byte addressing
              // mode: single bus (not applicable)
              // mode size: 8 bits (not applicable)
              // data: quad bus
              // dummy cycles: 8 (since LC = 00b)
              result = qspi_device.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ADDR_SIZE_32, QSPI_CFG_BUS_SINGLE, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_QUAD, 8);
              if (result != QSPI_STATUS_OK) {
                  printf("Switching to Quad Out Read failed");
              }
              result = qspi_device.read(CMD_4QOR, -1, ADDRESS, rx_buf, &buf_len);  // -1 indicates no value used for mode phase
              if (result != QSPI_STATUS_OK) {
                 printf("Read failed");
              }
              else {
                 printf("Good 4QOR Read After Write Addr 0x%X len %d", ADDRESS, buf_len);
                 for (int i = 0; i < (int)buf_len; i++){
                   printf("%d data 0x%X", i, rx_buf[i]);
                 }
              }
            
            • 3. Re: S25FL256S - DDR Quad I/O Read
              ApurvaS_36

              Hi Dennis,

               

              I would like to inform you that PSoC 62 does not support DDR feature. However, you can go through the following KBA about DLP Minimum Dummy Cycles for Enabling Data Learning Pattern (DLP) in Serial NOR Flash Devices – KBA228298 if you still want to learn about it.

              Please let me know if you have any further questions about DLP or DDR.

               

              Best Regards,

              Apurva

              • 4. Re: S25FL256S - DDR Quad I/O Read
                DeWa_4681626

                Hi Apurva,

                That is a bit unfortunate to hear PSoC 62 doesn't support DDR feature. Thanks for sharing the link about DLP; I did have the correct configuration. It would be nice if DDR support can be added so I can see my work in action

                 

                By the way, although datasheet pointed out that LC (CR1[7:6]) bits are volatile, the value persists even after a power cycle (instead of resetting back to default)

                 

                Thanks,

                Dennis

                • 5. Re: S25FL256S - DDR Quad I/O Read
                  ApurvaS_36

                  Hi Dennis,

                   

                  The below image is from the S25FL256S datasheet -

                  Could you please point out exactly where does the datasheet say that the LC bits are volatile?

                   

                  Regards,

                  Apurva

                  • 6. Re: S25FL256S - DDR Quad I/O Read
                    DeWa_4681626

                    Hi Apurva,

                    My bad. I was looking at Table 17 but forgot the fact that individual bits within a register can be non volatile.

                     

                    Thanks for all the help,Dennis