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.

CC2640 CC2650 sensor controller

Expert 1340 points

Other Parts Discussed in Thread: ADS1298, ADS1292

I have a task that currently uses the MCU to read data (SPI/I2C) from multiple sensors upon periodic interrupts generated by them (falling edge on GPIO pins). This task is lower priority than the BLE stack tasks but higher priority than a separate task that processes the sensor data. The data processing task blocks until a semaphore is posted from this data reading task. This seems to be working reasonably well. I want to begin optimizing the system and integrate the sensor control to read the SPI/I2C data.

Currently the sensor reading task blocks until any sensor sets a hwi. The hwi Interrupt handler only posts a semaphore (with event message) to unblock this task. I'll start with one SPI sensor. My questions are:

  1. Can I use a GPIO to detect an edge? From the sensor controller studio, it seems that I can detect high or low level only (and it's polled by the sensor controller task).
  2. The sensor is ADS1298 which does not have a FIFO. So I want to buffer multiple samples into an array and after say 8 samples, wake up the data processing task. How to I do multiple reads into an array, each time incrementing the starting address? 
  3. On the 8th read, is it possible to post to the same semaphore queue that's posted by the data reading task to wake up the data processing task? I need to know the event that caused wakeup since there are multiple data sources. Or do I need to make a new task for each sensor that uses the sensor controller?
  4. After the wake up, how do I read/copy the the array into the data processing task?

Thanks!

  • Hi TOSA,

    I have an answer to your first question only:

    Detecting interrupt on both edges is supported (see section 11.10.2, CC26xx SimpleLink Wireless MCU Technical Reference Manual).

    I didn't have the time to play around with sensor controller studio yet, therefore I cannot advice you on how it can be configured with the GUI.

  • 1) Triggering can either occur at high or low level (no transition required) or at rising or falling edge on the GPIO pin. Please read the GPIO Event Trigger documentation in SCS.
    2) Unless I misunderstand this should be fairly easy to implement with sensor controller RAM and register variables. If you need more details please ask.
    3) & 4) Only one task per project can implement the Event Handler Code task code block. This means you should insert your data processing code in your event handler(place within if statement). If the processing required a large amount of calculations I would consider implementing this on the main application processor instead. The Main CPU has direct access to the sensor controller RAM and can simply read out any content.
  • Hi Eirik,

    I downloaded SCS 1.1 and see the edge trigger GPIO now; I had 1.01 installed previously. Other questions I have:

    1. in parallel with the sensor controller SPI task, is it possible for the main CPU to access the same SPI peripheral, so that, for example, the user can configure registers on the sensor? These of course would need to pend on a semaphore for the SPI access, but can the handle to the SPI hardware still be obtained by the MCU while the sensor controller task is running? Or do I need to stop the sensor controller task, configure the sensor's registers, then restart the sensor controller task?
    2. Is it possible to use the sensor controller SPI/I2C to get data from different asynchronous sensors? For example, two different I2C sensors that don't have the same time base but they would assert the same GPIO pin which would need then require the two sensors to be polled to see which asserted the interrupt? What if they had two separate GPIO pins so that I didn't need to poll which sensor created the interrupt? In either case, how can I inform the CPU which sensor the data is from?
    3. (Ignoring question 2 and assuming a single sensor on an SPI/I2C bus), if there's enough AUX RAM, I can run independent SPI and I2C sensor controller tasks, each one with it's own event handler to get data back to the CPU?

    Thanks!

  • Hello Tosa,
    1)
    The SPI serial interface on the sensor controller is bit-banged and is not related to the SPI hardware module.
    2)
    SCS can only set up a single GPIO interrupt at a time, but you can implement two pin interrupts in RTOS and start the SC task based on which pin that was triggered. You can also run a single task which simply checks a variable set by the main application processor before the task is started.
    3)
    I think there is. You will just have to try. But they have to run sequentially (one after another) where the first one in line has to complete and end before the next task can run.
  • Hi Eirik,

    1) Even though the SCS uses bit banged SPI and the MCU uses the hardware module, they still cannot run "at the same time" right? What I mean is: suppose the SC task is running and reads data from the ADS1298 every 4ms. Let's say this task runs perpetually. In parallel, suppose the user configures an ADS1298 register to change the gain using the hardware SPI. How would these two SPI transactions share the same pins simultaneously? How would I use some kind of semaphore to prevent this? Using the hardware peripheral it's straightforward to use the semaphore to force the SPI transactions to occur serially. Or do I need to stop the SC task, the allow the gain to be changed, then restart the SCS task?

    2) 3) If the SC tasks run perpetually (read data on a GPIO interrupt), then running two SC tasks for two different GPIO pins will not work, correct? Is there a way to let two SC tasks run perpetually, reading data from the respective I2C or SPI sensor when a GPIO edge interrupt occurs?What happens if an interrupt occurs while the other sensor is being read?

    Thanks!

  • Hello Tosa,
    1)
    We are working on adding support for pin sharing between sensor controller tasks and ti-rtos tasks (i.e. code running on main application processor). This will be added to a future release.You need to stop the task before handing over the pins between the CM3 and SC.
    2)
    No, but you can try to combine it into a single task that both trigger on the same GPIO, but then on wake up check the level of another to decide whether to start I2C or SPI. Could this work?
  • Hi Eirik,

    I made a SC task using the SPI interface. The SPI routine only seems to operate if I use RTC based scheduling. If I use GPIO event trigger, the event is never called (even though the trigger is toggling per the logic analyzer). I saw the same issue in this thread. How can I get the GPI trigger to work? 

    Also, could you please help me understand the following?

    1. What does the # mean on parameters? For example Prototype: utilIncrAndWrap(value, #wrap; incrValue)
    2. The Code Language Reference states "To create a pointer to a data structure member, use the # operator." What does the # mean here and is it different from above?
    3. I don't understand how utilIncrAndWrap(value, #wrap; incrValue) works. For example, in the ADC  data logger example does utilIncrAndWrap(n, BUFFER_SIZE; output.head); on each execution. Is output.head only set to n once (regardless of how many times this statement executes as long as the task is active) and then in increments output.head on each execution until it hits BUFFER_SIZE and then resets to 0? Why not call utilIncrAndWrap(0, BUFFER_SIZE; output.head); instead since output.head is initially 0? Or is it set to n so that it's not hardcoded in case the initial value is not 0?
    4. For multi-buffered output data exchange, which parameter is the index to the pOutput and what are the fields outputSceBufferCtrl, outputDrvBufferCtrl and outputScePtr in:
      /// Sensor Controller task data (configuration, input buffer(s), output buffer(s) and internal state)
      typedef struct {
          struct {
              uint16_t outputSceBufferCtrl;
              uint16_t outputDrvBufferCtrl;
              uint16_t outputScePtr;
              SCIF_ADS1298_SC_DRIVER_OUTPUT_T pOutput[2];
              SCIF_ADS1298_SC_DRIVER_STATE_T state;
          } ads1298ScDriver;
      } SCIF_TASK_DATA_T;

  • Hello Tosa,
    You cannot share the pins between the sensor controller and the CM3. In the next version (SCS 1.1.1) we will add support for sharing in a manner where you will have to end the running sensor controller task, set up the IO config for CM3. When CM3 is done you can reestablish the IO config for the sensor controller again before restarting the task.

    1)
    As parameters in function calls it means a constant (number). You can use constants or immediate values.
    2)
    Yes, in this sense it is similar to the & operator in C. But it can only be used on data structure members.
    3)
    The utilIncrAndWrap(1,2,3) will increment the value in (1) and store it in (3). When the value reach (2) it will overflow (reset to 0). If set to (0, BUFFER_SIZE; output.head) the head would be set to 1 for ever after the first iteration. Initial value would be stored at index 0 and then all subsequent values would be stored at output.pSamples[1], which would be incorrect use of the buffer. You can access the procedure documentation by pressing F1 or double clicking on the procedure in the bottom right "Available Procedure" box in the code editor.
    4)
    Look at the "Capacitive Touch Data Logger" example code for how to use Multi-buffered output data exchange. You need to call scifGetTaskIoStructAvailCount to know if there are any available buffers handed over to the main application processor and then retrieve that buffer by calling scifGetTaskStruct.

    outputSceBufferCtrl and outputDrvBufferCtrl is used by the sensor controller code and framework to keep track of the buffers. This is handled automatically by the driver functions and you do not need to use these variables.
  • Hi Eirik,

    Thanks for answering the questions; they're clear now. However, I'm still having trouble using the SC GPIO event trigger. I'm doing a test case where I'm not using the CM3 SPI. Instead, another sensor is toggling a pin that is not assigned to any peripheral (DIO7). The SC task uses that to toggle another pin (DIO27). I see DIO7 toggle but not DIO27. How do I resolve this? (Similar configuration using RTC based execution works fine to toggle DIO27.) Thanks!

  • Hello Tosa,

    Please show me how you set up the GPIO Event Ttrigger.

  • Hi Eirik,

    For the GPIO trigger SC task:

    initialization: 

    evhSetupGpioTrigger(0, AUXIO_I_GPI, 0, EVH_GPIO_TRIG_ON_EDGE);

    event handler: 

    gpioSetOutput(AUXIO_O_TESTOUT); 
    //fwDelayUs(1000, FW_DELAY_RANGE_1_MS); 
    gpioClearOutput(AUXIO_O_TESTOUT);

    execution and termination are empty

    For the MCU code:

    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);
    scifStartTasksNbl(BV(SCIF_GPI_TOGGLE_GPO_TASK_ID));

    Also, some more questions: 

    1. According to this thread, it's possible to use CM3 SPI and SC SPI sequentially. Your previous response seems to indicate this is not possible until the next SCS revision "You cannot share the pins between the sensor controller and the CM3. In the next version (SCS 1.1.1) we will add support for sharing in a manner where you will have to end the running sensor controller task, set up the IO config for CM3. When CM3 is done you can reestablish the IO config for the sensor controller again before restarting the task." Which is correct?
    2. I'm doing a temporary implementation where I use RTC based executions and poll the ADS1298 DRDYb then read the data when ready. It seems to work but SC SPI runs at 2MHz, and I get bad data from the ADS1298. Is it possible to adjust/slow down the SC SPI SCK? In my CM3 SPI I need to use 500kHz; 1MHz or above gives bad data from the ADS1298. In this thread for the ADS1292 you mentioned there's a setting to make the 2MHz clock work. Is there such an issue with the ADS1298? If not, it may be some issue with my PCB layout.

    Thanks!

  • Hello,

    You should try to add some delay between setting the IO to 1 and clearing it again (The sensor controller is running on 24 MHz when in active mode).

    1) In the next release (version 1.1.1.) we will add a function called scifReinitIo to the framework which can be used to reinitialize the IO for AUX usage after it has been released from the main application processor application.

    2) We are looking into adding support for lower data rates, but timeline and which rates are not decided yet. I will check with the developer team.

  • Hi Eirik,

    Actually I did try the 1ms delay (fwDelayUs(1000, FW_DELAY_RANGE_1_MS);) but it didn't help. Any other thoughts? When is the target for v1.1.1 release?

    Thanks!

  • Hi Eirik,

    I noticed that v1.2.0 has just been released. Does this have the scifReinitIo feature? Is there a summary of the changes over time for SCS on the Web site? Also, I found the issue with the 2MHz SPI clock on the ADS1298. It turns out that there needs to be enough delay between the last SCK falling edge and the CSB rising edge (TSCCS in the datasheet). I can "adjust" this using the hardware SPI, but I'd need to be able to adjust it in the SC also. How can I do this (or does v1.2.0 address this)?

    Thanks!
  • Hello Tosa,

    Yes the use of this can be seen in the shared IO pins example.

    If you open the help viewer (F1) you can find information about all the changes in the "Revision History" tab.

    Are you referring to SCL stretch timeout? If so, this can be adjusted in the "Task resources" window  for your specific task in SCS.

  • Hi Eirik,

    Actually I'm referring to SPI. I need to adjust the CSB timing relative to SCK. Per the ADS1298's datasheet, there needs to be enough delay at the last SCK to CSB de-assertion otherwise data is corrupted. See tSCCS:

    Thanks!

  • Hello Tosa,

    Sorry, I looked at a I2C feature :).

    It seems this timing is related to when chip select is set low/high. Chip select is controlled independantly through the "SPI Chip Select" procedures spiBegin/spiEnd. Simply try to add the required delay before calling spiEnd and delay after spiBegin, but before calling any data transfer procedure.

  • Hi Eirik,

    Oops, I completely forgot it's a separate function to toggle CS versus doing the actual SPI transfer (I haven't looked at this issue for a while :) ). I'll implement this soon and post if any new issues pop up. Thanks for your help!
  • Hi Eirik,

    I'm able to get the SC to run by itself (it configures/gets data/notifies the MCU) from ADS1298, but I'm still having trouble using the SC and MCU peripheral sequentilly. I have a task, called configTask, and another task, called scTask. Theses are of the same priority. configTask uses the MCU SPI to configure the ADS1298 (register settings) and scTask uses the sensor controller to start (but not configure) and get data from the ADS1298. I want to keep the tasks separate so that the ADS1298 register configuration can be changed by the user via BLE before the scTask starts.

    In the configTask_init() I call SPI_open() and attempt to configure the ADS1298 (among many other things).

    in scTask_init() I call

    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);

    The call to scifInit(&scifDriverSetup); seems to override the SPI_open() call and the MCU is unable to communicate via SPI to the ADS1298 (as confirmed by the sub-optimal data read  in the scTask due to non-configuration of the ADS1298. Once the user connects to the MCU and enables notifications I call

    scifReinitTaskIo(BV(SCIF_RTC_POLL_AND_READ_ADS1298_TASK_ID));
    scifResetTaskStructs(BV(SCIF_RTC_POLL_AND_READ_ADS1298_TASK_ID), BV(SCIF_STRUCT_CFG));
    scifStartRtcTicksNow(32);	// n/65536 seconds poll
    scifStartTasksNbl(BV(SCIF_RTC_POLL_AND_READ_ADS1298_TASK_ID));
    

    When the user disconnects or disables notifications I call:

    scifStopRtcTicks();
    scifStopTasksNbl(BV(SCIF_RTC_POLL_AND_READ_ADS1298_TASK_ID));
    initSPI1();

    But any attempt to use the MCU SPI crashes the firmware. The shared IO example uses a single task to sequentially swap between MCU and SC, so my case is a little different, but should still work, right? Your advice is greatly appreciated :)

  • Hello Tosa,

    yes, the scif initialization routine will override the io pin configuration.

    You must use the SPI close() and open () routines. Refer to the Shared IO Pins example in the latest version on SCS.

  • Hi Eirik,

    I refactored my code to use one task to share the MCU SPI and SC SPI. Before the RTOS task runs, I initialize the SC driver, and then I call SPI_open() as follows:

    void taskFxn(UArg a0, UArg a1) {
    ...
    // Initialize the Sensor Controller
    scifOsalInit();
    scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
    scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
    scifInit(&scifDriverSetup);
    ... SdSpiHandle1 = SPI_open(CC2650_SPI1, &SdSpiParams1); ... SPI_transfer(SdSpiHandle1, &spiTransaction); // not working ... for (;;) { ... // start/stop SC here seems to work (SPI_close before SC starts, and SPI_open is called after SC stops but has no effect) } }

    However the MCU SPI does not respond to any commands. In the example UART_open() is called when MCU is needed, and the UART_close() is called followed by scifReinitTaskIo(). So I believe I'm following the example.

    I confirmed that the UART shared pins example does work. However if optimizations is set to higher than 2 (global or below is ok) then it does not work. Why is this?

    Your help in resolving this is much appreciated!

  • Hi Eirik,

    It seems that the issue is due to my not using the SPI peripheral CSN. I need to toggle the CSN as a GPIO since there are multiple sensors on the SPI port. Before I call SPI_open(), I do a PIN_open() on the CS pin, and do a PIN_close() after SPI_close(). However, I still don't get CS to toggle (MOSI and SCK seem to work fine, and the SC task seems to work fine). Any thoughts? Thanks!

  • Hello Tosa,
    I am not sure. Make sure to set the CS pin to unassigned in your board file (spiCC26XXDMAHWAttrs) to allow the pin driver to toggle it manually:
    .csnPin = PIN_UNASSIGNED
  • Hi Eirik,

    Yes, I used .csnPin=PIN_UNASSIGNED. Would you please be able to do a simple shared SPI test to validate if the GPIO pin can be shared with the SC for CSN usage? I modified the UART pin share example to do SPI. I can post it here if you like (but you'd need to modify the board file to match the EV kit since I'm testing it on my proprietary board). Thanks!
  • Hi Eirik,

    I pasted the basic SC-MCU SPI test code here:

    void taskFxn(UArg a0, UArg a1) {
    	PIN_State  pinState;
    	PIN_Handle  pinHandle;
    	PIN_Config aPinListHui[] = {
    			Board_SCS1 | PIN_GPIO_OUTPUT_EN | PIN_GPIO_HIGH | PIN_PUSHPULL,
    		PIN_TERMINATE                                                                               /* Terminate list                */
    	};
    
    	SPI_Params_init(&SdSpiParams1);
    	SdSpiParams1.bitRate  = 2000000;
    	SdSpiParams1.frameFormat  = SPI_POL0_PHA1;
    
        // Initialize the Sensor Controller
        scifOsalInit();
        scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
        scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
        scifInit(&scifDriverSetup);
    
        // Main loop
        while (1) {
            // S E N S O R   C O N T R O L L E R
    
            scifResetTaskStructs(BV(SCIF_SPI_WRITE_TASK_ID), BV(SCIF_STRUCT_CFG));
            scifExecuteTasksOnceNbl(BV(SCIF_SPI_WRITE_TASK_ID));
            Task_sleep(50000);
    
            // T I - R T O S   SPI   D R I V E R   W I T H   SPI   H A R D W A R E   P E R I P H E R A L
    
        	SdSpiHandle1 = SPI_open(CC2650_SPI1, &SdSpiParams1);
    //    	pinHandle = PIN_open(&pinState, aPinListHui);
    //    	PIN_setOutputValue(pinHandle, Board_SCS1, 0);
    		TIADS1298_checkStatus();
    //		PIN_setOutputValue(pinHandle, Board_SCS1, 1);
    //		PIN_close(pinHandle);
    		SPI_close(SdSpiHandle1);
            scifReinitTaskIo(BV(SCIF_SPI_WRITE_TASK_ID));
    //        Task_sleep(50000);
        }
    
    } // taskFxn
    
    void doSPI1(uint8_t *txbuf, uint8_t *rxbuf, uint8_t count)
    {
    	SPI_Transaction spiTransaction;
    	spiTransaction.arg = NULL;
    	spiTransaction.count = count;
    	spiTransaction.txBuf = txbuf;
    	spiTransaction.rxBuf = rxbuf;
    	PINCC26XX_setOutputValue(Board_SCS1, 0);
    	SPI_transfer(SdSpiHandle1, &spiTransaction);
    	PINCC26XX_setOutputValue(Board_SCS1, 1);
    }
    

    Any hints/thoughts are greatly appreciated. (You may be wondering why I don't use the hardware CS. The reason is at 2MHz SCK the tSCCS delay is violated. I posted another thread on how to adjust this delay, but if you know the answer, please tell :) ) Thanks!

  • Hello Tosa,

    First try to pend on a semaphore instead of using the wait statement (Task_sleep(50000);). In your sensor controller code generate an alert. Then pend on a semaphore instead which will be released by your callback.

    Semaphore_pend(Semaphore_handle(&semScTaskAlert), BIOS_WAIT_FOREVER);

    Let me know how this works out.

  • Hi Eirik,

    I'm having trouble with another SC issue (I'll get back to the pin sharing issue later) where the SC seems to be running correctly but after some period of time (many hours), it stops generating alert callbacks (using fwSwitchOutputBuffer). The SC is running properly per probing with a logic analyzer, but the application task stops getting callbacks after a long period of time. Other sensors in my system are working fine, so it seems only related to the SC. I disabled overflow checking and allow buffer switching even with overflow to see if this is the issue, but that is not the cause. I'm testing single buffered operation using fwGenAlertInterrupt now to see if that has the same issue. Any thoughts on why the callbacks stop occuring? Thanks!

  • Hello Tosa,
    I am not sure. Are you certain that the fwSwitchOutputBuffer procedure is called? You can toggle a IO before and after the procedure is called and monitor the IO with a logic analyzer.
  • Hi Eirik,

    It turns out that it's some issue with the semaphore that's posted by the hwi from fwGenAlertInterrupt or fwSwitchOutputBuffer that's causing the issue (the application task thus doesn't run and call scifClearAlertIntSource. So it's not a SC issue and this particular issue can be ignored. I'll get back to the GPIO pin sharing issue after I resolve this semaphore issue. Thanks!

  • Hi Eirik,

    Until I resolve the semaphore/task issue causing the function which contains scifClearAlertIntSource to not run, are there any issues if I call scifClearAlertIntSource and scifAckAlertEvents in the hwi and thus before the task function which accesses and copies the data from the SC's output buffer? I've been testing it and so far it seems stable and the data looks good. Thanks!
  • Hello Tosa,
    This thread is becoming a bit complex, please post new questions in new threads when you have new topics in your Q's. Thank you.
    I think it in general should be OK, but not recommended.