Este documento discute:
1. Sistemas em tempo real e seus requisitos temporais, como garantir a periodicidade de tarefas e determinismo.
2. Como implementar um sistema que trabalhe com requisitos temporais, necessitando de um relógio preciso, informar a frequência de cada processo e garantir que os tempos de execução cabem no tempo disponível.
3. A criação de drivers para dispositivos, como o driver para LCD utilizando funções de inicialização, escrita e acesso.
3. Real time
● Capacidade de um
sistema em garantir
a peridiocidade de
uma tarefa
● Determinismo
4. Requisitos temporais
● Para implementar um sistema que trabalhe
com requisitos temporais:
1)Deve existir um relógio que trabalhe com uma
frequência precisa.
2)O kernel deve ser informado da frequência, ou
período, de execução de cada processo.
3)A soma dos tempos de cada processo deve
“caber” no tempo disponível do processador.
5. ●
1a
condição:
● É necessário um timer que possa gerar uma
interrupção.
●
2a
condição:
● Adicionar as informações na estrutura do
processo
●
3a
condição:
● Testar, testar e testar.
● Em caso de falha:
– Chip mais rápido
– Otimização
Requisitos temporais
6. Rotina de Interrupção
//colocar no MCUinit.c na função isrVrti()
#include “kernel.h”
__interrupt void isrVrti(void){
KernelClock();
//limpar a flag de interrupção
CRGFLG = 0x80;
}
7. Rotina de Interrupção
//colocar no kernel.c
#define MIN_INT -30000
void KernelClock(void){
unsigned char i;
i = ini;
while(i!=fim){
if((pool[i].start)>(MIN_INT)){
pool[i].start--;
}
i = (i+1)%SLOT_SIZE;
}
}
//colocar no kernel.h
void KernelClock(void);
8. Exercício
● Montar um relógio binário onde cada led
pisca numa frequência diferente
1
2
3
4
1 segundo
2 segundos
4 segundos
8 segundos //Ligar o 1o led
PORTB = PORTB | 0x01;
//Desligar o 1o led
PORTB = PORTB & ~0x01;
//Piscar o 1o led
PORTB = PORTB ^ 0x01;
9. Driver
● Driver é uma abstração em software do
hardware da placa, suas funcionalidades,
opções e modos de funcionamento.
● É dependente do processador,dos
componentes conectados e das ligações
entre eles.
10. Driver
● Exemplo:
● Display de LCD:
– 16 colunas X 2 linhas
– Compatível com HD44780 (Hitachi)
● Dragon12
– Ligação em 4 bits
– Acesso à EN e RS
● MC9HCS12DG256
– Utilizada a porta K
● Rotinas de inicialização e comunicação
13. LCD + Dragon 12 + HCS12
● Utilizar as portas do HCS12 conforme
ligação da Dragon12
● PORTK(6:2) → Data
● PORTK(1) → Enable
● PORTK(0) → RS (data/cmd)
● Montar as rotinas de acordo com o
datasheet do HD44780
● Comunicação em 4 bits
14. Rotinas de acesso ao LCD
● Referencia para implementação das rotinas
● http://www.evbplus.com/hcs12_9s12_resources
/app_notes.html
● Apresenta 4 funções
● void initLcd(void)
● void writeLine(char *string, int line)
● void writeLcd8(unsigned char data, unsigned char rs)
● void writeLcd4(unsigned char data, unsigned char rs)
● void lcdDelay(unsigned long constant)
15. Rotinas de acesso ao LCD
void writeLcd4(unsigned char data, unsigned char rs)
{
unsigned char hi, lo;
/* split byte into 2 nibbles and shift to line up
* with data bits in port K */
hi = ((data & 0xf0) >> 2) | (rs & 0x01) ;
lo = ((data & 0x0f) << 2) | (rs & 0x01) ;
/* do write pulses for upper, then lower nibbles */
PORTK = hi; // write with EN=0
PORTK = hi | ENBIT; // write with EN=1
PORTK = hi; // write with EN=0
PORTK = lo; // write with EN=0
PORTK = lo | ENBIT; // write with EN=1
PORTK = lo; // write with EN=0
/* allow instruction to complete */
lcdDelay(DELAY40US);
} // end writeLcd4()
16. Rotinas de acesso ao LCD
void writeLcd8(unsigned char data) {
unsigned char temp;
/* shift upper nibble to data bits in port K */
temp = (data >> 2); // rs is always 0
/* Now do the EN pulsing */
PORTK = temp; // write with EN=0
PORTK = temp | ENBIT; // write with EN=1
PORTK = temp; // write with EN=0
/* allow instruction to complete */
lcdDelay(DELAY40US);
} // end writeLcd8()
17. Rotinas de acesso ao LCD
void lcdDelay(unsigned long constant) {
volatile unsigned long counter;
for(counter = constant; counter > 0; counter--);
} // end lcdDelay()
18. Rotinas de acesso ao LCD
void LCD_init(void) {
/* initialise port */
DDRK = 0xff;
writeLcd8(0x30); // tell it once
lcdDelay(DELAY4_1MS);
writeLcd8(0x30); // tell it twice
lcdDelay(DELAY100US);
writeLcd8(0x30); // tell it thrice
// last write in 8-bit mode sets bus to 4 bit mode
writeLcd8(0x20);
/* In 4 bit mode, write upper/lower nibble */
writeLcd4(0x28, 0); // 4-bit, 2 lines, 5x7 matrix
writeLcd4(0x0c, 0); // disp on, cursor & blink off
writeLcd4(0x01, 0); // display clear
writeLcd4(0x06, 0); // disable display shift
} // end initLcd()
19. Rotinas de acesso ao LCD
void writeLine(char *string, int line) {
int i;
unsigned char instruction;
/* Set address in LCD module */
if( 1 == line)
instruction = 0xc0; // write bottom line
else
instruction = 0x80; // write top line
writeLcd4( instruction, 0); // rs=0 means command
/* blast out 16 bytes */
for( i = 0; i < LCDWIDTH; i++) {
writeLcd4( string[i], 1); // rs=1 means data
}
} // end writeLine()
20. Criação de um driver
● Para a criação de um driver basta
encapsular estas funções num conjunto
organizado e de fácil acesso.
● Headers e defines
● A mudança do driver não deve gerar
nenhuma alteração no código da aplicação.
● A criação de um driver deve se concentrar
na função e não nos recursos do
dispositivo.
21. Padronização
● A forma de uso de um drivers é
extremamente ligada a seu dispositivo.
● Padronizar os diversos tipos de drivers
envolve conceder concessões e inserir um
overhead que pode ser prejudicial ao
sistema
● No entanto isto permite construir um
sistema para gerenciamento dos mesmos
22. Padronização
● É possível separar as funções de um
dispositivo em 3 modelos
● Inicialização
● Execução de serviço/funcionalidade
● Retorno de informação
● Função de acesso ao driver
23. Padronização
● As funções do tipo inicialização são
executadas antes de utilizar o dispositivo.
● Podem tomar muito tempo
● Fazem parte do “boot” do sistema
24. Padronização
● As funções de execução de serviços são as
funções que realizam as operações do
dispositivo
● Escrever no LCD, gerar um sinal de PWM,
enviar uma informação via serial
● Em geral são executadas rapidamente
podendo ser sequenciadas num processo
sem impactos na velocidade de execução
25. Padronização
● As funções de retorno de informação
devolvem valores obtidos pelos dispositivos
● Leitura de uma tecla, recepção de um valor via
serial
● Estas funções são eventuais e não
determinísticas.
● Por esse motivo é uma boa pratica não esperar
que elas aconteçam.
26. Padronização
● Para simplificar a padronização foi criado
um modelo com:
● Uma função de inicialização do driver
● Um vetor com ponteiros de função com cada
função de execução
● Um sistema de callback para cada evento de
resposta do dispositivo
● Uma função que retorna uma struct do
driver
28. Estruturas para a criação do driver
//Device Drivers Types (dd_types.h)
//ptr. de func. para uma função do driver
typedef char(*ptrFuncDrv)(void *parameters);
//estrutura do driver
typedef struct {
char drv_id;
ptrFuncDrv *drv_func;
ptrFuncDrv drv_init;
} driver;
//função de retorno do driver
typedef driver* (*ptrGetDrv)(void);
30. Driver genérico
#ifndef drvGenerico_h
#define drvGenerico_h
#include "dd_types.h"
//lista de funções do driver
enum {
GEN_PORTB, GEN_END
};
//função de acesso ao driver
driver* getGenericoDriver(void);
#endif // drvGenerico_h
31. Driver genérico
//(drvGenerico.c)
// implementação do driver em struct
// apresenta todas as funções do driver
static driver thisDriver;
//lista de funções que o driver contém
static ptrFuncDrv this_functions[GEN_END];
33. Driver genérico
//(drvGenerico.c)
//função para acesso ao driver
//deve inicializar a estrutura do driver
//e a lista de funções disponíveis
driver* getGenericoDriver(void) {
//função de inicialização
thisDriver.drv_init = initGenerico;
//funções do driver
this_functions[GEN_PORTB] = ChangePORTB;
//atualizando a referencia da lista
thisDriver.drv_func = &this_functions;
return &thisDriver;
}
Endereço da
função