ELT048 - SOE
Drivers
Rodrigo Almeida
Universidade Federal de Itajubá
Revisão
● Sistema de tempo real
● Requisitos temporais
Real time
● Capacidade de um
sistema em garantir
a peridiocidade de
uma tarefa
● Determinismo
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.
●
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
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;
}
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);
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;
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.
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
Rotina de inicialização do LCD
Esquemático LCD - Dragon12
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
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)
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()
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()
Rotinas de acesso ao LCD
void lcdDelay(unsigned long constant) {
volatile unsigned long counter;
for(counter = constant; counter > 0; counter--);
} // end lcdDelay()
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()
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()
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.
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
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
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
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
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.
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
Padronização
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);
Drive genérico
● Desenvolvimento de um drive que altera o
valor da portaB (LED's)
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
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];
Driver genérico
//(drvGenerico.c)
//funcionalidades implementadas
char changePORTB(void *parameters) {
PORTB = (char) parameters;
return FIM_OK;
}
//função para inicialização do hardware
char initGenerico(void *parameters) {
DDRB = 0xFF;
thisDriver.drv_id = (char) parameters;
return FIM_OK;
}
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
Exercício
● Desenvolver um driver para o LCD
utilizando o modelo proposto

Desenvolvimento de drivers para sistemas embarcados

  • 1.
    ELT048 - SOE Drivers RodrigoAlmeida Universidade Federal de Itajubá
  • 2.
    Revisão ● Sistema detempo real ● Requisitos temporais
  • 3.
    Real time ● Capacidadede um sistema em garantir a peridiocidade de uma tarefa ● Determinismo
  • 4.
    Requisitos temporais ● Paraimplementar 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árioum 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 //colocarno 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 //colocarno 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 umreló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: ● Displayde 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
  • 11.
  • 12.
  • 13.
    LCD + Dragon12 + 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 acessoao 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 acessoao 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 acessoao 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 acessoao LCD void lcdDelay(unsigned long constant) { volatile unsigned long counter; for(counter = constant; counter > 0; counter--); } // end lcdDelay()
  • 18.
    Rotinas de acessoao 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 acessoao 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 umdriver ● 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 formade 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ívelseparar 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çõesdo 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çõesde 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çõesde 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 simplificara 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
  • 27.
  • 28.
    Estruturas para acriaçã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);
  • 29.
    Drive genérico ● Desenvolvimentode um drive que altera o valor da portaB (LED's)
  • 30.
    Driver genérico #ifndef drvGenerico_h #definedrvGenerico_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çãodo 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];
  • 32.
    Driver genérico //(drvGenerico.c) //funcionalidades implementadas charchangePORTB(void *parameters) { PORTB = (char) parameters; return FIM_OK; } //função para inicialização do hardware char initGenerico(void *parameters) { DDRB = 0xFF; thisDriver.drv_id = (char) parameters; return FIM_OK; }
  • 33.
    Driver genérico //(drvGenerico.c) //função paraacesso 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
  • 34.
    Exercício ● Desenvolver umdriver para o LCD utilizando o modelo proposto