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.

CC2640R2F: Using spi with cc2640r2f sensor controller

Part Number: CC2640R2F
Other Parts Discussed in Thread: CC2640,

Trying to use SPI with sensor controller. I am working on a project which had a Nordic chip interfaced to a Blackfin DSP. The interface was implemented using SPI, a chip select and a DataRdy.

  • The Nordic chip[ would assert DataRdy to interrupt the DSP.
  • The DSP would assert the chip select.
  • Each Toggle of the DataRdy line after that would tell the DSP to grap data off the SPI
  • This toggling and data exchange would occur for 10 bytes.
  • After 10 bytes the DataRdy toggling would stop and chip select would be taken away.

We have since replaced the Nordic with the TI cc2640r2. I am trying to adjust the use of the SPI to the DSP interface.

I have working C code on the cc2640 processor which has implemented a successful transfer of data over the SPI using the

scheme outlined above. Currently it does cc2640 --> DSP but the Nordic implementation support for bytes from cc2640<-- at the same transfer. I did not implement this in the cc2640 processor.

***QUESTION***  the cc2640 data put into the spi fifo a byte at a time (because of the use of DataRdy) seems to support only 8 bytes, after that bytes get repeated but do not send real byte 9 and 10. I am assuming that I would have to take chip select away and then assert it again in order to get more then 8 bytes.

So I moved over to the sensor processor. I was able to get the same 8 bytes transfer implemented including chip select and DataRdy just like the cc2640 C code. I modified the architecture of the code to use alerts etc.. and the data from cc2640 to the DSP works and the data at the DSP is correctly received. 

But then I tried to move to using the TxRX function to try to get bytes in both directions but I only get zero when reading the MOSI data in the sensor controller

I have a logic analyzer on clock, chip select, Data Rdy and MOSI and MISO. I can see all 10 bytes on MISO (cc2640-->DSP) and also see 10 bytes of data on MOSI (cc2640<--DSP). This is on a logic analyzer with an interpreter running and specifying which pins are which (MOSI/MISO). The MISO data is interpreted correctly and seems good and the MISO data is interpreted correctly and seems good. By interpreted I means sampled with the clock. The MISO data arrives and is accpeted by the DSP and the data being applied to MOSI fromthe DSP seems correct byte being read at the sensor controller is always zero.

This is the code that transfer 10 bytes

U16 xmitByte = 0;
U16 rcvByte = 0;

for (U16 n=0; n < BufferDataSize; n++) {

gpioToggleOutput(AUXIO_O_DREADY);

xmitByte = output.BufferData[n];
spiTxRx8bit(SPI_POL1_PHA1, xmitByte; rcvByte);
output.CommandBuffer[n] = rcvByte;

tdly = 30; // Tdly is about 10.3us
while (tdly != 0) {
tdly = tdly - 1;
}

gpioGetInputValue(AUXIO_I_SCSN; cs); // Sample cs
ifnot (cs == 0) {
abortspi = 1;
}

}

If I replace the spiTxRx8bit with spiTx8bit it works in one direction.

So any clue or guidance to what I need to do different or try in order to resolve this. I guess I could go back to the C code in the cc2640 that worked and modify it to do both directions but I was hoping I could move forward and not have to back track to the C code implementation. The sensor controller implementation seems to be working great and interfaces well with the BLE architecture I have implemented.

Also I have been successful using the sensor controller and BLE platform in order to have a transmitter acquire data from the AtoD and transmitt the data. This is the receive side. So I am a little familiar with the sensor controller and getting the RTOS to handle using it. I have established flags and input and output data buffers accessible from the BLE processor.

Thanks,

Paul Hembrook

  • Hi Paul,

    Could you clarify if the CC2640R2F is acting as the SPI master or slave in this situation, the sensor controller only supports SPI master mode so I expect this to be the case. However, you say the DSP will assert the chip select which makes it sound like the DSP is actually the master in this situation.

    When trying this out in C code, did you use the TI SPI Driver or did you make your own implementation? The TI Driver supports full-duplex transfers per default so it should be easy to implement what want using the Driver. My understanding is that what you are after is something like:

    CC2640R2F says it is ready, that means it is prepared to send data to the DSP.
    The DSP selects the device using CS and then reads out the data.
    The DSP waits for the CC2640R2F to prepare a new transaction and to notify the DSP.
    The DSP then performs another transaction/read of data.

    * repeat until done *
    DSP raises CS again and the CC2640R2F would stop toggling "data ready".

    This functionality is basically what you get in the default SPI slave and master examples shipped with the CC2640R2F SDK, I recommend you check it out if you have not already done so.
  • I took over this architecture which was implemented in a previous product. The DSP seems to be the master in the fact that it asserts the CS and I believe it supplies the clock. The initial DataRdy asserted by the cc2640 is to interrupt the DSP and prepare him to do an SPI transfer. While in the transfering of the data byte by byte we repurposed the DataRdy to toggle at each byte so if the DSP spi software is interrupted it can 'pace' the spi transfer. I do not know why a DMA was not used but this is the architecture that is implemented.

    When I did the code in the cc2640 I did use the spi driver but at the time I was developing the code I only used and tested the transfer of data from cc640 to the DSP. I sent 1 byte at a time using the driver and toggling the DataRdy.

    I swithced over to the Sensor Controller to implement the working direction and then extend it to also support the DSP to cc2640 direction. I believe I selected 'slave' as one of the parameters. I also tried to modify the clock parameter (bit rate) but it did not change so I assume the DSP is supplying the clock.

    The initial DataRdy assert by the cc2640 (previouslt the nordic) is done when it has received a data packet from a remote acquisition peripheral. The remote acquisition system is now another cc2640 which uses the sensor controller and AD to acquire multiple channels of data (4) and packatize it and send to a receiving cc2640 base unit. The receiving cc2640 (base unit) receives the packet and needs to transfer it to the DSP for a lot of post processing and filtering and then sending it over rs232 to a PC for displaying. I do not know why the DSP is not using DMA with the SPI, maybe a limitation of the DSP (Blackfin). I know the DataRdy is used to pace the transferring of each byte.

    The example I have found seem to be using the driver and cc2640. I seem to have an ok understanding of what needs to be done to init, set parameters and perform a transfer. This operation is also a 'Blocking' operation. I did not pursue doing full duplex since I wanted to move to the sensor controller.

    If there is a sensor controller example using spi I can not find it. I have many of the SDK's include the academy and

    Other questions:

    (1) why does the SPI interface in both the cc2640 driver and sensor conroller seem to send only 8 bytes. If I try to send 10 it seems to repeat some of the previous data rather than use the 9th or 10th byte. Does the driver (and sensor controller) seem tolet me fill a FiFo with 8 bytes only. Is it framing data in 8 bytes (FiFo size) ?  I am assuming if I take CS away and then re-assert it that it would allow me to another 8 bytes. I would like to transfer more than 8 bytes.

    (2) If I change the sensor  controller to do a TX of 8 bytes and then do a RX of 8 bytes that would be a possible change. This woul be more like a typical read req./write answer  of an SPI transaction.

    (3) I was a little confussed when implementing the AD in the sensor controller in our remote acquisition peripheral. And now with using the sensor controller in our base unit. In regards to the remote peripheral which is using the AD if I uses the sensor controller how much of the init and paramter stuff do I need to do in the cc6240 if the sensor controller is doing all the acquisition. I know about setting up for gettings alerts etc... but do I have to do the init and parameter setting or does the selections made in the sensor controller do that stuff.

    (4) As in #3 above when in the base unit of ours which is using the SPI with the sensor controller how much cc2640 code do I need to do as far as init, parameters etc ??

    (5) I am having an issue accessing 'Help' while in the sensor controller but have found the folder where the html files are and have been going through some of those. Is there any reason the help selection in the sensor controller does not access the help folder ?

    (6) One last item is that when I have the IDE debugging (using j-link) with NO breakpoints and I let it run it does not seem to let the sensor controller run. I monitor some debug pins from the sensor controller and they are not changing. If I terminate the debug and power cycled the blard the code runs just fine. Any clue why the debugging would have an issue with the sensor controller ??

    Here is what I do to setup SPI:

         SPI_init();                                   // Initialize the SPI driver
         SPI_Params_init(&spiParams);                  // Initialize SPI parameters
         spiParams.dataSize = 8;                       // 8-bit data size
         spiParams.mode = SPI_SLAVE;                   // Slave
         spiParams.frameFormat = SPI_POL1_PHA1;        //
         spiParams.transferMode = SPI_MODE_BLOCKING;   //
         spiParams.bitRate = 1000000;                      //

         spiHandle = SPI_open(Board_SPI0, &spiParams);
         if (spiHandle == NULL) {
             return(SC_RXDSP_OPEN_FAIL);  // SPI_open() failed
         }


    Here is what I do to start the Sensor Controller:

        scifOsalInit();                 // Initialize the operating system abstraction layer of the scif framework
        scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
        scifInit(&scifDriverSetup);     // Initialize the SC with our SC task driver
        uint32_t rtc_Hz = 1;            //
        scifStartRtcTicksNow(0x00000042 / rtc_Hz);      //   1.007 ms

        // Start the Sensor Controller
        scifStartTasksNbl(BV(SCIF_RX_TO_DSP_TASK_ID));                  // Starts the SC task

    I want to make sure that I am not interfering with what the sensor controller is doing. I found issues with using some GPIO for debug signals and the cc2640 using those pins as well. Even thuogh I removed the code using the debug pins in the sensor conroller the fact that I had the I/O mapped stop the cc2640 code from being able to use them. When I removed the signals from the I/O map the GPIO worked as expected in the cc2640. So any details you can give me with what the sensor controller and cc2640 need to do for using the SPI would be apprcited.

    Here are the SDk's I have:

    Where are the example for spi and is there any examples for the sensor controller.

    Sorry I sent so much but I final made time to communicate my issues.

    Paul H.

  • Hi Paul,

    If the DSP is indeed the master in the system then I think you should move away from using the Sensor Controller (SC) SPI (which is bit-banged) as this is a "Master" implementation.

    1, 4)

    I think you might be confusing the SC SPI with the TI-RTOS SPI Driver (which is using the actual SPI hardware). The SPI parameters you say you are using are related to the TI-RTOS driver, when calling SPI_open() you are configuring the actual SPI hardware (which do support slave mode as you noted in the "Mode" parameter) and not the SC implementation. The SC SPI also do not feature any FIFO feature while the actual hardware do offer this feature. 

    The TI-RTOS driver can be operated in blocking or callback mode; both modes are full-duplex. Blocking mode will block the TI-RTOS task until completed while Callback mode will return right away. In callback mode, you then instead get a interrupt/callback when the transfer completes. In blocking mode, the SPI driver will use either polling operations or DMA transfers depending on the number of frames it expects to send/receive. This threshold is configurable in the SPI driver HW attributes (found in the board file).

    Here is some pseudo code on how it could look using the TI-RTOS driver (based on my understanding of the use case).  

    void myCallback(SPI_Handle handle, SPI_Transaction *transaction) {
        // Reset dataRdy
        GPIO_toggle(dataRdy);
    
        // Post semaphore
        Semaphore_post(mySpiSemaphore);
    }
    
    void someFunction() {
    
        SPI_Transaction transaction;
        uint8_t txBuf[2] = {0};
        uint8_t rxBuf[2] = {0};
    
        SPI_init();                                   // Initialize the SPI driver
        SPI_Params_init(&spiParams);                  // Initialize SPI parameters
        spiParams.dataSize = 8;                       // 8-bit data size
        spiParams.mode = SPI_SLAVE;                   // Slave
        spiParams.frameFormat = SPI_POL1_PHA1;        //
        spiParams.transferMode = SPI_MODE_CALLBACK;   //
        spiParams.transferCallbackFxn = myCallback;
        spiParams.bitRate = 1000000;                      
    
        spiHandle = SPI_open(Board_SPI0, &spiParams);
        if (spiHandle == NULL) {
         return(SC_RXDSP_OPEN_FAIL);  // SPI_open() failed
        }
    
        // Send/Receive 10 frames from DSP (1 at a time)
        for(int i = 0; i <1; i++) {
    
        // Prepare transfer buffers
        txBuf[1] = theDataToSend[i];
        transaction.count = 1 + 1;
        transaction.txBuf = txBuf;
        transaction.rxBuf = rxBuf;
    
        // Prepare the transfer so that the SPI slave is ready when the DSP master communicates (callback mode, this call will return right away)
        status = SPI_transfer(spiHandle, &transaction);
    
        // Toggle DataRdy so that the DSP will perform the transfer
        GPIO_toggle(dataRdy);
    
        // Wait for transfer to complete
        Semaphore_pend(mySpiSemaphore, BIOS_WAIT_FOREVER);
    
        }
    }
    

    Looking at the example, you might note that I always send 2 bytes. This is related to the errata that exists for the SPI hardware where you, in slave mode, could lose the first data frame. The workaround here is to always append a dummy frame is front of the data that you then discard on the master side. This means the DSP would need to perform 2-frame transfers each time for this workaround to work. 

    You could also use the same example but instead perform 1 transfer of 10 frames. The DSP would still be responsible of pacing the data out and you would get a callback back when the DSP had performed all 10 transfers. This assuming you wanted to move away from using DataRdy for each single frame.

    The actual TI-RTOS examples can be found under:

    <SDK>/examples/rtos/CC2640R2_LAUNCHXL/drivers/spi*

    2)

    As mentioned earlier, I don't think this is a simple approach based on the fact that the SC implementation is Master only.

    3)

    Typically, what you need to do is what you already do when starting the SC. You do not need to do any peripheral specific initialization in addition to this. What you need to keep in mind is not to use the same pins in your main application that you also use in the SC. There is ways to "share" pins between the two processors but if you really don't need to do this I would avoid it.

    As an example, in the SC ADC use case, you don't need to do any ADC configuration in your application in regards to pins or peripheral, this is handled in the SC code.

    5)

    I'm not sure on why you can't open the help section. Normally, hitting "F1" (Help->Sensor Controller Studio Help) should open up the help section.

    6)

    I'm not sure why the debugging should cause an issue in your case. I will need to look this up and get back to you.

    Best Regards,

    Max

  • Hi Paul H,

    Regarding the J-Link issue, would it be possible for you to try using another debugger (like a XDS) to see if you see the same problem?
  • It would be difficult for me to try another debugger. I will see if I can later but right know I am in a cricital phase of a project.
  • Thanks for answering my questions.

    I would like to pursue two paths. First the Sensor Controller solution then the TI driver solution.

    (1) My plan for the Sensor Conroller is to have a transfer from the SC to DSP of 8 bytes complete. This has worked in the past. Then I should be able to proceed on and perform a transfer from DSP to SC. This has not worked in full duplex but I am assuming even with the SC bit banging that this should work.

    In the SC I would do a seperate for loop doing the TX and then do a for loop doing the receive. Can I do that back to back operation with the chip select being active or will I need to take chip select away and then return it active between the two operations. This is basically doing the TX/RX in two seperate operations instead of full duplex.

    (2) Then I will bring back my code that uses the TI driver and try to perform the full duplex transfer. I am not sure I understand the work around with the 2 bytes. Does that mean I will need to do a DataRdy then transfer 2 bytes (instead of 1), toggle DataRdy and transfer 2 bytes (instead of 1) and on and on. The work around must be when I would be getting data from the DSP since I already have the data to the DSP working fine. Is the work around for when data is being sent from the DSP.

    I will need to check my board file about frame size. Is the frame size what you are referring to as the amount of data sent during one Chip Select session. Meaning I lower chip select, send data bytes then raise chip select when done. I currently can send 8 bytes to the DSP during a single session of the Chip Select. If I extend that to send 10 the last 2 bytes are not the byte 9 and 10 that I am sending.

    I will look through your examples again. But if you can just read through my plan above and make sure that it is possible for my plan to work I can move on.

    Thanks,
    Paul H.
  • Hi Paul,

    1) If you implement your own bit-bang SPI, you could get any functionality you want (to the limit of the SC). The already existing SPI Master implementations I however still doubt will work good in both directions. I guess you could get lucky in this but generally, two SPI masters talking to each will be tricky to coordinate.

    2) Yes, you would have to add the extra byte for every single transfer. This means that if you want to do multiple single frame transfers, you would need to make multiple double frame transfers instead. If you do a single long transfer (lets say 30 frames) you would need to do a 31 frame transfer instead. Basically, for every SPI_transfer() call you do as a slave, you would need to append that extra byte. This issue is only related to the MISO line (if the DSP is the master, that is CC2640R2 -> DSP), which means it is related to the TX FIFO when acting as a slave.

    Frame size is the number of bits a single entry contains (4,5,6 ... - 16 bit). For example, if you do a 3 frame transfer with 10-bit frame size, this would mean you are sending 30 bit-s in total (3 x 10). The frame size is not equal to the data send during "one CS session" (I guess it would be if you always only send 1 frame).

  • Hi M-W,

    I wil play with the SC implementation but for now we can close that issue I appreciate all your help and insight.

    So I will begin working on upgrading my single direction transfer to full dules using the TI frivers and internal hardware. But I still hae an issue with the 8 byte transfer. This is an issue with both my SC implementation and the TI driver implemenatation in one direction.

    If The code running in the BLE does a TX to the DSP and tries to send 10 bytes only 8 bytes are the data exspected and the last 2 are not. I see this at the DSP and on a logic analyzer. The analyzer shows 10 cycles of data clocks (8 clocks for each byte). I send  1 byte TX and toggle my DataRdy (CS always asserted) and do this loop for 8 bytes everything is fine at the DSP and on the logic analyzer. If I make it 10 bytes I get 8 good bytes at the DSP and logic anlayzer and the last 2 bytes are either a repeat of the first 2 byte sent of zeroes. This is what I see on the logic analyzer. If I force the last 2 byte transfer to a constant instead of pulling data from a buffer they are still not transferred correctly. So I compressed the data to only need to transfer 8 bytes. This 8 byte implentation is working now with data being sampled at our peripheral, sent to the central, received in the BLE, transferreed over SPI, filtered by DSP and displayed on the PC. So I am pretty comfortable that all the buffering and messaging and semaphores and allerts are working great. Bt 10 bytes not so good tested locally in a loop and not using buffes just a series of known bytes.

    I believe I have the SPI interface set up correctly. I just don't know why after I send the 8th byte that any byte transfer after that sends incorrect data.Obviously after 10 bytes I drop chip select and start the operation over 5 ms later. This 5ms cycle is what our system works at based on receiving samles from the peripheral.

    I have debugged this very local with the data being feed with 10 constant byte values and I see what the transfer does in a loop (with some delay between test loops). I see the last 2 bytes not correct on the analyzer and at the DSP. So I have removed all the messaging and buffers and just get down to moving 10 specific byte values to the DSP.

    I can send you a snap shot of the logic analyzer if you can tell me how to get it to you.

    I will work on updating my SPI driver transfer to be full deplex with the working 8 bytes and see what I get but I would definetly like to be transferring 10 bytes or more.

    Paul H.

  • Hi Paul,

    Your "10 byte" sounds strange, would it be possible for you to share your CC2640R2F code as well as the snap shot? If so, I could have a look at it and see if I can figure anything out. If possible, it would be great if you could create an example with a "dummy DSP" (another CC2640 device if you got one) that I could run the code against to be sure I setup everything in the same way.

    I note regarding the SC, if you absolutely want to leverage the SC for this you do not need to use the available "SPI master" implementation. You could choose to implement a "proper" SPI slave in code (bit-banging it yourself) and if you find out you need to squeeze the performance even more you can implement your own ASM routines for the sensor controller (this is basically what the SPI API is today). You can find most of the APIs that exist today in:

    <SC INSTALL DIR>/proc_defs

  • Hi Paul,

    Got any updates on this?
  • Hi M-W,

    So I gave some thought to your insight and have targeted my focus to implementing the SPI interface between the BLE and DSP with C code in the BLE and not the sensor controller.

    I retrieved a previous version of code that I had developed before I moved to trying the sensor controller. I did not pick using the TI driver because I needed to toggle and manage the DataRdy etc.. so I developed code that wrote directly to the TX data register. That is why I mention FiFo previously. I guess I wasn’t as clear about how my code was accessing the SPI. So you are probably thinking what am I talking about when I was describing things.

    So this retrieved code was always able to send up to 8 bytes from BLE to DSP. Any more than 8 bytes and the bytes after 8 was not the data being sent. All this is observed with a logic analyzer on the SPI bus. Occasionally I do run an emulator on the DSP side and see what the DSP is actually reading off the bus and verifying it matches what the analyzer says.

    I worked on the BLE side and tried to prefill the FiFo (8 bytes) and then add the additional 2 bytes when I exhausted sending the eight. I know when I am transferring each byte since I control DataRdy. This did not fix anything. So I played around with the prefill and at what byte transfer (toggling of DataRdy) to add the 2 additional bytes. I am adding in two since it seemed the SPI was more consistent and repeatable when the total transfer count was a multiple of 2 and the addition of bytes was 2 as well. Eventually I discovered the prefill count that worked and when to add the additional 2 bytes. I am now able to transfer 10 bytes. I also went a few steps further and went to 14 bytes and at that time verified that the correct data which was on the SPI analyzer was the data being received by the Blackfin DSP.

    The prefill and adding time frame does not seem to be related to empty or full. There is no half full and I do not monitor these full or empty status to determine when to add data. In a simple loop of writing to the TX register, toggling DataRdy and then waiting for some time it looks like a prefill of bytes 0-5 is a good number.

    So what I implemented was a prefill of bytes from the BLE Transmit buffer 0-5. I have a table that indicates what to do as each DataRdy byte transfer is done. The table indicates which data from the buffer to add to the FiFo or not to do an add at all. What is working for 12 bytes is at the DataRdy toggle 4 add bytes 6 and 7, at toggle 6 add byte 8 and 9 and at toggle 8 add byte 10 and 11. This seems to work. All 12 bytes are received at the DSP correctly. I further extended the transfer to do14 bytes, adjusting the table and it still worked great.

    Since this seems to work fine I am now going to move on to DSP -> BLE transfer of bytes during the above transfer. I will be placing a byte on the SPI during each of the transfer toggle of DataRdy that the DSP is seeing. I will try a byte to the hardware register every time I receive a byte but I think this side will require a prefill as well, which I will probably move too quickly. I think I remember putting a byte in the register did not work but this will be a good point to start. I thought this is when I was seeing zero all the time.

    Eventually my goal will be to do a new architecture of this SPI interface but I will need to go to the Blackfin architecture and understand it SPI hardware. Critical right now is to get a full duplex SPI data transfer of 10 bytes working to allow the rest of the development team to continue as I tune or redo the SPI.

    Can you give some thought to what I did on the BLE -> DSP transfer and hopefully this is a implementation I can move forward with.

    Can you think about the DSP -> BLE transfer I am working on now. You mentioned about a hardware issue with SPI and the first byte of a frame. How do you think that will affect what I am trying to do ? Any thoughts or comments about doing a prefill and adding to the FiFo ?

    Thanks,

    Paul Hembrook

  • Hi M-W,

    Disregard my questions about DSP -> BLE. I was thinking as if this would be the BLE side when it really is the DSP. But do you know of any issue with the BLE side receiving data on the SPI full duplex ?
  • Hi Paul,

    There is no issues that I'm aware of connected to the receiving data as a slave. I'm a bit confused by the issues you had with filling the FIFO, would it be possible to share your code implementation with me so that I could look at it?