Ce diaporama a bien été signalé.
Nous utilisons votre profil LinkedIn et vos données d’activité pour vous proposer des publicités personnalisées et pertinentes. Vous pouvez changer vos préférences de publicités à tout moment.

Webinar: Porque o RTOS não faz o que eu quero?

Nesta apresentação iremos abordar três conceitos comuns na programação embarcada e como eles devem ser modificados para que funcionem quando se tem um RTOS no meio: multitasking, temporização e compartilhamento de variáveis.

Acesse o video em: https://www.embarcados.com.br/webinars/webinar-porque-o-rtos-nao-faz-o-que-eu-quero/

  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Webinar: Porque o RTOS não faz o que eu quero?

  1. 1. 1
  2. 2. 2 2
  3. 3. Sobre • 10 anos como professor de sistemas embarcados • Replanejamento do curso • Maior ênfase em atividades práticas de projetos - modelo para as novas DCNs • https://www.youtube.com/cniweb (dia 30/10/2020) • Atividades na pandemia • Aulas remotas com vídeos, slides e atividades gratuitos • 120 kits eletrônicos montados e enviados para os alunos • https://www.youtube.com/c/rodrigomaximianoantunesdealmeida 3
  4. 4. • Como pensar em baremetal • O código evolui no tempo • Os três conceitos • Multitasking • Temporização • Compartilhamento de variáveis • Watchdog • Migrando para RTOS Cronograma 4
  5. 5. Disclaimer... • 100 slides • 45: com código em linguagem C • 32: de texto/teoria • 19: para títulos, introdução e conclusão 5
  6. 6. Disclaimer... • 100 slides • 45: com código em linguagem C • 32: de texto/teoria • 19: para títulos, introdução e conclusão • 04: sobre filosofia 6
  7. 7. Disclaimer... “O limite da minha linguagem significa o limite do meu mundo” 7
  8. 8. Disclaimer... “O limite da minha linguagem significa o limite do meu mundo” “Se falarmos uma linguagem diferente, nós perceberíamos o mundo de algum modo diferente” 8
  9. 9. Disclaimer... “O limite da minha linguagem significa o limite do meu mundo” “Se falarmos uma linguagem diferente, nós perceberíamos o mundo de algum modo diferente” Ludwig Wittgenstein 9
  10. 10. • Quando começamos a aprender programação somos treinados a pensar que um programa tem começo meio e fim. • A primeira dificuldade em começar a trabalhar com embarcados é mudar esse pensamento. • O programa não é uma simples sequência de atividades com começo meio e fim mas um conjunto de atividades que devem ser executadas ciclicamente enquanto o sistema estiver ligado. Começando 10
  11. 11. Mas porque funcionava? • O sistema operacional se ocupava de manter toda a infraestrutura funcionando. • Agora a responsabilidade é do programador. 11
  12. 12. Programandoparadesktop void main (void){ int num, arg; for(;;){ arg = scanf("%d",&num); if (arg > 0){ printf("%d",num); } } return; } 12
  13. 13. Programandoparadesktop void main (void){ int num, arg; for(;;){ arg = scanf("%d",&num); if (arg > 0){ printf("%d",num); } } return; } Impressão Leitura Teste valor válido 13
  14. 14. • Para saber que uma tecla foi pressionada é preciso saber se ela estava solta no passado. E o que muda? 14
  15. 15. Programandoparaembarcados void main (void){ int num; for(;;){ kpDebounce(); if (kpRead() != num){ num = kpRead(); if (num != 0){ lcdInt(a) } } } return; } 15
  16. 16. Programandoparaembarcados void main (void){ int num; for(;;){ kpDebounce(); if (kpRead() != num){ num = kpRead(); if (num != 0){ lcdInt(a) } } } return; } Infra teclado Verificação de pressionamento Impressão Leitura Teste valor válido 16
  17. 17. Programandoparaembarcados for(;;){ kpDebounce(); if (kpRead() != num){ num = kpRead(); if (num != 0){ lcdInt(a) } } } 17
  18. 18. Evolução no tempo • Deve-se interpretar o loop infinito como algo que é executado várias vezes, como se fosse uma sequência de comandos //primeira execução kpDebounce1(); if (kpRead1() != a1){ a2 = kpRead2(); if (a2 != 0){ lcdInt(a2) } } //segunda execução kpDebounce2(); if (kpRead3() != a2){ a3 = kpRead4(); if (a3 != 0){ lcdInt(a3) } } //terceira execução kpDebounce(); if (kpRead5() != a3){ a3 = kpRead6(); if (a3 != 0){ lcdInt(a3) } } 18
  19. 19. Programandoparaembarcados for(;;){ kpDebounce(); if (kpRead() != num){ num = kpRead(); if (num != 0){ lcdInt(a) } } } kpDebounce1(); if (kpRead1() != a1){ a2 = kpRead2(); if (a2 != 0){ lcdInt(a2) } } kpDebounce2(); if (kpRead3() != a2){ a3 = kpRead4(); if (a3 != 0){ lcdInt(a3) } } kpDebounce(); if (kpRead5() != a3){ a3 = kpRead6(); if (a3 != 0){ lcdInt(a3) } } 19
  20. 20. Programandoparaembarcados for(;;){ kpDebounce(); if (kpRead() != num){ num = kpRead(); if (num != 0){ lcdInt(a) } } } kpDebounce1(); if (kpRead1() != a1){ a2 = kpRead2(); if (a2 != 0){ lcdInt(a2) } } kpDebounce2(); if (kpRead3() != a2){ a3 = kpRead4(); if (a3 != 0){ lcdInt(a3) } } kpDebounce(); if (kpRead5() != a3){ a3 = kpRead6(); if (a3 != 0){ lcdInt(a3) } } 20
  21. 21. Deve-se, no presente, guardar a informação para, no futuro, poder perguntar sobre o passado. for(;;){ kpDebounce(); if (kpRead() != a){ a = kpRead(); if (a != 0){ lcdInt(a) } } } (iteração atual) (próxima iteração) (iteração passada) 21
  22. 22. Novos requisitos • Manter a infraestrutura funcionando • debounce de teclas • update de displays multiplexados • recepção de dados da serial • leitura de analógicos e checagem de alarme • contagem de tempo 22
  23. 23. Multitasking 23
  24. 24. Multitasking • Execução de várias atividades em “paralelo” • Organizar o sistema • Máquinas de estados temporizadas 24
  25. 25. for(;;){ //************* início do top-slot *************** ssdUpdate(); kpDebounce(); //********* início da máquina de estado ********** switch(slot){ case 0: LeTeclado(); slot = 1; break; case 1: RecebeSerial(); slot = 2; break; case 2: VerificaADC(); slot = 0; break; default: slot = 0; break; } //************ início do bottom-slot *************** } ExemplocomM.E. 25
  26. 26. Temporização 26
  27. 27. • Existem dois requisitos que envolvem tempo • Contagem de tempo para sincronizar algum evento • Responder à um evento o mais rápido possível Temporização 27
  28. 28. Contar tempo • Fazer uso da estrutura de tempo do loop principal • Pode ser impreciso • Utilizar uma interrupção de timer por HW • Depende de suporte do microcontrolador/processador 28
  29. 29. for(;;){ //************* início do top-slot *************** timerReset(5000); //5 ms para cada slot ssdUpdate(); kpDebounce(); //********* início da máquina de estado ********** switch(slot){ case 0: LeTeclado(); slot = 1; break; case 1: RecebeSerial(); slot = 2; break; case 2: VerificaADC(); slot = 0; break; default: slot = 0; break; } //************ início do bottom-slot *************** timerWait(); } ExemplocomM.E. 29
  30. 30. Agilizar a resposta à evento • Aumentar a frequência do pooling: for(;;){ timerReset(5000); //5 ms para cada slot switch(slot){ case 1: RecebeSerial(); slot = 2; break; 30
  31. 31. Agilizar a resposta à evento • Aumentar a frequência do pooling: for(;;){ timerReset(5000); //5 ms para cada slot switch(slot){ case 1: RecebeSerial(); slot = 2; break; 100 100 ns 31
  32. 32. Agilizar a resposta à evento • Aumentar a frequência do pooling: • Interrupções; for(;;){ timerReset(5000); //5 ms para cada slot switch(slot){ case 1: RecebeSerial(); slot = 2; break; 100 100 ns //Interrupção da serial void serialISR (void) interrupt 1 { buffer[pos] = SERIAL_DATA_REGISTER; //teste para evitar overflow if (pos >= 50){ pos = 0; } } 32
  33. 33. void serialISR (void) interrupt 1 { buffer[pos] = SERIAL_DATA_REGISTER; if (++pos >= 50){ pos = 0; } } void main(void){ systemInit(); for(;;){ timerReset(5000); //5 ms para cada slot ssdUpdate(); kpDebounce(); switch(slot){ case 0: LeTeclado(); slot = 1; break; case 1: ProcessaSerial(); slot = 2; break; case 2: VerificaADC(); slot = 0; break; default: slot = 0; break; } timerWait(); } } M.E.T.+ISR 33
  34. 34. Compartilhamento de variáveis 34
  35. 35. • Podem gerar problemas • Mais de uma pessoa modificando o valor • Corromper os valores • Não se sabe quem tem/faz acesso às variáveis • Solução: passar sempre que possível por por parâmetro • Cuidado: passar referência pode causar o mesmo problema da variável global Variáveis globais 35
  36. 36. • Necessárias para comunicação entre ISR e o restante do programa • É possível remover parte dos problemas/perigos através de um encapsulamento por driver e cuidado na criação/programação do driver. • Mas para o driver em si ela continua como global. Variáveis globais 36
  37. 37. Compartilhamentodevariáveis static char buffer[50]; static char pos=0; void serialISR (void) __interrupt 1 { //Interrupção da serial buffer[pos] = SERIAL_DATA_REGISTER; if (pos >= 50){ pos = 0; } //teste para evitar overflow } void main (void){ InicializaSerial(); InicializaInterrupcao(); for(;;){ if (buffer[pos] == 'n'){ if (VerificaCRC(buffer)){ ExecutaAcao(buffer); } pos = 0; } EntrarEmModoDeBaixoConsumo(); } } 37
  38. 38. • Multitasking • Temporização • Compartilhamento de variáveis Resumo 38
  39. 39. Exemplo crítico Aumentando a confiabilidade do sistema 39
  40. 40. Watchdog 40 memória final > prescaler ÷1 ÷2 ÷4 ÷n tempo controle início incrementa contador MCLR/RESET CLRWDT(); t=0;
  41. 41. void serialISR (void) __interrupt 1 { buffer[pos] = SERIAL_DATA_REGISTER; if (++pos >= 50){ pos = 0; } } void main(void){ systemInit(); for(;;){ timerReset(5000); //5 ms para cada slot ssdUpdate(); kpDebounce(); switch(slot){ case 0: LeTeclado(); slot = 1; break; case 1: ProcessaSerial(); slot = 2; break; case 2: VerificaADC(); slot = 0; break; default: slot = 0; break; } CLRWDT(); //10 ms - margem de segurança timerWait(); } } M.E.T.+ISR+Watchdog 41
  42. 42. Alterar dinamicamente a sequência das tarefas 42
  43. 43. Ponteiros de Função •Armazenam o endereço do início de uma função. •A manipulação do valor obedece todas as regras de manipulação de ponteiros. • A única exceção é na chamada da função apontada. •É necessário indicar a assinatura da função: a quantidade e tipos dos parâmetros. • É comum utilizar um typedef para simplificar a criação dos ponteiros. 43
  44. 44. //funções void func1 (void){ printf("Primeira Função"); } void func2 (void){ printf("Segunda Função"); } //criando um ponteiro para função typedef void (*pointerTest)(void); pointerTest foo; void main (void){ for(;;) { foo = func1; //OBS: Sem parênteses foo(); //chamando a função 1 foo = func2; //OBS: Sem parênteses foo(); //chamando a função 2 } } Ponteirosdefunção 44
  45. 45. pointerTest foo; void main (void){ for(;;) { func1(); //chamando a função 1 func2(); //chamando a função 2 CLRWDT(); } } Reordenaçãodinâmica 45
  46. 46. pointerTest foo; void main (void){ for(;;) { func1(); //chamando a função 1 if(tick <= 10) func2(); //chamando a função 2 CLRWDT(); } } Reordenaçãodinâmica 46
  47. 47. pointerTest foo; void main (void){ for(;;) { func1(); //chamando a função 1 if(tick <= 10) func2(); //chamando a função 2 CLRWDT(); } } Reordenaçãodinâmica 47
  48. 48. pointerTest foo; void main (void){ for(;;) { foo = func1; //OBS: Sem parênteses foo(); //chamando a função 1 foo = func2; //OBS: Sem parênteses foo(); //chamando a função 2 CLRWDT(); } } Reordenaçãodinâmica 48
  49. 49. //na interrupção do timer: // if (++tick>15) clock=0; pointerTest foo; void main (void){ for(;;) { foo = func1; foo(); //chamando a função 1 foo = func2; if(tick <= 10) foo(); //chamando a função 2 CLRWDT(); } } Reordenaçãodinâmica 49
  50. 50. //na interrupção do timer: // if (++tick>15) clock=0; pointerTest foo; void main (void){ for(;;) { foo = func1; if(tick <= 10) foo = func2; foo(); //chamando a função 1 ou 2 CLRWDT(); } } Reordenaçãodinâmica 50
  51. 51. //na interrupção do timer: // if (++tick>15) clock=0; pointerTest foo[10]; int task; void main (void){ foo[0] = func1; foo[1] = func2; for(;;) { task = 0; if(tick <= 10) task = 1; foo[task](); //chamando a função 1 ou 2 CLRWDT(); } } Reordenaçãodinâmica 51
  52. 52. //na interrupção do timer: // if (++tick>15) clock=0; pointerTest foo[10]; int task; void main (void){ foo[0] = func1; foo[1] = func2; for(;;) { if(tick <= 10){ task = 0; }else{ task = 1; } foo[task](); //chamando a função 1 ou 2 !!! CLRWDT(); } } Reordenaçãodinâmica 52
  53. 53. //na interrupção do timer: // if (++tick>15) clock=0; pointerTest foo[10]; int task; void main (void){ foo[0] = func1; foo[1] = func2; //demais funções... for(;;) { if (tick <= 5) task++; //executa todas else if(tick <= 10) task=(task+1)%3; //executa só 0-2 else task = 0; //executa só 0 foo[task](); //chamando a função task CLRWDT(); } } Reordenaçãodinâmica 53
  54. 54. //na interrupção do timer: // if (++tick>15) clock=0; pointerTest foo[10]; int task; void main (void){ foo[0] = func1; foo[1] = func2; //demais funções... for(;;) { if (tick <= 5) task++; //executa todas else if(tick <= 10) task=(task+1)%3; //executa só 0-2 else task = 0; //executa só 0 foo[task](); //chamando a função task CLRWDT(); } } KERNEL! 54
  55. 55. //na interrupção do timer: // if (++tick>15) clock=0; pointerTest foo[10]; int task; void main (void){ foo[0] = func1; //xTaskCreate(1) foo[1] = func2; //xTaskCreate(2) vStartScheduler(); } void vStartScheduler(void){ for(;;) { if (tick <= 5) task++; //executa todas else if(tick <= 10) task=(task+1)%3; //executa só 0-2 else task = 0; //executa só 0 foo[task](); //chamando a função task CLRWDT(); } } 55
  56. 56. Permite pausar uma tarefa/processo para executar outro: Preempção Liu, Xing, et al. "Memory and energy optimization strategies for multithreaded operating system on the resource-constrained wireless sensor node." Sensors 15.1 (2015): 22-48. 56
  57. 57. Permite pausar uma tarefa/processo para executar outro: Perdemos ambos o sequenciamento E a execução linear Preempção Liu, Xing, et al. "Memory and energy optimization strategies for multithreaded operating system on the resource-constrained wireless sensor node." Sensors 15.1 (2015): 22-48. 57
  58. 58. Porque o RTOS não faz o que eu quero? 58
  59. 59. Porque o RTOS não faz o que eu quero? 59
  60. 60. • Multitasking: ignorar a ideia que cada tarefa é “independente” • Temporização: mau uso de rotinas de delay e resposta à eventos • Compartilhamento de variáveis: corrupção de informação Porque utilizamos errado os 3 conceitos 60
  61. 61. Multitasking • Ignorar a ideia que cada tarefa é “independente” • Ao se tornar independente as tarefas perdem qualquer relação de sincronia que poderiam ter. • A ordem de execução não mais é conhecida • Troca de contexto: pode pausar “qualquer” tarefa em “qualquer” momento 61
  62. 62. Temporização • Mau uso de rotinas de delay e resposta à eventos • Ainda achamos que a velocidade de execução de uma tarefa depende do quanto de código ela possui • ignoramos as trocas de contexto e as prioridades • Confundir delay com sincronização de tempo • Usar interrupções pois “continuam funcionando” 62
  63. 63. Temporização • O RTOS é um gerente • Ele não realiza “trabalho útil” 63
  64. 64. Temporização • O RTOS é um gerente • Ele não realiza “trabalho útil” • e ainda cobra por isso. 64
  65. 65. Compartilhamento de variáveis • Corrupção de informação • A troca de contexto pode interromper a leitura/escrita em qualquer momento, maior criticidade em variáveis multibyte (long, double, vetores) • Não existe sequenciamento/ordem na execução das tarefas 65
  66. 66. Como resolver? 66
  67. 67. Como resolver? • Multitasking: ignorar a ideia que cada tarefa é “independente” • Planejar cada tarefa como um programa individual • Temporização: mau uso de rotinas de delay e resposta à eventos • Definir explicitamente onde os tempos de execução são requisitos essenciais • Compartilhamento de variáveis: corrupção de informação • Toda interação deve ser mediada pelo SO 67
  68. 68. Planejar cada tarefa como individual • Cada tarefa deve ser planejada como independente: • Se houver iteração temporal: utilizar semáforos/mutexes • Se houver iteração de informação: filas • Observar se existe problema em pausar o código: • Caso exista: é possível remover isso reorganizando a tarefa? • Se não for possível: utilize estruturas “anti-pausa” • taskEnterCritical(); vTaskSuspendAll(); • Se o problema for apenas entre X threads: mutexes 68
  69. 69. Definir os tempos de execução • Ao montar o programa em baremetal automaticamente as funções apresentam uma rotina de execução sequencial e temporal. • É necessário verificar quais dessas funções continuam exigindo esse requisito • Rotinas que precisam de tempo fixo de execução • utilizar a rotina de delayUntil() • Ações que devem aguardar um tempo fixo antes da próxima atividade • delay() • Certificar se o problema é tempo ou sincronia entre atividades 69
  70. 70. Toda interação mediada pelo SO • Interação temporal/sequencial • Semáforos • Interação de recursos compartilhados • Semáforos e mutexes • Compartilhamento de variáveis • Mutexes ou filas 70
  71. 71. Exemplo FreeRTOS + SoftWatchdog 71
  72. 72. void serialISR (void) interrupt 1 { buffer[pos] = SERIAL_DATA_REGISTER; if (++pos >= 50){ pos = 0; } } void main(void){ systemInit(); for(;;){ timerReset(5000); //5 ms para cada slot ssdUpdate(); kpDebounce(); switch(slot){ case 0: LeTeclado(); slot = 1; break; case 1: ProcessaSerial(); slot = 2; break; case 2: VerificaADC(); slot = 0; break; default: slot = 0; break; } CLRWDT(); //10 ms - margem de segurança timerWait(); } } M.E.T.+ISR+Watchdog 72
  73. 73. void ssdUpdate(void) {vTaskDelay( 5000);} void kpDebounce(void) {vTaskDelay( 5000);} void LeTeclado(void) {vTaskDelay(15000);} void ProcessaSerial(void){vTaskDelay(15000);} void VerificaADC(void) {vTaskDelay(15000);} void main (void) xTaskCreate(ssdUpdate, "ssd", 100, NULL, 10, NULL); xTaskCreate(kpDebounce, "kp", 100, NULL, 10, NULL); xTaskCreate(LeTeclado, "tec", 100, NULL, 10, NULL); xTaskCreate(ProcessaSerial,"com", 100, NULL, 10, NULL); xTaskCreate(VerificaADC, "adc", 100, NULL, 10, NULL); vTaskStartScheduler(); CLRWDT(); } InterruptdrivencomWatchdog 73
  74. 74. void ssdUpdate(void) {vTaskDelay( 5000);CLRWDT();} void kpDebounce(void) {vTaskDelay( 5000);CLRWDT();} void LeTeclado(void) {vTaskDelay(15000);CLRWDT();} void ProcessaSerial(void){vTaskDelay(15000);CLRWDT();} void VerificaADC(void) {vTaskDelay(15000);CLRWDT();} void main (void) xTaskCreate(ssdUpdate, "ssd", 100, NULL, 10, NULL); xTaskCreate(kpDebounce, "kp", 100, NULL, 10, NULL); xTaskCreate(LeTeclado, "tec", 100, NULL, 10, NULL); xTaskCreate(ProcessaSerial,"com", 100, NULL, 10, NULL); xTaskCreate(VerificaADC, "adc", 100, NULL, 10, NULL); vTaskStartScheduler(); } InterruptdrivencomWatchdog 74
  75. 75. Watchdog e a preempção •As tarefas são executadas em “paralelo” • Não existe um ponto único onde pode-se colocar o watchdog • Se for colocado dentro de uma tarefa, apenas ela será monitorada • Dentro de todas, o watchdog não funciona corretamente 75
  76. 76. Watchdog e a preempção •Solução • Criar uma tarefa que irá monitorar as demais • Esta tarefa irá limpar o watchdog, ou não •Problemas • Todas as tarefas têm que se comunicar com ela 76
  77. 77. int tudo_certo; TaskHandle_t h_taskA = NULL; TaskHandle_t h_SWT = NULL; void main( void ){ // HW init ... xTaskCreate(vTaskA, "", 100, NULL, 10, &h_taskA); xTaskCreate(vSWTask,"", 100, NULL, 10, &h_SWT); tudo_certo = FALSE; //... vTaskStartScheduler(); } 77 FreeRTOS+SoftWatchdog
  78. 78. void vTaskA( void *pvParameters ){ for(;;){ //Execução da tarefa normalmente //Manda o aviso para a SWT (novo CLRWDT();) tudo_certo = TRUE; } } 78 FreeRTOS+SoftWatchdog
  79. 79. void vSWTask( void *pvParameters ){ for(;;) { //Cria um WDT com 100 ticks de tempo if(tudo_certo){ //Tudo certo desta vez, bora pra próxima CLRWDT(); }else{ //Tarefa não respondeu em 100 ticks //aguarda o WD de hardware atuar for(;;); } } } 79 FreeRTOS+SoftWatchdog
  80. 80. • Sim! • Resolvemos o problema de usar o watchdog em um ambiente multitask preemptivo • A maioria dos periféricos não é thread-safe, é necessário usá-los com cautela • Mesmo havendo várias tarefas, apenas 1 é responsável pelo watchdog, permitindo que as demais funcionem em paralelo sem maiores problemas. tudo_certo? 80
  81. 81. • Não: a variável é compartilhada (global). • Quando mais funções forem adicionadas, mais tarefas irão ler/escrever a variável num ambiente multitask preemptivo. a. Task A vai colocar tudo_certo em TRUE (terminando sua execução) b. Preempção! c. Task B coloca tudo_certo em FALSE por algum erro d. Preempção! e. Task A “estraga” o sinal da Task B voltando tudo certo pra TRUE. tudo_certo? 81
  82. 82. QueueHandle_t fila_WD; TaskHandle_t h_taskA = NULL; TaskHandle_t h_taskB = NULL; TaskHandle_t h_SWT = NULL; void main( void ){ // HW init ... xTaskCreate(vTaskA, "", 100, NULL, 10, &h_taskA); xTaskCreate(vTaskB, "", 100, NULL, 10, &h_taskB); xTaskCreate(vSWTask,"", 100, NULL, 10, &h_SWT); fila_WD = xQueueCreate(10, sizeof(struct msg*)); //... vTaskStartScheduler(); } 82 FreeRTOS+SoftWatchdog
  83. 83. void vTaskA( void *pvParameters ){ for(;;){ //Execução da tarefa normalmente //Manda o aviso para a SWT (novo CLRWDT();) xQueueSend( xQueue, (void*) &pxMessage, 0); } } 83 FreeRTOS+SoftWatchdog
  84. 84. void vSWTask( void *pvParameters ){ if( xQueue != 0 ){ for(;;) { //Cria um WDT com 100 ticks de tempo if(xQueueReceive(xQueue, &(pxRxedMessage), 100)){ //Tudo certo desta vez, bora pra próxima CLRWDT(); }else{ //Tarefa não respondeu em 100 ticks //aguarda o WD de hardware atuar for(;;); } } } } 84 FreeRTOS+SoftWatchdog
  85. 85. • Sim! • Multitask Ok! • Compartilhamento de variável Ok! tudo_certo (v2.0)? 85
  86. 86. • Sim! • Multitask Ok! • Compartilhamento de variável Ok! tudo_certo (v2.0)? na verdade não!! 86
  87. 87. void vSWTask( void *pvParameters ){ if( xQueue != 0 ){ for(;;) { //Cria um WDT com 100 ticks de tempo if(xQueueReceive(xQueue, &(pxRxedMessage), 100)){ //Tudo certo desta vez, bora pra próxima CLRWDT(); }else{ //Tarefa não respondeu em 100 ticks //aguarda o WD de hardware atuar for(;;); } } } } 87 FreeRTOS+SoftWatchdog
  88. 88. • Cria uma flag para cada uma das tarefas. • Deste modo não há problema em uma única tarefa ficar reiniciando o watchdog. Events Group 88
  89. 89. EventGroupHandle_t xSoftWDT; // Criado na main xSoftWDT = xEventGroupCreate(); void vATask( void *pvParameters ){ for(;;){ //Execução da tarefa normalmente uxBits = xEventGroupSetBits( xSoftWDT, 1<<0 ); } } void vBTask( void *pvParameters ){ for(;;){ //Execução da tarefa normalmente uxBits = xEventGroupSetBits( xSoftWDT, 1<<1 ); } } 89 FreeRTOS+SoftWatchdog
  90. 90. uxBits = xEventGroupWaitBits( xSoftWDT, // Handle 0x03, // Bits monitorados pdTRUE, // Apaga os bits no fim pdTRUE, // Espera por todos 100 ); // Timout FreeRTOS+SoftWatchdog 90
  91. 91. void vSoftWatchDogTask( void ){ EventBits_t uxBits; for(;;){ uxBits = xEventGroupWaitBits(xSoftWDT,0x03,pdTRUE,pdTRUE,100); if( ( uxBits & ( 0x03 ) ) == ( 0x03 ) ){ // Tudo certo, todas as tasks deram ACK }else if( ( uxBits & 1<<0 ) != 0 ){ // Apenas Task A deu ACK }else if( ( uxBits & 1<<1 ) != 0 ){ // Apenas Task B deu ACK }else{ // Ninguém retornou, aguarda o HW Watchdog for(;;); } CLRWDT(); } } 91 FreeRTOS+SoftWatchdog
  92. 92. • Sim! • Multitask Ok! • Compartilhamento de variável Ok! tudo_certo (v2.0)? 92
  93. 93. • Sim! • Multitask Ok! • Compartilhamento de variável Ok! • Tempo? tudo_certo (v2.0)? 93
  94. 94. void vSoftWatchDogTask( void ){ EventBits_t uxBits; for(;;){ uxBits = xEventGroupWaitBits(xSoftWDT,0x03,pdTRUE,pdTRUE,100); if( ( uxBits & ( 0x03 ) ) == ( 0x03 ) ){ // Tudo certo, todas as tasks deram ACK }else if( ( uxBits & 1<<0 ) != 0 ){ // Apenas Task A deu ACK }else if( ( uxBits & 1<<1 ) != 0 ){ // Apenas Task B deu ACK }else{ // Ninguém retornou, aguarda o HW Watchdog for(;;); } CLRWDT(); } } 94 FreeRTOS+SoftWatchdog
  95. 95. void vSoftWatchDogTask( void ){ EventBits_t uxBits; TickType_t xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); for(;;){ vTaskDelayUntil( &xLastWakeTime, 100); uxBits = xEventGroupWaitBits(xSoftWDT,0x03,pdTRUE,pdTRUE,0); if( ( uxBits & ( 0x03 ) ) == ( 0x03 ) ){ // Tudo certo, todas as tasks deram ACK }else if( ( uxBits & 1<<0 ) != 0 ){ // Apenas Task A deu ACK }else if( ( uxBits & 1<<1 ) != 0 ){ // Apenas Task B deu ACK }else{ // Ninguém retornou, aguarda o HW Watchdog for(;;); } CLRWDT(); } } 95 FreeRTOS+SoftWatchdog
  96. 96. void vSoftWatchDogTask( void ){ EventBits_t uxBits; TickType_t xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); for(;;){ vTaskDelayUntil( &xLastWakeTime, 100); uxBits = xEventGroupWaitBits(xSoftWDT,0x03,pdTRUE,pdTRUE,0); if( ( uxBits & ( 0x03 ) ) == ( 0x03 ) ){ // Tudo certo, todas as tasks deram ACK }else if( ( uxBits & 1<<0 ) != 0 ){ // Apenas Task A deu ACK, resetar apenas B? vTaskDelete( h_TaskB); xTaskCreate(vATask,"",100,NULL,10,&h_TaskB); }else if( ( uxBits & 1<<1 ) != 0 ){ // Apenas Task B deu ACK, resetar apenas A? }else{ // Ninguém retornou, aguarda o HW Watchdog for(;;); } CLRWDT(); } } 96 FreeRTOS+SoftWatchdog
  97. 97. Questionamentos finais •Eu tenho necessidade dos recursos que o SO/RTOS traz? •A simplificação que o SO traz para o projeto vale o overhead do uso? •Me planejei para modelar o sistema e suas interações? •Entendi que existe uma mudança brusca de filosofia? • Desktop vs Embarcados; • Baremetal vs RTOS; • Single vs Multicore; • Estruturada vs OO; 97
  98. 98. There is always a well-known solution to every human problem — neat, plausible, and wrong. H. L. Mencken 98
  99. 99. Rodrigo Almeida rodrigomax@unifei.edu.br @rmaalmeida Contatos 99
  100. 100. Obrigado 100

    Soyez le premier à commenter

Nesta apresentação iremos abordar três conceitos comuns na programação embarcada e como eles devem ser modificados para que funcionem quando se tem um RTOS no meio: multitasking, temporização e compartilhamento de variáveis. Acesse o video em: https://www.embarcados.com.br/webinars/webinar-porque-o-rtos-nao-faz-o-que-eu-quero/

Vues

Nombre de vues

439

Sur Slideshare

0

À partir des intégrations

0

Nombre d'intégrations

333

Actions

Téléchargements

8

Partages

0

Commentaires

0

Mentions J'aime

0

×