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.

3rd task not running

Hi!


The code had 2 task (T1 and T2), and worked fine. When I added a third task (T3), it does not run, even with highest priority. As you can see in the screen below, the task2 "moveTalon" has priority 3, and the others have max 2. The other tasks runs ok, but, "moveTalon" doesn't even launch.


There is the full code. I'm using TM4C1294XL board, with CCS V6.0.1 and the latest TI-RTOS platform.


Thanks!

/*
 * main.c
 *
 *  Created on: 23/02/2015
 *      Author: Hk
 */

/* ********************************************************
 * ** Universidade Tecnológica Federal do Paraná - UTFPR **
 * ** Departamento Acadêmico de Eletrônica               **
 * ** Curso de Engenharia Eletrônica                     **
 * ** Disciplina de Sistemas Operacionais                **
 * ** Prof.: L. F. Copetti                               **
 * ** Aluno: H. C. Kaiser                                **
 * ********************************************************
 *
 * Este trabalho visa projetar um sistema de controle de braço robótico.
 * O braço será controlado por acelerômetro e botão de ação, e atuado por servomotores.
 * A programação embarcada utilizará a placa TI Tiva-C Connected Launchpad TM4C1294XL, com sistema
 * operacional RTOS.
 * Os códigos foram gerados no programa Code Composer Studio V6.0, com TI-RTOS instalado.
 *
*/

// --------------------------------------------------------
// Inclusões das bibliotecas usadas no programa
// --------------------------------------------------------

// Bibliotecas SYS/BIOS
#include <xdc/std.h>  						//mandatory - have to include first, for BIOS types
#include <ti/sysbios/BIOS.h> 				//mandatory - if you call APIs like BIOS_start()
#include <xdc/runtime/Log.h>				//needed for any Log_info() call
#include <xdc/cfg/global.h> 				//header file for statically defined objects/handles

// Bibliotecas TIVAWARE
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/debug.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/adc.h"
#include "driverlib/pwm.h"
#include "driverlib/pin_map.h"

// --------------------------------------------------------
// Definições estáticas
// --------------------------------------------------------
#define PWM_FREQ 50												// Define a frequência de
																// funcionamento dos servomotores

// --------------------------------------------------------
// Declaração de protótipos
// --------------------------------------------------------
void hardware_init (void);
void delay (void);
void moveTalon (void);
void moveServo (void);
void readAcc (void);

// --------------------------------------------------------
// Definição de estrutura para mailboxes
// --------------------------------------------------------
typedef struct MsgObj {
	uint32_t AccX;
	uint32_t AccY;
} MsgObj, *Msg;

typedef struct TalonObj {
	int talonDir;												// Último movimento registrado - 1 abre, -1 fecha
	uint32_t talonPos;											// Posição final da garra
} TalonObj, *Talon;

// --------------------------------------------------------
// Código principal
//---------------------------------------------------------
void main (void)
{
   hardware_init();												// Inicialização do dispositivo
   BIOS_start();												// Inicia o agendador de BIOS
}

void hardware_init (void)
{
	int i;
	// Variáveis para configuração do PWM
	volatile uint32_t ui32SysClkFreq; 							// Valor retornado por SysClockFreqSet()
	volatile uint32_t ui32PWMClock;								// Frequência do clock do PWM
	volatile uint32_t ui32Load;									// Período do PWM
	volatile uint32_t ui32Adjust;								// Valor inicial de posição dos servos

	// Mailbox para acionamento da garra
	TalonObj talon;

	ui32SysClkFreq = SysCtlClockFreqSet ((SYSCTL_XTAL_25MHZ |
											  SYSCTL_OSC_MAIN |
											  SYSCTL_USE_PLL|
											  SYSCTL_CFG_VCO_480), 120000000);

	// Habilitação da porta P4 para acionamento da garra
	SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOD);
	GPIOPinTypeGPIOInput (GPIO_PORTD_BASE, GPIO_PIN_0);
	GPIOPadConfigSet (GPIO_PORTD_BASE, GPIO_PIN_0, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPD);

	// Habilitação do ADC
	SysCtlPeripheralEnable (SYSCTL_PERIPH_ADC0);
	SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOE);

	// Habilitação do PWM
	SysCtlPeripheralEnable (SYSCTL_PERIPH_PWM0);
	SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOF);
	SysCtlPeripheralEnable (SYSCTL_PERIPH_GPIOG);

	// Configurações do ADC
	ADCHardwareOversampleConfigure (ADC0_BASE, 64);
	GPIOPinTypeADC (GPIO_PORTE_BASE, GPIO_PIN_0 |				// Pino PE0
									 GPIO_PIN_1 |				// Pino PE1
									 GPIO_PIN_2 );				// Pino PE2
	ADCSequenceConfigure (ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
	ADCSequenceStepConfigure (ADC0_BASE, 1, 0, ADC_CTL_CH3);
	ADCSequenceStepConfigure (ADC0_BASE, 1, 1, ADC_CTL_CH2);
	ADCSequenceStepConfigure (ADC0_BASE, 1, 2, ADC_CTL_CH1|ADC_CTL_IE|ADC_CTL_END);
	ADCSequenceEnable (ADC0_BASE, 1);

	// Configurações do PWM
	PWMClockSet (PWM0_BASE,PWM_SYSCLK_DIV_64);					// CLK do PWM em 1.875 MHz
	GPIOPinConfigure (GPIO_PF1_M0PWM1);							// Direciona saida do PWM da garra
	GPIOPinConfigure (GPIO_PF2_M0PWM2);							// Direciona saida do PWM do pulso
	GPIOPinConfigure (GPIO_PF3_M0PWM3);							// Direciona saida do PWM do cotovelo superior
	GPIOPinConfigure (GPIO_PG0_M0PWM4);							// Direciona saida do PWM do cotovelo inferior
	GPIOPinConfigure (GPIO_PG1_M0PWM5);							// Direciona saida do PWM da base
	GPIOPinTypePWM (GPIO_PORTF_BASE, GPIO_PIN_1 |
									 GPIO_PIN_2 |
									 GPIO_PIN_3);				// Configura porta F pinos 1~3 para PWM
	GPIOPinTypePWM (GPIO_PORTG_BASE, GPIO_PIN_0 |
									 GPIO_PIN_1);				// Configura porta G pinos 0~1 para PWM
	ui32PWMClock = ui32SysClkFreq / 64; 						// 120MHz/64
	ui32Load = (ui32PWMClock / PWM_FREQ) - 1; 					// 1875000/55 - 1
	ui32Adjust = 700;											// Servos na posição central
	PWMGenConfigure (PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_DBG_RUN);
	PWMGenConfigure (PWM0_BASE, PWM_GEN_1, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_DBG_RUN);
	PWMGenConfigure (PWM0_BASE, PWM_GEN_2, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_DBG_RUN);
	PWMGenPeriodSet (PWM0_BASE, PWM_GEN_0, ui32Load);
	PWMGenPeriodSet (PWM0_BASE, PWM_GEN_1, ui32Load);
	PWMGenPeriodSet (PWM0_BASE, PWM_GEN_2, ui32Load);
	PWMGenEnable (PWM0_BASE, PWM_GEN_0);
	PWMGenEnable (PWM0_BASE, PWM_GEN_1);
	PWMGenEnable (PWM0_BASE, PWM_GEN_2);
	PWMPulseWidthSet (PWM0_BASE, PWM_OUT_1, ui32Adjust * ui32Load / 10000);
	PWMPulseWidthSet (PWM0_BASE, PWM_OUT_2, ui32Adjust * ui32Load / 10000);
	PWMPulseWidthSet (PWM0_BASE, PWM_OUT_3, ui32Adjust * ui32Load / 10000);
	PWMPulseWidthSet (PWM0_BASE, PWM_OUT_4, ui32Adjust * ui32Load / 10000);
	PWMPulseWidthSet (PWM0_BASE, PWM_OUT_5, ui32Adjust * ui32Load / 10000);
	PWMOutputState (PWM0_BASE, PWM_OUT_1_BIT, true);
	PWMOutputState (PWM0_BASE, PWM_OUT_2_BIT, true);
	PWMOutputState (PWM0_BASE, PWM_OUT_3_BIT, true);
	PWMOutputState (PWM0_BASE, PWM_OUT_4_BIT, true);
	PWMOutputState (PWM0_BASE, PWM_OUT_5_BIT, true);

	talon.talonDir = 1;
	talon.talonPos = 700;
	Mailbox_post (Talon_Mbx, &talon, BIOS_WAIT_FOREVER);

	for (i = 0; i < 100; i++)	delay();
}

void delay (void)
{
	SysCtlDelay(1200000);
}

void moveTalon (void)
{
	// Estático para configuração do PWM
	static uint32_t ui32SysClkFreq = 120000000;

	// Variáveis para controle do punho
	uint32_t ui32AdjustTalon;
	uint32_t ui32Load;
	int talonLastDir;
	uint32_t flagMove = 0;

	// Mailbox para leitura do último valor da garra e direção
	TalonObj talon;

	ui32Load = (ui32SysClkFreq/64)/PWM_FREQ - 1;

	while (1){
		Mailbox_pend (Talon_Mbx, &talon, BIOS_WAIT_FOREVER);
		ui32AdjustTalon = talon.talonPos;
		talonLastDir = talon.talonDir;
		flagMove = GPIOPinRead (GPIO_PORTD_BASE, GPIO_PIN_0);
		while (GPIOPinRead (GPIO_PORTD_BASE, GPIO_PIN_0) == 1){
			if (ui32AdjustTalon > 400 && ui32AdjustTalon < 850){
				if (talonLastDir == 1) ui32AdjustTalon -= 5;
				else ui32AdjustTalon += 5;
				PWMPulseWidthSet (PWM0_BASE, PWM_OUT_1, ui32AdjustTalon * ui32Load / 10000);
				delay();
			}
		}

		if (ui32AdjustTalon <= 400) ui32AdjustTalon = 405;
		if (ui32AdjustTalon >= 850) ui32AdjustTalon = 845;

		if (flagMove == 1){
			talonLastDir = -1*talonLastDir;
			flagMove = 0;
		}

		talon.talonDir = talonLastDir;
		talon.talonPos = ui32AdjustTalon;
		Mailbox_post (Talon_Mbx, &talon, BIOS_WAIT_FOREVER);
	}
}

void moveServo (void)
{
	// Estático para configuração do PWM
	static uint32_t ui32SysClkFreq = 120000000;

	// Variáveis para controle dos servos
	uint32_t ui32AdjustWrist = 640;
	uint32_t ui32AdjustSupElbow;
	uint32_t ui32AdjustInfElbow = 1250;
	uint32_t ui32AdjustBase = 500;
	uint32_t ui32Load;

	// Variáveis diferenciais para controle do pulso
	uint32_t ui32BasePrev;
	int difBase;

	// Criação da caixa de mensagens
	MsgObj msg;

	ui32Load = (ui32SysClkFreq/64)/PWM_FREQ - 1;

	while (1) {
		// Leitura das mensagens na mailbox
		Mailbox_pend (MonCtl_Mbx, &msg, BIOS_WAIT_FOREVER);

		// Armazenamento de valores prévios para controle do pulso
		ui32BasePrev = ui32AdjustBase;

		// Carregamento dos valores
		ui32AdjustBase = msg.AccX/3 + 100;
		ui32AdjustInfElbow = msg.AccY/2 - 200;

		// Ajuste do pulso
		difBase = ui32AdjustBase - ui32BasePrev;
		if (difBase > 25) ui32AdjustWrist -= 50;
		else if (difBase < -25) ui32AdjustWrist += 50;
		else{
			if (ui32AdjustWrist > 670) ui32AdjustWrist -= 14;
			if (ui32AdjustWrist > 640) ui32AdjustWrist -= 1;
			if (ui32AdjustWrist < 640) ui32AdjustWrist += 1;
			if (ui32AdjustWrist < 620) ui32AdjustWrist += 14;
		}

		// Ajuste do cotovelo superior
		if (ui32AdjustInfElbow > 650) ui32AdjustSupElbow  = ui32AdjustInfElbow - 400;

		// Movimentação dos servos
		PWMPulseWidthSet(PWM0_BASE, PWM_OUT_2, ui32AdjustWrist * ui32Load / 10000);
		PWMPulseWidthSet(PWM0_BASE, PWM_OUT_3, ui32AdjustSupElbow * ui32Load / 10000);
		PWMPulseWidthSet(PWM0_BASE, PWM_OUT_4, ui32AdjustInfElbow * ui32Load / 10000);
		PWMPulseWidthSet(PWM0_BASE, PWM_OUT_5, ui32AdjustBase * ui32Load / 10000);
	}
}

void readAcc (void)
{
	// Variáveis para leitura do acelerômetro
	uint32_t ui32ACCValues [4];
	volatile uint32_t ui32AccX;
	volatile uint32_t ui32AccY;

	// Criação da caixa de mensagens
	MsgObj msg;

	// Leitura do ADC
	while (1){
		ADCIntClear(ADC0_BASE, 1);
		ADCProcessorTrigger (ADC0_BASE, 1);
		while(!ADCIntStatus (ADC0_BASE, 1, false))	{}
		ADCSequenceDataGet (ADC0_BASE, 1, ui32ACCValues);
		ui32AccX = ui32ACCValues [0];
		ui32AccY = ui32ACCValues [1];

		// Envio dos valores para a caixa de mensagens
		msg.AccX = ui32AccX;
		msg.AccY = ui32AccY;
		Mailbox_post (MonCtl_Mbx, &msg, BIOS_WAIT_FOREVER);
	}
}

  • Hi Heber,
    I haven't seen anything that stands out as wrong. Looks like you create your tasks in your .cfg file, can I see that piece of code? Also can I see a screen shot of the detailed view of the Task module on ROV?

    Thanks,
    Moses
  • Hi Moses!

    The current code in .cfg is here:

    /* ================ Driver configuration ================ */
    var TIRTOS = xdc.useModule('ti.tirtos.TIRTOS');
    TIRTOS.useGPIO = true;
    var mailbox0Params = new Mailbox.Params();
    mailbox0Params.instance.name = "MonCtl_Mbx";
    Program.global.MonCtl_Mbx = Mailbox.create(12, 2, mailbox0Params);
    LoggingSetup.loadTaskLogging = true;
    var mailbox1Params = new Mailbox.Params();
    mailbox1Params.instance.name = "Talon_Mbx";
    Program.global.Talon_Mbx = Mailbox.create(48, 2, mailbox1Params);
    var task0Params = new Task.Params();
    task0Params.instance.name = "task0";
    Program.global.task0 = Task.create("&readAcc", task0Params);
    var task1Params = new Task.Params();
    task1Params.instance.name = "task1";
    task1Params.priority = 2;
    Program.global.task1 = Task.create("&moveServo", task1Params);
    var task2Params = new Task.Params();
    task2Params.instance.name = "task2";
    task2Params.priority = 3;
    Program.global.task2 = Task.create("&moveTalon", task2Params);

    Now about the screens.

    First I took those screen prints down here. In this moment, tasks "readAcc" and "moveServo" had worked well. Task "moveTalon" didn't run.

    After that, I did removed the tasks and inserted all of them again. Now only the task "moveTalon" is running, the others tasks doesn't show up...

    Also, it's the first time a task reached the max range for stack size.


    Thanks!

    Heber Kaiser

  • Could it be related somehow to mailbox wait config?
  • Heber,

         Again your cfg file looks good and your ROV shots besides the idle task reaching its stack peak looks good too. Lets now look into what you're doing in your tasks. From the code you provided earlier, could your tasks not be yielding to each other like you expect? In the first case where you assign moveTalon the lowest priority 1 and assign the other 2 tasks priority 2, it looks like MoveTalon is ready to run but never gets the opportunity. In this first case, this could be happening:

    • moveServo runs and blocks on the Mailbox_pend of MonCtl_Mbx yielding to readAcc
    • readAcc now runs and posts to the MonCtl_Mbx making moveServo ready to run again. But readAcc doesn't have any way for it to yield to other tasks so it repeatedly posts to MonCtl_Mbx till it's full and then it yields
    • moveServo can now run again since it's the higher priority ready task. Note moveTalon is ready all this time but hasn't had a chance to run
    • The above cycle continues again

    In the second case:

    • moveTalon has the highest priority(3) so it runs and probably never yields to moveServo and readAcc. I see it pends on Talon_Mbx and I see you post to that same Mailbox in the same task. Do you have anywhere else in  your code that you post to Talon_Mbx because it looks like it blocks forever on the Mailbox_pend at the beginning of the while loop.

    If my hypothesis is true, you'll have to re-design how you synchronize your tasks.

    Let me know if this helps

    Moses

  • Moses,
    Thanks for the help!

    In both cases, tasks are suffering starvation. There is a way to configure the limit time (quantum, someone said) that tasks runs until forcedly yield to others?

    Or how to set up a starvation prevention, where tasks that are in ready status for too much time runs after some?

    Thanks again!
    Heber Kaiser
  • Moses,

    A simple detail passed me...

    The lack of "Task_yield()" solved everything! Just added this function in the last line before ending "while(1)" loop, and all worked OK!!!
    I can keep those mailboxes, with no need to re-design tasks sync...

    Glad about your efforts!
    Best regards!
    Heber Kaiser
  • Heber/Moses,

    Thanks a lot!!!
    That solved my problem too.
    I have two tasks with the same priority, and only one of them was running while the second task was starving.
    Putting "Task_yield()" at the end of the "while(1)" loop really did the job.

    Best regards,
    Oryan Dallal