This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Tool/software: TI C/C++ Compiler
Hi,
I' working with the DK-TM4C129X on the Quad-SPI Flash, where I could find the same problem as in my "real" target hardware.So I'm referring to the DK and there usb_dev project, as this can be easier cross-checked. The example usb_dev etc. works, but when I look into the details, I found that the MX66L51235FRead() functions does only use single-SPI.
I changed the MX66L51235FRead() and the reading ROM function from
ROM_SPIFlashRead(SSI3_BASE, ui32Addr, pui8Data, ui32Count);
to
ROM_SPIFlashDualRead(SSI3_BASE, ui32Addr, pui8Data, ui32Count);
which still runs. I checked the oszilloscope and saw the 2xtimes Outputs as expected. But when using
ROM_SPIFlashQuadRead(SSI3_BASE, ui32Addr, pui8Data, ui32Count);
the result is obviously wrong. Do I have to consider something special or is there something missing?
Thanks in advance
Micky
Hi Michael,
Can you elaborate the problem? What do you mean it is obviously wrong? Is it not operating in quad mode or is it not outputting the data in the bit order you desire?
Well, I write 1,2,3,4 to the flash.
I re-read it and I retrieve this values back with ROM_SPIFlashRead and ROM_SPIDualFlashRead but not with ROM_SPIFlashQuadRead.
The latter I see something as AA,AA,AA,AA. If I write lager packets, I see sometimes values I wrote, but only a few and more random-wise.
Edit: You can check it easily with DK-TM4C129X. I've also a customized hardware with a different Flash, but same behavior. With both I also did test ROM_SPIFlashXXXXReadNonBlocking with DMA, which runs also only with Single or Dualmode and not Quadmode
Hi Michael,
I have compared how it is coded between the ROM_SPIFlashDualRead and ROM_SPIFlashQuadRead. Other than those lines of code that are specific to the Quad mode, I don't really see any difference between the two. You can find the source code of the ROM_SPIFlashQuadRead() function in <TivaWare_Installation>/utils/spi_flash.c. Unfortunately, I don't have a DK board with me. I wonder if it will make a difference if you call the SPIFlashQuadRead instead of ROM_SPIFlashQuadRead which is a driver function stored in the ROM. Can you please try? It will be easier to debug a non-ROM function. I'm just not 100% sure if the ROM-based function for SPIFlashQuadRead is up to date or having any issue.
void SPIFlashQuadRead(uint32_t ui32Base, uint32_t ui32Addr, uint8_t *pui8Data, uint32_t ui32Count) { uint32_t ui32Trash; // // Drain any residual data from the receive FIFO. // while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Trash) != 0) { } // // Set the SSI module into write-only mode. // MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE); // // Send the quad read command. // MAP_SSIDataPut(ui32Base, CMD_QREAD); // // Send the address of the first byte to read. // MAP_SSIDataPut(ui32Base, (ui32Addr >> 16) & 0xff); MAP_SSIDataPut(ui32Base, (ui32Addr >> 8) & 0xff); MAP_SSIDataPut(ui32Base, ui32Addr & 0xff); // // Send a dummy byte. // MAP_SSIDataPut(ui32Base, 0); // // Set the SSI module into Quad-SPI read mode. In this mode, dummy writes // are required in order to make the transfer occur; the SSI module will // ignore the data (the SPI flash will never see the dummy data since // Quad-SPI read mode is a uni-directional input mode). // MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_QUAD_READ); // // See if there is a single byte to be read. // if(ui32Count == 1) { // // Perform a single dummy write, marking it as the end of the frame. // MAP_SSIAdvDataPutFrameEnd(ui32Base, 0); } else { // // Perform a dummy write to prime the loop. // MAP_SSIDataPut(ui32Base, 0); // // Loop while there is more than one byte left to be read. // while(--ui32Count != 1) { // // Perform a dummy write to keep the transmit FIFO from going // empty. // MAP_SSIDataPut(ui32Base, 0); // // Read the next data byte from the receive FIFO and place it into // the data buffer. // MAP_SSIDataGet(ui32Base, &ui32Addr); *pui8Data++ = ui32Addr & 0xff; } // // Perform the final dummy write, marking it as the end of the frame. // MAP_SSIAdvDataPutFrameEnd(ui32Base, 0); // // Read the next data byte from the receive FIFO and place it into the // data buffer. // MAP_SSIDataGet(ui32Base, &ui32Addr); *pui8Data++ = ui32Addr & 0xff; } // // Read the final data byte from the receive FIFO and place it into the // data buffer. // MAP_SSIDataGet(ui32Base, &ui32Addr); *pui8Data++ = ui32Addr & 0xff; }
Hi Michael,
I have some suggestions and questions.
1. Can you probe the J7 jumpers for all the signals on the DK board using a logic analyzer? Is it meeting the timing requirement by the MX66L5?
2. Call the MAP_SSIDataGetNonBlocking as in below example code before you call ROM_SPIFlashQuadRead to make sure any residual data in the RXFIFO are first removed. I suspect there may be some residual data in the RXFIFO and you may be reading these data instead of reading the received data that will be read out later.
// // Read any residual data from the SSI port. This makes sure the receive // FIFOs are empty, so we don't read any unwanted junk. This is done here // because the SPI SSI mode is full-duplex, which allows you to send and // receive at the same time. The SSIDataGetNonBlocking function returns // "true" when data was returned, and "false" when no data was returned. // The "non-blocking" function checks if there is any data in the receive // FIFO and does not "hang" if there isn't. // while(MAP_SSIDataGetNonBlocking(SSI3_BASE, &pui32DataRx[0])) { }
3. If the theory in #2 is correct then you may be able to read the correct data if you read more times. For example, earlier you said you wrote 1,2,3,4 to the SPI flash but when you read them back you were reading wrong data. If you only read 4 bytes and these happen to be the residual data then you will read the wrong data. If you were to read like 8 bytes, I wonder if you will start to see the data you wrote.
Hi Charles,
the Jumper Settings are correct, the Signals are in the timing as I configure them. On the DK I checked 1 MHz to 40 MHz. Dual Mode always works, Quad never. Anyway the original example of the DK is 12.5 Mhz, if I correctly remember.
I made up to 1024 Reads configured, but it doesnot see the proper data, either.
Micky
Hi Michael,
I'm not saying you have a jumper connection issue. I'm saying you can probe the SPI flash signals with a logic analyzer or a scope through the J7 jumper to see if the data is first correctly written to the flash and how the flash is returning the data when you read it.
Can you please reply to my #2?
Hi Michael,
Another thing that came across my mind is how the data is put out in Quad-mode by the MCU and how the SPI flash interpret the data. I would suggest an experiment. Simply just write one data with the value of 0x01 and read it back. What would you get? Since it is a Quad-Mode, it really depends on how the MCU put out the D0 bit. Look at the MX66L5 datasheet below. The SPI flash is expecting the D0 to be on the SID0 on the second cycle. What if the MCU has a incompatible bit ordering wrt the SPI flash. For example, if you write 0x1 as the data to the flash and the "1" actually appears on the SSI3 instead of the SSI0. Even if the "1" is driven out on the SID0 but driven out in the first cycle by the MCU rather than the second cycle as expected by the flash. Therefore, if you do the experiment to only write one data with and 0x01 and read it back, we should be able to prove if the bit-ordering compatibility in Quad-mode is at play.
Hi Charles,
I always write only in single mode. Therefore the data is written correctly for sure.
Only when reading back with Quad the values are wrong. To #2: I used your given function, so I did check with your function, too. The while-loop is there, but no effect, same as with the while loop before the ROM call.
I changed the program to
uint8_t g_pui8MX66L51235FData[32]={0x12,0x34,0x56,0x78,0x9A,0xBC,0xDE,0xF0}; /// MX66L51235FSectorErase(0); // // Program some data into the first page of the SPI flash. This assumes // that the data buffer has been filled with the data to be programmed. // MX66L51235FPageProgram(0, g_pui8MX66L51235FData, sizeof(g_pui8MX66L51235FData)); // // Read some data from the second page of the SPI flash. // MX66L51235FRead(0x00, g_pui8MX66L51235FData, sizeof(g_pui8MX66L51235FData));
and the Readfunction I changed to
void MX66L51235FRead(uint32_t ui32Addr, uint8_t *pui8Data, uint32_t ui32Count) { // // Write the extended address register. // MX66L51235FWriteEAR(ui32Addr); // // Assert the chip select to the MX66L51235F. // ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0); uint32_t uTrash; while(MAP_SSIDataGetNonBlocking(SSI3_BASE, &uTrash)) { } // // Read the requested data. // ROM_SPIFlashQuadRead(SSI3_BASE, ui32Addr, pui8Data, ui32Count); // // De-assert the chip select to the MX66L51235F. // ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, GPIO_PIN_1); }
In this case, if only 4-bit are disturbed it should be better seen. The result in the debugger in g_pui8MX66L51235FData is 0xCC,0xCC followed 30 times by 0xDD.
Here the Chip Select Signal in Quadmode:
If I look at the DAT0...DAT3 lines, I see in Dual mode, that DAT0 and DAT1 is carrying the bits. In Quadmode I don't see Bits on DAT1 to DTA3. This will mean, somehow the driver is not configuring the flash properly or the flash is not working properly with the non continuous CLK Signal.
Regards
Micky
Since I have a DK-TM4C129X design kit, Charles asked me to look into this. I created a small test case and I am able to reproduce your results. I will debug it and let you know what I find.
Hi Bob,
thanks for the feedback and the support.
BTW: I have exactly the same issue if using DMA (SPIFlashReadQuadNonBlocking). With that, there are still a lot of pauses during DMA Transfer, which has the consequence, that Single SPI transfer is only about 10% faster than Dual (as told, quad doesnot work properly). In single mode, there is no pause.
This will be my next question, if it would be possible to decreases the pause between the DMA reads by any configuration.
Regards
Micky
I think the issue with QUAD SPI transfer is in the configuration of the Macronix serial flash. There is a non-volatile bit in the status register that must be set before going into QUAD mode. By default, that bit is cleared.
https://www.macronix.com/Lists/Datasheet/Attachments/7401/MX66L51235F,%203V,%20512Mb,%20v1.1.pdf
Hi Bob,
I tried with
void vfnQuadSPIFlashWriteStatus(uint32_t ui32Base,uint8_t uRegStatus,uint8_t uRegConf) { uint32_t ui32Data; // // Drain any residual data from the receive FIFO. // while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Data) != 0) { } //WR Enable ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0); MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE); MAP_SSIAdvDataPutFrameEnd(ui32Base, 0x6); ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 1); // Wait for Write Enable while ((ufnQuadSPIFlashReadStatus(ui32Base,0x5) & 0x2)==0); ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0); // // Set the SSI module into write-only mode. // MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE); // // Send the write status register command. // MAP_SSIDataPut(ui32Base, 0x1); MAP_SSIDataPut(ui32Base, uRegStatus); MAP_SSIAdvDataPutFrameEnd(ui32Base, uRegConf); ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 1); } uint8_t ufnQuadSPIFlashReadStatus(uint32_t ui32Base,uint8_t uCMD) { uint32_t ui32Data; ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 0); // // Drain any residual data from the receive FIFO. // while(MAP_SSIDataGetNonBlocking(ui32Base, &ui32Data) != 0) { } // // Set the SSI module into write-only mode. // MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_WRITE); // // Send the READ status register command. // MAP_SSIDataPut(ui32Base, uCMD); // // Set the SSI module into read/write mode. In this mode, dummy writes are // required in order to make the transfer occur; the SPI flash will ignore // the data. // MAP_SSIAdvModeSet(ui32Base, SSI_ADV_MODE_READ_WRITE); MAP_SSIDataPut(ui32Base, 0); MAP_SSIDataGet(ui32Base, &ui32Data); MAP_SSIAdvDataPutFrameEnd(ui32Base, 0); // // Read the value of the status register. // MAP_SSIDataGet(ui32Base, &ui32Data); ROM_GPIOPinWrite(GPIO_PORTQ_BASE, GPIO_PIN_1, 1); // // Return the status register value. // return(ui32Data & 0xff); }
But this seems not to work (it will wait for ever for the WREN Bit).
I tried to enable with vfnQuadSPIFlashWriteStatus(SSI3_BASE,64,0); The read result is still wrong and unchanged to described above.
Not sure what you are trying to do. There are already SPIFlashReadStatus() and SPIFlashWriteStatus() functions in spi_flash.c. Since in this implementation the chip select is done by GPIO, you need to wait until the SPI is no longer busy before raising chip select after the SPIFlashWriteStatus() function.
Hi Bob,
Bob Crosby said:Not sure what you are trying to do. There are already SPIFlashReadStatus() and SPIFlashWriteStatus() functions in spi_flash.c. Since in this implementation the chip select is done by GPIO, you need to wait until the SPI is no longer busy before raising chip select after the SPIFlashWriteStatus() function.
I want to set the Flash into Quad Mode. According to the data sheet of the flash, the Register must be set as follows:
I tried the functions as you mentioned with
while(1)
{
SPIFlashWriteEnable(SSI3_BASE);
uStatus=SPIFlashReadStatus(SSI3_BASE);
if (uStatus & 0x2)
break;
}
SPIFlashWriteStatus(SSI3_BASE,64);
uStatus=SPIFlashReadStatus(SSI3_BASE);
But this doesnot work. Same as with the example I've given above. Perhaps you could check.
To be complete: I have a special hardware with a different chip, which is quad enabled by default. This flash responses to the read, here I got results, which are wrong, too, but are more related to the original data. Therefore I tried to use the DK in order to make it easier for you to check and validate. So a running example for the Quad Spi Mode on the DK would be very helpful. At least the DK is designed to work with the quad flash mode.
Regards
Micky
Sorry, I don't have any examples using QUAD mode on the DK-TM4C129X board. I will work on one, but it may take me some time. I will give you an update before the end of the week.
I am seeing the same problem as you. I am confident the issue is in understanding the Macronix chip as the SPI output from the TM4C129X is what I expect as seen on the logic analyzer. Still working on it when I can.
Hi Bob,
with a Winbond W25Q128JV I don't have the configuration issue, as I ordered one, with already being in the non volatile Quad Mode. Nevertheless I donot get correct results.
I tried the NonBlocking functions with DMA, and watched the clock signals (see above plot). I'd expected them more continuously. I see only 2 Clocks and then a bigger gap. Perhaps this is somehow disturbing the Flash or this is disturbing the W25Q128JV but not the DK-Flash and the latter doesnot work due to the configuration. I'm waiting for your reply.
I also tried to get more continuous read clocks to the Flash by mutating UDMA_ARB_xx in the DMA function SPIFlashIntHandler of spi_flash.c:
uDMAChannelControlSet(pState->ui32TxChannel,
UDMA_SRC_INC_NONE |
UDMA_DST_INC_NONE |
UDMA_SIZE_8 | UDMA_ARB_2);
uDMAChannelControlSet(pState->ui32RxChannel,
UDMA_SRC_INC_NONE |
UDMA_DST_INC_8 |
UDMA_SIZE_8 | UDMA_ARB_4);
I can change the read results with that, but the results are not better or the transfer stops working. Again, DMA Dualmode does work. If I alter the defaults of UDMA_ARB_xx above, I get wrong results on both Flashes.
Additionally the overall performance is disappointing. With my 80 MHz System clock (40 MHz for SPI of W25Q128JV) I have about 5 MByte/s with DMA in single mode (that's good of course). In Dual mode I have about 6 MByte/s, in Quad mode (wrong results, but anyway) I have about 7 MBytes/s. So although the number of lines doubles, the increase of performance is very low. The DMA inserts gaps (see above plot). Can this be tuned somehow?
Regards.
Did you attach new plots, or are you referring to the earlier scope shots of September 10th? I too see the gaps between pairs of clock edges in quad mode. That is a function of the SPI state-machine and unfortunately cannot be changed.
Yes, I'm referring to the scope shots of September 10th. I'm curious, if you manage to make the DK Flash working in Quad mode, or if this mode is not working at all in combination of Flash and TM4C.
Attached I measured with the Dual Mode with DMA. There are also gaps, but the device is read 8 times (16 Bit) , then a small gap and than a bigger one. The second shot is a more complete shot for many addreses . There is a relative long setup of the flash and then the DMA bursts.
Hi Bob,
did you make any progress on this topic or can you confirm, that the quadmode is not running with the DSK (and my Winbound) Flash? Additionally it is also not possible to accelerate the access time for Dual (or if working) Quad mode (see the gaps in the single transfers above)?
I found an additional problem with DMA: If I set up an DMA, this will run only as long as I donot program not more 1024 Bytes of transfer (to internal memory). If I understood the spi_flash.c code correctly, this should be possible by simple adding a bigger transfer number, and the handler shall dissect the transfer into 1024 Byte transfers. I cannot make this running, but a (repeated) 1024 Bytetransfer is possible.
Regards
Micky
I have some more information on operation of the SSI in Quad mode. The state-machine of the SSI requires a minimum of 24 system clock cycles to read from the FIFO and process the shifting. Here is logic analyzer showing quad mode at 10MHz SSI Clock. Notice no delays between the transfers. The time to transfer one byte is 200nS.
Now increasing the SSI clock to 20MHz, we see gaps in the SSI clock and the time to transfer one byte is still 200nS.
The clock pulses got smaller as expected, but the throughput is still limited. Increasing the SSI clock to the maximum of 60MHz causes a small additional delay, probably due to synchronization.
Bottom line, in quad mode the maximum transfer rate is 5M Bytes/s. There is no advantage in running the SSI clock faster than 10MHz.
Likewise, in Bi mode, the maximum transfer rate is also 5M Bytes/s, but using a 20MHz SSI clock. All of this is based on a 120MHz system clock. (In the last image note that my logic analyzer does not decode Bi- mode. Ignore the interpreter which is the bottom line.)
Hi Bob,
thanks for the information. Can you provide the code for the DK you used, please.
Regards
Micky
The code I used for the logic analyzer traces was run on an EK-TM4C1294XL simply because it was easier to attach the logic analyzer probes. The code is attached./cfs-file/__key/communityserver-discussions-components-files/908/EK_2D00_QuadSPIMaster.zip
Hi Bob,
thanks for that code. It seems to me completely different to that in spi_flash.c.
Perhaps that's the reason why the non-blocking ROM functions (and the DMA transfer) donot work with Quadmode. As there is a 5M sample/s limit anyway, there seems no advantage of this mode, if the SPI is fast enough to operate with 40 MHz, which most flashes do. So at least for that this seems useless, or is there any advantage of using the quadmode like the loading of the registers for each transfer is somehow faster?
Regards
Micky
If the board and the flash device can operate properly with a 40MHz SPI clock without EMI emission problems, then you are correct. There is no inherent advantage of using quad mode. The clear disadvantage is the additional pins required.