Arquivo de 10 agosto, 2010
Sistema operacional de tempo real: faça você mesmo (VII)
Publicado por Marcelo Barros em Programação, Sistemas embarcados em agosto 10, 2010
Para finalizar, uma breve discussão sobre a inicialização do sistema, através da função main(), listada a seguir:
int main(void)
{ /* Saving the current stack pointer. It will be used by the scheduler. */
SaveSchedStackPointer();
EnterCriticalSection();
/* initialize control structures and create all user tasks */
BRTOS_Initialize();
/* call user initialization: you must create at least one thread */
BRTOS_Application_Initialize();
/* the stack pointer should point to the first available task stack,
and the context should be subtracted. This way, the calling of
GoToScheduler will not fail
*/
asBrtosTasks[ucCurrentTask].pusStackPtr += NUM_REGS_IN_CONTEXT;
RestoreStackPointer();
LeaveCriticalSection();
/* go to to scheduler routine*/
GoToScheduler();
}
Várias tarefas são esperadas e não requerem explicações. Percebam que o escalonador vai compartilhar a pilha desta função, já que o SP dele é salvo a partir dela. O que tem de estranho aqui é a manipulação feita no ponteiro da pilha da tarefa corrente e no SP. No fundo, estamos recriando a situação de pilha que acontece no caso de uma interrupção, por isso removemos os registros de R3 a R15, restauramos o SP da tarefa e realizamos um salto para o escalonador, como se esta fosse realmente a tarefa corrente. Depois deste ponto, o processamento segue normalmente.
Os pontos de entrada dentro do escalonador (save_context_entry e dont_save_context_entry) foram inicialmente criados para permitir entrada no escalonador com ou sem salvamento de contexto mas no final eu optei por entrar da forma explicada, mesmo que perdendo algum tempo fazendo e desfazendo a pilha.
Bom, este post encerra esta série. Eu aprendi muito fazendo este sistema em 2005 e ele está longe de ser perfeito ou de ser qualquer referência absoluta no assunto mas ele deixa claro os problemas que enfrentamos ao construir um RTOS.
Espero que tenham gostado.!
Sistema operacional de tempo real: faça você mesmo (VI)
Publicado por Marcelo Barros em Programação, Sistemas embarcados em agosto 10, 2010
Apesar de a maior parte do BRTOS ter sido coberta, existem alguns detalhes importantes que precisam ser explicados para o adequado funcionamento do sistema. Neste post vamos explorar a implementação da rotina BRTOS_CreateTask().
O controle de tarefas do sistemas é extremamente simples, composto por um vetor de TCBs chamado asBrtosTasks (veja post IV). Ao pedir a criação de uma tarefa, uma nova posição é usada neste vetor. Os parâmetros necessários são o ponto de entrada da tarefa (entry_point), o endereço da pilha (stack_addr), time slice (time_slice) e prioridade (pri). Estes parâmetros são guardados no vetor de TCBs (asBrtosTasks) e a tarefa é colocada no estado de “READY”, ou seja, pronta para executar. Vale lembrar que a maioria dos RTOS permite iniciar uma tarefa em estado de espera, ou seja, que não saia rodando imediatamente. Isto não está implementado no BRTOS.
asBrtosTasks[usNumTasks].pfEntryPoint = entry_point; asBrtosTasks[usNumTasks].pusStackBeg = (unsigned short *) stack_addr; /* ponteiro corrente da pilha */ asBrtosTasks[usNumTasks].pusStackPtr = (unsigned short *) stack_addr; asBrtosTasks[usNumTasks].usTimeSlice = MSEC_TO_TICKS(time_slice); asBrtosTasks[usNumTasks].ucPriority = pri; asBrtosTasks[usNumTasks].ucTaskState = BRTOS_TASK_STATE_READY;
Até aqui tudo bem, fácil e previsível. O que não é óbvio é que você precisa preparar a pilha inicial da tarefa. Releia o post anterior sobre o escalonador e verá que ele começa salvando os registros gerais (R3 a R15) e confia plenamente que na pilha estarão o SP e o PC, geralmente colocados lá pelo acontecimento da interrupção do escalonador (interrupção de watchdog, veja posts II e III). No entanto, isto não aconteceu no momento da criação da tarefa e é necessário imitar esta pilha inicial. Erre aqui e seu sistema provavelmente vai resetar.
E tem mais um detalhe que não pode ser ignorado. Comentamos no post IV que uma tarefa geralmente é um laço infinito mas que alguns cuidados precisam ser tomados caso ela retorne ou não seja um laço. Um retorno de modo não interrompido no MSP430, feita pela instrução ret,, apenas muda o PC para que está na pilha (sem SR, neste caso). O macete aqui é colocar um local válido e seguro para este novo PC, no nosso caso uma função chamada BRTOS_TaskEnd(), descrita mais abaixo.
O diagrama da pilha inicial da tarefa ficará então como a seguir. Lembre-se que a lógica de pilha do MSP430 é apontar para um valor livre e decrescer quando valores são adicionados (isto também é dependente de plataforma).
+-----------------+ | | <-- pusStackPtr +-----------------+ | R15 | +-----------------+ | R14 | +-----------------+ | ... | +-----------------+ | R3 | +-----------------+ | PC | +-----------------+ | SR | +-----------------+ | BRTOS_TaskEnd | <-- pusStackBeg +-----------------+
O código necessário para criar esta pilha inicial está a seguir:
/* if task returns some day, prepare stack */
*(asBrtosTasks[usNumTasks].pusStackPtr) = (unsigned short) BRTOS_TaskEnd;
asBrtosTasks[usNumTasks].pusStackPtr -=1;
/* status register and program counter */
*(asBrtosTasks[usNumTasks].pusStackPtr) = (unsigned short) 0;
asBrtosTasks[usNumTasks].pusStackPtr -=1;
*(asBrtosTasks[usNumTasks].pusStackPtr) = (unsigned short) entry_point;
asBrtosTasks[usNumTasks].pusStackPtr -=1;
/* prepare for first RestoreContext(): dummy NUM_REGS_IN_CONTEXT regs */
for(i = 0 ; i < NUM_REGS_IN_CONTEXT ; i++)
{
*(asBrtosTasks[usNumTasks].pusStackPtr) = (unsigned short) 0;
asBrtosTasks[usNumTasks].pusStackPtr -= 1;
}
E a implementação da função BRTOS_TaskEnd() é bem simples também, apenas coloca a tarefa no estado de “TERMINATED” e fica num laço infinito de forma que ela não estrague nada até que o escalonador rode novamente e escolha uma tarefa do grupo de tarefas prontas para serem executadas (READY). Daria para fazer algo melhor aqui sem grandes modificações, como uma implementação que permita um reinício (RESTART) da tarefa mesmo depois de ela ter ido para terminate, algo geralmente encontrado em sistemas de tempo real.
static void BRTOS_TaskEnd(void)
{
EnterCriticalSection();
asBrtosTasks[ucCurrentTask].ucTaskState = BRTOS_TASK_STATE_TERMINATED;
LeaveCriticalSection();
while(1);
}
No próximo post falaremos de mais um detalhe relacionado à inicialização do sistema. Até lá !
-
You are currently browsing the archives for 0, 10 \10\UTC agosto \10\UTC 2010
Blog Stats
- 162,754 hits
Principais mensagens
- Como fazer o seu cubo de leds 5x5x5
- Introdução ao desenvolvimento de drivers para Linux
- O guia definitivo para os iniciantes em Net-SNMP (1)
- Gerência de Redes com SNMP - Apostila
- A chave para o enriquecimento
- O guia definitivo para os iniciantes em Net-SNMP (6)
- Ensino
- Projetos
- O guia definitivo para os iniciantes em Net-SNMP (5)
- Sistema operacional de tempo real: faça você mesmo (I)
Comentários