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.

LAUNCHXL-CC1310: SPI not working as expected

Part Number: LAUNCHXL-CC1310
Other Parts Discussed in Thread: CC1310

Hello.

I am trying to control a 1Gb NAND Flash memory model w25n01gv from Winbond (using the Mikroe Flash 5 Click board: www.mikroe.com/flash-5-click) through the SPI driver of a CC1310 LaunchPAD.

Before going on building all the I/O API, I have just written a pair of basic functions to test the communication with the memory: read the JEDEC ID and read one of the three status registers.

Looking for the correct setting of the CC1310 SPI frame format I searched the memory datasheet (www.winbond.com/.../W25N01GV Rev O 092619.pdf) and took this information:

- SPI frame of 8 bits

- /CS pin has to be LOW during all the memory command (during all the SPI transaction)

- Input: memory reads bit data from master in rising edges of clock

- Output: memory prepares bit data after falling edges of clock and can be read from master in rising edges of clock

- Memory accepts clock signal normally LOW or normally HIGH during bus standby times

Reading the CC1310 reference manual about the SPI modes I saw that the /CS line is only held LOW during a complete SPI transaction when using Phase-Control=1, so I started the tests using SPI0 with 1MHz, frame format set to SPI_POL0_PHA1 and defining the CC1310_LAUNCHXL_SPI0_CSN in the PIN_Config BoardGpioInitTable[]. It didn't work.

To see what was happening I connected an oscilloscope to /CS (red signal), CLK (yellow signal), MISO (magenta signal) and MOSI (green signal) pins. This is what I saw when reading a status register (Byte 0: command, Byte 1: register address, Byte 2: register value returned):

 <SR1 - CS SPI0 - POL0_PHA1 - 1MHz - SPI0>

As you can see the /CS pin goes up between SPI frames and nothing came out from the memory. To discard a misname of the mode, I changed to SPI_POL0_PHA0, and this is what I got:

 <SR1 - CS SPI0 - POL0_PHA0 - 1MHz - SPI0>

Except a clock/2 delay for the active edge of the clock, everything was the same. No difference in the /CS pin between the SPI_POL0_PHA1 and SPI_POL0_PHA0 modes. I checked SPI_POL1_PHA1 and SPI_POL1_PHA0: the clock pin in idle times was HIGH as expected, but /CS line went up between SPI frames in all cases.

To try to solve the situation I defined a GPIO pin for manual control of /CS line and checked with SPI_POL0_PHA1:

 <SR1 - CS GPIO - POL0_PHA1- 1MHz - SPI0>

Now I had /CS LOW during all the transaction but no output from the memory yet.

I changed the test from reading the status register to reading the Jedec ID (Byte 0: command, Byte 1: dummy, Byte 2: manufacturer ID returned, Byte 3-4: device ID returned):

 <Jedec - CS GPIO - POL0_PHA1- 1MHz - SPI0>

Same as the register test: not working.

Then I remembered that the memory use rising edges for input and output bit data and if I was manually controlling de /CS line with a external pin, I didn't need the PHA set to 1 (moreover if it didn't work as expected). So I tried with SPI_POL0_PHA0:

 <Jedec - CS GPIO - POL0_PHA0- 1MHz - SPI0>

Finally I got an output from the memory!... but not the correct one: I got a manufacturer ID of 0xDC instead of the expected 0xEF. And nothing for the device ID: 0x0000 instead of the expected 0xAA21.

I also saw big instant pulses in the MISO line. Possibly due to the cables I am using to connect the memory to the CC1310 LaunchPAD. Thinking on this and knowing that the LaunchPAD has another memory connected to the SPI0, I tried again all the same tests with the SPI1. Everything worked the same way as with the SPI0. And the POLxPHA1 problem exists in both SPI0 and SPI1.

Then I realized that the 0xDC I was getting in the last test, would be a 0xEF if the clock train was continuous and not having the gaps it has between the SPI frames.

Taking into account all the results of the tests I have the next questions:

1. Why the /CS pin is going HIGH after each frame in the POLxPHA1 modes when the reference manual of CC1310 says it will keep LOW during all the SPI transaction? Any way it can works as in the specification?

2. Why is it associated the /CS (SSIn_FSS) behaviour with the Phase-control? Isn't it more interesting and compatible with more devices to separate the roles and that we can set in the SPI parameters the Polarity and Phase on the one hand and a new parameter like "SSIn_FSS continuous transfer" on the other hand where we can choose between single frame /CS or continuous frame /CS? This would avoid the need to implement an external GPIO dedicated to control /CS and avoid the lags associated to GPIO signals.

3. Why are there those clock stops between frames? Shouldn't it be a continuous train of pulses from the beginning of the transaction to the end? I suppose it is related to the /CS control behaviour made in the SPI driver. When in PHA=0 the /CS must go HIGH between frames, so the clock must stop at those moments. On the other hand when in PHA=1 /CS should be held LOW and the clock could be continuous... but as I showed you before this mode is not working properly. And even working as intended, It will not work for me as the memory needs rising edges of clocks to input and output data. Another reason to consider the implementation of a separate SPI parameter to control /CS as I have said in previous point 2. How can I get a continuous train of clock pulses with active rising edges to make the memory work?

And I have some questions about the pin configuration of the SPI driver:

4. Why all the SPI pin are defined in the PIN driver "PIN_Config BoardGpioInitTable[]" array as PULLDOWN inputs? Shouldn't CLK and MOSI be defined as outputs?

5. To disable the /CS SPI pin I have seen I need to define CC1310_LAUNCHXL_SPI0_CSN as PIN_UNASSIGNED. This prevents propagating the signal into a pin. Nevertheless if I define the CC1310_LAUNCHXL_SPI0_CSN to a pin and I don't include this pin configuration in the "PIN_Config BoardGpioInitTable[]" array, I have seen this pin has the /CS signal. How could it be? Is it the pin defined at runtime inside the SPI driver and we don't need to configure it statically in the pin array?

Regards,

Juan Pablo Novo

  • Hi Juan,

    I will look closer at your questions tomorrow and get back to you. 

    In the mean while, have you considered using the NVS driver provided from TI to interface with your external flash? It should support the Winbond W25xx family out of the box, you do not need to re-invent the wheel here unless you want to :)

  • Hi Juan,

    1) This depends a bit on how you use and configure the driver. Per default, there is a 10 frame limit that much be reached in a single transaction for the driver to use DMA operation. If the transaction is smaller than this, a polling approach is used which can look like several small transactions and not a single large one (which would mean the CS toggles in (0,1) mode.

    This should not be a problem for you as the memory do not support this mode anyway. It only support (0,0) and (1,1). Mode (1,1) should also keep the CS low, but to get this behavior I would expect that you need to force the driver to always work in DMA mode. You can do this by going into the board file, finding the HwAttrs struct that relates to the SPI peripheral you use, and set the "minDmaThreshold" value down to 1. 

    2) The best answer I can give you here is that is per IP design and how the format is typically used. There is not really any set way how  a device handles CS and many "SPI compatible" devices also dictates their own requirements. It is not uncommon that a SW CS (much like you did) is used because of this.

    3) Referring to 1) here, it is most likely due to you ending up doing polling transfers because the DMA limit is not reached. 

    4) This table simply defines the state of the pins when not being used by any part of the application. As soon as you open a driver instance, it will take ownership of the pins and reconfigure them as needed. 

    5) The PIN array you refer to is (again) just setting the default values of the PIN. If you look at the HwAttrs table I talked about before, you can see that the pins you use for the SPI hardware is passed into this structure. In other words: PIN_Config BoardGpioInitTable[] -> default values when not used, spiCC26XXDMAHWAttrs[] -> configuration for SPI driver, including PINs to use.

    In the end of the day, this chip family is supported by the NVS driver, which means we already have support for it in the SDK (which should also serve as indication that you can actually interface to it). 

  • Hello M-W.

    Thank you for your quick answers.

    I will try to reduce the DMA threshold and tell you back the results.

    About using the NVS driver to manage the memory I wasn't quite sure about NVS could do it as I read about the many differences about NOR and NAND Flash memories. For example: sector size in the NVS driver is defined as the erase sector size. In NOR the sector is the basic memory unit for reading/writing and it can be erased individually (or in bigger blocks). But in NAND the basic memory unit for reading/writing is the page and the smallest size to be erased is the block (a determined number of pages). So how you set the NVS sector size for NAND memories? Page size? Block size?

    Besides that I reviewed the NVS driver documentation and found it is a basic interface to read/write/erase memory pages/sectors/blocks/regions. It has to be understood to configure it adequately to the target memory used (for example: what is the verify buffer size related to a NAND memory? How to access the full memory with the regions size paradigm proposed by the NVS?) and if you want to make special tasks with the memory (as reading/writing status registers, working with the page read buffer, continuous reading, managing the bad block internal table, etc) you have to implement them apart.

    So I thought it would be easiest and faster for me to build an API to access the memory through SPI with all the function I need, than learning and testing NVS driver and mixing read/write/erase from NVS functions with specific SPI API functions from me.

    Best regards,

    Juan Pablo Novo

  • Hi Juan,

    Most likely you would need to tweak the sector sizes etc. found in the driver itself (as it expects 256 byte pages and this is hardcoded). If you closer at the source code, you should see that they share most of the same OP codes etc. If you think it is to much of an effort to use the NVS driver interface, you can always use this as a base for your project as it is able to function with other chips from the W25 family (and they share both interface and op-codes to some extent).

    As for the "verified buffer size", this is simply a buffer used by software to verify the memory content. It is used as the temp buffer which the driver reads out data into. The size of the buffer do not need to relate to the memory itself but a smaller buffer means it need to iterate more times.

    The NVS driver is a basic "fit most"-kind of driver. As it should cater multiple manufactures and flash types, the functionality is limited to the minimum supported set shared across the intended memories. This means that you are right in that it might be better to do your own if you require access to more of the feature set offered by the memory you use. In this case, the driver could however still serve as a guideline on how to setup and handle the SPI part, even if you do not require the rest of the logic. 

  • Hi, M-W.

    Here are the results of using "minDmaTransferSize=1":

     <Jedec - CS GPIO - POL0_PHA0- 1MHz - SPI1>

    The minDMA change did nothing to the gaps, although the manufacturer ID value returned (0xDE) is closer to the expected one (0xEF). No device ID value returned (0x0000, instead of 0xAA21).

     <Jedec - CS GPIO - POL0_PHA1- 1MHz - SPI1>

    Here the minDMA works. But as the edge is not correct, nothing is returned.

     <Jedec - CS GPIO - POL0_PHA1- 1MHz - SPI1 - zoom out>

    This is the same as the last one, but zoomed out so it shows the DMA load introduced in the spiTransaction() that makes the GPIO /CS changes with extra delay. This is what I think can be solved adding a specific /CS parameter into the SPI parameters struct.

     <Jedec - CS GPIO - POL1_PHA1- 1MHz - SPI1>

    Finally I tested this. It has the correct edge and the continuous train of pulses. I believe this should be the correct one, but unfortunately the memory doesn't return valid values. They are the same as in the first case with POL0_PHA0...

    I am beginning to think if the memory could have a problem. Today I am measuring the MISO line directly from the memory, without connecting it to the CC1310, and, as you can see, the MISO presents the same big peaks as before. They appear when changing levels and some more even when there are no changes. It is very strange, don't you think?

    I will ask Winbond about this issue and probably in the meanwhile buy some replacements to test other ones and see what happens.

    I will set this as resolved by your side and I will tell you back when I have more information.

    Again, thank you for your help.

    Best regards,

    Juan Pablo Novo

  • Hi Juan,

    I agree that the spikes do look strange, maybe it has to do with how the device is connected to the board (or it is faulty). Based on the traces, it really seems like the device outputs 0xDE if one follows the (0,0) (1,1) modes they say one should. Only if you pretend to sample on the falling edge, it makes somewhat sense (however, this would leave no hold time as it also updates data on this edge).

    I will stay tuned from further information from you if you find something out.