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.

CC26xx Sensor Controller startup question

Other Parts Discussed in Thread: CC2640

Hi...

I'm attempting to use the SensorController in a CC26xx.   My intent is to pass information to the controller via the shared AUX memory, then "manually" start the controller via scifStartTasksNbl(TASK_ID).    The initialization code will write the external peripheral, then enable the event monitoring via evhSetupGpioTrigger(0,AUXIO_I_DATA_RDY,1,EVH_GPIO_TRIG_ON_EDGE);    The assumption is that the RisingEdge of the specified signal will cause the EventHandling code to be executed.  

I have successfully written code for Initialization, EventHandling, and Termination.   I assume that the Execution code is not necessary if all activity is event driven.    The code "compiles" in Sensor Controller Studio (a couple of strange syntax things, but got it to compile without errors).   The produced code compiles along with my application code in CCS.

From the CC2640,  I initialize the sensor controller via:

// Initialize the Sensor Controller
scifOsalInit();
//scifOsalRegisterCtrlReadyCallback(scCtrlReadyCallback);
scifOsalRegisterTaskAlertCallback(scTaskAlertCallback);
scifInit(&scifDriverSetup);
// scifStartRtcTicksNow(0x00010000 / 8);

I commented out the ...ReadyCallback since the docs say it is optional and I don't think I need to know when the SensorController is "ready".   And I commented out the ...RtcTicksNow since I'm not using schedule-based processing (only event initiated processing).

When I run my code, I don't see any activity on the mapped SPI pins (there should  transactions during the initialization code).

Questions:

1. I do not map the IO Pins at the CC2640 level (only in the SensorController code).   I assume that the pin mapping in the Sensor Controller is sufficient.   Is this correct?

2. Is there other initialization necessary for the scif?  I am assuming that scifInit() performs all that is necessary.   Is this correct, or am I missing something that is needed to get things going?

Thanks!

  • Hello Ed,
    1) Yes, you only need to leave them unassigned by your RTOS application. The generated driver framework will set up the pins.
    2) I will check this and come back to you.
  • Thanks...
    Looking forward to your answer to part 2. Right now I don't see any outputs "wiggling" from the execution of the Initialization code after issuing scifStartTasksNbl(TASK_ID). My initialization code ends with:

    evhSetupGpioTrigger(0,AUXIO_I_ADC_RDY,1,EVH_GPIO_TRIG_ON_EDGE);

    Am I correct in assuming that after receiving sclStartTasksNbl(), the sensor controller run the Initialization code, then will stall, waiting for the rising edge of AUXIO_I_ADC_RDY, then run the Event Handler Code?

    Am I also correct in assuming that after running the Event Handler Code, the sensor controller will stall, waiting for another rising edge? Or do I have to issue another
    evhSetupGpioTrigger(0,AUXIO_I_ADC_RDY,1,EVH_GPIO_TRIG_ON_EDGE);
    at the end of the Event Handler Code to re-enable it?

    I'm assuming that it re-enables itself until an scifStopTasksNbl() is issued from the RTOS application...

    Thanks!
  • 2) scifInit() & scifStartTasksNbl should be sufficient.


    Am I correct in assuming that after receiving sclStartTasksNbl(), the sensor controller run the Initialization code, then will stall, waiting for the rising edge of AUXIO_I_ADC_RDY, then run the Event Handler Code?

    Correct


    The trigger is one-shot. You will need to re-enable it at the end of the event handler code with the same procedure call you issued in the initialization code.

  • Hi Eirik,
    Thanks for the reply.

    The help section for evhSetupGpioTrigger includes:

    GPIO-based Event Handler Code triggering can be set up from within the Initialization Code, Execution Code or Event Handler Code by calling fwSetupGpioEvent() with specified level or edge.

    and

    Enabling this resource will cause the AUX domain to run at 32 kHz (instead of having no clock) when the Sensor Controller and System CPU are in standby mode. The resulting AUX domain clock switching increases slightly the time to enter and exit standby mode for both Sensor Controller and System CPU.

    I'm using evhSetupGpioTrigger() to attempt to trigger on a rising edge of a GPIO pin. What is the function fwSetupGpioEvent()?

    Does calling evhSetupGpioTrigger put the SensorController into a standby mode? Does the second statement (above) imply that following the rising edge I'm looking for, it could take up to 1 full 32 kHz period before the event code begins execution?

    Thanks!
  • Hello Ed,
    fwSetupGpioEvent does not exist. It is just a typo. I notified the developer team to correct this for the next release. Yes, evhSetupGpioTrigger will allow the sensor controller domain to go into standby if you have no other code running. I will check the details of the impact on clock switching next week and get back to you.
  • Hi Eirik,
    Thanks.
    I'm attempting to collect data from a sensor that provides info at a 4 KHz rate. It provides a pulse at that rate, but the pulse width is only a single 4 MHz clock period (there is no way to adjust this). (BTW, this is a TI sensor.)

    I see that the SensorController docs state: "The GPIO pin is sampled at 32 kHz, and must be held active for at least 2 x 32 kHz periods to be captured safely." Is this also true for edge-detected signals, or just for the level-sensitive signals?

    If the wider pulses are needed for edge-detected signals, then perhaps I can use a very tight loop to "poll" the pin. I see in swcu117d that most instructions require two clocks. Does the SensorController run at 24 MHz? Do you have a recommendation on how to achieve the detection of this pulse?

    Thanks!
  • Hi Eirik,

    Going on the assumption that even for a rising edge, a pulse must be > 2 x 32kHz period,  I wrote some code that polls the PIN.   The code is:

    <?xml version="1.0" encoding="ISO-8859-15"?>
    <!DOCTYPE proc_def SYSTEM "proc_def.dtd"[]>
    <proc_def name="waitForRisingEdge" version="1.0.0">
    <desc>Loops, waiting for a rising edge on the specified pin.</desc>
    <task_resource_ref>Edge Detect</task_resource_ref>
    <param type="imm" name="auxio">Pin to watch for rising edge.</param>
    <code>
    <![CDATA[
           L{waitForLow}: iobtst #(I{auxio} & 0x07), [#(IOP_AIODIO0_GPIODIN + (I{auxio} >> 3))]
                                       biob1 L{waitForLow}
           L{waitForHi}:     iobtst #(I{auxio} & 0x07), [#(IOP_AIODIO0_GPIODIN + (I{auxio} >> 3))]
                                       biob0 L{waitForHi}
    ]]>
    </code>
    </proc_def>

    I also wrote a couple of .prd files to allow me to create an infinite loop.    Inside the loop, I call "waitForRisingEdge()"  then the code that collects the sensor data.

    If I comment out the "waitForRisingEdge()" call, I see the proper activity to collect the data, but if I leave the "waitForRisingEdge()" in, I don't see anything.

    The "waitForRisingEdge()" first waits to insure that the specified PIN is low.   Then it enters a two instruction loop until the specified PIN is high.

    Assuming that the Sensor Controller is running at 24 MHz, and each instruction takes 2 clocks, the loop should take 4 clocks.   The loop is then effectively running at 6 MHz.      Since the pulse is 0.25 us in width (4 MHz), at least one of the iobtst instructions should see a '1', but it appears that I'm not seeing any.

    What am I missing?    Is there a pulse rejection circuit on the input Pins?

    Thanks!

  • Found it... The initialization code in the .red file has to show the Edge Detection pin as an input...
  • Hi Eirik,

    Looks like this has caused another problem...

    A review of the problem:

    1. I need to get data from a sensor that is producing data at a 4 KHz rate (perhaps 5 KHz in the future).

    2. The sensor puts out a positive pulse when data is ready. But the pulse width is a single 4 MHz clock in width.

    3. The edge-detect trigger in the Sensor Controller requires a pulse at least 2 x 32 KHz clock periods in width to successfully detect it.

    4. I wrote some assembly code that continuously polls the appropriate pin looking for a rising edge. This seems to catch the pulse nicely.

    5. Since the new edge detector is code based, it needs to run all of the time. (I can't end the task, expecting to come back and look later.) So I wrote some additional assembly code (BeginInfiniteLoop, EndOfInfiniteLoop) that is used in my "initialization" code. The initialization code now initializes the sensor, but then enters the infinite loop. The loop contains the EdgeDetector, then code that reads the sensor, and puts the data into a buffer. I am using the multi-buffer arrangement (2 buffers). When a buffer is full, I issue the switch buffers call, that should create an alert. The loop then goes back to the top where it waits for the next edge.

    6. This all seems to work well, except I never get the Alert interrupt back on the ARM side. Looking at the documentation in more detail, it says that the alert will not be generated until the task has completed. Since my task is in an infinite loop, it never completes, so no alert is generated!

    7. I considered using "scheduled" event to try to end my task after a rising edge was detected and processed, to restart the task before another edge was expected, but the resolution of the scheduling timer is 4 KHz. So after receiving one pulse, doing the processing, etc. I would miss the next pulse if the timer waits another 4KHz period before starting to look again!

    Is there some way to get an alert to the ARM without the task completing?

    Thanks!
    Ed
  • Hi Ed,

    Why don't you use GPIO edge detection in MCU domain? This requires a minimum of 1 CPU cycle to be detected. You can setup a GPIO to enable edge detection interrupt. The interrupt will trigger an ISR to run. In the ISR, you can start SCE to read data. In this way, you don't need the infiniteLoop at all.
  • Thanks. I guess I could try this, but have been concerned about being preempted by the BLE stack task. Since the data is coming in every 250 (or perhaps 200) microseconds, I was concerned about "chopping" up the processing too much... I was hoping to find a solution within the Sensor Controller...
  • Hello Ed,
    The next version to be released this month (version 1.2.0) will have a procedure for generating alert during task execution called fwGenQuickAlertInterrupt.
  • Hello again Ed,

    Here is a suggestion to improve your loop to get it fast enough. Be aware this might cause a deadlock if the external sensor stops providing pulses.

       <internal name="temp0"/>
       <code>
           <![CDATA[
               ld          RS{temp0}, #(EVCTL_SCEEVSEL_AUXIO0 + I{auxio})
               out         RG{temp0}, [#IOP_EVCTL_SCEWEVSEL]
               wev0        #WEVSEL_PROG
               wev1        #WEVSEL_PROG
           ]]>
       </code>
  • Eirik,

    Many thanks!

    A couple of additional questions:

    1. The new release is of SensorStudio, correct? Will it have any dependencies on the RTOS version? I'm still using RTOS 2.13 (although I'd like to be using RTOS 2.15, but can't get it to compile correctly with the BLE stack).

    2. I'm on a pretty tight schedule at this point. Can you give me some idea when to expect the release (1st week of Feb, 2nd week of Feb, etc.)?

    3. I like your code for the edge detection. I hadn't thought of using the power control instructions for edge detection... In the case where the external sensor stops production pulses, as you said, the Sensor Controller will stop. I assume that the "scifStopTasksNbl(BV(TASK_ID))" call will still clear things out?

    Thanks again!

    Ed
  • Hi Eirik,

    A couple of other comments/questions (of lower priority):

    1. Can you explain the difference between a variable defined in the Sensor Controller code (I'll call them "local variables") versus one defined in the "state" area? Is it only the visibility of that value to the ARM? Do local variables maintain their values over multiple executions of the task? This came up when trying to use a pointer. There doesn't seem to be a way to define a pointer in "state" space. So to use it as such, I define a local variable that is a pointer, transfer the value from "state" space, then transfer the value back after using and incrementing it. If the only advantage to putting something in "state" is accessibility/observability from the ARM, then I can simplify things...

    2. Some of my data is 24-bit data. I'd like to perform some arithmetic on this data. I see that add/sub instructions set C and V flags, but it is implied that they ignore them when executing (ie. no add with carry). I guess multi-length arithmetic can be done by explicitly testing the appropriate flags, but this is not quite as efficient as addc, subc, etc. Have you created any "optimized" procedures for multi-length arithmetic? Are there other resources (undocumented?) that might help here?

    Thanks!
    Ed
  • Hello Ed,
    1.
    It will support 2.13 and newer versions. There is a porting guide for moving the BLE projects to TI RTOS 2.15.00.17 here:
    github.com/.../simple_ble_peripheral_tirtos_2p15

    2.
    It is scheduled for the third week.

    3.
    No, it will only continue from halt (wev0/wev1) on the set GPIO event. scifStopTasksNbl calls on scifCtrlTasksNbl that use the sensor controller RAM variable that is shared with the driver (External control data, in this case specifically scifData.pTaskCtrl->bvTaskTerminateReq). See the following framework used on waking up from standby and going back. This is placed by the compiler in the generated assembler listing file "sce.lst".
    C:\Program Files (x86)\Texas Instruments\Sensor Controller Studio\fw_templates\framework_template.asm
  • Hello Ed,
    Here is the answer to the low priority questions:

    1.
    The local variables (defined varName below) is placed in the processor registers R0-R7 and this is not accessible by the main application processor (CM3 on CCC2640) and is not retained in standby.

    Any variable access may be one of the following:
    varName - Register variable value (U16 or S16)
    pStructVar - RAM variable pointer (U16* or S16*)
    *pStructVar - Indirect access to RAM variable
    *(pStructVar++) - Indirect access to RAM variable, with pointer post-increment
    struct.var - Direct access to a data structure member
    struct.pArrayVar[n] - Direct access to a data structure array member, element n

    2.
    Not currently. But I will add a request for future releases of SCS (not the up coming). Is it not guaranteed to be included, but will probably be added if it can be made any more efficient than your proposal.
  • Hi Eirik,

    Thanks for the responses!

    With respect to #2 above, since I need to move forward before the third week of Feb, I'm looking for a work-around.

    In order to get the alert over to the ARM, I changed the sensor controller so that the task finishes when the buffer is filled and the swap is initiated (with the intent to start it again).

    I see the callback due to the buffer swap.

    But I need to get the sensor controller started again to gather more samples in the exchanged buffer, so in the callback I attempt to start the sensor controller again.

    I've tried both scifStartTasksNbl(), and scifStartTasksOnceNbl(), but the sensor controller doesn't start a second time.    I also tried putting a scifStopTasksNbl() before the "start", thinking that the sensor controller needs to be idle to start it...

    Is this a reasonable work-around?   Can the sensor controller be "restarted"?

    Is there a way to manually trigger the "execution" code from the ARM (it looks to me that this can only be done from the timer)?   

    Are there other ways to accomplish what I need?

    Thanks!!

  • Hi Eirik,
    I forgot to mention that I also perform the ResetTaskStructs between the stop and restart... So the overall task restart looks like:

    scifStopTasksNbl(BV(TASK_ID));
    scifResetTaskStructs(BV(TASK_ID),0);
    scifExecuteTasksOnceNbl(BV(TASK_ID));

    What am I missing?
    Thanks!
  • Also added in a "wait", but still no success:

    scifStopTasksNbl(BV(TASK_ID));
    scifWaitOnNbl(50);
    scifResetTaskStructs(BV(TASK_ID),0);
    scifExecuteTasksOnceNbl(BV(TASK_ID));
  • Hello Ed,

    Add the attached file to your proc_defs folder to get the new fw_gen_quick_alert_interrupt procedure.

    /cfs-file/__key/communityserver-discussions-components-files/538/fw_5F00_gen_5F00_quick_5F00_alert_5F00_interrupt.prd

  • Hi Eirik,

    This worked well!   Thanks!

    I am still having an issue with fwSwitchOutputBuffer.   I have a two buffer setup.   I'm still running this inside an "infinite loop" in the sensor controller.

    I used the "Quick" alert to notify the ARM (after collecting a buffer full of samples as shown here (A buffer and B buffer are from two sensors; both in a single buffer to be exchanged):

    if(state.bufCnt >= cfg.numSamples) {

        fwSwitchOutputBuffer();

        state.Aptr = #output.ABuffer;

        state.Bptr = #output.BBuffer;

        state.bufCnt = 0;

        fwGenQuickAlertInterrupt();

    }

    Then the SensorController code loops around to wait for more "edges" and collects more data.

    On the ARM side:

    void scTaskAlertCallback(void) {
          // Called when a buffer is ready from the Sensor Controller

          // Clear the ALERT interrupt source
          scifClearAlertIntSource();

          if(scifGetTaskIoStructAvailCount(SCIF_TASK_ID,SCIF_STRUCT_OUTPUT) == 1) {
             SCIF_OUTPUT_T *ptrOutput = scifGetTaskStruct(SCIF_TASK_ID, SCIF_STRUCT_OUTPUT);

             memcpy(RawAData,&(ptrOutput->ABuffer),sizeof(RawAData));
             memcpy(RawBData,&(ptrOutput->BBuffer),sizeof(RawBData));

             scifHandoffTaskStruct(SCIF_TASK_ID, SCIF_STRUCT_OUTPUT);
          }

          // Acknowledge the alert event
          scifAckAlertEvents();

          // Set a flag so task knows why it is being wakened.
          DataReceived = true;

          Semaphore_post(localSem);
    }

    My application runs but, but every other data buffer has all zeros.   I suspect I'm not grabbing the switched buffer address properly?   Do you see anything I've done wrong?

    Thanks!

    Ed

  • Hello Ed,
    Will this bug solution help for your program?
    e2e.ti.com/.../1741885