Relógio de tempo real
Registos RTC, formatos BCD, leituras coerentes e causas de interrupção.
Para ler 07:32:59, precisas de obter horas, minutos e segundos de registos diferentes. O RTC conserva a data e a hora com alimentação própria e continua a contar mesmo quando o computador está desligado; o timer usado para contar ticks mede apenas intervalos de execução. A hora do RTC pode datar uma partida; os ticks podem medir a sua duração.
Endereço e dados
O RTC tem registos internos. Para aceder a um deles, seleciona o índice pela porta 0x70 e transfere o valor pela porta 0x71. A porta de endereço também tem um bit relacionado com o controlo de NMI no PC; conserva a política exigida pelo ambiente em vez de o alterar sem intenção.
| Índice | Conteúdo |
|---|---|
0x00, 0x02, 0x04 | Segundos, minutos e horas |
0x01, 0x03, 0x05 | Campos do alarme |
0x07, 0x08, 0x09 | Dia do mês, mês e ano |
0x0A | Registo A, atualização e taxa periódica |
0x0B | Registo B, formatos e ativação de eventos |
0x0C | Registo C, causas de eventos |
0x0D | Registo D, validade da memória e hora |
Escrever 0x0A em 0x70 e ler 0x71 consulta A. Uma leitura de 0x71 sem selecionar antes o índice pode consultar o registo que outra operação deixou selecionado. Seleção e transferência formam uma operação lógica que deve ser protegida de acessos concorrentes segundo o ambiente. Para ler os segundos, por exemplo, escreve 0x00 em 0x70 e lê o valor em 0x71; para os minutos, repete com 0x02.
BCD e formato das horas
No registo B, DM, bit 2, seleciona binário quando vale 1 e BCD quando vale 0. O bit 1 seleciona 24 horas quando vale 1, ou 12 horas quando vale 0.
Em BCD, cada nibble representa um algarismo decimal. O valor 0x59 representa 59, não 89. A conversão é:
Para 0x59, o nibble alto vale 5 e o baixo vale 9, por isso o resultado é 10 vezes 5 mais 9, ou 59.
Esta fórmula assume dois algarismos BCD válidos. Um nibble acima de 9 é inválido. Em binário, 0x3B já representa 59 e não deve ser convertido por BCD.
No formato de 12 horas, o bit 7 do campo de horas marca PM, por isso retira-o antes de converter os algarismos. Para obter horas de 0 a 23, transforma 12 AM em 0 e soma 12 às horas PM depois de transformar 12 em 0. Assim, 12 AM dá 0, 12 PM dá 12 e 9 PM dá 21.
Não mudes o formato do RTC apenas para simplificar a leitura. Essa alteração afeta outros utilizadores do dispositivo e exigiria transformar os valores de tempo e alarme existentes.
Ler uma hora coerente
Os registos atualizam-se de forma assíncrona, por isso se leres os segundos de 07:32:59 e os minutos depois da passagem para 07:33:00, constróis 07:33:59, uma hora que o relógio nunca mostrou. Cada campo é válido isoladamente; a coerência exige que os campos pertençam à mesma atualização.
O registo A tem UIP, bit 7. O RTC assinala a atualização 244 µs antes de a começar e limpa UIP quando termina. Há por isso uma janela curta entre veres UIP a 0 e o início da escrita interna. Esperar UIP a 0 e depois ler os campos pressupõe que terminas antes da próxima atualização e que não és suspenso demasiado tempo durante a sequência.
Uma estratégia de polling reforça a coerência com repetição:
- Espera UIP a 0, com um limite de espera.
- Lê todos os campos e a configuração necessária para os interpretar; volta a consultar UIP e rejeita a leitura se estiver ativo.
- Repete a leitura a partir de UIP a 0.
- Aceita apenas duas fotografias consecutivas iguais e obtidas sem atualização assinalada; caso contrário, tenta novamente.
Esta estratégia depende de acessos curtos, de não haver outro programa a reconfigurar o relógio e de uma política de tentativas. Não dá ao programa controlo sobre os registos internos. Outra opção é usar a interrupção de fim de atualização e ler dentro do intervalo disponível antes da atualização seguinte.
O bit SET de B inibe atualizações para permitir escrever os campos de data e hora. Usá-lo descuidadamente para ler altera o funcionamento do dispositivo. Desativar interrupções num núcleo também não é uma solução universal para acessos concorrentes em vários núcleos.
Três causas, uma IRQ
O RTC pode produzir eventos periódicos, alarmes e fim de atualização. Todos usam IRQ8. B controla quais geram interrupções:
| Bit de B | Ativa |
|---|---|
| 6, PIE | Eventos periódicos |
| 5, AIE | Alarmes |
| 4, UIE | Fim de atualização |
A contém o seletor de taxa periódica. Para os valores usuais do seletor RS entre 3 e 15, a frequência é Hz. Por exemplo, RS = 6 dá 1024 Hz e RS = 15 dá 2 Hz. Preserva os bits superiores do registo ao alterar o seletor e não extrapoles a fórmula para os códigos especiais 0, 1 e 2.
O registo C assinala PF, AF e UF nos bits 6, 5 e 4. IRQF no bit 7 indica o pedido. Ler C limpa as causas assinaladas e permite que a linha deixe de manter esse pedido. Uma rotina que nunca lê C pode atender o primeiro evento e deixar de receber os seguintes.
Guarda o byte lido e testa cada causa com um if independente, porque com C = 0xD0 temos IRQF, PF e UF ativos e um else if trataria só um dos dois eventos. Os flags podem registar eventos mesmo quando a respetiva geração de interrupção está desativada; interpreta-os com a configuração aplicável.
Alarmes e validade
Os três campos de alarme comparam segundos, minutos e horas. Um campo com os dois bits superiores a 1 representa “qualquer valor”. Com hora e minuto indiferentes e segundos 0, o alarme coincide no início de cada minuto. Com os três campos indiferentes, coincide a cada segundo, se a geração de alarme estiver ativa.
O registo D tem VRT no bit 7. Se estiver a 0, a validade da memória e da hora é duvidosa, por exemplo após falha da alimentação de reserva. Converter bytes para uma data bem formada não prova que o relógio esteja certo.
Para alterar um bit de B, lê o valor anterior, modifica apenas a máscara pretendida e repõe-o quando terminares. Limpar PIE não deve mudar DM nem o formato de 12/24 horas. A limpeza final tem duas partes: desativar a causa no RTC e remover a subscrição no Minix.
Exercícios
Converter BCD e PM
O RTC está em BCD e formato de 12 horas. O byte de horas vale 0x89, com bit 7 a indicar PM. Qual é a hora em formato de 0 a 23?
Pista
Solução
0x89 contém PM e os algarismos BCD 09. Como é 9 PM, a conversão dá 9 + 12 = 21 horas. Não incluas o bit PM na conversão BCD.
Erros frequentes
Converter 0x89 inteiro como BCD ou tratar o byte como binário.
Atender causas simultâneas
O handler lê C e obtém 0xE0. Quais são as causas assinaladas e por que deve usar o byte guardado para as tratar?
Pista
Solução
IRQF está ativo e as causas são PF, periodic, e AF, alarm. UF não está ativo. A leitura de C limpa flags; reler C para decidir a segunda causa pode já não a mostrar. Guarda 0xE0 e usa if independentes para PF e AF.
Confere a tua resposta:
- Identifiquei PF e AF.
- Guardei o resultado da leitura de C.
- Usei testes independentes e expliquei o efeito de limpeza.
Erros frequentes
Tratar só uma causa com else if ou omitir a leitura de C e deixar o pedido ativo.
Reconstruir uma leitura impossível
A hora muda de 12:59:59 para 13:00:00. Lês horas antes da mudança e minutos e segundos depois. Que hora obténs e por que consultar UIP apenas uma vez pode não bastar?
Pista
Mais uma pista
O processo pode ser suspenso entre a consulta e as leituras.
Solução
Obténs 12:00:00, quase uma hora atrás da nova hora. Os campos pertencem a atualizações diferentes. UIP a 0 numa consulta anterior não impede uma atualização após suspensão do processo. Uma estratégia usa leituras completas repetidas e coerentes, ou uma leitura após fim de atualização, respeitando o intervalo de tempo disponível.
Confere a tua resposta:
- Construí uma hora que não corresponde ao instante real.
- Expliquei a atualização entre campos.
- Propus uma estratégia com hipóteses e repetição.
Erros frequentes
Supor que registos distintos são lidos como uma fotografia atómica ou que converter BCD resolve coerência.
Distinguir alarme e periodicidade
Em formato de 24 horas e BCD, os campos do alarme são hora 0xC0, minuto 0xC0 e segundo 0x30, com AIE ativo. Quando coincide o alarme? Isso equivale a configurar PIE para 2 Hz?
Pista
Solução
O alarme coincide no segundo 30 de cada minuto, qualquer que seja a hora. Não é PIE a 2 Hz: essa causa produz dois eventos periódicos por segundo, sem comparar campos do alarme. AF e PF permitem distinguir as causas no registo C.
Confere a tua resposta:
- Reconheci hora e minuto indiferentes.
- Obtive segundo 30 de cada minuto.
- Distingui AIE/AF de PIE/PF.
Erros frequentes
Converter 0xC0 como um número BCD ou tomar alarme repetido por frequência periódica.
Converter 12 AM para 24 horas
O RTC está em BCD e 12 horas. O byte de horas vale 0x12, sem bit PM. Qual é a hora em formato de 0 a 23?
Pista
Solução
Os algarismos BCD dão 12 e a ausência de PM indica AM. 12 AM transforma-se em 0. Sem esta regra, a leitura repetiria o 12 do meio-dia.
Erros frequentes
Converter 0x12 para 12 horas ou incluir um bit PM inexistente.