STR912:using binary semaphore between 2 tasks

ajinkya
2013-01-28
2013-09-16
  • ajinkya
    ajinkya
    2013-01-28

    Hello all,
    I am using STR912 comstick with freeRTOS to generate a variable width PWM using TIM1.
    Generation of variable width PWM is done.

    Now I have two tasks both generating PWM but of different variable widths.
    I want to switch between these two tasks on some event - high or low on a GPIO.

    For that I need binary semaphore since I have one resource to share i.e TIM1.
    If we use no semaphore with only one task it works fine.
    When I use binary semaphore it dose not work .

    //global variables

    xSemaphoreHandle xSemaphore = NULL;

    const unsigned long ONArrayOC2R = {0x94CA,0x1982,0x0CBC,0x0CBC,0x0CBC,0x1982,0x0CBC,0x0CBC,0x0CBC,
                                         0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,
                                         0x0CBC,0x1982,0x1982,0x0CBC,0x1982,0x0CBC,0x0CBC,0x0CBC,0x1982,
                                         0x1982,0x1982,0xCBC};
    const unsigned long ArrayOC1R = {0x64C3,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,
                                         0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,
                                         0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,0x075D,
                                         0x075D,0x075D,0x75D};

    const unsigned long OFFArrayOC2R = {0x94CA,0x1982,0x0CBC,0x0CBC,0x0CBC,0x1982,0x0CBC,0x0CBC,0x0CBC,
                                          0x1982,0x1982,0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x0CBC,
                                          0x0CBC,0x0CBC,0x0CBC,0x0CBC,0x1982,0x0CBC,0x1982,0x0CBC,0x0CBC,
                                          0x0CBC,0x1982,0x0CBC};

    static unsigned int PulseCount=0, RepeatSignal=0, ON_OFF_Flag;

    My main is -

    void main( void )
    {
    #ifdef DEBUG
    debug();
    #endif

    /* Setup any hardware that has not already been configured by the low
    level init routines. */
    prvSetupHardware();
        
              vSemaphoreCreateBinary( xSemaphore );   // create binary semaphore

           /* Start either the uIP TCP/IP stack or the lwIP TCP/IP stack. */
          
    #ifdef STACK_UIP
    /* Finally, create the WEB server task. */
    //xTaskCreate( vuIP_Task, "uIP", configMINIMAL_STACK_SIZE * 3, NULL, mainCHECK_TASK_PRIORITY - 1, NULL );
                     xTaskCreate(  vPWM_ON_Task, "PWM_AC_ON", configMINIMAL_STACK_SIZE * 3, NULL, mainCHECK_TASK_PRIORITY - 1,NULL);
                     xTaskCreate(  vPWM_OFF_Task, "PWM_AC_OFF", configMINIMAL_STACK_SIZE * 3, NULL, mainCHECK_TASK_PRIORITY - 2,NULL);
    #endif
             
    #ifdef STACK_LWIP_130
    vStartEthernetTasks(mainNET_TASK_BASE_PRIORITY);
    #endif

    /* Start the scheduler.

    NOTE : Tasks run in system mode and the scheduler runs in Supervisor mode.
    The processor MUST be in supervisor mode when vTaskStartScheduler is
    called.  The demo applications included in the FreeRTOS.org download switch
    to supervisor mode prior to main being called.  If you are not using one of
    these demo application projects then ensure Supervisor mode is used here. */
            //portBASE_TYPE xHigherPriorityTaskWoken = 0;
    vTaskStartScheduler();

    /* We should never get here as control is now taken by the scheduler. */
    for( ;; );
    }

    then I have the task definitions as -
    void vPWM_ON_Task(void)
    {
              TIM_DeInit(TIM1);
              VIC_DeInit();
              TIM_ClearFlag(TIM1,TIM_FLAG_OC2); 
      
              portENTER_CRITICAL();
              {
                      VIC_Config(TIM1_ITLine,VIC_IRQ, 0);
                      VIC_ITCmd(TIM1_ITLine,ENABLE);
                      VIC_InitDefaultVectors();
                      TIM1->SR &= 0x0000;
                      VIC0->FSR = 0x0000;
              }
              portEXIT_CRITICAL();
             
              if(GPIO_ReadBit(GPIO4,GPIO_Pin_7)!= Bit_RESET)   //this is the event for loading particular array of variable widths in ISR
              {
                ON_OFF_Flag = 1;
                gpio9_led_on();
              }
              /*************************************************/
              TIM1->OC1R = 0x00FF;
              TIM1->CR2 = 0x0810;                                 //set prescaler and interrupt enable
              TIM1->CR1 = 0x8250;                                 //start the timer
              TIM1->OC2R = 0x0FFF;
              /*************************************************/
              xSemaphoreTake( xSemaphore, configTICK_RATE_HZ / 2 );
    }

    The ISR is -

    void PWM_TIM1_IRQHandler(void)
    {
      portBASE_TYPE xHigherPriorityTaskWoken = 0;

    /* Give the semaphore in case the uIP task needs waking. */
    xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );

            /* Clear the interrupt. */
    TIM1->SR = 0x0000;
            VIC0->FSR = 0x0000;
           
            if(ON_OFF_Flag ==0)
                TIM1->OC2R = OFFArrayOC2R;    //first array
            else
              TIM1->OC2R = ONArrayOC2R;      //second array
           
            TIM1->OC1R = ArrayOC1R;
            PulseCount++ ;
            if(PulseCount >= 30)  
            {
              RepeatSignal++;
              PulseCount = 0 ;
            }
           VIC0->VAR = 0;
           asm("SUBS pc,lr,#4");                        //returning from ISR
    }

    Second task is-

    void vPWM_OFF_Task(void)
    {
              TIM_DeInit(TIM1);
              VIC_DeInit();
              TIM_ClearFlag(TIM1,TIM_FLAG_OC2); 
      
              portENTER_CRITICAL();
              {
                      VIC_Config(TIM1_ITLine,VIC_IRQ, 0);
                      VIC_ITCmd(TIM1_ITLine,ENABLE);
                      VIC_InitDefaultVectors();
                      TIM1->SR &= 0x0000;
                      VIC0->FSR = 0x0000;
              }
              portEXIT_CRITICAL();
             
              if(GPIO_ReadBit(GPIO4,GPIO_Pin_7)== Bit_RESET)
              {
                ON_OFF_Flag = 0;
                gpio9_led_on();
              }
              /*************************************************/
              TIM1->OC1R = 0x00FF;
              TIM1->CR2 = 0x0810;
              TIM1->CR1 = 0x8250;
              TIM1->OC2R = 0x0FFF;
              /*************************************************/
              xSemaphoreTake( xSemaphore, configTICK_RATE_HZ / 2 );
    }

    Is there something that I am doing wrong?
    How to make use of binary semaphores to get it working

     
  • Richard
    Richard
    2013-01-28

    If this is actually the code you are using then:

    - vPWM_ON_Task() has the wrong prototype to be a task.  It should take a void* parameter.

    - vPWM_ON_Task() must not exit just by dropping off the end of the function that implements the task.  A task must either run forever (typically in an infinite loop), or delete itself before it reaches the end of the function that implements it.

    Regards.

     
  • ajinkya
    ajinkya
    2013-01-28

    Thank you we made the changes.

    But even after making the changing the changes it is not working.
    Now is there any problem with semaphore?

     
  • Dave
    Dave
    2013-01-28

    Your interrupt service routine does not exit correctly. Why have you manually written the return from the function in assembly language? Write your interrupts as documented for the port on the FreeRTOS web pages.

     
  • ajinkya
    ajinkya
    2013-01-30

    Had one doubt:

    I am polling on One GPIO pin in void main()

    and created a task on some event on the GPIO (have one switch connected to it).

    If event detected -> create task -> go to task -> set some flags -> on Interrupt -> go to interrupt ->
    serve it -> on completion -> delete task

    else keep polling the GPIO.

    so question is
    1.on deletion of task where it will return ?

    2. and can we pass a pointer to array to a TASK?

     
  • Richard
    Richard
    2013-01-30

    You can pass a pointer to whatever you like to a task, as long as the code creating the task and the task itself agree on what the parameter points to.

    I don't understand your scenario though.

    If you create a task from main(), then start the task by calling vTaskStartScheduler(), main() will never run again.  If you delete the task and there are no other tasks then the only code that will run (other than the kernel tick interrupt) is the Idle task.

    Regards.

     
  • ajinkya
    ajinkya
    2013-01-30

    Thank you Richard,
    That gave clue to the solution of problem,
    I was just going through the documentation about task states.

    So if I want to poll on GPIO continuously I should do it in task only Right?? say taskA

    Now solution could be - void main() will create only this task(taskA) which will continuously poll GPIO and in-turn will create another task (taskB) on GPIO event (and now taskB can be deleted also since taskA is running continuously).

    But now I have one question how taskB will start / how it will switch to taskB?
    or do I need to create taskB in suspended state and resume on GPIO event in taskA.

     
  • ajinkya
    ajinkya
    2013-01-30

    And one more thing I just went through one of your replies richard:

    www.freertos.org/FreeRTOS_Support_Forum_Archive/May_2012/freertos_How_to_create_task_in_suspended_state_5262730.html

    This is a bit matching scenario which you explained in 2nd para.

    The conclusion is we can create a suspended task before vTaskStartScheduler() starts.

    I am a bit confused about starting taskB which is getting created (or resumed) on event on GPIO.
    I need your comment on this.

     
  • Richard
    Richard
    2013-01-30

    So if I want to poll on GPIO continuously I should do it in task only Right?? say taskA

    Once the scheduler has been started, tasks, interrupts and software timers are the only things that execute.  There is no option to poll IO from main() as main() will never execute at that time.

    The only way of running tasks is to call vTaskStartScheduler().  You cannot call a task function.

    Now solution could be - void main() will create only this task(taskA) which will continuously poll GPIO and in-turn will create another task (taskB) on GPIO event (and now taskB can be deleted also since taskA is running continuously).

    You only need to create task B if task B needs to do something in parallel with task A.  If task A is just polling IO and creating task B when the IO changes then consider having the IO trigger an interrupt and having the interrupt service routine signal a task.  Generally repeatedly creating and deleting tasks is not necessary and wasteful.

    But now I have one question how taskB will start / how it will switch to taskB?
    or do I need to create taskB in suspended state and resume on GPIO event in taskA.

    Task B can be created (if really necessary) at any time that you are not in a critical section (and don't have the scheduler locked).  It will run immediately that it is the highest priority task to run.  Therefore, if Task A creates task B, and Task B has a higher priority than Task A, then Task B will start running immediately - before Task A has returned from the xTaskCreate() function even.

    Regards.