Olá a todos.

Estou com várias dúvidas a respeito do freeRTOS, então vamos por partes.

Primeiramente, utilizei o exemplo, já disponível na arduino IDE, e fiz algumas alterações muito desprezíveis, mas vamos utiliza-lo como referência: ( LINK: Exemplo que editei para "facilitar" )

1- Nas linhas 1 e 2, são definidas as funções TaskLoop0 e TaskLoop1, que segue o exemplo original. Entretanto, pq é declarado logo no inicio? Afinal, elas são redeclaradas na linha 29 e 44. E se eu remover as linhas 1 e 2, não é exibido erro no compilador.

2- Vi que a função "void loop()" e "void setup()", seguindo a estrutura simples do arduino IDE, utilizam o core1 (vi em 2 ou 3 sites), isto quer dizer que, naturalmente, o core0 fica sempre inativo?

3- Da mesma forma, já que é designado o core1 na função "loop()", então pq é criado, no void setup(), uma tarefa para os dois cores e, em seguida, deixa o loop() vazio? Não bastaria apenas criar para o core0?

4- Na linha 33, é declarado o pino 3, dentro do "TaskLoop0" (core 0) como entrada, isto quer dizer que, para manuseá-lo (pino3), independente dos motivos, no core1, eu teria que declara-lo novamente?

5- tanto na "TaskLoop0" como na "TaskLoop1", é criado um loop infinito com um "for" (for (;;) {}). Este "for", funciona EXATAMENTE como o "void loop()" padrão? isto é, eu posso fazer chamadas de funções, dentro deste for? incluindo chamadas para bibliotecas?

Exemplo:

  • void TaskLoop1(void *pvParameters) {
  • (void) pvParameters;
  • for (;;){
  • funcao_qualquer();
  • }}

  • void funcao_qualquer(){
  • // Acontece algo.. gpio read/write, calculos, etc..
  • }

6- na linha 10 e 19, é definido o tamanho da "pilha". Imagino que se eu colocar um valor muito alto, irei esperdiçar/perder espaço, mas se for baixo, não funcionará. Tem alguma ferramenta que possa me informar o tamanho que está sendo utilizado?

7- Vi que, após criar a tarefa no void setup(), que era necessário adicionar um delay(500) (acho que foi no canal do FernandoK), isso é necessário? ou é balela?

Em principio, as questões são essas. O principal motivo de pensar em utilizar esta ferramenta (freeRTOS), é devido a um problema que estou tendo durante a execução de um código.

Este código, gerencia uma tela lcd tft (ili9488) e 74hc595 (além de outros componentes que não irão agregar valor no momento). A tela utiliza a lib tft_espi. O hc595, utiliza um código feito por mim, para gerar um sinal com pwm para leds (uma matriz simples).

O problema surge quando o código do hc595 está em execução e, uma chamada para o ili9488 é feita. Por um breve momento (menos de 1 segundo - tempo para atualizar a tela), todos os pinos ficam "apagados" (exemplo de vetor para 1 led (1,1,1,1,1,1,1,1,0,0) (brilho 80%).

O motivo disso, acredito eu, é que o modo como o código é "lido", aparentemente, é "linear" (como uma redação, que não pode pular nenhuma virgula). Então, naturalmente, cada linha será respeitada, e a próxima só será lida após a conclusão da anterior. 

Com isso, o número de ciclos de leitura do código (número de vezes que o "loop()" é executado dentro de um determinado tempo) diminui, pois as mudanças nas informações da tela demandam um pouco de tempo e, consequentemente, o "atraso" para iniciar o código do pwm, tornando-se visível aos nossos olhos.

Minha expectativa, é que com a divisão do trabalho (hc595() no core1, lcd() no core0, por exemplo), este tipo de problema seja resolvido, uma vez que, acredito eu, eles não irão entrar na mesma fila de leitura, e irão manipular os gpios por si. Estou certo? 

Exibições: 596

Responder esta

Respostas a este tópico

1- Mantive do jeito que está. 

2- (sem resposta)

3- (sem resposta)

4- acho que não

5- aparentemente, sim.

6- Jesus é quem sabe.

7- Não fiz.

Em todo caso, mantive todo o código dentro do loop(). Criei a tarefa da seguinte forma:

  • xTaskCreatePinnedToCore(TaskLoop0 , "TaskLoop0" , 10000 , NULL , 2 , NULL , 0); 

Adicionei meu código (não possui delay, mas possui uma tonelada de condicional - se necessário, posto ele -) atribuindo ao core 0, entretanto, retorna o erro:  https://pastebin.com/v7SWuMWX

Moral da história, vou deixar para outra oportunidade, pois achei que seria simples.

Oi Thiago,

Você já estudou com atenção aqui? https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-ref...

Tudo é complicado até entendermos, depois disso se torna simples.

Abs.

CK

Olá Carlos, honestamente? já olhei as referencias da espressif diversas vezes, mas foram poucas as vezes que realmente consegui entender e usar a informação. Dessa vez eu não olhei. Mas irei ler com cuidado. Afinal, a persistência na leitura aumenta a probabilidade de compreensão (tem que ser otimista)

Boa tarde TM.

por enquanto tenho aqui um pequeno computador disponivel , um pequeno MACBOOK Air  I7 ,

mas falta alguns caracteres de portugues.

Vou responder suas dificuldade como fazia o JCK, por partes:

1- Nas linhas 1 e 2, são definidas as funções TaskLoop0 e TaskLoop1, que segue o exemplo original. Entretanto, pq é declarado logo no inicio? Afinal, elas são redeclaradas na linha 29 e 44. E se eu remover as linhas 1 e 2, não é exibido erro no compilador.

Estas declaracoes sao " prototipagem de funcoes"  muito usadas em C, mas que a IDE do arduino nao leva muito a serio.

Em C se uma funcao e' chamada andes dela ser escrita, da erro de compilacao, a menos que se tenha criado um prototipo, como neste caso do seu exemplo.

O FreeTOS respeita esta regra, mas a IDE do arduino nao.  Esta e' uma pratica dos programadores experientes.

Se voce em C escrever um codigo assim:

void main()

{

xxxxx;

yyyyyy;

hugo());

}

void hugo()

{

zzzzz;

}

dara erro de compilacao, a mesmo que voce crie um protipo ante de chamar o hugo;

Correto em C

void hugo();

void main()

{

xxxxx;

yyyyyy;

hugo());

}

void hugo()

{

zzzzz;

}

RV mineirin

2- Vi que a função "void loop()" e "void setup()", seguindo a estrutura simples do arduino IDE, utilizam o core1 (vi em 2 ou 3 sites), isto quer dizer que, naturalmente, o core0 fica sempre inativo?

O Core 0 no ESP32 e' responsavel por algumas tarefas internas do procesador, como WIFI, RTC, BT, etc.

Ele pode ser usado para rotina de usuario, mas sempre vai dar preferencia 'as rotinas do sistema.

RV mineirin

3- Da mesma forma, já que é designado o core1 na função "loop()", então pq é criado, no void setup(), uma tarefa para os dois cores e, em seguida, deixa o loop() vazio? Não bastaria apenas criar para o core0?

Idem resposta 2.

4- Na linha 33, é declarado o pino 3, dentro do "TaskLoop0" (core 0) como entrada, isto quer dizer que, para manuseá-lo (pino3), independente dos motivos, no core1, eu teria que declara-lo novamente?

  1. pinMode(2, OUTPUT);    ?????  pino 2 ou 3?

O Setup roda como uma funcao "global", tudo que voce declarar nela, vai servir para qq task, mas declarando 

algo dentro de uma  funcao em uma task, so vale dentro dela, e' como uma variavel local.

5- tanto na "TaskLoop0" como na "TaskLoop1", é criado um loop infinito com um "for" (for (;;) {}). Este "for", funciona EXATAMENTE como o "void loop()" padrão? isto é, eu posso fazer chamadas de funções, dentro deste for? incluindo chamadas para bibliotecas?

Sim.

6- na linha 10 e 19, é definido o tamanho da "pilha". Imagino que se eu colocar um valor muito alto, irei esperdiçar/perder espaço, mas se for baixo, não funcionará. Tem alguma ferramenta que possa me informar o tamanho que está sendo utilizado?

Realmente 'e dificil saber o valor do stack para sua task, mas eu uso assim:

, configMINIMAL_STACK_SIZE + 4000

7- Vi que, após criar a tarefa no void setup(), que era necessário adicionar um delay(500) (acho que foi no canal do FernandoK), isso é necessário? ou é balela?

Nao uso este delay nos meus projetos, mas...... 

meu loop 'e assim:

void loop()
{
    vTaskDelay( 100 / portTICK_PERIOD_MS );
}

O resto e' com  as funcoes....

Dado o tamanho da resposta para cada postagem, achei melhor responder em uma única postagem.

1-

lá RV, sobre o "MACBOOK Air  I7", de pequeno não tem nada hahahaha.

Obrigado pela orientação. Como é uma regra de "C", não tem muito o que ser questionado. Isso também é visível quando é criado uma lib para o arduino IDE (.h e .cpp), onde é necessário fazer essa declaração no cabeçalho. 

2- Entendi, só acho estranho que, sempre que utilizo ele, do modo como apresentei, costumo receber erros e o controlador reinicia. Sempre referenciando algo ao watchdog. Normalmente a função que jogo no core0 tem várias condicionais. VAAAAAAAAAARIAS (5000, por exemplo). e mexe com os pinos VAAAAAAAAAARIAS vezes (2600, por ciclo). E vi algo, superficialmente, sobre esse assunto, entretanto, não fui capaz de compreender.

3- Duvida sanada.

4- Duvida sanada.

5- Duvida sanada.

6- essa definição "configMINIMAL_STACK_SIZE" ela contabiliza? ou define o mínimo necessário para o funcionamento da tarefa considerando-a vazia? 

7- "vTaskDelay( 100 / portTICK_PERIOD_MS );" Irei pesquisar sobre.

Após realizar alguns testes, como o meu objetivo era fazer controle de brilhos do led, através de um 595, vi que não era possível faze-lo.

O motivo, é que o recurso OBRIGA um delay de, no minimo "1ms estimado" (pode variar para mais, a depender do código), caso contrário dará erro na execução, e esse tempo oferece diferença nas atualizações dos estados do led. Ou seja, você faz um duty para 60%, mas ele estará em 50%. E quando estiver em 99%, estará em 80~90%, e ao atingir o 100%, ele ficará com 100%. ou seja, de 99% para 100% haverá um salto no brilho, indesejado.

Não sei como o "void loop() {}" funciona, entretanto, ele não "precisa" dessa pausa.

Para solucionar minha questão, também testei a interrupção, que apresentou um resultado melhor, mas também não foi 100% perfeito. 

A solução definitiva veio ao migrar algumas funções (que faziam controle de LCD TFT e i2c) para o core0, e colocar delay de 100 e 50ms respectivamente.

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço