Converting Sensor reading from hardware timer to software timer, no longer works

john6340 wrote on Tuesday, March 19, 2019:

Hello!

A quick question.

So basically, I had a code snippet something like this:


getDistanceValue() {

PLIB_PORTS_PinDirectionOutputSet(PORTS_ID_0, PORT_CHANNEL_E, PORTS_BIT_POS_5);
PLIB_PORTS_PinToggle(PORTS_ID_0, PORT_CHANNEL_E, PORTS_BIT_POS_5);
delayUs(5);
PLIB_PORTS_PinClear(PORTS_ID_0, PORT_CHANNEL_E, PORTS_BIT_POS_5);
PLIB_PORTS_PinDirectionInputSet(PORTS_ID_0, PORT_CHANNEL_E, PORTS_BIT_POS_5);
delayUs(20);
while (PLIB_PORTS_PinGet(PORTS_ID_0, PORT_CHANNEL_E, PORTS_BIT_POS_5) == 0) {
startCountUs = _CP0_GET_COUNT();
}
while (PLIB_PORTS_PinGet(PORTS_ID_0, PORT_CHANNEL_E, PORTS_BIT_POS_5) != 0) {
timeUs = (_CP0_GET_COUNT() - startCountUs) / US_SCALE;
}

distance = timeUs / (PING_DISTANCE_PULSE_CONVERSION_COEFF);
return distance;
}

This function was verified as working previously using the hardware timer on the board I had. 
DelayUs is a function I created that just delays by microsec using the chip clock.

Now the problem happens when I try to use software timer for this.

Basically I have the timer call back function as below:

static void vTimerCallback(TimerHandle_t pxTimer){
SensorData data;
data.value = getDistanceValue();
data.dataTag = DISTANCE_SENSOR_ONE;

 if(!pushSensorData(&roverADistanceQueue, data)) {
    badErrorRoutine(QUEUE_PUSH_DATA_FAIL);
}

}


And the part where I try to call it is here:


xTaskCreate((TaskFunction_t) _my_task
“my tasks”,
1024, NULL, 1, NULL);

TimerHandle_t timerHandle100ms = xTimerCreate(
        "timer100Ms", /* name */
        pdMS_TO_TICKS(100), /* period time */
        pdTRUE, /* auto reload */
        (void*)0, /* timer ID */
        vTimerCallback);
if (timerHandle100ms == NULL) {
   // error
}
if (xTimerStart(timerHandle100ms, 0) != pdPASS) {
    // error
}

/**************
 * Start RTOS * 
 **************/
vTaskStartScheduler(); /* This function never returns. */

This is the only task that is working. and for config:

/* Software timer related definitions. */
define configUSE_TIMERS 1
define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)
define configTIMER_QUEUE_LENGTH 100
define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2)
define configUSE_DAEMON_TASK_STARTUP_HOOK 0

Yet it does not work. It seems like no data is being collected using this timer.

Is it because my getSensorValue function has blocking calls in it?

Thanks in advance

rtel wrote on Tuesday, March 19, 2019:

It is not clear from your post what is not working. First, are you sure
the timer task is running? You can verify by putting a break point in
the prvTimerTask() function in FreeRTOS/Source/timers.c. If that is
running try placing a break point in the callback function.

I don’t think you show the implementation of getSensorValue(), but it is
generally bad to block in a timer callback as that blocks all timer
callbacks.

john6340 wrote on Tuesday, March 19, 2019:

My apologies for not making it clear!

So basically I have a sensor that uses pulse (hence, the blocking calls I implemented) and the goal is to use a timer and everytime timer expires, I collect the data and push to queue. The getDistanceValue() function is the very first snippet of code I show.

So previously using a hardware timer and ISR, I was able to do this. I can verify that the callback function is reached, but for somereason despite no changes in the getDistanceValue() function implementation, I am not getting any valid reading values. I was wondering if this had anything to do with how software timers work. I understand it is a bad practice to have a blocking call, but in theory I’m just trying to achieve this one functionality but it just doesnt work with the software timer.

rtel wrote on Tuesday, March 19, 2019:

In your case I don’t think you are ‘blocking’ in the RTOS sense, which
means stopping the task from executing and going to a different task, as
much as just taking a long time for the function to complete.

I would suggest just trying to get the timer working by itself, without
calling your sensor code, in the first instance. Just have the timer
toggle an LED (or increment a counter if no LEDs are available) and
ensure it is executing at the expected frequency. Once you have that
working you can add your code back in, and then if it stops working
again, you can step through your code to see why.