Fábio Pereira

Microcontroladores RL78 Guia Básico

1ª Edição

Versão 1.0

Joinville - SC Edição do Autor 2013

Microcontroladores RL78: Guia Básico 1

Copyright © 2013 Fábio Pereira Todos os direitos reservados.

É proibida a redistribuição, de forma parcial, do conteúdo deste livro ou arquivo eletrônico. A utilização parcial do material desta obra é condicionada a sua citação como fonte do conteúdo. Todas as marcas registradas, nomes ou direitos de uso citados neste livro pertencem aos seus respectivos proprietários. O autor acredita que todas as informações apresentadas nesta obra estão corretas e podem ser utilizadas para qualquer fim legal. Entretanto, não existe qualquer garantia implícita ou explícita, de que o uso de tais informações conduzirá sempre ao resultado esperado.

Acesse: www.perse.com.br para adquirir cópias impressas adicionais.

Material para download disponível em: www.sctec.com.br/blog

ISBN: 978-85-8196-334-1

2 Microcontroladores RL78: Guia Básico

Agradecimentos

Este é o meu nono livro e ele não teria sido possível sem a colaboração de algumas pessoas, por isso, os meus agradecimentos a: - André Machado de Oliveira, da Renesas do Brasil, pela amizade e incentivo (há anos) na utilização dos microcontroladores Renesas, além do suporte, ajuda na revisão do texto, sugestões, kits e apoio incondicional ao livro. - Huéliquis Fernandes, da Renesas do Brasil, pela amizade e grande apoio dado à viabilização deste livro e também por acreditar no meu trabalho. - Felipe Torrezan e Leonardo Carlos Afonso, da Renesas do Brasil, pelo apoio técnico, ajuda na revisão e suporte ao livro. - William Severino, da America, pelas sugestões iniciais e apoio dado ao livro. - Ritesh Tyagi, diretor da área de marketing de microcontroladores pelo apoio da Renesas Electronics America a edição deste livro. - José Carlos Nunes, da VLA, representante da Renesas no Brasil, pelo apoio dado ao livro, sugestões e amostras.

Dedicatória

Escrever um livro implica em centenas de horas de dedicação. Por isso, quero dedicar este livro a minha esposa Débora e agradecer pelo carinho, compreensão, apoio e por estar ao meu lado! Amo você!

Microcontroladores RL78: Guia Básico 3

Sobre o Autor

Fábio Pereira é técnico em Eletrônica (CEFET-PR), bacharel em Direito (ACE-SC), especialista em projeto de equipamentos eletrônicos (CEFET-SC) e autor de outros oito livros na área de programação de microcontroladores (sete deles em português e um em inglês). Também atuou como professor de disciplinas relacionadas a microcontroladores e programação em C em cursos técnicos e universidades na região de Joinville e atualmente trabalha como advogado e nas horas vagas mantém o seu blog FPB (www.sctec.com.br/blog) além de desenvolver projetos de sistemas embarcados. Ao longo dos últimos 20 anos, desenvolveu diversas aplicações utilizando diferentes plataformas tais como 8051, ARM, AVR, Cortex, Coldfire, HC908, HCS08, MSP430, PIC, RL78, Z8-Encore, Z-80 em diferentes linguagens como Assembly, BASIC, C e Pascal. Outros livros do autor: ® Microcontroladores PIC: Técnicas Avançadas; ® Microcontroladores PIC: Programação em C; ® Microcontroladores HC908Q: Teoria e Prática; ® Microcontroladores MSP430: Teoria e Prática; ® Microcontroladores HCS08: Teoria e Prática; ® Tecnologia ARM: Microcontroladores de 32 bits; ® HCS08 Unleashed: Designer’s guide to the HCS08 ; ® Microcontrolador PIC18 Detalhado : Hardware e Software. Para entrar em contato com o autor, acesse o blog: www.sctec.com.br/blog

4 Microcontroladores RL78: Guia Básico

Sobre a Renesas

Renesas é uma empresa japonesa na área de eletrônica e foi fundada em 2003 como uma joint venture entre a Hitachi e a Mitsubishi Electric, ambas gigantes japonesas com grande atuação na área da eletrônica. Em 2010 a NEC Electronics Corporation juntou-se à Renesas e trouxe com ela a sua linha de microcontroladores e microprocessadores (expandindo ainda mais a já ampla linha de MCUs e MPUs da Renesas). A linha de produtos fabricados pela Renesas é digna do peso dos três principais sócios da empresa: vai de microcontroladores 8 bits de baixo custo (como os 78K0 desenvolvidos pela NEC e H8 desenvolvidos pela Hitachi), passando pelos microcontroladores de 16 bits (H8, e M16C desenvolvidos pela Hitachi, 78K0R desenvolvidos pela NEC e RL78 da Renesas), microcontroladores de 32 bits (como o R32C, RX e RH850 da Renesas, desenvolvido pela NEC e os SuperH desenvolvidos pela Hitachi), até microprocessadores SoC de alta performance para os mercados móveis e automotivos (utilizando múltiplos núcleos ARM, Cortex e SuperH). Além dos MCUs e MPUs a Renesas fabrica diversos outros semicondutores como integrados LSI, ASSP, Displays, IGBTs, MOSFETs, etc. A Renesas foi o quinto maior fabricante de semicondutores nos anos de 2010 e 2011 e o primeiro em venda de microcontroladores no mesmo período. A participação da Renesas no mercado mundial de microcontroladores é de aproximadamente 28%, com vendas anuais de mais de 4 bilhões de dólares. A empresa possui diversos escritórios ao redor do mundo. No Brasil, a presença da empresa vem crescendo, com um escritório em São Paulo e investimentos em divulgação e ampliação da margem local de mercado.

Microcontroladores RL78: Guia Básico 5

6 Microcontroladores RL78: Guia Básico

Índice

1. Introdução ...... 13 1.1. Uma Breve História da Computação ...... 13 1.2. Sistemas Embarcados ...... 17 1.3. Conceitos Básicos...... 18 1.4. Microcontroladores RL78...... 30 1.5. Pinagens e Encapsulamentos ...... 32 1.6. R5F100LEA ...... 35 1.7. Kits e Ferramentas de Programação ...... 36 1.8. Convenções Utilizadas ...... 38

2. Ferramentas de Programação ...... 41 2.1. O Ambiente Embedded Workbench EWRL78...... 41 2.1.1. Criando o Primeiro Projeto ...... 41 2.1.2. Simulando um Programa...... 46 2.1.3. Depurando um Programa ...... 51 2.1.4. Gerando o Código Final ...... 52

3. Arquitetura e Modelo de Programação ...... 55 3.1. A CPU RL78 ...... 55 3.1.1. Registradores Especiais da CPU ...... 56 3.1.1.1. Registrador PSW...... 57 3.1.1.2. Registrador PC...... 58 3.1.1.3. Registrador SP ...... 58 3.1.1.4. Registradores ES e CS ...... 60 3.1.1.5. Registrador PMC ...... 60 3.1.2. Mapa de Memória ...... 61 3.1.3. Modos de Endereçamento ...... 63 3.2. Conjunto de Instruções Assembly ...... 65 3.2.1. Instruções de Manipulação de Dados...... 65 3.2.2. Instruções Aritméticas, Lógicas e de Comparação...... 66 3.2.3. Instruções de Incremento e Decremento ...... 68 3.2.4. Instruções de Rotação e Deslocamento de Bits...... 68 3.2.5. Instruções de Manipulação e Processamento de Bits ...... 71 3.2.6. Instruções de Desvio ...... 71

Microcontroladores RL78 Guia Básico 7

3.2.7. Instruções para Sub-rotinas e Funções...... 72 3.2.8. Instruções de Pulo Condicional...... 73 3.2.9. Instruções de Controle da CPU...... 73 3.2.10. Temporização das Instruções ...... 74 3.3. Módulo OCD e Código de Segurança (Security ID) ...... 74 3.4. Configurações do Chip...... 76

4. Suporte à CPU ...... 81 4.1. Reset...... 81 4.2. Sistema de Clock...... 83 4.2.1. Oscilador X1...... 84 4.2.2. Oscilador XT1...... 85 4.2.3. Oscilador Interno de Alta Frequência ...... 86 4.2.4. Oscilador Interno de Baixa Frequência...... 87 4.2.5. Registradores do Sistema de Clock...... 87 4.2.6. Exemplo...... 91 4.3. Gerenciamento de Energia ...... 92 4.3.1. Modo Halt...... 93 4.3.2. Modo Stop...... 93 4.3.3. Modo Snooze ...... 94 4.3.4. Gerenciamento de Clock...... 95 4.3.5. Dicas para Reduzir o Consumo de Energia...... 96 4.3.6. Exemplo...... 96 4.4. Clock/Buzzer Output...... 98 4.4.1. Exemplo...... 99 4.5. Detector de Baixa Tensão...... 100 4.5.1. Modo Reset...... 100 4.5.2. Modo Interrupção...... 101 4.5.3. Modo Interrupção e Reset...... 101 4.5.4. Registradores do LVD ...... 102 4.6. Watchdog (WDT)...... 104 4.6.1. Exemplo...... 106 4.7. Regulador Interno de Tensão...... 108

5. Portas de Entrada e Saída...... 109

8 Microcontroladores RL78: Guia Básico

5.1. Registradores das Portas de E/S ...... 110 5.2. Redirecionamento de Funções...... 116 5.3. Exemplo...... 117

6. Sistema de Interrupções ...... 120 6.1. Categorias de Interrupções ...... 122 6.2. Sistema de Interrupções do RL78...... 122 6.2.1. Sistema de Prioridades de Interrupção ...... 126 6.2.2. Latência de Interrupção...... 128 6.2.3. Utilizando os Bancos de Registradores dos RL78...... 129 6.3. Interrupções Externas ...... 130 6.3.1. Exemplo ...... 132 6.4. Interrupção de Teclado ...... 133 6.4.1. Exemplo ...... 133

7. Periféricos de Temporização...... 135 7.1. Timer de Intervalo (IT)...... 136 7.1.1. Exemplo ...... 137 7.2. RTC ...... 138 7.2.1. Configuração do RTC ...... 140 7.2.2. Registradores do RTC...... 141 7.2.3. Ajuste do RTC...... 145 7.2.4. Exemplo ...... 146 7.3. TAU...... 148 7.3.1. Visão Geral de uma Unidade TAU ...... 149 7.3.2. Operação em Modo Timer/Gerador de Onda Quadrada ...... 151 7.3.3. Operação no Modo Gerador de Atraso/Disparo Único ...... 154 7.3.4. Operação em Modo Contador de Eventos...... 156 7.3.5. Operação como Divisor de Frequência ...... 157 7.3.6. Operação no Modo de Captura de Período...... 158 7.3.7. Operação no Modo de Captura de Ciclo ...... 159 7.3.8. Operação no Modo de Pulso Configurável ...... 160 7.3.9. Operação em Modo PWM...... 164 7.3.10. Registradores das TAU ...... 167 7.4. Outros Timers...... 175

Microcontroladores RL78 Guia Básico 9

8. Periféricos de Analógicos ...... 177 8.1. Detalhes Gerais do Conversor A/D ...... 177 8.2. Modos de Operação...... 183 8.2.1. Conversão Simples ou Múltipla...... 183 8.2.2. Conversão de Um Canal ou Varredura de Canais...... 184 8.2.3. Formas de Disparo do Conversor...... 184 8.2.3.1. Disparo por Software...... 185 8.2.3.2. Disparo por Hardware ...... 185 8.3. Referência Interna de Tensão ...... 186 8.4. Sensor de Temperatura...... 186 8.5. Operação em Modo Snooze...... 187 8.6. Registradores do ADC...... 188 8.7. Exemplo ...... 191 8.8. Outros Periféricos Disponíveis...... 192 8.8.1. Comparador Analógico...... 192 8.8.2. Conversor A/D de 12 bits...... 192 8.8.3. Conversor D/A...... 192

9. Periféricos de Comunicação...... 193 9.1. Unidades SAU...... 193 9.1.1. Registradores das SAU ...... 196 9.1.2. Modo UART ...... 203 9.1.2.1. Configuração do Baud Rate...... 205 9.1.2.2. Operação em Modo Snooze...... 208 9.1.2.3. LIN...... 208 9.1.2.4. API Applilet ...... 208 9.1.2.5. Exemplo ...... 209 9.1.3. Modo CSI...... 211 9.1.3.1. Configuração do Baud Rate...... 214 9.1.3.2. API Applilet ...... 215 9.1.4. Modo I 2C...... 216 9.1.4.1. I 2C Simplificado na SAU ...... 218 9.1.4.2. Configuração do Baud Rate...... 221 9.1.4.3. Comunicação I 2C...... 221 9.1.4.4. API Applilet ...... 223 9.2. Unidades IICA (I 2C)...... 224 9.2.1. Operação da IICA ...... 225 9.2.2. API Applilet...... 226 9.2.3. Registradores IICA ...... 228

10 Microcontroladores RL78: Guia Básico

10. Tópicos Avançados ...... 233 10.1. Ajuste BCD ...... 233 10.2. Funções de Segurança ...... 234 10.2.1. Checagem de CRC da Flash...... 235 10.2.2. Checagem de Paridade da RAM ...... 236 10.2.3. Bloqueio de Registradores e da RAM...... 237 10.2.4. Execução de Opcode Ilegal (Trap)...... 238 10.2.5. Acesso Ilegal à Memória (IAW) ...... 238 10.2.6. Verificação do A/D ...... 238 10.2.7. Verificação do Clock...... 238 10.3. CRC de Uso Geral ...... 239 10.4. Gravação e Apagamento da Flash e DataFlash...... 240 10.4.1. FSL...... 240 10.4.1.1. Utilização da FSL ...... 245 10.5. Hardware de Multiplicação e Divisão ...... 251 10.6. DMA...... 253 10.6.1. Registradores dos Canais de DMA ...... 256 10.6.2. Exemplo ...... 259 10.7. Otimizando Aplicações para o RL78...... 261 10.7.1. Tamanho do Dado...... 261 10.7.2. Endereçamento Rápido ...... 262 10.7.3. Campos de Bit...... 262 10.7.4. Funções CALLT...... 263 10.8. Utilizando o Applilet3 ...... 264 10.8.1. Configuração do Timer de Intervalo ...... 266 10.8.2. Configuração da UART ...... 269

11. Exemplos de Aplicação...... 271 11.1. Utilização de Módulos LCD Alfanuméricos ...... 271 11.2. Mostrador Analógico no LCD...... 278 11.3. Termômetro Digital ...... 281 11.4. Medidor de Distância por Ultrassom...... 284

12. Tabela ASCII ...... 289

Microcontroladores RL78 Guia Básico 11

12 Microcontroladores RL78: Guia Básico

1

Introdução 1. Introdução

O objetivo deste livro é apresentar a família RL78 de microcontroladores da Renesas, com ênfase nos modelos RL78/G13. Antes de nos dedicarmos ao estudo deles é importante conhecer um pouco da história da computação digital, além de revisar conceitos cruciais na área da eletrônica digital e lógica de programação.

1.1. Uma Breve História da Computação

As primeiras máquinas de computação de que se tem notícia datam de 1623 (a máquina de cálculos de Wilhelm Schickard) e 1642 (a máquina Pascaline de Blaise Pascal). Ambas eram totalmente mecânicas e utilizavam intrincados mecanismos para realizar operações de adição. Em 1671, o matemático e filósofo alemão Gottfried Von Leibniz desenhou a Staffelwalze (também conhecida como “Stepped Reckoner” ou calculadora de passos), a primeira calculadora mecânica capaz de realizar as quatro operações básicas da matemática (adição, subtração, multiplicação e divisão).

Figura 1.1 – Pascaline Figura 1.2 – Stepped Reckoner Fonte: http://fr.wikipedia.org/wiki/Fichier:Arts_et_Metiers_Pascaline Fonte:http://en.wikipedia.org/wiki/File:Leibniz_Stepped_Reckoner.png _dsc03869.jpg Todas essas máquinas eram apenas calculadoras mecânicas e não podiam ser programadas para executar operações predefinidas. As primeiras máquinas programáveis surgiram no início do século XIX e eram muito diferentes do conceito atual de um computador. O tear Jacquard (criado por Joseph Marie Jacquard em 1801) é provavelmente a primeira máquina passível de ser programada pelo usuário. Utilizando cartões de papel perfurados, era possível programar complexos padrões a serem tecidos, aumentando drasticamente a flexibilidade dos teares, que até então somente podiam tecer um mesmo padrão. Isso permitiu que um mesmo tear fosse utilizado para produzir diferentes padrões de tecidos.

Introdução 13

Alguns anos depois (1837), Charles Babbage desenhou a sua “Analytical Engine” (máquina analítica) que seria provavelmente o primeiro computador totalmente programável se ela tivesse sido realmente construída.

Figura 1.3 - Tear Jacquard. Figura 1.4 – Cartões perfurados para programação Fonte: http://commons.wikimedia.org/wiki/Image:Jacquard.loom. do tear Jacquard. Fonte: http://en.wikipedia.org/ full.view.jpg wiki/File:Jacquard.loom.cards.jpg O grande progresso da computação ocorreu com o advento das “Tabulating ” (máquinas de tabular) de Herman Hollerith (manufaturadas pela “Computing Tabulating Recording Corporation”, que algum tempo depois originou a IBM). As máquinas de tabular de Hollerith também utilizavam cartões de papel perfurados e permitiram que o censo Norte-Americano de 1890 fosse completado em apenas dezoito meses (o censo anterior, de 1880, foi completado em sete anos!). Essas máquinas não eram programáveis, mas foram um passo importante na direção dos computadores programáveis. Em 1941, no Iowa State College, o pesquisador John Vincent Atanasoff projetou e construiu o Atanasoff-Berry Computer (ABC), primeiro computador eletrônico norte-americano. Ele foi projetado especificamente para auxiliar na resolução de equações lineares e, apesar de não ser programável nem ser máquina Turing completa, o ABC apresentou alguns conceitos importantes: • Sistema organizado com unidades separadas de computação e de memória (como nos computadores atuais). • Memória capacitiva regenerativa com aproximadamente 3.200 capacitores organizados em dois tambores, cada um com 32 bandas de 50 capacitores (duas bandas não eram utilizadas e ficavam como reserva), resultando numa capacidade total de armazenamento de 60 números de 50 bits. Esse sistema de regeneração foi o precursor dos sistemas de refresh das memórias DRAM atuais e funcionava rotacionando os tambores num eixo com pinças para acesso aos dados.

14 Microcontroladores RL78: Guia Básico

• Unidade lógica e aritmética (ULA) totalmente eletrônica construída com uso de cerca de 280 válvulas a vácuo. • O sistema de I/O era composto de um sistema primário e um sistema secundário para resultados intermediários (utilizado quando os problemas sendo resolvidos excediam a capacidade de armazenamento da memória eletrônica interna). O primeiro computador digital (e binário) totalmente programável foi o Z3, projetado e construído pelo engenheiro alemão Konrad Zuse em 1941.

Esse comp utador utilizava cerca de 2.000 relés no papel de chaves, portanto era eletromecânico. O programa era armazenado externamente numa fita perfurada, permitindo que diferentes programas fossem executados com relativa facilidade. O Z3 possuía em seu conjunto d e instruções praticamente todas as Figura 1.5 - Zuse Z3. funcionalidades encontradas nos computadores Fonte:http://www.computerhistory.org/timeline/images/1941_zuse_z3_ modernos, com exceção das instruções de large.jpg desvio (que foram implementadas posteriormente no microcódigo para cálculos em ponto flutuante). Em 1943, os pesquisadores do Post Office Research Station em Dollis Hill (Inglaterra) apresentaram o protótipo de um dos primeiros computadores eletrônicos: o Colossus Mark 1. Esse computador (na verdade a sua segunda geração, Colossus Mark 2) foi utilizado para auxiliar na decodificação das mensagens alemãs criptografadas durante a Segunda Guerra Mundial. Outro famoso computador dessa era foi o ENIAC (Electronic Numerical Integrator And Computer), um computador eletrônico projetado e construído pelo Laboratório de Pesquisa Balística do Exército Norte-Americano, em 1946, para auxiliar no cálculo de tabelas de artilharia e outros problemas matemáticos complexos (como os relacionados ao projeto das primeiras bombas atômicas). O ENIAC era um computador enorme, composto p or milhares de válvulas eletrônicas, diodos de cristal e relés. Possuía registradores decimais de dez dígitos e operava com clock de 100kHz, consumindo cerca de 174kW em operação. Uma de suas grandes fraquezas era o sistema de armazenamento do programa, qu e era realizado pela interligação de fios no interior do computador. Sendo assim, qualquer alteração implicava esforço considerável. Em 1948, alguns melhorame ntos foram Figura 1.6 - ENIAC. Fonte: adicionados ao ENIAC; o mais importante foi um http://en.wikipedia.org/wiki/Image:Classic_shot_of_the_ENIAC.jpg

Introdução 15

dispositivo de leitura de programa utilizando tabelas de funções (proposto pelo matemático John von Neumann). Esse mecanismo funcionava como uma ROM (Read-Only Memory ou memória somente de leitura) de programa primitiva. Outro computador famoso e importante foi o ASCC (Automatic Sequence Controlled Calculator - calculadora automática de sequência controlada) da IBM (também conhecido como IBM Mark I), projetado por Howard H. Aiken da Universidade de Harvard e construído pela IBM em 1944. Ele foi o primeiro computador totalmente automático e que funcionava de forma muito semelhante aos computadores modernos. O ASCC era um computador eletromecânico e possuía memórias separadas para o armazenamento das instruções do programa e os dados. Essa arquitetura ficaria conhecida como “arquitetura Harvard”. Já o IBM SSEC (Selective Sequence Electronic Calculator - calculadora eletrônica de sequência seletiva), construído em 1948, implementava outra abordagem para a sua arquitetura interna: um espaço de memória unificado onde são armazenadas tanto as instruções quanto os dados. Essa arquitetura ficou conhecida como “Von Neumann” ou Princeton, em homenagem ao matemático John von Neumann da Universidade de Princeton (EUA), ainda que John Presper Eckert (um dos homens por trás do projeto do ENIAC) tenha proposto a mesma arquitetura anos antes de Von Neumann. Essas duas arquiteturas de computadores (Von Neumann e Harvard) ainda estão em uso mesmo nos mais modernos computadores da atualidade. A Figura 1.7 mostra os diagramas simplificados dessas duas arquiteturas. A arquitetura Von Neumann (também chamada Princeton) caracteriza-se por utilizar três barramentos de comunicação que são compartilhados pela memória e E/S, um para o endereçamento (seleção da posição a ser lida ou escrita), um para o controle (seleção do tipo de operação a ser realizada) e outro para dados (que carrega a informação propriamente dita). A arquitetura Harvard, por sua vez, utiliza conjuntos de barramentos separados para as memórias e E/S, diferenciando ainda entre memória de programa (onde ficam armazenados as instruções do programa) e de dados (onde ficam os dados utilizados pelo programa).

Endereço (programa) Endereço Memória Dados (programa) Memória de Programa/ Controle (programa) Programa Dados Endereço (dados) Controle CPU Dados (dados) Memória de CPU Controle (dados) Dados

Endereço (periféricos) Periféricos Dados (periféricos) Dados Periféricos Controle (periféricos)

Arquitetura Von Neumann (Princeton) Arquitetura Harvard Figura 1.7

Cada arquitetura apresenta prós e contras: Von Neumann oferece mais flexibilidade, pois não faz distinção entre instruções e dados. Por outro lado, ela impõe uma única largura para o barramento de dados, implicando que uma CPU de 8 bits busque instruções de 8 ou múltiplos de

16 Microcontroladores RL78: Guia Básico

8 bits. Outro ponto fraco da arquitetura Von Neumann é um problema conhecido como “gargalo de Von Neumann”, causado pela capacidade limitada de transferência de dados da memória, quando comparada à necessidade da CPU de acessar a memória para leitura de instruções e a leitura/escrita de dados. Apesar de todos os problemas impostos por essa arquitetura, ela ainda é vastamente utilizada pela maioria dos computadores atuais e dos microprocessadores e microcontroladores no mercado. Na arquitetura Harvard, a velocidade é o benefício mais relevante do arranjo de múltiplos barramentos: enquanto executa uma instrução, a CPU pode ler e escrever dados na memória de dados e simultaneamente buscar a próxima instrução na memória de programa. Neste caso, os prós e contras se misturam devido à distinção entre a memória de programa e de dados: normalmente não é possível ter dados na memória de programa ou instruções na memória de dados. Algumas máquinas Harvard incluem instruções especiais que permitem o acesso à memória de programa para leitura/escrita de dados. Outras implementam áreas especiais de memória compartilhadas por instruções e dados. Além das arquiteturas de projeto citadas, existem também dois diferentes conceitos básicos de projeto do conjunto de instruções de um processador: o conceito CISC e o conceito RISC. O conceito CISC (computador com conjunto complexo de instruções) defende que a máquina possua uma grande quantidade de instruções (normalmente acima de 100), capazes de desempenhar as mais diferentes tarefas. Máquinas CISC normalmente possuem instruções complexas que realizam uma série de operações. Já o conceito RISC (computador com conjunto reduzido de instruções) defende que a máquina possua um conjunto pequeno de instruções, mas que devem ser executadas rapidamente. Máquinas RISC normalmente possuem instruções simples e rápidas e necessitam de múltiplas instruções para realizar operações mais complexas. Normalmente encontramos máquinas RISC associadas à arquitetura Harvard, ao passo que as máquinas CISC normalmente utilizam a arquitetura Von Neumann.

1.2. Sistemas Embarcados

A aplicação de computadores em dispositivos móveis ou capazes de ser movidos resultou em uma geração totalmente diferente de computadores e originou o termo “” ou sistema embarcado. Um dos primeiros sistemas embarcados de que se tem notícia foi o Apollo Guidance Computer, ou AGC. Ele foi um computador (na verdade um microcomputador) de 16 bits (15 de dados mais um de paridade), que operava a 1,024MHz e que possuía 2.048 words de memória RAM e 36.864 words de memória de programa. Este microcomputador foi um dos primeiros computadores digitais a utilizar circuitos integrados e foi utilizado para o controle das espaçonaves Apollo (que em diversas missões nas décadas de 60 e 70, levaram o homem à Lua). Ele também possuía uma IHM (Interface Homem Máquina) composta de um teclado numérico e displays eletroluminescentes, através da qual os astronautas podiam operá-lo, inserir

Introdução 17

e visualizar dados, executar comandos e programas e até mesmo reprogramá-lo (como aconteceu na missão Apollo 14).

A – Módulos AGC e DSKY B – Módulo DSKY. Fonte:http://www.computerhistory.org/timeline/images/ Fonte: http://en.wikipedia.org/wiki/File:Agc_view.jpg 1968_apollo.jpg Figura 1.8

O AGC utilizava a primeira geração de circuitos integrados (portas NOR duplas com 3 entradas cada e implementadas utilizando tecnologia RTL – Resistor Transistor Logic), mas foi o advento do microprocessador (o 4004 desenvolvido pela Intel em 1971) e posteriormente do microcontrolador (o TMS1000 desenvolvido pela Texas Instruments em 1971 e lançado em 1974) que permitiu que os sistemas embarcados pudessem ser barateados e terem reduzidos drasticamente o seu tamanho físico e o consumo de energia (todos fatores importantes quando se fala em sistemas embarcados). Atualmente os microcontroladores e o termo “sistema embarcado” possuem uma aplicação muito ampla, sendo utilizados em equipamentos simples (como torradeiras, cafeteiras, etc.) até complexos (como equipamentos médicos, smartphones, GPS, etc.).

1.3. Conceitos Básicos

Eletrônica é a ciência que estuda e aplica a eletricidade (o movimento de cargas elétricas) aos componentes (resistores, capacitores, indutores, semicondutores etc.) para construir circuitos complexos que podem interagir com o ambiente ou com os seres humanos. De cafeteiras a TVs LCD, de lâmpadas elétricas a smartphones, de relógios de pulso a tablets e computadores, interagimos diariamente com um grande número de diferentes dispositivos elétricos e eletrônicos, alguns dos quais são tão pequenos ou simples que sequer nos damos conta da sua existência. Dentro do universo da eletrônica, uma das áreas mais interessantes e que movimenta o mercado é a dos microprocessadores e microcontroladores, pequenos chips que incluem internamente praticamente toda a eletrônica necessária para construir máquinas e dispositivos dotados de alguma forma de inteligência. A base por trás dos microcontroladores e microprocessadores é a eletrônica digital. Para melhor entendê-la, é necessária uma breve reflexão sobre como o universo funciona.

18 Microcontroladores RL78: Guia Básico

O mundo é analógico: a temperatura de uma sala, a intensidade da luz, o tempo, as dimensões físicas de uma caixa, o som, a distância entre casas e trabalhos, tudo isso é medido por grandezas analógicas. Elas podem ser medidas utilizando algum tipo de unidade de medição e podem variar consideravelmente (imagine que nada no mundo é exatamente igual; mesmo os mecanismos produzidos pela máquina mais precisa serão ligeiramente diferentes se medidos com a devida precisão). Por outro lado, os computadores modernos são máquinas eminentemente binárias. Eles somente podem reconhecer dois tipos de informação: 0 (falso) ou 1 (verdadeiro). As imagens, filmes e cores que vemos na tela de um computador ou em filme em DVD, a música que ouvimos de um CD player ou de um MP3 player, tudo isso pode ser reduzido somente a zeros e uns. As razões para utilizar um sistema binário (digital) em vez de um sistema analógico são muito simples: 1. Por existirem somente dois níveis de tensão, é mais simples projetar os circuitos eletrônicos de computadores digitais. A utilização de transistores como chaves permite obter dois níveis distintos de tensão (0V para chave aberta ou falso e 5V para chave fechada ou verdadeiro). 2. A matemática por trás dos modernos computadores é baseada na álgebra booleana, criada por George Boole (um matemático e filósofo inglês que viveu no século XVIII e que criou a álgebra booleana, baseada em dois estados: verdadeiro e falso). Vemos então que os computadores utilizam a base binária, ao passo que nós, seres humanos, utilizamos a base decimal, constituída de 10 diferentes símbolos (0 a 9) e adotada em virtude de possuirmos 10 dedos nas mãos (as mãos foram o primeiro instrumento de cálculo na história da humanidade), mas além dessas duas bases, existem outras bases numéricas importantes, entre elas a octal (que utiliza 8 diferentes símbolos, de 0 a 7) e hexadecimal (base 16 diferentes símbolos, de 0 a 9, A, B, C, D, E, F). A base hexadecimal permite representar diretamente um valor binário utilizando poucos dígitos. Ela foi muito importante nos primórdios da computação, pois permitia que os sistemas de apresentação de dados utilizassem displays com poucos dígitos, assim como os teclados também eram mais fáceis de construir (displays eram itens complexos e caros até a década de 80, foi somente com a invenção dos LEDs e posteriormente dos displays LED que houve uma redução significativa no custo dos mesmos). A facilidade de representação de valores binários em hexadecimal é oriunda do processo de conversão, que é absolutamente simples e intuitivo (o mesmo não ocorre com binário e decimal, por exemplo). Para entender a razão desta simplicidade, vejamos como funciona o sistema de bases numéricas. Primeiramente, é importante observar que em qualquer base numérica existem dígitos e através da junção de múltiplos dígitos é que se pode representar uma quantidade arbitrária qualquer. O primeiro dígito (o menos significativo) em qualquer base tem sempre o peso 1. Ele corresponde a base elevada a potência 0. O dígito de magnitude imediatamente superior é o da

Introdução 19

base elevada a potência 1 e assim por diante. Os pesos das diferentes posições nas bases numéricas podem ser vistos na tabela 1.2. Binário Decimal Hexadecimal 0000 0 0 0001 1 1 0010 2 2 0011 3 3 0100 4 4 0101 5 5 0110 6 6 0111 7 7 1000 8 8 1001 9 9 1010 10 A 1011 11 B 1100 12 C 1101 13 D 1110 14 E 1111 15 F Tabela 1.1

Peso 3 2 1 0 Binário 23=8 22=4 21=2 20=1 Decimal 10 3=1000 10 2=100 10 1=10 10 0=1 Hexadecimal 16 3=4096 16 2=256 16 1=16 16 0=1 Tabela 1.2

Seguindo a tabela 1.2, o número 1001 binário equivale a 1*8 + 0*4 + 0*2 + 1*1 = 9 decimal, o número 1001 decimal equivale a uma milhar (1*1000) mais uma unidade (1*1) e o número 1001 hexadecimal equivale a 1*4096 + 1*1 = 4097 decimal. É fácil perceber que com dois dígitos binários podemos representar até 4 diferentes valores (00, 01, 10 e 11), com dois dígitos decimais podemos representar até 100 diferentes valores (de 0 a 99) e com dois dígitos hexadecimais podemos representar até 256 valores (de 0 a FF). Mas além da simplificação da representação de dados (em termos de redução no número de dígitos), a base hexadecimal oferece ainda a facilidade adicional de permitir a simples e rápida conversão de/para binário. Tudo o que é necessário é agrupar os dígitos binários em nibbles (conjuntos de 4 bits) e em seguida realizar diretamente a conversão de/para hexadecimal. Vejamos alguns exemplos: 01000010 em binário pode ser separado em 0100 e 0010, 0100 equivale a 4 hexadecimal, 0010 equivale a 2 hexadecimal, então 01000010 binário equivale a 42 hexadecimal. 10100110 em binário, 1010 equivale a A hexadecimal, 0110 equivale a 6 hexadecimal, então 10100110 binário equivale a A6 hexadecimal. A recíproca também é

20 Microcontroladores RL78: Guia Básico

verdadeira: 7B hexadecimal, 7 hexadecimal equiva e 0111 binário e B hexadecimal equivale a 1011 binário, então 7B hexadecimal equivale a 01111011 binário! A aritmética, em qualquer que seja a base, também é baseada em princípios comuns e deve sempre levar em consideração a quantidade de símbolos únicos existentes na base, para cada posição numérica. Assim, a soma de 7 + 5 em decimal é feita agrupando os dígitos de magnitude equivalente. Nos casos onde não há dígito para representar a magnitude desejada, ocorre o transporte para a próxima posição: 7 + 5 12 No caso, a adição de 7 com 5, resulta que não há um símbolo decimal único para representar a grandeza, por isso, há um transporte para a próxima posição. Nas operações em outras bases (seja binário, hexadecimal, etc.), o procedimento é exatamente o mesmo. Vejamos a adição dos valores binários 10 + 10: 10 + 10 100 Outro exemplo, desta vez em hexadecimal. Vejamos a adição de 9 + 9: 9 + 9 12 Quando se realiza operações aritméticas envolvendo bytes (conjuntos de 8 bits), diz-se que ocorre um transporte (carry em inglês) quando há um transporte binário do bit 7 (o oitavo bit do byte). No caso das operações de subtração, utiliza-se basicamente o mesmo princípio da adição e os circuitos somadores, no entanto, para a subtração, faz-se a soma do minuendo com subtraendo, sendo este escrito com sinal inverso: 10 10 - + 4 é o mesmo que -4 6 6 Isto permite que as unidades lógicas e aritméticas dos microprocessadores e microcontroladores possam realizar operações de subtração a partir de um circuito somador. Para isso, utiliza-se uma representação binária chamada de “complemento de dois”, que consiste no complemento (inversão de todos os bits) e a adição de um. Assim, para obtermos o equivale a -4, utilizamos o valor absoluto 4 para obter o complemento de dois conforme abaixo: Valor absoluto (4) 0 0 0 0 0 1 0 0 Complemento 1 1 1 1 1 0 1 1 + 1 0 0 0 0 0 0 0 1 Resultado 1 1 1 1 1 1 0 0 Para realizar a operação 10-4 podemos, através de uma adição (8 bits), fazer:

Introdução 21

10 0 0 0 0 1 0 1 0 + -4 1 1 1 1 1 1 0 0 Resultado 0 0 0 0 0 1 1 0 A representação em complemento de dois também é utilizada nas operações com números sinalizados (como os signed char e signed int em C). Neste caso, o bit mais significativo (aquele mais à esquerda) representa o sinal (0 = positivo e 1 = negativo), enquanto que os demais bits representam a magnitude do número. Assim, a representação binária de 8 e 16 bits em complemento de dois segue a seguinte forma: sinal Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 sinal Bit 14 Bit 13 Bit 12 Bit 11 Bit 10 Bit 9 Bit 8 Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 Figura 1.9 A tabela a seguir mostra uma escala reduzida dos valores decimais de 8 bits sinalizados e a sua representação binária em complemento de dois. Decimal Binário 127 01111111 126 01111110 ...... 2 00000010 1 00000001 0 00000000 -1 11111111 -2 11111110 ...... -126 10000010 -127 10000001 -128 10000000 Tabela 1.3 Agora que já vimos alguns conceitos importantes acerca de bases numéricas e suas operações básicas é hora de rever alguns dos conceitos relacionados aos circuitos digitais que formam a base para os computadores e microcontroladores. Circuitos digitais podem ser construídos com transistores (circuitos TTL - Transistor- Transistor Logic), MOSFETs (circuitos CMOS - Complementary Metal-Oxide-Seminconductor), etc. Nos circuitos TTL, transistores NPN e PNP, figura 1.10B, são utilizados para controlar os níveis lógicos no interior do chip. Nos circuitos CMOS, MOSFETs canal N e canal P (figura 1.10C), fazem o papel das chaves. O propósito é sempre o mesmo: utilizar um elemento de comutação para simular uma chave, de forma a produzir os dois estados lógicos possíveis. Com base na álgebra booleana existem Figura 1.10 - Três elementos de comutação quatro funções básicas na eletrônica digital: NÃO,

22 Microcontroladores RL78: Guia Básico

E, OU e OU exclusivo (ou simplesmente EOU). A função NÃO realiza a inversão do nível lógico de entrada: NÃO 0 = 1 e NÃO 1 = 0. A função E retorna verdadeiro (1) quando todas as entradas são verdadeiras, a função OU retorna verdadeiro quando qualquer uma das entradas é verdadeira e a função EOU retorna verdadeiro quando as entradas são diferentes. A tabela 1.4 mostra a tabela verdade para as três funções lógicas básicas. Entrada Saída A B AND OR EOR 0 0 0 0 0 0 1 0 1 1 1 0 0 1 1 1 1 1 1 0 Tabela 1.4 - Funções lógicas básicas da eletrônica digital

Nas figuras 1.11A e 1.11B é possível ver como são construídas portas lógicas NÃO e NÃO-E utilizando MOSFETs.

A - Porta lógica NÃO B - Porta lógica NÃO-E (NAND) Figura 1.11

Os símbolos padronizados das funções lógicas básicas (chamadas portas lógicas) estão representados na figura 1.12.

Figura 1.12 - Portas lógicas básicas: NÃO (A), E (B), OU (C) e EOU (D)

Utilizando estas funções lógicas básicas é possível criar circuitos digitais complexos que podem ser classificados em duas categorias: circuitos combinacionais e sequenciais. Nos circuitos combinacionais, a saída é uma função do sinal de entrada. Alguns exemplos são os somadores, subtratores, comparadores digitais etc. A figura 1.13A mostra a implementação de um somador completo (o bloco básico dos circuitos aritméticos de qualquer computador). Nos circuitos sequenciais, a saída é uma função não somente do conteúdo atual da entrada, mas também dos estados anteriores. Alguns exemplos de circuitos lógicos sequenciais

Introdução 23

são os flip-flops, registradores, contadores, latches etc. A figura 1.13B mostra um latch de dados que constitui um dos elementos básicos de memória nos computadores modernos.

A - Somador completo B - Latch de dados Figura 1.13 Os circuitos lógicos sequenciais e combinacionais são elementos construtivos básicos das CPUs (Unidades Centrais de Processamento) dos microprocessadores e microcontroladores que utilizamos diariamente. Mas o que é microprocessador? Como ele funciona? Qual a diferença entre microprocessador e microcontrolador? Para entender o que é um microprocessador, primeiro devemos entender mais alguns conceitos relacionados a programação. Um programa é a codificação em linguagem computacional de um algoritmo lógico criado para resolver um problema específico. Para escrever um programa, é necessário analisar cuidadosamente o problema a ser resolvido, identificando todos os passos necessários para se atingir a solução. Uma vez determinados os passos para chegar à solução, é preciso criar um algoritmo que os descreva. A utilização de uma ferramenta gráfica como um fluxograma pode auxiliar na criação de tal algoritmo. Como exemplo, imagine o problema simples de contar de 0 até 10. Os passos para a solução deste problema poderiam ser:

1. Iniciar a contagem em 0. 2. A contagem atual é igual a 10? 3. Sim? Então vai para o final. 4. Não? Então incrementa a contagem em um. 5. Retorna ao passo 2.

Listagem 1.1

O fluxograma que descreve o algoritmo sugerido pode ser visto na figura 1.14. Estando de posse do algoritmo, é possível iniciar a codificação do programa de forma que um computador entenda, mas como se faz isso? A resposta é simples: utilizando a linguagem binária de zeros e uns!

24 Microcontroladores RL78: Guia Básico

Figura 1.14 - Fluxograma À primeira vista pode parecer incrível que um computador capaz de desempenhar tarefas tão complexas (como navegar pela Internet, reproduzir música, jogos etc.) somente seja capaz de diferenciar zeros de uns, mas é exatamente isso que acontece. De fato, é possível agrupar bits formando-se sequências maiores, que podem representar números, instruções, cores ou o que quer que o programador deseje representar. Qualquer computador, microcomputador, microprocessador, microcontrolador, etc. reconhece algumas sequências de bits como instruções. Essas instruções dizem o que ele deve fazer: adicionar números, armazenar algo na memória, desviar para outro ponto do programa etc. A CPU é responsável pela leitura dessas instruções da memória, sua interpretação e execução. Esses grupos de bits que possuem significado especial para a CPU são chamados de códigos de operação (em inglês operation codes ou opcodes ). Computadores diferentes frequentemente possuem diferentes CPUs e diferentes CPUs possuem diferentes opcodes para as instruções que elas reconhecem (isso explica por que você não pode executar uma aplicação de um celular Android ® em um celular iPhone ® ou vice versa). Tomemos como exemplo a instrução clear (CLRB). Ela apaga (preenche com zero) um registrador ou o conteúdo de uma posição da memória. Nos microcontroladores RL78, essa instrução pode ser representada por diversos opcodes (dependendo do tipo de operando da instrução), assim, a instrução CLRB end (apaga o conteúdo da posição de memória indicada por end) é representada pelo código binário 11110100 xxxxxxxx yyyyyyyy (onde xxxxxxxx yyyyyyyy é o endereço em binário de end). Após a leitura do opcode na memória do chip, a CPU decodifica a instrução e executa a operação indicada. Depois de apagar o conteúdo da posição de memória end, a CPU busca uma nova instrução no endereço seguinte da memória e o processo de decodificação e execução é realizado novamente. A figura 1.15 demonstra os ciclos básicos de execução de uma instrução. No interior da CPU encontramos normalmente alguns importantes elementos (que variam de um modelo de CPU para outro): o decodificador de instruções (responsável por decodificar

Introdução 25

cada opcode), o PC (Program Counter - contador de programa, responsável por controlar a sequência do programa), a unidade lógica e aritmética (ULA, Busca instrução na memória responsável pelos cálculos), o registrador acumulador de resultados, além de outros registradores de propósitos gerais. Decodifica a instrução O decodificador de instruções é um circuito lógico que traduz os opcodes na sequência interna Escreve o resultado da operação de microoperações necessárias para realizar a operação descrita pela instrução. Algumas CPUs utilizam um decodificador Figura 1.15 - Ciclos de chamado de hardwired, ao passo que outras utilizam execução de uma instrução. um decodificador baseado em microcódigos. Os decodificadores hardwired são normalmente mais rápidos, pois fazem com que grupos de bits do opcode selecionem e ativem diretamente as partes da CPU necessárias para a execução da instrução. Os decodificadores baseados em microcódigos utilizam máquinas de estado para realizar a decodificação das instruções, o que os torna normalmente mais lentos e ao mesmo tempo mais flexíveis que os decodificadores hardwired. A maioria das CPUs modernas inclui também algum tipo de memória interna. Os elementos básicos de memória interna são os registradores, geralmente utilizados para o armazenamento temporário de dados e no controle da operação da CPU. Os registradores mais importantes em praticamente todas as arquiteturas são o contador de programa (PC) e o acumulador. O contador de programa (PC) é um registrador especial responsável pelo controle e sequenciamento do fluxo do programa. Devido ao fato de ser uma máquina sequencial (na maioria dos casos), a CPU deve executar uma sequência de instruções armazenadas em algum tipo de memória. A função do PC é apontar o endereço de memória onde a próxima instrução a ser executada encontra-se armazenada. A instrução apontada pelo PC é buscada e enviada ao decodificador seguindo os passos descritos na figura 1.15. Antes de completar a instrução corrente a CPU automaticamente incrementa o PC de forma que ele aponte sempre o endereço de memória da próxima instrução. O acumulador é utilizado principalmente nas operações lógicas e aritméticas. A maioria das CPUs utiliza o conteúdo do acumulador como um operando nas instruções aritméticas e lógicas (o outro operando pode ser um registrador ou um valor lido da memória). Como veremos mais adiante, os RL78 não possuem um registrador acumulador específico, ao invés disso existe um conjunto de registradores que podem também atuar como acumuladores. Outro componente importante da CPU é a unidade lógica e aritmética (ULA). Esse circuito lógico combinacional é utilizado por todas as operações aritméticas e lógicas. Na maioria dos sistemas, a ULA possui duas entradas (os operandos das operações): uma é geralmente conectada ao acumulador e a outra, a um registrador ou recebe um valor lido da memória. Os resultados das operações da ULA são normalmente armazenados no acumulador.

26 Microcontroladores RL78: Guia Básico

Antes de retomarmos o tópico de programação, vejamos a diferença entre microprocessador e microcontrolador. Em poucas palavras, podemos dizer que microprocessador é um chip com uma CPU, ULA e circuitos básicos de suporte. Esses chips necessitam de memórias externas e outros chips para poderem realizar tarefas úteis. Já o microcontrolador é um chip que integra num mesmo encapsulamento a CPU, ULA, circuitos de suporte, memórias e periféricos. Um microcontrolador é frequentemente referido como um computador num único chip. A aplicação alvo de um microprocessador também é diferente daquela de um microcontrolador. Enquanto um microprocessador é projetado para ser utilizado em computadores e dispositivos computacionais (como tablets e smartphones) de uso geral, capazes de executar programas complexos e sistemas operacionais, um microcontrolador, por outro lado, é projetado para realizar tarefas específicas e executar programas mais simples (geralmente sem a necessidade de um sistema operacional).

É cada vez mais complexo estabelecer uma distinção entre microprocessadores e i microcontroladores, pois estes tornam-se mais e mais complexos e muitas vezes confundem-se com microprocessadores.

Voltando ao tópico de programação, é fácil constatar que a utilização de números binários e opcodes para escrever um programa pode ser bastante trabalhosa, especialmente porque dificultam a leitura e o entendimento do código, além de aumentar a probabilidade de erros (inclusive aqueles oriundos de falhas de digitação). Por isso, ainda na década de 1950 surgiu a primeira linguagem de programação, o assembly. Na verdade, a linguagem assembly é somente uma representação simbólica dos opcodes. Utilizando um programa especial (chamado Assembler ou montador), os mnemônicos assembly são traduzidos diretamente para códigos binários (opcodes). Essa tradução é feita numa razão de um para um, ou seja, cada instrução assembly é traduzida em um único opcode. Sendo assim, para podermos programar uma máquina, é necessário primeiramente conhecer quais instruções essa máquina é capaz de entender e como utilizá-las corretamente. Considerando a CPU dos RL78, existem cinco instruções (de um conjunto de oitenta e uma) que podem ser utilizadas para implementar o programa descrito na listagem 1.1: CLRB: apaga o conteúdo de um registrador ou endereço da memória. CMP a,b: compara o conteúdo de uma registrador ou posição da memória (operando “a”) com o conteúdo do segundo operando (“b”), modificando os bits Z, CY e AY, de acordo com o resultado (a comparação é feita pela subtração do operando “b” do operando “a”). INC: adiciona um ao operando. BR: desvio incondicional para o endereço especificado. BZ : desvio para o endereço especificado no caso do flag Z = 1. A figura 1.16 apresenta uma adaptação do fluxograma da figura 1.13 utilizando instruções assembly do RL78.

Introdução 27

Início

CLRB CNT

CMP CNT,#10

INC CNT

Fim Figura 1.16

A listagem 1.2 mostra o programa codificado em linguagem assembly. Ele foi escrita com base em algumas considerações iniciais: 1. O programa é armazenado a partir do endereço 0x000CE (0x significa que o número está em hexadecimal). Este é normalmente o endereço inicial da memória flash para armazenamento de programas nos microcontroladores RL78; 2. A variável “cnt” está localizada no endereço 0xEF00 da memória, o primeiro endereço válido da memória RAM no modelo do RL78/G13 utilizado (o R5F100LE); 3. Utilizaremos o prefixo “N:” para especificar um endereço de 16 bits na memória do microcontrolador, esta é a notação utilizada pelo compilador IAR para representar o modo de endereçamento direto de 16 bits (maiores detalhes serão vistos no capítulo 3); 4. Uma constante (como o valor 10 decimal) é escrita precedida do símbolo #. Este símbolo indica ao assembler que o valor que o segue é uma constante imediata; 5. Os endereços e opcodes estão escritos em base hexadecimal.

Analisando o fluxograma da figura 1.16 e a listagem 1.2, podemos entender o funcionamento do pequeno programa apresentado. É fácil perceber que a instrução CMP possui um importante papel no controle do programa. Endereço Opcode Assembly Comentários 000CE F500EF CLRB N:cnt Apaga o conteúdo da memória cnt repete: 000D1 4000EF0A CMP N:cnt,#10 Compara o valor de cnt com 10 (cnt-10) 000D5 DD07 BZ final Desvia para “final” se Z=1 (Z=1 se na comparação anterior cnt era igual a 10) 000D7 A000EF INC N:cnt Incrementa cnt em um 000DA EFF7 BR repete Desvia para “repete” 000DC final: Listagem 1.2

28 Microcontroladores RL78: Guia Básico

A instrução “CMP N:cnt,#10” realiza a comparação entre dois valores: o conteúdo da variável “cnt” e o valor imediato 10 decimal. Observando a coluna dos opcodes, encontramos o valor 0x4000EF0A, sendo 0x40 o código da instrução, 0x00EF o endereço do operando “cnt” na memória de dados (o endereço da variável é 0xEF00 e na instrução é escrito em formato little endian, iniciando pela parte menos significativa) e finalmente a constante com a qual deve ser feita a comparação (0x0A que é a representação hexadecimal de 10 decimal).

Os termos little endian e big endian são utilizados em computação para especificar como uma máquina armazena dados numéricos de múltiplos bytes na memória. No formato little endian tais dados são armazenados na memória sempre iniciando-se i pelo seu byte menos significativo, já no formato big endian , tais dados são armazenados na sua forma natural, ou seja, iniciando-se pelo byte mais significativo. Exemplo: o número 0x1234 hexadecimal é armazenado 0x34,0x12 no formato little endian e 0x12,0x34 no formato big endian!

Observe que a comparação é realizada por meio de uma operação de subtração realizada no interior da ULA. De acordo com o resultado da comparação (subtração) alguns bits do registrador PSW são alterados: Z, AC e CY. Se o valor do contador for igual a 10, o bit Z é setado. Em seguida, a instrução “BZ final” é o chamado desvio condicional. Este tipo de instrução avalia uma condição e efetua o desvio do programa caso a condição seja verdadeira. No caso, a instrução avalia o estado do bit Z (localizado no registrador PSW) e desvia para “final” caso Z=1. Caso Z=0, a instrução não produz efeito e o programa segue a sua sequência natural. Note que o opcode da instrução é 0xDD07, onde 0xDD indica a instrução propriamente dita (BZ) e 0x07 é o endereço de destino do desvio. Nestas instruções o endereço de destino é escrito relativamente ao endereço da instrução de desvio, ou seja, o valor 0x07 indica que o endereço de destino é igual ao endereço de BZ (0x000D5) mais o deslocamento 0x07, ou seja, 0x000DC. A próxima instrução “INC N:cnt” faz o incremento do valor da variável “cnt”, ou seja, soma um ao conteúdo dela. Novamente podemos perceber que o opcode da instrução é 0xA000EF, onde 0xA0 indica a instrução INC e 0x00EF é o endereço little endian da variável “cnt”. A última instrução “BR final” provoca o desvio do fluxo do programa para o endereço indicado por “repete”, ou seja 0x000D1. O opcode da instrução é 0xEFF7, sendo 0xEF o código da instrução e 0xF7 o deslocamento do endereço de destino. Observe que neste caso o endereço de destino está localizado antes da instrução de desvio e por isso o deslocamento é negativo. O valor de deslocamento é calculado da seguinte forma: 0xD1 (o destino) – 0xDA (endereço onde está a instrução de desvio) = 0xF7. Note que 0xF7 é a representação em complemento de dois do número -9 decimal. Analisando o programa inteiro podemos perceber que inicialmente a variável “cnt” é iniciada em zero “CLRB N:cnt”, em seguida verificamos se o valor dela é igual a 10 “CMP N:cnt,#10”, caso negativo “BZ final”, o programa segue, incrementa a variável “INC N:cnt” e em seguida desvia “BR repete” para uma nova comparação. Quando a comparação da variável com

Introdução 29

10 “CMP N:cnt,#10” resulta verdadeira (Z=1), o desvio condicional “BZ final” é tomado e o programa desvia para o endereço “final”! Esta foi apenas uma apresentação rápida da operação de uma CPU e de como uma sequência de instruções é executada. No decorrer do livro vamos explorar em mais detalhes o funcionamento de cada instrução dos RL78.

1.4. Microcontroladores RL78

A linha de microcontroladores RL78 da Renesas é derivada da união de duas linhas de microcontroladores: a linha 78K0R originalmente desenvolvida pela NEC e R8C da Renesas. Os microcontroladores RL78 são máquinas CISC de 16 bits que possuem como diferencial a sua alta eficiência, decorrente de duas características importantes das CPUs RL78: alta velocidade de execução de código (pois utilizam um pipeline de três estágios que faz com que 56% das instruções sejam executadas em apenas um ciclo de clock) e consumo de energia extremamente baixo (graças ao design focado principalmente na eficiência energética e a utilização de tecnologias de semicondutores de baixo consumo de energia), o consumo de energia, no melhor caso, é de aproximadamente 66µA/MHz. Um regulador interno de tensão também auxilia na redução do consumo de energia e permite que os RL78 apresentem níveis muito baixos de emissão eletromagnética (EMI). Além de consumirem pouca energia quando em operação, a existência dos modos de baixo consumo de energia halt, stop e snooze permite reduzir grandemente o consumo de energia quando a CPU não está em operação. Em termos de performance, os RL78 podem operar até 32MHz, executam a maioria das instruções em 1 ou 2 ciclos de clock e possuem capacidade de endereçamento de até 1MiB, permitindo que o fabricante disponibilize grandes quantidades de memória flash e RAM (até 512KiB de flash e até 32KiB de RAM nos modelos mais poderosos lançados até o momento). A linha de periféricos inclui unidades de temporização TAU onde cada canal de 16 bits pode atuar praticamente como um timer independente, relógio de tempo real com calendário, timer de intervalo, timer para controle de motores (até 6 canais de PWM), interfaces de comunicação serial (síncronas SPI e I 2C, assíncronas UART/LIN e USB), conversor A/D de 8, 10 ou 12 bits (com capacidade de varredura de 4 canais), conversor D/A, comparadores analógicos, controlador de displays LCD, etc. Praticamente todos os modelos contam com DMA (Direct Memory Access - acesso direto a memória) de 1 ou 2 canais, que permite automatizar as transferências entre os periféricos e a memória, dispensando a intervenção da CPU. Além de facilitar a transferência de dados entre a memória e os periféricos, o DMA também pode auxiliar na redução do consumo de energia (permitindo fazer transferências enquanto a CPU está em modo halt). A maioria dos modelos (exceto os G10) possui suporte a divisão e multiplicação, em alguns modelos por meio de um módulo periférico de hardware, em outros, por meio de instruções DSP especiais (RL78/G14).

30 Microcontroladores RL78: Guia Básico

Também estão disponíveis periféricos de segurança como, por exemplo, checagem de erros na memória flash (ECC com CRC) e RAM (paridade), watchdog com janela de tempo, detector de baixa tensão, detecção de falha de oscilador e de acesso a endereço ilegal da memória. A linha RL78 é composta dos seguintes membros: Modelos de uso geral: • RL78/G10 – com versões de 10 e 16 pinos, capacidades de memória flash de 1KiB até 4KiB e memória RAM de 128 até 512 bytes. Estes microcontroladores possuem núcleo de 8 bits e operam a até 20MHz, incluem interfaces de comunicação como UART, SPI e I 2C (nos modelos de 16 pinos), conversor A/D de 10 bits, comparador analógico (nos modelos de 16 pinos) e são os elementos de uso geral e mais baixo custo da linha RL78. Nestes chips a faixa de tensões de alimentação vai de 2,0 a 5,5V. • RL78/G12 - com versões de 20, 24 e 30 pinos, capacidades de memória flash de 2KiB até 16KiB, memória RAM de 256 bytes até 2KiB e dataflash até 2KiB. Estes microcontroladores operam a até 24MHz, incluem interfaces de comunicação como UART, SPI e I 2C, conversor A/D de 10 bits, DMA (em alguns modelos) e juntamente com os G10 são os elementos de uso geral e mais baixo custo da linha RL78. o RL78/G1C - com versões de 32 e 48 pinos, capacidade de memória flash de 32KiB, memória RAM de 5,5KiB e dataflash de 2KiB. Estes microcontroladores operam a até 24MHz e incluem interfaces de comunicação como UART, SPI, I 2C e USB 2.0 full speed (12Mbits/s) capaz de operar como host ou device e compatível com a versão 1.2 da especificação de carga de bateria pela porta USB (até duas portas USB disponíveis). • RL78/G13 - com versões de 20 a 128 pinos, capacidades de memória flash de 16KiB até 512KiB, memória RAM de 2KiB até 32KiB e dataflash de 4 ou 8KiB. Estes microcontroladores operam a até 32MHz, incluem múltiplas interfaces de comunicação como UART, SPI, I 2C, conversor A/D de 10 bits, DMA e são voltados ao uso geral em aplicações de pequena e média complexidade. o RL78/G1A - com versões de 25 a 64 pinos, capacidades de memória flash de 16KiB até 64KiB, memória RAM de 2KiB até 4 KiB e dataflash de 4KiB. Estes microcontroladores operam a até 32MHz, incluem interfaces de comunicação como UART, SPI e I 2C, DMA e um conversor A/D de 12 bits. • RL78/G14 - com versões de 30 a 100 pinos, capacidades de memória flash de 16KiB até 256KiB, memória RAM de 2,5KiB até 24KiB e dataflash de 4 ou 8KiB. Estes microcontroladores operam a até 32MHz, além dos periféricos da linha G13, incluem instruções DSP para processamento digital de sinais, timer para controle de motores, D/A de 8 bits e comparador analógico. Eles são os membros mais avançados da linha RL78 e são voltados ao uso geral em aplicações de média complexidade. Com controlador de display LCD integrado:

Introdução 31

• RL78/L12 - com versões de 32 a 64 pinos, capacidades de memória flash de 8KiB até 32KiB, memória RAM de 1KiB até 1,5KiB e dataflash de 2KiB. Estes microcontroladores operam a até 24MHz e incluem controladores para displays LCD com até 280 segmentos (13 a 39 segmentos com 4 planos ou 18 a 35 segmentos com 8 planos). • RL78/L13 - com versões de 64 e 80 pinos, capacidades de memória flash de 16KiB até 128KiB, memória RAM de 1KiB até 8KiB e dataflash de 4KiB. Estes microcontroladores operam a até 24MHz e incluem controladores para displays LCD com até 376 segmentos (36 a 51 segmentos com 4 planos ou 32 a 47 segmentos com 8 planos). Modelos destinados a aplicações específicas: • RL78/D1x - com versões de 48 a 100 pinos, capacidades de memória flash de 24KiB até 256KiB, memória RAM de 2KiB até 16KiB e dataflash de 8KiB. Estes microcontroladores operam a até 32MHz e incluem controladores para displays LCD com até 212 segmentos (4 planos com até 53 segmentos), controlador de motor de passo e gerador de som, são voltados a aplicações de mostradores e painéis automotivos. • RL78/F1x - com versões de 20 a 64 pinos, capacidades de memória flash de 8KiB até 64KiB, memória RAM de 512 bytes até 4KiB e dataflash de 4KiB. Estes microcontroladores operam a até 32MHz, suportam temperaturas de até 150ºC e são voltados para aplicações automotivas em dispositivos de carroceria (car body). • RL78/I1x - com versões de 20 a 38 pinos, capacidades de memória flash de 32KiB até 64KiB, memória RAM de 2KiB até 4KiB e dataflash de 4KiB. Estes microcontroladores operam a até 32MHz, com tensões de alimentação de 2,7 a 5,5V e incluem controladores PWM para leds , UART com suporte a DALI e DMX512 e são voltados a aplicações de controle de iluminação e correção de fator de potência.

1.5. Pinagens e Encapsulamentos

Abaixo apresentamos a pinagem de alguns modelos de RL78:

Figura 1.17 – Modelos de 10 pinos (RL78/G10)

32 Microcontroladores RL78: Guia Básico

Figura 1.18 – Modelos de 20 pinos (RL78/G12)

Figura 1.19 – Modelos de 20 pinos (RL78/G13)

Figura 1.20 – Modelos de 30 pinos (RL78/G13)

Introdução 33

Figura 1.21 – Modelos de 64 pinos (RL78/G13) Pinos especiais:

• VDD - alimentação positiva (1,6 a 5,5 Volts, nos G10 é de 2,0 a 5,5V)

• EV DD0 - alimentação positiva (1,6 a 5,5 Volts) para as portas P0, P1, P3, P4, P5, P6, P7 e P14

• VSS - referência de terra (0 Volt)

• EV SS0 - referência de terra (0 Volt) para as portas P0, P1, P3, P4, P5, P6, P7 e P14 • REGC - estabilização do regulador interno (conectar um capacitor de 0,47 a 1µF)

• RESET - sinal de reset ativo em nível lógico “0” • P40/TOOL0 – pino de E/S (bit 0 da porta 4) e pino de programação/depuração (TOOL0)

Cuidado ao utilizar o pino TOOL0 como E/S na aplicação, pois cargas muito elevadas O neste pino podem prejudicar a programação e a depuração do chip no circuito!

34 Microcontroladores RL78: Guia Básico

1.6. R5F100LEA

O microcontrolador objeto de estudo deste livro é o R5F100LEA, um membro da linha RL78/G13 de microcontroladores da Renesas. Ele inclui uma CPU RL78, além de 64kibibytes de memória flash, 4.096 bytes de memória RAM e 4.096 bytes de memória dataflash. Este chip pode operar a até 32MHz e a tensão de alimentação pode ir de 1,6 a 5,5 Volts. Além das características gerais dos RL78/G13, o R5F100LEA inclui também: • 58 pinos de entrada/saída, divididos em 11 portas de entrada/saída (E/S): P0, P1, P2, P3, P4, P5, P6, P7, P12, P13 e P14; • Diversos pinos podem ser configurados para operar como saídas dreno aberto e podem fazer interface com outros níveis de tensão (desde que dentro da faixa de 1,6 a 5,5V); • Seis pinos de interrupção externa, com borda de sensibilidade configurável; • Oito pinos de interrupção de teclado (geram interrupção ao mudar de estado); • Quatro diferentes periféricos de temporização: o Duas unidades de temporização TAU, cada uma com 8 canais (total de 16 canais). Cada canal do TAU pode operar como um timer independente ou ser utilizado em conjunto com outros canais. Os canais dos TAU podem fazer captura de sinais (medição de período), comparação (geração de interrupção ou sinais de largura definida), PWM, etc. o Relógio de tempo real com calendário e interrupção de alarme, que pode operar com clock externo de 32768Hz ou com clock interno de 15kHz; o Timer de interrupção periódica (12 bits) que pode ser utilizado para criar bases de tempo; o Watchdog programável com operação em “janela de tempo”. • Dois tipos de interface de comunicação (até 7 portas seriais simultâneas): o Duas unidades seriais SAU, que podem operar no modo SPI de 3 fios, UART ou I2C simplificado* (a SAU0 pode operar como 4 canais SPI/I 2C ou 2 canais UART, a SAU1 pode operar como 2 canais SPI/I 2C ou 1 canal UART com suporte a LIN); o Uma unidade I 2C completa. A interface I 2C simplificada não pode operar no modo escravo e nem suporta o modo multimaster. • Conversor A/D de 10 bits com 12 canais de entrada, taxa de conversão de até 470ksps (mil amostras por segundo), varredura de até 4 canais, comparador digital interno e capacidade de operação em modo snooze; • Quatro canais de DMA, cada canal pode transferir blocos de até 1024 bytes ou words (um byte ou word a cada disparo).

Introdução 35

1.7. Kits e Ferramentas de Programação

A Renesas possui uma série de kits disponíveis para facilitar o aprendizado e desenvolvimento de aplicações com o RL78. O kit mais acessível é o YRPBRL78G13, também chamado de “Promotion Board” do RL78/G13. Este kit consiste numa PCI contendo um R5F100LEA e um microcontrolador 78F0730, que atua como programador e depurador USB.

Figura 1.22 – YRPBRL78G13

A placa possui também dois leds, um cristal de 32.768Hz conectado ao oscilador secundário do RL78, um trimpot, duas fileiras de pads conectados aos pinos de E/S do chip e um conector para programação do RL78 através de um programador E1 externo. Também existem jumpers que podem ser utilizados para medição do consumo de corrente do chip. A figura 1.23 mostra as conexões das duas fileiras de 30 pinos nas bordas da placa (o pino 1 é indicado na borda da placa).

Não conectado Não conectado P30 P70 P05 P71 P06 P72 P147 P73 P146 P74 P137 P75 P41 P76 P42 P77 (conectado ao LED D2) P43 P31 P120 P63 T_RESET P62 P27 P61 P26 P60 P25 P50 P24 P51 P23 P52 (conectado ao trimpot R15) P22 P53 AV REFM P54 AV REFP P55 P130 P17 P04 P16 P03 P15 P02 P14 (recebe dados da COM virtual) P01 P13 (transmite dados para a COM virtual) P00 P12 P141 P11 P140 P10 VDD VDD GND GND

Conector E1 Figura 1.23

36 Microcontroladores RL78: Guia Básico

Para desenvolvimento de aplicações mais avançadas o “Starter kit” ou RSK do RL78/G13 inclui 4 leds, 3 teclas de usuário, módulo de display LCD de 8 caracteres por 2 linhas, cristal de 20MHz e de 32.768Hz, conector para depurador E1, porta serial DB9 e interface LIN. O kit inclui um depurador E1 que pode ser utilizado para programar e depurar qualquer microcontrolador RL78, RX e alguns modelos do R8C, e V850.

Figura 1.24 – Starter kit do RL78/G13 Figura 1.25 – Depurador/programador E1

Outro kit bastante interessante e que inclui uma quantidade de periféricos muito maior que os anteriores, é o “Demonstration kit” do RL78/G14. Ele utiliza um microcontrolador R5F104PJA (256KiB de flash, 8KiB de dataflash e 24KiB de RAM num encapsulamento de 100 pinos) e inclui diversos periféricos interessantes na placa: módulo Wi-Fi GainSpan GS1011, display LCD TFT gráfico de 1,5 polegadas, display Eink com seis segmentos, conector para cartão MicroSD, acelerômetro de 3 eixos, sensor de temperatura, EEPROM I 2C de 512kib, memória flash SPI de 8Mib (conectada ao módulo Wi-Fi), sensor de luz, microfone, alto falante, sensor de IR, led IR, conector serial DB9, treze leds de usuário, 4 teclas (1 reset), potenciômetro, FET com conector externo, TRIAC isolado com conector externo, portas de expansão e depurador TK integrado com conector USB.

Figura 1.26 – Demonstration kit do RL78/G14

Introdução 37

1.8. Convenções Utilizadas

No decorrer deste livro utilizamos algumas convenções para representação de símbolos, nomes e outros termos técnicos: • Este livro utiliza as unidades de informação padronizadas pela Comissão Internacional de Eletrotécnica (IEC) em 2000, as quais foram criadas para ajudar na diferenciação entre os padrões decimais (utilizados no cotidiano) e os padrões binários (utilizados para representar grandezas binárias, comuns no mundo da computação digital):

Prefixo Padrão Prefixo Binário (Sistema Internacional) (Sistema Internacional) Prefixo Símbolo Peso Prefixo Símbolo Peso Kilo k 10 3 kibi Ki 210 Mega M 10 6 mebi Mi 220 Giga G 10 9 gibi Gi 230 Tera T 10 12 tebi Ti 240 Peta P 10 15 pebi Pi 250 Exa E 10 18 exbi Ei 260 Tabela 1.5

Note que 1024 bytes são 1KiB e 1024 bits são 1Kibit! • Referências a nomes de bit e nomes de registrador são feitas sempre utilizando letras maiúsculas. • As referências aos nomes dos bits são feitas sempre utilizando o nome ou a associação do nome do registrador e o nome do bit no seguinte formato: REGISTRADOR.BIT. Assim, a referência ao bit Z do registrador PSW pode ser feita apenas ao nome do bit (Z) ou PSW.Z. • Para representar genericamente um conjunto de registradores ou bits pertencentes a um periférico ou registrador, utilizamos a letra “x” minúscula. Assim, o termo Px representa qualquer um dos seguintes registradores: P0, P1, P2, etc. No caso dos timers, TAUx poderá significar TAU1 ou TAU0 e assim por diante. • Os símbolos C utilizados neste livro são aqueles definidos e fornecidos pela IAR. Os registradores e bits específicos que podem ser manipulados diretamente pelo código em C estarão sempre grafados em letras maiúsculas. Os símbolos escritos com a primeira letra minúscula “b” referem-se aos bits dos registradores e somente devem ser utilizados nas operações envolvendo registradores. Por exemplo: para se setar o bit RTCEN (registrador PER0) é possível escrever RTCEN = 1 (uma operação de manipulação direta de bit) ou ainda PER0 = bRTCEN (uma operação de escrita de 8 bits no registrador). Os símbolos bXXXX estão definidos no arquivo myRL78.h.

38 Microcontroladores RL78: Guia Básico

• No decorrer do texto, as palavras reservadas da linguagem C estão escritas em negrito. • As notas importantes são apresentadas utilizando a seguinte caixa de texto:

i Esta é uma nota importante!

• As dicas de utilização utilizam a seguinte caixa de texto:

O Esta é uma dica!

• Os registradores do microcontrolador são representados por figuras como a mostrada a seguir: Registrador LVIM (Exemplo)

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura LVIOMSK LVIF LVISEN 0 0 0 0 0 LVIM Escrita 0 0 Reset 0* 0 0 0 0 0 0* 0* * Após um reset LVD este registrador não é alterado. Nome do Bit Descrição Bit C Símbolo C Controle de escrita no registrador LVIS: LVISEN 0 – escrita desabilitada (não produz efeito) LVISEN bLVISEN 1 – escrita habilitada Máscara de estado de saída do LVD: LVIOMSK 0 – LVD operando normalmente LVIOMSK bLVIOMSK 1 – LVD em estabilização Indicador de status do LVD: 0 – tensão (V ) ≥ valor configurado (V ) (ou quando o LVIF DD LVD LVIF bLVIF LVD está desligado) 1 – tensão (V DD ) < valor configurado (V LVD )

Vejamos como ler a tabela: Existem três linhas rotuladas “Leitura”, “Escrita” e “Reset”. A primeira e a segunda linhas indicam a função de cada bit na sua leitura e escrita respectivamente. A linha “Reset” indica o estado de cada bit após um reset. Os bits 0 e 1 deste registrador são do tipo “somente leitura”, o que significa que eles somente podem ser lidos pelo software, mas não modificados por ele.

A leitura do bit 0 do registrador retorna o estado do bit LVIF , mas a escrita no mesmo não produz efeitos. Da mesma forma, a leitura do bit 1 retorna o estado do bit LVIOMSK, mas a escrita não produz efeitos. Os bits 2 a 6 não são implementados e a leitura deles retorna sempre o valor “0”. Normalmente se recomenda escrever somente “0” nos bits não implementados. Alguns bits

Introdução 39

podem apresentar um “?” no seu estado de reset. Isso significa que ele não é alterado após um reset. O bit 7 (LVISEN) pode ser lido ou escrito pelo software. Desta forma, supondo que o registrador LVIM possua o valor 0x00, após a seguinte linha de código: LVIM = 0x81; O registrador irá conter o valor 0x80 (já que o bit 0 não é alterado pelo programa). Observe que os símbolos definidos na coluna “Bit C” estão incluídos nos headers do chip e são fornecidos juntamente com o compilador (pasta include dentro da pasta onde foi instalado o compilador IAR). Cada modelo de microcontrolador possui dois arquivos header com as definições dos seus registradores SFR e GPR: o arquivo “ior5f10xxx.h” para os SFR principais e “ior5f10xxx_ext.h” para o conjunto de registradores estendido. No caso do microcontrolador utilizado neste livro (R5F100LE) os arquivos header são "ior5f100le.h" e "ior5f100le_ext.h". Os símbolos mostrados na coluna “Símbolo C” estão definidos no arquivo “myRL78.h” que pode ser baixado juntamente com os projetos deste livro.

40 Microcontroladores RL78: Guia Básico

2

Ferramentas de Programação 2. Ferramentas de Programação

2.1. O Ambiente Embedded Workbench EWRL78

O ambiente IAR Embedded Workbench for RL78 (EWRL78) é um IDE que integra editor, compilador, assembler, linker, simulador e depurador em um único software. Os leitores dos livros “MSP430: Teoria e Prática” e “Tecnologia ARM: Microcontroladores de 32 bits” irão perceber que o EWRL78 (como é chamado o Embedded Workbench para os RL78) é muito semelhante ao EW430 e EWARM. Esta identidade de ambientes é sem dúvida uma vantagem para os desenvolvedores que necessitam trabalhar com múltiplas plataformas, pois o tempo gasto com a familiarização com a ferramenta de programação é amplamente reduzido. 2.1.1. Criando o Primeiro Projeto No decorrer deste tópico o leitor poderá aprender como configurar corretamente o ambiente EWRL78 (versão 1.20) e a criação de um projeto em linguagem C. Para criar um novo projeto no IAR, é necessário selecionar a opção “Create a New Project” dentro do menu principal.

Figura 2.1A Figura 2.1B

Em seguida, devemos selecionar a linguagem de programação a ser utilizada no projeto. Nos exemplos deste livro, utilizaremos a linguagem C, por isso, a seleção deve ser feita conforme a figura 2.1A. Uma vez selecionada a linguagem é necessário dar um nome ao projeto, conforme demonstra a figura 2.1B.

Ferramentas de Programação 41

Feito isso, teremos uma tela igual a representada na figura 2.2. Nela encontramos a janela do workspace atual (2), a janela de edição de código fonte (3) e a janela de mensagens da IDE (4) e a seleção do modo do projeto (1).

1

3

2

4

Figura 2.2

O projeto inclui um arquivo genérico “main.c” que consiste no mínimo de código necessário a um programa em C, ou seja, apenas a função principal (main). Vencida esta etapa é necessário configurar o projeto. Para isso, selecione a opção Project > Options... no menu principal ou, alternativamente, pressione as teclas ALT+F7, ou ainda, pressione o botão direito do mouse sobre a janela do workspace e selecione a opção Options no menu flutuante. A janela de opções (figura 2.3) será exibida. As configurações de projeto feitas para o modo “Debug” (item 4 da figura 2.2) deverão ser feitas também para o modo “Release”. O modo “Debug” é útil durante a fase de desenvolvimento e testes da aplicação, ao passo que a o modo “Release” é utilizado para geração do código final (normalmente um arquivo .hex para gravação em produção). Nesta janela, o programador irá selecionar o modelo de RL78 utilizado (no campo Device), além do modelo de memória a ser utilizado para o código (Code model) e dados (Data model) e como as constantes “near” serão colocadas na memória. Modelos “near” utilizam apenas um segmento de 64KiB de memória, ao passo que modelos “far” utilizam todo o espaço de 1MiB de endereçamento. Preferencialmente devemos utilizar modelos “near”, pois eles geram códigos menores e mais rápidos que os gerados com modelos “far”.

42 Microcontroladores RL78: Guia Básico

Pressione este botão para selecionar a CPU

Figura 2.3

Ainda na categoria “General Options”, clique na aba “Library Configuration”. Ali é possível selecionar o tipo de biblioteca padrão C que será utilizada com o projeto (“Normal DLIB”, “Full DLIB” ou “Custom”) e também é possível selecionar se o compilador deve ou não utilizar o hardware de multiplicação integrado (“ Use hardware multiplier/divider unit ”). Esta opção, ao ser selecionada, faz com que o compilador inclua uma pequena biblioteca (cerca de 260 bytes) que faz com que o multiplicador/divisor por hardware seja utilizado para acelerar as operações de divisão e multiplicação. Cabe ao programador decidir sobre a necessidade ou não de se utilizar o hardware multiplicador/divisor interno, mas via de regra, se você tiver 260 bytes de flash sobrando, os benefícios em termos de ganho de velocidade valem o espaço adicional necessário. Além das configurações da categoria “General Options” é importante também configurarmos outras opções. Na categoria “C/C++ compiler”, verifique a aba “Output” e certifique-se de que a opção “Generate debug information” esteja selecionada. Esta opção faz com que o compilador gere informações adicionais necessárias à depuração do programa. Na aba “Optimizations” é possível configurar algumas opções de otimização de código. Por hora não iremos nos preocupar com isso, mas para produção de código final, é importante utilizar a otimização máxima do compilador (“level high”). Note que é possível otimizar o programa para ocupar menos espaço (Optimize for space), para ser executado mais rapidamente (optimize for speed) ou para a melhor relação custo/benefício entre velocidade e tamanho (balanced). Na categoria “Linker”, aba “Output”, é importante que a opção “Debug information for C- SPY” esteja selecionada. Ela é responsável por gerar código de depuração necessário para que a ferramenta C-SPY possa funcionar corretamente.

Ferramentas de Programação 43

Ainda na categoria “Linker” é possível selecionar outro arquivo de configuração do linker. Isto é necessário quando se necessita modificar a forma como o linker utiliza e distribui código e dados na memória do microcontrolador. Um exemplo típico é o uso das bibliotecas FSL, FDL ou EEL para armazenamento de dados na flash, todas elas necessitam de modificações na configuração do linker para poder operar corretamente. Adicionalmente, pode ser interessante configurar o linker para gerar um arquivo de informações sobre a utilização e alocação da memória. Para isso, basta selecionar a aba “List” e habilitar a opção “Generate linker listing”. O arquivo .map gerado irá conter diversas informações acerca da distribuição das funções e símbolos na memória do chip. Também é possível verificar a quantidade de memória flash e RAM utilizada.

Seleção do depurador a ser utilizado pelo EWRL78

Figura 2.4 Finalmente, o último passo para configuração do projeto consiste em selecionar o tipo de depurador a ser utilizado. Esta seleção será realizada conforme o tipo de hardware de depuração disponível. Normalmente iremos optar entre o simulador e um depurador externo como o TK ou E1. A opção pelo simulador (figura 2.4) pode ser interessante para se testar trechos de código, desde que estes não utilizem nenhum periférico dos RL78, pois o simulador da IAR não simula periféricos internos do microcontrolador. Uma vez que o projeto esteja configurado, podemos nos dedicar ao programa propriamente dito. Assim, o arquivo “main.c” do projeto recém criado deve ser alterado conforme a listagem do exemplo 2.1. Este programa exemplo irá fazer com que o led da placa de demonstração do RL78 pisque. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE"

44 Microcontroladores RL78: Guia Básico

__root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED_D2 P7_bit.no7

unsigned long int temp, cnt;

void main( void ) { PM7_bit.no7 = 0; // porta P77 como saída cnt = 0; while (1) { LED_D2 = 1; for (temp=100000;temp;temp--); LED_D2 = 0; for (temp=100000;temp;temp--); cnt++; } } Exemplo 2.1 – Pisca led por software

Uma vez que o programa tenha sido digitado (ou carregado) corretamente, a aparência do IDE deve ser próxima a da figura 2.5. Podemos então passar a etapa de compilação e depuração. Para proceder à compilação e montagem completa do projeto, basta clicar no botão MAKE indicado na figura 2.5. O IDE irá automaticamente compilar e “linkar” o programa, gerando os arquivos binários conforme selecionado nas opções do projeto. O mesmo efeito pode ser obtido pressionando-se a tecla F7 ou selecionando-se a opção Project>Make no menu principal.

DEBUG MAKE Depurar o Compilar o projeto atual projeto atual

Figura 2.5

Ferramentas de Programação 45

Após o processo, a janela de mensagens da IDE estará mostrando, na aba Build, as mensagens emitidas pelo compilador e pelo linker. Caso a mensagem exibida seja diferente de “Total number of errors: 0” e “Total number of warnings: 0”, verifique o código digitado a procura de erros.

2.1.2. Simulando um Programa Após termos compilado o programa, podemos passar ao teste do mesmo. Primeiramente iremos testar o programa utilizando o simulador do EWRL78. Para isso é necessário selecionar a opção simulator na janela de opções do projeto conforme a figura 2.4. Pressionando-se o botão DEBUG (figura 2.5), poderemos dar início a uma sessão de depuração utilizando o simulador. Após pressionar o botão DEBUG, a tela do IDE deverá passar a ser aquela da figura 2.6.

Botões do depurador Go to

Janela de disassembly

Figura 2.6 – Depurador do EWRL78 Repare que a janela de mensagens apresenta informações na aba Debug Log, informando que o download foi completado e que o Target (dispositivo alvo, que no caso é o simulador) foi ressetado. Além disso, temos uma nova janela (Disassembly) e uma barra de botões do depurador. A janela Disassembly apresenta uma visão da memória de programa do chip, incluindo os endereços de memória, o conteúdo hexadecimal e a instrução assembly correspondente. Permeando as instruções assembly encontramos linhas de código C: as instruções seguintes a cada linha de código C representam as instruções necessárias para executar a tarefa determinada pela linha de código de alto nível.

46 Microcontroladores RL78: Guia Básico

O campo “Go to” permite visualizar o código a partir de um endereço específico, por exemplo: se o programador desejar visualizar o código a partir do endereço 0x2000, basta entrar com este valor no campo “Go to” e pressionar a tecla ENTER. As linhas destacadas em fundo verde representam o próximo comando/instrução a ser executado A barra de botões do depurador permite controlar a execução do programa: estão disponíveis botões para executar o programa, paralisar a execução, execução passo a passo, criação de breakpoints, etc. A figura 2.7 apresenta a função de cada um dos botões. Saída do modo de depuração; Executa o programa até um ponto de parada (breakpoint) ou o término do programa (tecla F5); Executa o programa até o ponto em que se encontra o cursor; Pula para o próximo comando (o atual é executado sem visualização no depurador) (tecla F10); Executa o programa até o término da função atual (teclas SHIFT + F11); Executa a próxima instrução ou comando (passo a passo) (tecla F11); Executa a próxima instrução ou comando (se for uma chamada de função, ela é inteiramente executada e o controle retorna para a instrução seguinte à chamada); Para a execução do programa; Reset do processador. Figura 2.7 – Botões de controle do depurador

Utilizando a execução passo a passo (tecla F10), podemos acompanhar exatamente o que ocorre com a CPU RL78 durante a execução dos comandos C ou das instruções assembly. Observe que se a janela selecionada for a disassembly, a execução passo a passo do programa será feita instrução por instrução assembly. Se a janela selecionada for a do código fonte em C, a execução do programa será de comando por comando C. Além de executar o programa é possível visualizar o estado dos registradores da CPU e dos periféricos, além do conteúdo das variáveis e da memória.

Para visualizar o conteúdo dos Seleção do conjunto registradores é necessário selecionar a opção de registradores a View > Register no menu principal. Isto fará ser visualizad o com que a janela Register (figura 2.8) seja apresentada na tela. A janela “Register” pode ser utilizada para visualizar e alterar o conteúdo tanto dos registradores da CPU (conforme mostra a figura 2.8) como de qualquer registrador de periféricos. Para selecionar o conjunto de Contadores de ciclos registradores a ser apresentado, basta utilizar a caixa drop-down localizada no topo da janela. Figura 2.8 – Janela de registradores

Ferramentas de Programação 47

Agora que já vimos os procedimentos para execução do programa, o próximo passo é visualizarmos o conteúdo das variáveis. No presente caso, iremos nos limitar a visualizar as variáveis globais “temp” e “cnt”. Para isso, basta selecionar a opção View > Statics no menu principal, o que irá fazer com que a janela da figura 2.9A seja apresentada.

Figura 2.9A Figura 2.9B Repare que estão listados outros símbolos globais, como os bytes de opção (option bytes) e a variável “temp”, que aparece na última linha. Também são apresentados os endereços onde os símbolos estão armazenados. No caso da variável “temp”, o endereço da mesma é 0xFEF00. Caso necessário, também é possível alterar o formato de visualização da variável, bastando clicar com o botão direito do mouse sobre a mesma e no menu flutuante selecionar a opção desejada (figura 2.9B). Também é possível alterar o valor de qualquer variável, basta clicar sobre ela e digitar o novo valor seguido da tecla ENTER. Uma outra possibilidade interessante é a janela de visualização em tempo real “Live Watch”, ela permite que se acompanhe a alteração do conteúdo das variáveis em tempo real, ou seja, durante a execução do programa. Selecionando a opção View > Live Watch no menu principal será apresentada uma janela similar a da figura 2.10A, onde podem ser inseridas as variáveis cujo conteúdo se deseja visualizar em tempo real.

Figura 2.10A Figura 2.10B Por padrão, o conteúdo da janela “Live Watch” é atualizado a cada segundo (1000ms), mas este valor pode ser modificado na janela de opções da IDE (Tools > Options no menu principal). A figura 2.10B mostra esta janela e o campo para alteração do intervalo de atualização da janela “Live Watch”. Outra característica importante é a criação de breakpoints (pontos de parada) que são utilizados para interromper a execução do programa. Os breakpoints permitem que o

48 Microcontroladores RL78: Guia Básico

programador possa paralisar o programa em um determinado ponto ou no instante em que uma determinada condição ocorra (breakpoints condicionais). Primeiramente, iremos criar um breakpoint de código, que consiste em marcar uma determinada linha de código ou um endereço de memória que ao ser atingido, a execução do programa é suspensa. Para fazer isso, basta um duplo-clique na área cinza que precede a linha de código na janela do código fonte. A título de exemplo, sugerimos que se dê um duplo-clique na linha de programa indicada como breakpoint 1 na figura 2.11. Ao fazer isso, surgirá um círculo vermelho em frente a linha, indicando que a mesma possui um breakpoint ativo. Antes de prosseguirmos com os testes é interessante que o leitor habilite a janela de breakpoints, de forma a poder visualizar e selecionar os breakpoints marcados. Para fazer isso, basta selecionar a opção View > Breakpoints no menu principal.

Breakpoint Breakpoint 2 1

Jane la de breakpoints

Figura 2.11 – Breakpoints Uma vez que tenha marcado o breakpoint e ativado a janela de breakpoints, a aparência do IDE deve ser aproximadamente igual a da figura 2.11. Se o leitor desejar, poderá iniciar a execução do programa pressionando a tecla F5 e verá que o programa será executado até encontrar o ponto marcado como breakpoint 1 na figura 2.11. Até aqui, nada mais fizemos do que criar breakpoints de código. No entanto, podemos adicionar inteligência ao mesmo: clique com o botão direito do mouse sobre a variável “temp” no código fonte, no menu que irá surgir (figura 2.12A), selecione a opção “Set Data Breakpoint for ‘temp’”. Um novo breakpoint será adicionado na janela de breakpoints (figura 2.12B).

Ferramentas de Programação 49

Figura 2.12A Figura 2.12B Figura 2.12C Clicando-se com o botão direito do mouse sobre o data breakpoint na janela de breakpoints e selecionando-se a opção “Edit” será apresentada a janela da figura 2.12C, na qual é possível preencher a condição desejada para que o programa seja interrompido (no caso o programa irá parar quando “temp” atingir o valor 10000). Se o programa for executado (tecla F5), o leitor poderá observar que a execução será paralisada na linha do comando for e no mesmo instante, a janela de visualização das variáveis estáticas estará indicando que a variável “temp” possui o valor 10000, exatamente o que seria de se esperar. Desta forma, criamos um breakpoint condicional. Finalmente é importante saber que é possível desabilitar temporariamente um breakpoint. Para isso, basta clicar sobre a marca em frente ao mesmo na janela de breakpoints. Um breakpoint desabilitado é representado como um círculo vermelho preenchido de branco. Uma característica interessante do simulador é a disponibilidade de dois contadores de ciclos (CCTIMER1 e CCTIMER2), que podem ser utilizados para se efetuar medições do tempo de execução do programa ou de trechos do mesmo, inclusive com a possibilidade de alterar o conteúdo dos mesmos de forma a facilitar as medições. Estes contadores estão disponíveis na janela de visualização de registradores da CPU do simulador. As figuras 2.13 e 2.14 demonstram a utilização do contador de ciclos para medição do intervalo de tempo transcorrido durante uma chamada à função atraso no nosso programa exemplo. Na figura 2.13, o CCTIMER1 foi zerado manualmente antes de executar o comando for .

Figura 2.13 A figura 2.14 mostra o conteúdo do CCTIMER1 após a execução do laço for . Observe que o conteúdo do mesmo é apresentado em vermelho, indicando que o mesmo foi alterado desde o último comando do depurador.

50 Microcontroladores RL78: Guia Básico

Figura 2.14 Observando o conteúdo do CCTIMER1 e conhecendo o clock da CPU, podemos facilmente determinar o tempo total de execução da função. Supondo que a CPU estivesse operando a 32MHz, este tempo seria 1/32MHz * 1965555 = 61,42 ms.

2.1.3. Depurando um Programa Os procedimentos para depuração de um programa utilizando o TK (integrado em diversos kits da Renesas) ou um depurador externo como o E1 ou E20 são praticamente idênticos aos descritos para a simulação do programa. Primeiramente é importante alterar as configurações do projeto, especialmente a seleção do driver de depuração. A seleção é realizada na janela de opções do projeto, na categoria Debugger conforme mostra a figura 2.15A). Uma vez selecionado o driver de depuração adequado é necessário configurar as opções de download (figura 2.15B): a opção “Suppress” permite iniciar a depuração sem que se altere a memória flash do microcontrolador. A opção “Verify” permite que o código seja programado e verificado na memória do chip.

Figura 2.15A Figura 2.15B A primeira sessão de depuração do projeto irá apresentar a janela da figura 2.16. Ao clicar no botão OK, a janela de configuração do depurador (figura 2.17) será apresentada.

Figura 2.16

Ferramentas de Programação 51

Nesta janela é possível configurar diversas opções do depurador, incluindo o código de identificação (ID code), clock principal e auxiliar, parada dos periféricos ao parar o programa, distribuição de memória no chip, etc.

Figura 2.17 Os procedimentos já vistos para o simulador podem também ser aplicados ao depurador in circuit (inclusive a janela de visualização em tempo real “Live Watch”).

Atenção: caso uma gravação em andamento tenha sido interrompida ou tenha sido gravado valores incorretos nos bytes de opção, é possível que o depurador não consiga reprogramar a memória flash do microcontrolador. Neste caso, uma possível solução é utilizar software Renesas Flash Programmer (RFP) e realizar o apagamento O da memória do chip. Este programa pode ser baixado no seguinte endereço: http://am.renesas.com/products/tools/flash_prom_programming/rfp/ index.jsp . Para download é necessário preencher um simples cadastro (gratuito) no site. Este cadastro também permite acesso a outros documentos e arquivos disponíveis no site da Renesas.

2.1.4. Gerando o Código Final Uma vez que a aplicação tenha sido completamente testada e esteja operando dentro das especificações do projeto, é necessário gerar um arquivo para gravação do microcontrolador. Apesar de ser tentador utilizar o programa gravado na memória do chip através de uma sessão de depuração (no modo “Debug”), é importante ressaltar que o programa gravado desta forma irá manter o depurador interno (OCD) ativado, fazendo com que a quantidade de energia consumida pelo chip seja maior, especialmente nos modos halt e stop. Por isso, é importante gerar um arquivo (normalmente do tipo Intel .hex) para gravação através de uma ferramenta como o Renesas Flash Programmer (RFP). A configuração do projeto em modo “Release” deve seguir todos os passos já mostrados para o projeto em modo “Debug”, com exceção das opções do linker, especialmente a geração do

52 Microcontroladores RL78: Guia Básico

arquivo de saída (aba Output), que deverá ser configurada para “Other” e selecionado o formato “intel-extended”. Na aba “Extra Output” deverá ser marcada a opção “Generate extra output file” e “Override default”. O nome do arquivo poderá então ser configurado pelo programador, não esquecendo de utilizar a extensão “.hex”.

Figura 2.18A Figura 2.18B

Ferramentas de Programação 53

54 Microcontroladores RL78: Guia Básico

3

Arquitetura e Modelo de Programação 3. Arquitetura e Modelo de Programação

Como já dissemos na parte introdutória deste livro, os microcontroladores RL78 utilizam uma CPU CISC de 16 bits capaz de operar a até 32MHz. Neste capítulo iremos estudar em maiores detalhes as principais características da CPU RL78, bem como o seu modelo de programação e modos de operação. 3.1. A CPU RL78

A linha de microcontroladores RL78 utiliza uma CPU derivada da linha 78K0R (inicialmente desenvolvida pela NEC). Os RL78 utilizam a mesma estrutura de registradores, conjunto de instruções, modos de operação e mapas de memória da linha 78K0R. A CPU utiliza a arquitetura Von Neumann modificada, com um mapa de memória unificado para dados e programa, mas utilizando barramentos de acesso distintos, permitindo que ocorram operações simultâneas de busca de instrução (na flash) e leitura/escrita da dados (na RAM). O modelo de programação da CPU RL78 é baseado num conjunto de 4 bancos de 8 registradores de uso geral da CPU, cada um com capacidade de 8 bits. Diversas instruções permitem também tratar conjuntos de dois registradores como um único registrador de 16 bits. Os registradores de propósitos gerais da CPU são batizados de X, A, B, C, D, E, H e L, ou ainda R0 a R7. Os conjuntos de 16 bits são batizados de AX, BC, DE e HL, ou ainda RP0 a RP3.

O leitor mais experiente poderá perceber alguma similaridade entre o modelo de programação da CPU RL78/78K0R e outros microprocessadores mais antigos, como o e inclusive o Intel 8080. Esta similaridade não é mera coincidência, pois a linha 78K0 i foi projetada pela NEC utilizando como base o modelo de programação (registradores e conjunto básico de instruções) do Z80 (originado do 8080). Posteriormente, a NEC aprimorou a CPU 78K0 de 8 bits e lançou a linha 78K0R de 16 bits!

Outra característica interessante é que os registradores de uso geral mencionados acima estão mapeados na memória RAM do chip, o que permite uma enorme flexibilidade ao programador, sendo possível inclusive acessá-los através de ponteiros em C! A existência de quatro conjuntos ou bancos de registradores também é uma característica importante, pois permite trocas de contexto extremamente rápidas (uma troca de contexto típica é a que ocorre na alternância entre o processamento de programa e o processamento de uma interrupção). Em arquiteturas tradicionais (com apenas um conjunto de registradores da CPU), quando ocorre uma interrupção, é necessário salvar os registradores da CPU na pilha, antes de se realizar

Arquitetura e Modelo de Programação 55

o tratamento da interrupção. Ao final do tratamento da interrupção, é necessário restaurar o estado dos registradores da CPU antes de retornar ao programa principal. Todas estas operações consomem tempo precioso da CPU. Nos RL78, basta utilizar um banco de registradores para o processamento do programa e outros bancos para as interrupções. Basicamente, o único registrador da CPU que ainda precisará ser preservado na pilha é o PSW (dependendo da complexidade do programa, outros podem necessitar ser preservados na pilha também). A tabela 3.1 mostra os registradores de uso geral da CPU, bem como a organização dos bancos e os endereços absolutos de memória onde os mesmos estão mapeados.

Registradores Endereço na RAM 16 bits 8 bits Banco 0 Banco 1 Banco 2 Banco 3 H (R7) 0xFFEFF 0xFFEF7 0xFFEEF 0xFFEE7 HL (RP3) L (R6) 0xFFEFE 0xFFEF6 0xFFEEE 0xFFEE6 D (R5) 0xFFEFD 0xFFEF5 0xFFEED 0xFFEE5 DE (RP2) E (R4) 0xFFEFC 0xFFEF4 0xFFEEC 0xFFEE4 B (R3) 0xFFEFB 0xFFEF3 0xFFEEB 0xFFEE3 BC (RP1) C (R2) 0xFFEFA 0xFFEF2 0xFFEEA 0xFFEE2 A (R1) 0xFFEF9 0xFFEF1 0xFFEE9 0xFFEE1 AX (RP0) X (R0) 0xFFEF8 0xFFEF0 0xFFEE8 0xFFEE0 Tabela 3.1

3.1.1. Registradores Especiais da CPU Além dos registradores de uso geral, a CPU dos RL78 inclui outros registradores especiais: • Program Status Word ( PSW ), de 8 bits, e que é utilizado para armazenar bits de estado da CPU; • Program Counter ( PC ), de 20 bits, e que é utilizado para indicar o endereço da próxima instrução a ser executada; • Stack Pointer ( SP ), de 16 bits, e que aponta o topo da pilha de memória; • Extra Segment ( ES ), de 8 bits, e que armazena os 4 bits mais significativos utilizados por algumas instruções no acesso aos dados (endereços de 20 bits); • Code Segment ( CS ), de 8 bits, e que armazena os 4 bits mais significativos utilizados em algumas instruções de desvio ou chamada de sub-rotina; • Processor Mode Control ( PMC ), de 8 bits, e que controla o espelhamento de memória disponível em alguns modelos. Assim como os registradores de uso geral da CPU, os registradores especiais também estão mapeados na memória RAM do chip. A tabela 3.2 mostra o endereço de cada um deles (SPL é o byte menos significativo do SP e SPH é o byte mais significativo do SP).

56 Microcontroladores RL78: Guia Básico

Endereço Registrador 0xFFFF8 SPL 0xFFFF9 SPH 0xFFFFA PSW 0xFFFFB Reservado 0xFFFFC CS 0xFFFFD ES 0xFFFFE PMC Tabela 3.2

Adicionalmente, os microcontroladores da linha RL78/G14 incluem um registrador acumulador de 32 bits (MACR) utilizado pelas instrução de multiplicação e acúmulo MACH e MACHU. O registrador MACR também está mapeado na área de SFRs nos endereços 0xFFFF0 (MACRL, que guarda os 16 bits inferiores do MACR) e 0xFFFF2 (MACRH, que guarda os 16 bits superiores do MACR).

3.1.1.1. Registrador PSW

O registrador PSW contém alguns importantes bits de controle da CPU RL78. Nele estão localizados os sinalizadores ou flags da ULA (Unidade Lógica e Aritmética), os bits de seleção do banco de registradores de uso geral e os bits de controle do sistema de interrupção. Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura IE Z RBS1 AC RBS0 ISP1 ISP0 CY PSW Escrita Reset 0 0 0 0 0 1 1 0 Primeiramente vejamos a função dos bits Z, AC e CY, relacionados à ULA: Z – indicador de zero. Este bit é setado quando determinadas operações resultam em um valor igual a zero. AC – transporte auxiliar (auxiliary carry). O transporte auxiliar, nas operações de adição, quando setado, indica que houve transporte do bit 3 para o bit 4 do resultado. Nas operações de subtração, quando setado, indica que houve empréstimo do bit 4 para o bit 3. CY – transporte (carry). Ele é setado quando ocorre transporte nas operações de adição ou empréstimo nas operações de subtração. Nas operações de rotação e deslocamento de bits, ele recebe o bit deslocado para fora do registrador. Também pode atuar como um acumulador de bit em algumas operações de manipulação de bits. Os bits RBS1 e RBS0 selecionam o banco de registradores a ser utilizado. A tabela 3.3 mostra as configurações possíveis.

Arquitetura e Modelo de Programação 57

RBS1 RBS0 Banco 0 0 0 0 1 1 1 0 2 1 1 3 Tabela 3.3

Apesar de ser possível alterar estes bits através de operações de escrita, tanto no registrador PSW quanto no endereço de memória 0xFFFFA, os RL78 possuem uma instrução assembly específica para modificar estes bits: SEL RBx, onde x é o número do banco (0 a 3). Finalmente, temos os 3 bits relacionados ao sistema de interrupções dos RL78: IE, ISP1 e ISP0. O bit IE é o controle global de interrupções, quando IE = 0, as interrupções (exceto as não mascaráveis) estão desabilitadas ao passo que quando IE = 1, todas as interrupções estão habilitadas. Os RL78 possuem duas instruções especiais para manipular o bit IE: DI (Disable Interrupts), que faz IE = 0 e EI (Enable Interrupts) que faz IE = 1. Os bits ISP1 e ISP0 controlam a prioridade atual de interrupção. O sistema de interrupções dos RL78 possui 4 níveis de prioridade (0 a 3), sendo o nível 0 o de maior prioridade e 3 o de menor prioridade. A disponibilidade de um sistema com quatro níveis de prioridade significa que é possível configurar prioridades diferentes para cada fonte de interrupção e, além disso, é possível que uma interrupção de mais alta prioridade interrompa uma interrupção de menor prioridade que se encontre em tratamento. Veremos mais detalhes sobre o sistema de interrupções dos RL78 no capítulo 6.

3.1.1.2. Registrador PC

O PC (Program Counter) indica o endereço na memória onde está localizada a próxima instrução a ser executada. Nos RL78 o PC possui um tamanho de 20 bits e não pode ser acessado diretamente pelo usuário. Após um reset, o registrador PC é carregado com o conteúdo do vetor de reset (endereços 0x00000 e 0x00001 da memória).

3.1.1.3. Registrador SP

O apontador da pilha (SP) indica o topo da pilha de software, uma estrutura de dados utilizada para armazenamento de endereços de retorno das sub-rotinas, funções e interrupções, além de permitir também o armazenamento de dados (as variáveis locais de uma função C são armazenadas na pilha). O registrador SP possui largura de 16 bits, o que significa que a pilha está limitada a um tamanho máximo de 65536 bytes, o que não constitui nenhuma limitação séria, já que o RL78 mais poderoso até o momento possui 32KiB de memória RAM. O registrador SP é internamente

58 Microcontroladores RL78: Guia Básico

dividido em dois bytes, sendo o SPH a parte alta do SP e SPL a parte baixa do SP (veja a tabela 3.2). Outra característica da pilha dos RL78 é que ela possui alinhamento par e o bit menos significativo do SP é sempre mantido em 0. Isso significa que não é possível guardar bytes na pilha, apenas words de 16 bits. Além disso, a pilha cresce para baixo, ou seja, a cada word armazenada na pilha, o SP é decrementado em 2.

Observe que o SP aponta sempre para endereços de oito bits na memória RAM, por isso, após i salvar uma word (2 bytes) na pilha, o SP é decrementado em 2!

A tabela 3.4 demonstra o comportamento do SP e a utilização da pilha em todos os casos possíveis. Endereço da Pilha PUSH AX PUSH PSW CALL/CALLT Interrupções/BRK SP SP-1 A PSW 0x00 PSW SP-2 X 0x00 PC19-PC16 PC19-PC16 SP-3 PC15-PC8 PC15-PC8 SP-4 PC7-PC0 PC7-PC0 Tabela 3.4

O primeiro caso (PUSH AX) demonstra o empilhamento de dados. A instrução assembly PUSH permite salvar um par de registradores (AX, BC, DE ou HL) na pilha. Nestes casos, primeiramente é salvo o registrador mais significativo (A, B, D ou H) no endereço SP-1 e em seguida o registrador menos significativo (X, C, E, ou L) é salvo no endereço SP-2, que passa a ser o novo topo da pilha. No segundo caso (PUSH PSW), o conteúdo do registrador PSW é salvo na posição indicada por SP-1 e o valor zero é salvo na posição SP-2, que passa a ser o novo topo da pilha. O terceiro caso demonstra a utilização da pilha em uma chamada de sub-rotina ou função utilizando as instruções assembly CALL ou CALLT. A primeira posição da pilha recebe o valor zero, e as posições seguintes recebem o valor do PC (que aponta a instrução seguinte ao CALL/CALLT) dividido em três bytes: em os bits 19 a 16 do PC são salvos em SP-2, os bits 15 a 8 do PC são salvos em SP-3 e os bits 7 a 0 do PC são salvos em SP-4, que passa a ser o novo topo da pilha. O quarto exemplo demonstra a utilização da pilha num evento de interrupção ou execução de uma instrução BRK (que é uma interrupção por software). A pilha é utilizada de forma muito semelhante ao terceiro caso, porém, o PSW é salvo na primeira posição (o PSW é sempre preservado na pilha numa interrupção).

Após um reset o conteúdo do registrador SP é indeterminado e por isso ele deve ser inicializado para apontar para uma área válida de memória RAM antes que se utilizem i interrupções ou chamadas de sub-rotina/função! Esta inicialização é feita automaticamente pelos compiladores C.

Arquitetura e Modelo de Programação 59

3.1.1.4. Registradores ES e CS

Os registradores ES e CS são utilizados para auxiliar no endereçamento de dados (ES) e programa (CS). Ambos atuam como complemento para formar endereços de 20 bits, necessários para acessar toda a faixa de 1MiB de memória dos RL78.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 ES3 ES2 ES1 ES0 ES Escrita Reset 0 0 0 0 1 1 1 1

Nos RL78, as instruções que acessam a memória para ler escrever dados estão normalmente restritas a operar na faixa de endereços entre 0xF0000 e 0xFFFFF. A existência do registrador ES e de um modo de endereçamento especial permite que as instruções utilizem dados localizados em qualquer endereço de memória, esta funcionalidade é utilizada principalmente na leitura de constantes armazenadas nas áreas de memória flash. Já o registrador CS é utilizado para endereçamento de programa. Como o PC dos RL78 possui 20 bits, mas a maioria das instruções de desvio utilizam operandos de 16 bits, é necessário utilizar o registrador CS para se ter acesso a toda a faixa de 1MiB de memória dos RL78.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 CS3 CS2 CS1 CS0 CS Escrita Reset 0 0 0 0 0 0 0 0

3.1.1.5. Registrador PMC

O registrador PMC (Processor Mode Control) é utilizado para controlar o espelhamento da primeira faixa de 64KiB de memória dos RL78.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 0 0 MAA PMC Escrita Reset 0 0 0 0 0 0 0 0

Nos RL78/G12, G13, G14 e G1A, quando o bit MAA está setado, o bloco de 64KiB compreendido entre 0x00000 e 0x0FFFF é espelhado na faixa compreendida entre 0xF0000 e 0xFFFFF. Isto permite que se acesse dados constantes (armazenados em flash) e dados da RAM no mesmo banco de memória. Quando MAA=0, a faixa entre 0x10000 e 0x1FFFF é espelhada na região entre 0xF0000 e 0xFFFFF. Note que, como veremos mais adiante, a memória RAM e os registradores SFR dos RL78 também estão localizados na faixa de endereços entre 0xF0000 e 0xFFFFF. Neste caso, os endereços com RAM/SFR possuem preferência e irão manter esta funcionalidade. Apenas os endereços não implementados nesta área é que poderão acessar a área espelhada.

60 Microcontroladores RL78: Guia Básico

Uma particularidade deste registrador é que ele somente pode deve ser modificado uma única vez e na inicialização do programa, além disso, após setado o bit MAA, é necessário esperar um ciclo de clock antes de se acessar a área espelhada. 3.1.2. Mapa de Memória Como já vimos, os microcontroladores RL78 possuem um espaço de endereçamento de 1MiB. Este espaço é compartilhado por memória flash, RAM e registradores SFR. A figura 3.1 mostra o mapa de memória simplificado para alguns modelos de RL78 (G12 com 4KiB de flash, G13 com 64KiB de flash e G13 com 512KiB de flash). R5F10267/10277/102A7 R5F100xE R5F100xL 0xFFFFF Registradores de funções especiais SFR Registradores de funções especiais Registradores de funções especiais 0xFFF00 (256 bytes) SFR (256 bytes) SFR (256 bytes) 0xFFEFF Registradores de propósito geral (32 Registradores de propósito geral (32 Registradores de propósito geral (32 bytes) 0xFFEE0 bytes) bytes) 0xFFEDF

0xFFD00 RAM (512 bytes) RAM (4KiB) 0xFFCFF

0xFEF00 RAM (32KiB) 0xFEEFF

0xF7F00 0xF7EFF

0xF3000 Área reservada Espelhamento (51,75KiB) Espelhamento (19,75KiB) 0xF2FFF 0xF2000 0xF1FFF 0xF1800 Dataflash (8KiB) 0xF17FF Dataflash (4KiB)

0xF1000 Dataflash (2KiB) 0xF0FFF

0xF0800 Área reservada Área reservada Área reservada 0xF07FF Registradores de funções especiais SFR Registradores de funções especiais Registradores de funções especiais 0xF0000 (2KiB) SFR (2KiB) SFR (2KiB) 0xEFFFF

0x80000 Área reservada 0x7FFFF Área reservada

0x10000 Área reservada 0x0FFFF

0x01000 Memória flash (512KiB) Memória flash (64KiB) 0x00FFF

0x00000 Memória flash (4KiB) Figura 3.1

Podemos perceber que os endereços iniciais da memória são ocupados pela memória flash, onde é armazenado o programa a ser executado. Esta área de memória varia de 2KiB (no menor RL78) a 512KiB. Observe que, para efeitos de apagamento, a memória flash é organizada em blocos de 1KiB (não é possível apagar áreas menores que 1KiB). A função de apagamento FSL_Erase(), parte da biblioteca FSL de manipulação da memória flash, utiliza como parâmetro o número do bloco de memória, conforme a figura 3.2. Podemos facilmente calcular o número de qualquer bloco a partir de um endereço, utilizando-se a fórmula (apenas a parte inteira do resultado deve ser utilizada): Endereço Endereço hex( ) N = ou N hex( ) = BLOCO 1024 BLOCO 400x0 Após a área de memória flash encontra-se uma área reservada e não implementada, por esta razão não é permitido acessar esta faixa de endereços para nenhum propósito (operações de

Arquitetura e Modelo de Programação 61

leitura ou escrita nestas áreas podem provocar um reset por acesso ilegal à memória (IAW) caso o bit IAWEN esteja setado no registrador IAWCTL ou quando o watchdog está ativado).

0x7FFFF 0x7FC00 Bloco 511 0x7FBFF 0x7F800 Bloco 510 0x7F7FF 0x7F400 Bloco 509 0x7F3FF 0x7F000 Bloco 508

...

0x01FFF 0x01C00 Bloco 7 0x01BFF 0x01800 Bloco 6 0x017FF 0x01400 Bloco 5 0x013FF 0x01000 Bloco 4 0x00FFF 0x00C00 Bloco 3 0x00BFF 0x00800 Bloco 2 0x007FF 0x00400 Bloco 1 0x003FF 0x00000 Bloco 0 Figura 3.2

A faixa de endereços entre 0xEF000 e 0xEFFFF não é implementada do ponto de vista do i usuário, mas contém memória ROM com código utilizado pelas bibliotecas de escrita na flash (FSL e FDL). Por esta razão, a execução de código nesta área não gera um reset IAW.

Em seguida temos uma das áreas dedicadas aos registradores de funções especiais (SFR), que controlam os periféricos e algumas funcionalidades dos microcontroladores RL78. Esta área é seguida por outra faixa de endereços não implementados (reservados). A área seguinte é a dataflash. Esta área de memória (opcional, conforme o modelo de microcontrolador utilizado) é destinada exclusivamente ao armazenamento de dados não voláteis, ou seja, dados que devem ser mantidos mesmo quando o microcontrolador é desligado (por exemplo, senhas, configurações, etc.). A área de dataflash difere da área de flash normal principalmente por utilizar um barramento de acesso exclusivo. Isto permite que se realizem operações na dataflash em paralelo com o acesso a memória flash de código. Nos modelos em que a memória dataflash não está presente, esta área de memória é reservada e não deve ser utilizada (conforme já dito para as demais áreas reservadas). Seguindo a área de dataflash encontramos (nos modelos com 12KiB ou mais de memória flash) a área de espelhamento de memória. Já vimos a finalidade e forma de utilização do espelhamento de memória no tópico 3.1.1.5, quando estudamos o registrador PMC. No topo da faixa de endereçamento encontramos a área de memória RAM, os registradores de propósito geral (GPRs), que são os registradores da CPU mapeados na memória RAM e outra área de registradores de funções especiais (SFR).

62 Microcontroladores RL78: Guia Básico

Uma característica interessante acerca dos RL78 é que os primeiros 4KiB da memória flash são ocupados por uma série de elementos conforme mostra a figura 3.3. Os primeiros 206 bytes são ocupados pelos vetores de interrupção (64 vetores de 16 bits), tabela de endereços de CALLT (32 endereços de 16 bits), bytes de opção e código de segurança. Isto significa que na prática, um microcontrolador de 4KiB possui apenas 3890 bytes de área útil para código.

0x00FFF 0x000CE Área de programa 0x000CD 0x000C4 Área de código de segurança (Security ID) (10 bytes) 0x000C3 0x000C0 Área de bytes de opção (4 bytes) 0x000BF 0x00080 Área de tabela CALLT (64 bytes) 0x0007F 0x00000 Área de Vetores de Interrupção (128 bytes) Figura 3.3

Este bloco inicial de 4KiB é chamado de bloco de boot e em microcontroladores com 16KiB ou mais de flash, podem existir dois blocos de boot: o primeiro localizado nos endereços mostrados na figura 3.3 e o segundo no bloco de 4KiB imediatamente posterior (endereços 0x01000 a 0x01FFF). A existência de dois blocos de boot permite que a aplicação possa alterar um bloco de boot com total segurança, resistindo inclusive a falhas de alimentação durante a operação de gravação do novo bloco de boot (esta funcionalidade é extremamente útil em boot loaders). A funcionalidade de bloco duplo de boot é utilizada através da função FSL_InvertBootFlag() que inverte o sinalizador que identifica o bloco de boot atual. Desta forma, supondo uma atualização de firmware em campo, o boot loader pode escrever o novo código de boot no bloco de boot 1 e somente após completar e verificar a gravação de todo o bloco de boot 1 é que a função FSL_InvertBootFlag() é chamada, invertendo o flag de bloco de boot ativo e selecionando o bloco 1 para o boot. Na próxima atualização o boot loader irá modificar o bloco de boot 0, mantendo o bloco 1 totalmente operacional.

3.1.3. Modos de Endereçamento A CPU RL78 suporta diversos modos de endereçamento. Estão disponíveis praticamente todos os principais modos de endereçamento encontrados nas CPUs RISC/CISC atuais (quatro modos para programa e oito para dados). Os modos de endereçamento de código (utilizados nos desvios e chamadas de sub-rotinas ou funções) incluem: 1. Endereçamento relativo de 8 ou 16 bits: neste modo o valor do operando (em complemento de dois) é somado ao PC, de forma a obter o endereço de destino do programa; 2. Endereçamento absoluto de 16 ou 20 bits: o endereço do operando é utilizado como destino do desvio/chamada. Operandos de 16 bits devem ser precedidos do símbolo “!” e operandos de 20 bits devem ser precedidos do símbolo “!!”. Endereços de 16 bits estão limitados sempre aos primeiros 64KiB de memória;

Arquitetura e Modelo de Programação 63

3. Endereçamento de tabela CALLT: neste modo utiliza-se um operando de 5 bits para especificar uma das 32 posições da tabela de saltos CALLT localizada na área entre 0x00080 e 0x000BF. Isto permite chamar funções na faixa de endereços de 0x00000 a 0x0FFFF utilizando instruções CALLT com tamanho de apenas 2 bytes, reduzindo o tamanho final do código; 4. Endereçamento por registrador: o conteúdo de um dos pares de registradores (AX, BC, DE ou HL) é utilizado em conjunto com o registrador CS para formar o endereço de destino de 20 bits. Os modos de endereçamento de dados são os seguintes: 1. Implícito: o operando não está escrito com o opcode mas está implícito no mesmo; 2. Registrador: o operando é um dos registradores de 8 ou de 16 bits; 3. Direto: o operando é uma posição de memória especificada pelo operando de 16 bits (endereços entre 0xF0000 e 0xFFFFF) ou em qualquer posição da memória (com o uso do registrador ES); 4. Endereçamento rápido (short): o operando de 8 bits especifica um endereço na faixa entre 0xFFE20 e 0xFFF1F. Este modo permite um rápido acesso a uma pequena porção da RAM, aos GPRs e uma parte dos SFRs; 5. Endereçamento SFR: o operando de 8 bits especifica um endereço na faixa entre 0xFFF00 e 0xFFFFF (uma das áreas dos SFR). Este modo permite um rápido acesso aos principais SFRs do microcontrolador; 6. Endereçamento indireto por registrador: o par de registradores especificado pelo operando (DE ou HL) contém o endereço do operando. Este modo comporta-se exatamente como os ponteiros em C. A faixa de memória endereçável é aquela entre os endereços 0xF0000 e 0xFFFFF, ou qualquer área de memória (com o uso do registrador ES); 7. Endereçamento de base (base address): neste modo um par de registradores (normalmente BC, DE, HL ou SP) fornece o endereço base e um valor imediato de 8 ou 16 bits fornece o deslocamento. A soma do endereço base mais o deslocamento fornece o endereço do dado. Este modo permite acesso aos dados salvos na pilha (como por exemplo as variáveis locais em funções C), além de permitir também operações com outras estruturas de dados (como arrays); 8. Endereçamento de base indexado: este modo é semelhante ao anterior, mas o par de registradores HL fornece o endereço base e os registradores B ou C fornecem o índice. O endereço do dado é obtido pela soma da base mais o índice (é possível utilizar o registrador ES para cobrir toda a faixa de memória); De maneira geral, podemos dizer que o modo de endereçamento rápido (short) é o mais rápido para acesso à memória RAM do microcontrolador (já que o tamanho total da instrução é menor que nos demais modos). Por isso, sempre que possível, devemos manter as variáveis mais utilizadas na área compreendida entre os endereços 0xFFE20 e 0xFFEDF. Podemos utilizar o modificador __saddr para forçar o compilador IAR a armazenar uma ou mais variáveis nesta área da RAM.

64 Microcontroladores RL78: Guia Básico

3.2. Conjunto de Instruções Assembly

O conjunto de instruções dos RL78 é bastante poderoso e constitui, sem dúvidas, uma das grandes qualidades desta linha de microcontroladores. O conjunto de instruções é enxuto (81 instruções) quando comparado a outras máquinas CISC, mas é muito poderoso, com diversos recursos interessantes como: suporte a dados de 8 ou 16 bits, suporte a operações com 1 bit, instruções DSP (somente nos RL78/G14), diversos tipos de desvios relativos, absolutos, condicionais e incondicionais e tabela de desvios (CALLT). Outra característica interessante é a presença de instruções de pulo condicional, que executam ou não a próxima instrução baseadas em algumas condições. Este tipo de instrução é comum em máquinas RISC, mas incomum em máquinas CISC. Também está presente a instrução BTCLR (testa e, caso verdadeiro, apaga e desvia), que é especialmente útil em operações atômicas envolvendo semáforos. Para facilitar o estudo do conjunto de instruções dos RL78, vamos dividí-lo em algumas categorias, conforme o tipo de operação realizada pela instrução.

3.2.1. Instruções de Manipulação de Dados Permitem manipular dados, ou seja, transferir informação para os registradores do microcontrolador e entre os registradores e a memória. MOV dst,fnt – copia um dado de 8 bits especificado pelo operando fonte (fnt) para o destino especificado (dst). Os flags do PSW não são alterados. MOVW dst,fnt – copia um dado de 16 bits especificado pelo operando fonte (fnt) para o destino especificado (dst). Os flags do PSW não são alterados. Esta instrução pode ser utilizada para inicializar o SP com um valor imediato ou com o valor de AX e também pode ser utilizada para copiar SP para um dos pares de registradores (AX, BC, DE ou HL). MOVS [HL+dsl],X ou MOVS ES:[HL+dsl],X– copia um dado de 8 bits especificado pelo operando fonte (registrador X) para o destino especificado (conteúdo de HL mais deslocamento dsl, opcionalmente com o uso do ES), altera os bits Z e CY no PSW de acordo com o resultado da operação. XCH dst,fnt – permuta o conteúdo de 8 bits do operando fonte especificado (fnt) pelo conteúdo do operando destino (dst). Os flags do PSW não são alterados. XCHW AX,fnt – permuta o conteúdo de 16 bits do operando fonte especificado (fnt) pelo conteúdo do operando destino (registrador AX). Os flags do PSW não são alterados. ONEB dst – o operando especificado por dst recebe o valor 0x01. Os flags do PSW não são alterados. ONEW dst – o operando especificado por dst recebe o valor 0x0001. Os flags do PSW não são alterados. CLRB dst – o operando especificado por dst recebe o valor 0x00. Os flags do PSW não são alterados.

Arquitetura e Modelo de Programação 65

CLRW dst – o operando especificado por dst recebe o valor 0x0000. Os flags do PSW não são alterados.

3.2.2. Instruções Aritméticas, Lógicas e de Comparação São as instruções utilizadas para efetuar cálculos (basicamente adição, subtração e multiplicação) de 8 ou 16 bits, além de operações lógicas bit a bit (AND, OR e XOR) e também a comparação de dados (comparação entre variáveis e de variáveis com zero). Os microcontroladores da linha G14 incluem também instruções DSP (multiplicação, divisão e multiplicação e acúmulo). ADD dst,fnt – adiciona o conteúdo de 8 bits do operando fonte (fnt) ao conteúdo do operando de destino (dst). O resultado é armazenado no destino. Os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se o resultado é zero, CY é setado se o resultado é maior que 255 e AC é setado se houve transporte do bit 3 para o bit 4 na operação, nos demais casos os flags são apagados). ADDC dst,fnt – adiciona o conteúdo de 8 bits do operando fonte (fnt) ao conteúdo do operando de destino (dst) mais o carry (CY). O resultado é armazenado no destino. Os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se o resultado é zero, CY é setado se o resultado é maior que 255 e AC é setado se houve transporte do bit 3 para o bit 4 na operação, nos demais casos os flags são apagados). ADDW dst,fnt – adiciona o conteúdo de 16 bits do operando fonte (fnt) ao conteúdo do operando de destino (dst). O resultado é armazenado no destino. Os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se o resultado é zero, CY é setado se o resultado é maior que 65535, nos demais casos os flags são apagados, AC é indefinido). No caso especial onde dst é o registrador SP, o operando fnt somente pode ser um valor imediato de 8 bits e o PSW não é alterado. SUB dst,fnt – subtrai o conteúdo de 8 bits do operando fonte (fnt) do conteúdo do operando de destino (dst). O resultado é armazenado no destino. Os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se o resultado é zero, CY é setado se houve empréstimo (dst era menor que fnt) e AC é setado se houve transporte do bit 3 para o bit 4 na operação, nos demais casos os flags são apagados). SUBC dst,fnt – subtrai o conteúdo de 8 bits do operando fonte (fnt) e do carry (CY) do conteúdo do operando de destino (dst). O resultado é armazenado no destino. Os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se o resultado é zero, CY é setado se houve empréstimo (dst era menor que fnt) e AC é setado se houve empréstimo do bit 4 para o bit 3 na operação, nos demais casos os flags são apagados). SUBW dst,fnt – subtrai o conteúdo de 16 bits do operando fonte (fnt) do conteúdo do operando de destino (dst). O resultado é armazenado no destino. Os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se o resultado é zero, CY é setado se houve empréstimo (dst era menor que fnt), nos demais casos os flags são apagados, AC é indefinido). No caso especial onde dst é o registrador SP, o operando fnt somente pode ser um valor imediato de 8 bits e o PSW não é alterado.

66 Microcontroladores RL78: Guia Básico

MULU X – multiplicação sem sinal de 8 bits do conteúdo do registrador X pelo conteúdo do registrador A, armazenando o resultado de 16 bits em AX. Os flags do PSW não são alterados. AND dst,fnt – realiza a operação lógica AND entre os 8 bits do operando fonte (fnt) e os 8 bits do operando destino (dst), armazenando o resultado no destino. O bit Z no PSW é alterado (setado se o resultado for zero, caso contrário é apagado). OR dst,fnt – realiza a operação lógica OR entre os 8 bits do operando fonte (fnt) e os 8 bits do operando destino (dst), armazenando o resultado no destino. O bit Z no PSW é alterado (setado se o resultado for zero, caso contrário é apagado). XOR dst,fnt – realiza a operação lógica XOR entre os 8 bits do operando fonte (fnt) e os 8 bits do operando destino (dst), armazenando o resultado no destino. O bit Z no PSW é alterado (setado se o resultado for zero, caso contrário é apagado). CMP dst,fnt – compara o conteúdo de 8 bits do operando fonte (fnt) com o conteúdo do operando destino (dst), subtraindo fnt de dst. O resultado é descartado e os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se os dois valores são iguais, CY é setado se dst é menor que fnt e AC é setado se houve empréstimo do bit 4 para o bit 3 na operação, nos demais casos os flags são apagados). CMP0 dst – compara o conteúdo de 8 bits do operando destino (dst) com zero, subtraindo 0 de dst. O resultado é descartado e os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se dst é igual a zero, CY é setado se dst é menor que zero e AC é setado se houve empréstimo do bit 4 para o bit 3 na operação, nos demais casos os flags são apagados). CMPS dst,fnt – compara o conteúdo de 8 bits do operando fonte (fnt) com o conteúdo do operando destino (dst), subtraindo fnt de dst. O resultado é descartado e os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se os dois valores são iguais, CY é setado se A=0, X=0 ou se os valores são diferentes e AC é setado se houve empréstimo do bit 4 para o bit 3 na operação, nos demais casos os flags são apagados). CMPW dst,fnt – compara o conteúdo de 16 bits do operando fonte (fnt) com o conteúdo do operando destino (dst), subtraindo fnt de dst. Os bits Z, CY e AC no PSW são alterados de acordo com o resultado da operação (Z é setado se os dois valores são iguais, CY é setado se dst é menor que, nos demais casos os flags são apagados, AC é indefinido). Instruções de divisão, multiplicação e multiplicação e acúmulo (exclusivas dos RL78/G14): MULHU – multiplicação sem sinal de 16 bits do conteúdo do registrador BC pelo conteúdo do registrador AX, armazenando o resultado de 32 bits em BC (parte alta) e AX (parte baixa). Os flags do PSW não são alterados. MULH – multiplicação de 16 bits com sinal do conteúdo do registrador BC pelo conteúdo do registrador AX, armazenando o resultado de 32 bits em BC (parte alta) e AX (parte baixa). Os flags do PSW não são alterados. DIVHU – divisão sem sinal de 16 bits do conteúdo do registrador AX pelo conteúdo do registrador DE, armazenando o resultado de 16 bits em AX e o resto da divisão em DE. Os flags do PSW não são alterados.

Arquitetura e Modelo de Programação 67

DIVWU – divisão sem sinal de 32 bits do conteúdo dos registradores BCAX pelo conteúdo dos registradores HLDE, armazenando o resultado de 32 bits em BCAX e o resto da divisão em HLDE. Os flags do PSW não são alterados. MACHU – multiplicação de 16 bits e acúmulo, sem sinal, do conteúdo do registrador BC pelo conteúdo do registrador AX, somando o resultado ao registrador de 32 bits MACR. Os flags CY e AC do PSW são alterados: AC é sempre apagado e CY é setado quando a soma ao MACR ultrapassa a capacidade do mesmo (overflow). MACH – multiplicação de 16 bits e acúmulo, com sinal, do conteúdo do registrador BC pelo conteúdo do registrador AX, somando o resultado ao registrador de 32 bits MACR. Os flags CY e AC do PSW são alterados: CY é setado quando a soma ao MACR ultrapassa a capacidade do mesmo (overflow), ou seja, quando o resultado é maior que 0x7FFFFFFF (limite positivo) ou menor que 0x80000000 (limite negativo), AC é setado quando o resultado acumulado é negativo e apagado quando o resultado acumulado é positivo.

3.2.3. Instruções de Incremento e Decremento Estas instruções são utilizadas para realizar o incremento (soma um) ou decremento (subtrai um) de registradores ou posições de memória. INC dst – incrementa o conteúdo de 8 bits do destino (dst). Os flags Z e AC no PSW são alterados: Z é setado se o resultado for igual a zero, caso contrário é apagado, AC é setado caso ocorra um transporte do bit 3 para o bit 4, caso contrário é apagado. INCW dst – incrementa o conteúdo de 16 bits do destino (dst). Os flags do PSW não são alterados. DEC dst – decrementa o conteúdo de 8 bits do destino (dst). Os flags Z e AC no PSW são alterados: Z é setado se o resultado for igual a zero, caso contrário é apagado, AC é setado caso ocorra um empréstimo do bit 4 para o bit 3, caso contrário é apagado. DECW dst – decrementa o conteúdo de 16 bits do destino (dst). Os flags do PSW não são alterados.

3.2.4. Instruções de Rotação e Deslocamento de Bits As instruções de deslocamento de bits são utilizadas para deslocar um ou mais bits à esquerda ou à direita e implementam em assembly as mesmas operações dos operadores << e >> em C. SHR dst,cnt – desloca o conteúdo de 8 bits especificado por dst em cnt posições à direita. O valor zero é inserido na posição mais significativa e o bit excedente é armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. Esta operação equivale ao operador >> e cada posição deslocada equivale a uma divisão inteira (sem sinal) por 2. O operando cnt pode ter qualquer valor entre 1 e 7.

68 Microcontroladores RL78: Guia Básico

SHRW dst,cnt – desloca o conteúdo de 16 bits especificado por dst em cnt posições à direita. O valor zero é inserido na posição mais significativa e o bit excedente é armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. Esta operação equivale ao operador >> e cada posição deslocada equivale a uma divisão inteira (sem sinal) por 2. O operando cnt pode ter qualquer valor entre 1 e 15.

SHL dst,cnt – desloca o conteúdo de 8 bits especificado por dst em cnt posições à esquerda. O valor zero é inserido na posição menos significativa e o bit excedente é armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. Esta operação equivale ao operador << e cada posição deslocada equivale a uma multiplicação inteira (sem sinal) por 2. O operando cnt pode ter qualquer valor entre 1 e 7.

SHLW dst,cnt – desloca o conteúdo de 16 bits especificado por dst em cnt posições à esquerda. O valor zero é inserido na posição menos significativa e o bit excedente é armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. Esta operação equivale ao operador << e cada posição deslocada equivale a uma multiplicação inteira (sem sinal) por 2. O operando cnt pode ter qualquer valor entre 1 e 15.

SAR dst,cnt – desloca o conteúdo de 8 bits especificado por dst em cnt posições à direita. O estado do bit 7 (sinal) é mantido na posição mais significativa e propagado à direita a cada posição deslocada e o bit excedente é armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. Cada posição deslocada equivale a uma divisão inteira (com sinal) por 2. O operando cnt pode ter qualquer valor entre 1 e 7.

SARW dst,cnt – desloca o conteúdo de 16 bits especificado por dst em cnt posições à direita. O estado do bit 15 (sinal) é mantido na posição mais significativa e propagado à direita a cada posição deslocada e o bit excedente é armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. Cada posição deslocada equivale a uma divisão inteira (com sinal) por 2. O operando cnt pode ter qualquer valor entre 1 e 15.

Arquitetura e Modelo de Programação 69

As instruções de rotação de bits operam de forma semelhante às de deslocamento, porém o bit excedente é realimentado, formando uma malha fechada ou anel, por isso o termo rotação. ROR dst,cnt – rotaciona o conteúdo de 8 bits especificado por dst em cnt posições à direita. O bit excedente é realimentado na parte mais significativa (bit 7) e também armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. O operando cnt pode ter qualquer valor entre 1 e 7.

ROL dst,cnt – rotaciona o conteúdo de 8 bits especificado por dst em cnt posições à esquerda. O bit excedente é realimentado na parte menos significativa (bit 0) e também armazenado em CY (registrador PSW). Os demais flags do PSW não são alterados. O operando cnt pode ter qualquer valor entre 1 e 7.

RORC dst,cnt – rotaciona através do carry o conteúdo de 8 bits especificado por dst em cnt posições à direita. O bit excedente é armazenado em CY (PSW) e o conteúdo prévio de CY é deslocado para a parte mais significativa (bit 7). Os demais flags do PSW não são alterados. O operando cnt pode ter qualquer valor entre 1 e 7.

ROLC dst,cnt – rotaciona através do carry o conteúdo de 8 bits especificado por dst em cnt posições à esquerda. O bit excedente é armazenado em CY (PSW) e o conteúdo prévio de CY é deslocado para a parte menos significativa (bit 0). Os demais flags do PSW não são alterados. O operando cnt pode ter qualquer valor entre 1 e 7.

70 Microcontroladores RL78: Guia Básico

ROLWC dst,cnt – rotaciona através do carry o conteúdo de 16 bits especificado por dst em cnt posições à esquerda. O bit excedente é armazenado em CY (PSW) e o conteúdo prévio de CY é deslocado para a parte menos significativa (bit 0). Os demais flags do PSW não são alterados. O operando cnt pode ter qualquer valor entre 1 e 15.

3.2.5. Instruções de Manipulação e Processamento de Bits Nesta categoria encontramos as instruções específicas para manipulação e operação (AND, OR, XOR, NOT) com dados de 1 bit. MOV1 dst,fnt – copia o bit do operando fonte (fnt) para o operando destino (dst). Um dos operandos deverá sempre ser o bit CY do registrador PSW. AND1 CY,fnt – realiza a operação lógica AND entre o bit especificado por fnt e CY, armazenando o resultado em CY. Os demais flags do PSW não são alterados. OR1 CY,fnt – realiza a operação lógica OR entre o bit especificado por fnt e CY, armazenando o resultado em CY. Os demais flags do PSW não são alterados. XOR1 CY,fnt – realiza a operação lógica XOR entre o bit especificado por fnt e CY, armazenando o resultado em CY. Os demais flags do PSW não são alterados. NOT1 CY – inverte o estado de CY. Os demais flags do PSW não são alterados. SET1 fnt – seta o bit especificado por fnt. Não altera o PSW (a não ser que ele seja alvo da instrução). CLR1 fnt – apaga o bit especificado por fnt. Não altera o PSW (a não ser que ele seja alvo da instrução).

3.2.6. Instruções de Desvio Provocam o desvio do programa para outro endereço de memória. O assembler utiliza os seguintes símbolos para especificar endereços: $ – endereços relativos de 8 bits (o destino pode estar até 127 bytes a frente ou 128 bytes atrás da instrução seguinte ao desvio); $! – endereços relativos de 16 bits (o destino pode estar até 32767 bytes a frente ou 32768 bytes atrás da instrução seguinte ao desvio); ! – endereços absolutos de 16 bits (os 4 bits mais significativos do PC são mantidos em zero), o destino deve estar na mesma página de 64KiB da instrução; !! – endereços absolutos de 20 bits;

Arquitetura e Modelo de Programação 71

BR dst – desvio incondicional para o destino especificado por dst. O destino pode ser o conteúdo do registrador AX (em conjunto com o registrador CS), um endereço relativo de 8 ou 16 bits, ou um endereço absoluto de 16 ou 20 bits. Esta instrução não altera o PSW. BC dst – desvio relativo para dst caso tenha havido transporte (CY = 1). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BNC dst – desvio relativo para dst caso não tenha havido transporte (CY = 0). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BZ dst – desvio relativo para dst caso zero (Z = 1). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BNZ dst – desvio relativo para dst caso diferente de zero (Z = 0). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BH dst – desvio relativo para dst caso “maior que” (OU lógico de Z e CY igual a 0). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BNH dst – desvio relativo para dst caso “menor ou igual” (OU lógico de Z e CY igual a 1). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BT bit,dst – desvio relativo para dst caso o operando especificado por bit seja verdadeiro (igual a 1). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BF bit,dst – desvio relativo para dst caso o operando especificado por bit seja falso (igual a 0). Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW. BTCLR bit,dst – desvio relativo para dst caso o operando especificado por bit seja verdadeiro (igual a 1), o bit testado é apagado caso esteja setado. Esta instrução suporta somente endereçamento relativo de 8 bits e não altera o PSW.

3.2.7. Instruções para Sub-rotinas e Funções Nesta categoria encontramos as instruções projetadas para implementação de chamadas e retorno de sub-rotinas, funções e interrupções. Além disso, estão inclusas nesta categoria as instruções para manipulação da pilha, normalmente utilizadas dentro das sub-rotinas e funções. Os mesmos símbolos para endereçamento vistos nas instruções de desvio são válidos para estas instruções. CALL dst – chamada de sub-rotina/função no destino especificado por dst. O endereço de 20 bits da instrução seguinte ao CALL é salvo na pilha, o SP é decrementado em 4 e o programa é desviado. O destino pode ser o conteúdo de um dos pares de registradores (AX, BC, DE ou HL), um endereço relativo de 16 bits, ou um endereço absoluto de 16 ou 20 bits. Esta instrução não altera o PSW. CALLT dst – chamada de sub-rotina/função no destino especificado por dst. O endereço de 20 bits da instrução seguinte ao CALLT é salvo na pilha, o SP é decrementado em 4 e o programa é desviado. O destino especifica um dos endereços de 16 bits na tabela CALLT. Esta instrução não altera o PSW.

72 Microcontroladores RL78: Guia Básico

BRK – interrupção por software. O conteúdo do PSW e o endereço de 20 bits da instrução seguinte ao BRK são salvos na pilha, o SP é decrementado em 4 e o programa é desviado para o endereço especificado pelo vetor de interrupção por software. O bit IE é apagado e os demais bits do PSW não são alterados. RET – retorno de sub-rotina/função. O endereço de 20 bits salvo na pilha é carregado no PC, o SP é incrementado em 4 e o programa é desviado. Esta instrução não altera o PSW. RETI – retorno de interrupção (exceto BRK). O conteúdo do PSW é recuperado da pilha e o endereço de 20 bits salvo na pilha é carregado no PC, o SP é incrementado em 4 e o programa é desviado. RETB – retorno de interrupção por software (BRK). O conteúdo do PSW é recuperado da pilha e o endereço de 20 bits salvo na pilha é carregado no PC, o SP é incrementado em 4 e o programa é desviado. PUSH reg – salva um dos registradores (PSW, AX, BC, DE ou HL) na pilha. O SP é decrementado em 2. Esta instrução não altera o PSW. POP reg – recupera um dos registradores (PSW, AX, BC, DE ou HL) da pilha. O SP é decrementado em 2. Esta instrução não altera o PSW (exceto quando ele é alvo da instrução).

3.2.8. Instruções de Pulo Condicional Estas instruções funcionam de forma semelhante aos desvios condicionais, no entanto, ao invés de provocar um desvio estas instruções apenas pulam a instrução seguinte caso a condição seja verdadeira (na verdade, ao invés de pular, a instrução seguinte é executada como um NOP e não produz qualquer resultado). SKC – pula a próxima instrução se tiver ocorrido transporte (CY = 1). O PSW não é afetado. SKNC – pula a próxima instrução se não tiver ocorrido transporte (CY = 0). O registrador PSW não é afetado. SKZ – pula a próxima instrução se zero (Z = 1). O PSW não é afetado. SKNZ – pula a próxima instrução se diferente de zero (Z = 0). O PSW não é afetado. SKH – pula a próxima instrução se “maior que” (OU lógico de Z e CY igual a 0). O PSW não é afetado. SKNH – pula a próxima instrução se “menor ou igual” (OU lógico de Z e CY igual a 1). O PSW não é afetado.

3.2.9. Instruções de Controle da CPU Estas instruções controlam algumas funcionalidades e modos de operação de CPU RL78. SEL RBx – seleciona um dos bancos de registradores (RB0, RB1, RB2 ou RB3). O registrador PSW não é afetado. NOP – nenhuma operação é executada pela CPU. O registrador PSW não é afetado.

Arquitetura e Modelo de Programação 73

EI – habilita as interrupções (seta o bit IE no registrador PSW). Somente o bit IE do PSW é alterado. DI – habilita as interrupções (apaga o bit IE no registrador PSW). Somente o bit IE do PSW é alterado. HALT – entra em modo halt de baixo consumo de energia (o clock de CPU é paralisado, os periféricos continuam operando normalmente). O registrador PSW não é afetado. STOP – entra em modo stop de baixo consumo de energia (o clock de CPU e dos periféricos é paralisado, somente alguns periféricos podem continuar operando neste modo). O registrador PSW não é afetado.

3.2.10. Temporização das Instruções Graças ao pipeline de três estágios (busca, decodificação e acesso a memória), a CPU RL78 é muito rápida. De fato, a maioria das instruções (56%) é executada em apenas um ciclo de clock e 86% das instruções são executadas em até 2 ciclos de clock! Algumas instruções e alguns modos de endereçamento podem fazer com que sejam necessários mais ciclos de clock para se completar a execução. Instruções que desviam o fluxo do programa (e por isso necessitam esvaziar o pipeline) também necessitam de mais ciclos (3 ou mais, conforme a instrução). Outro fator que influencia na velocidade de execução é a origem dos dados: utilizar dados armazenados em RAM é substancialmente mais rápido que utilizar dados armazenados na memória flash. A tabela 5.5 do manual de software dos RL78 (R01US0015EJ0100) apresenta as temporizações para todas as instruções e variações de modos de endereçamento.

3.3. Módulo OCD e Código de Segurança (Security ID)

Todos os modelos de microcontroladores RL78 incluem um módulo de gravação e depuração integrado, chamado de OCD (On Chip Debug). Ele é responsável pela comunicação entre o chip e o hardware externo de depuração (TK, E1, E20, etc.). O E1, por ser um hardware genérico e que atende a outros microcontroladores Renesas além do RL78, utiliza um conector de comunicação de quatorze vias. No entanto, uma das grandes vantagens dos RL78 é que o seu OCD comunica-se através de apenas um fio, por isso, é possível utilizar um adaptador como o mostrado na figura 3.4, de forma a converter o conector de quatorze pinos do E1 em um conector de apenas quatro pinos!

74 Microcontroladores RL78: Guia Básico

Figura 3.4 A figura 3.5 mostra a conexão do RL78 ao conector de depuração de quatro pinos mostrado na figura 3.4.

Figura 3.5 Outra funcionalidade muito importante em qualquer microcontrolador é a proteção da propriedade intelectual do programa gravado na memória do mesmo. Sem esta proteção, qualquer pessoa ou empresa poderia ser acesso ao programa, podendo estudá-lo ou copiá-lo quantas vezes desejasse. Para prevenir este tipo de situação o módulo OCD possui um mecanismo de segurança que impede a leitura da memória flash caso não seja fornecida a senha correta. Esta senha é composta de 10 bytes e é gravada juntamente com a aplicação na memória flash do microcontrolador (endereços 0x000C4 a 0x000CD). Para aumentar ainda mais a segurança, é possível configurar o chip para apagar a memória caso a senha fornecida seja incorreta (veja mais detalhes nos bytes de configuração no próximo tópico). A configuração do código de segurança (security ID) pode ser feita conforme mostra a listagem 3.1. Os valores dentro da array senha devem ser substituídos por valores definidos pelo programador!/* Security ID */ #pragma location = “SECUID” __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0}; Listagem 3.1

É importante declarar o security ID com o modificador __far, especialmente nos modelos G10 e G12 com 8KiB ou menos de flash e quando se utiliza o modelo near para o armazenamento de código. Caso __far não seja utilizado, o compilador armazenará o O security ID na RAM ao invés da flash, resultando em mal funcionamento. O modificador __far permite contornar este problema, além disso, o seu uso com modelo de memória far ou com outros modelos de chip não provoca nenhum efeito colateral!

Arquitetura e Modelo de Programação 75

3.4. Configurações do Chip

Os microcontroladores RL78, possuem algumas configurações internas que devem ser inicializadas antes de sua operação. Para essa finalidade, o fabricante incluiu quatro bytes de configuração localizados na área da memória flash do microcontrolador (endereços 0x000C0 a 0x000C3), também chamados opbyte0 a opbyte3. A seguir apresentamos a função de cada um dos bytes de configuração.

Lembre-se de que quando utilizar a facilidade de bloco duplo de boot será necessário gravar i os bytes de configuração nos dois blocos de boot, ou seja, nos endereços 0x000C0 a 0x000C3 e 0x010C0 a 0x010C3!

Endereço BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0x000C0 WDTINIT WINDOW1 WINDOW0 WDTON WDCS2 WDCS1 WDCS0 WDSTBYON Escrita

Nome do Bit Descrição Símbolo C Habilitação da interrupção do watchdog: 0 – interrupção desativada WDTINIT bWDTINIT 1 – interrupção habilitada (gera interrupção quando a contagem do watchdog chega a 75% do tempo de estouro) Seleção do período de janela aberta do watchdog: 00 – proibido - WINDOW1 WINDOW0 01 – 50% WDT_WINDOW50 10 – 75% WDT_WINDOW75 11 – 100% WDT_WINDOW100 Controle de operação do watchdog: WDTON bWDTON 0 – watchdog desativado 1– watchdog ativado Tempo de estouro do watc hdog (considerando a frequência

fIL =17,25kHz) 6 000 – 2 /f IL (±3,71ms) WDT_3ms 7 001 – 2 /f IL (±7,42ms) WDT_7ms WDCS2 8 010 – 2 /f IL (±14,84ms) WDT_14ms WDCS1 9 WDCS0 011 – 2 /f IL (±29,68ms) WDT_29ms 11 100 – 2 /f IL (±118,72ms) WDT_118ms 13 101 – 2 /f IL (±474,90ms) WDT_474ms 14 110 – 2 /f IL (±0,9498s) WDT_949ms 16 111 – 2 /f IL (±3,79919s) WDT_3799ms Operação do watchdog nos modos halt ou stop: WDSTBYON bWDSTBYON 0 – watchdog parado 1 – watchdog operacional Utilize o símbolo WDT_OFF (definido em myRL78.h) para desativar o watchdog!

76 Microcontroladores RL78: Guia Básico

Endereço BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0x000C1 VPOC2 VPOC1 VPOC0 1 LVIS1 LVIS0 LVIMDS1 LVIMDS0 Escrita

Nome do Bit Descrição Símbolo C Seleção do modo de operação do detector de baixa tensão (LVD): 00 – proibido - LVIMDS1 LVIMDS0 01 – modo interrupção LVD_INT_MODE 10 – modo de interrupção e reset LVD_INTRES_MODE 11 – modo de reset LVD_RESET_MODE VPOC2 VPOC1 VPOC0 Veja a tabela abaixo: Veja a tabela abaixo LVIS1 LVIS0

V /V V LVD LVDH LVDL VPOC2 VPOC1 VPOC0 LVIS1 LVIS0 Símbolo C Subida Descida Descida* 1 1,67V* 2 1,63V - 0 0 0 1 1 LVD_VMODE0 1,77V 1,73V 1,63V 0 0 0 1 0 LVD_VMODE1 1,88V* 2 1,84V - 0 0 1 1 1 LVD_VMODE2 1,88V 1,84V 1,63V 0 0 0 0 1 LVD_VMODE3 1,98V 1,94V 1,84V 0 0 1 1 0 LVD_VMODE4 2,09V 2.04V 1,84V 0 0 1 0 1 LVD_VMODE5 2,50V* 2 2,45V - 0 1 0 1 1 LVD_VMODE6 2,61V 2,55V 2,45V 0 1 0 1 0 LVD_VMODE7 2,71V 2,65V 2,45V 0 1 0 0 1 LVD_VMODE8 2,81V* 2 2,75V - 0 1 1 1 1 LVD_VMODE9 2,92V 2,86V 1,63V 0 0 0 0 0 LVD_VMODE10 2,92V 2,86V 2,75V 0 1 1 1 0 LVD_VMODE11 3,02V 2,96V 2,75V 0 1 1 0 1 LVD_VMODE12 3,13V 3,06V 1,84V 0 0 1 0 0 LVD_VMODE13 3,75V 3,67V 2,45V 0 1 0 0 0 LVD_VMODE14 4,06V 3,98V 2,75V 0 1 1 0 0 LVD_VMODE15 1 * VLVDL é a tensão de reset no modo de interrupção e reset *2 Configuração não permitida quando o LVD opera em modo de interrupção e reset Para desativar o LVD, basta configurar VPOC2=1 no modo de interrupção ou no modo de reset (também é possível utilizar o símbolo C LVD_OFF definido em myRL78.h).

Arquitetura e Modelo de Programação 77

Endereço BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0x000C2 CMODE1 CMODE0 1 FRQSEL4 FRQSEL3 FRQSEL2 FRQSEL1 FRQSEL0 Escrita

Nome do Bit Descrição Símbolo C Seleção do modo de operação da memória flash: 00 – baixa tensão (LV) (1 a 4MHz, tensão de alimentação de 1,6 a 5,5V) FLASH_LV

CMODE1 01 – configuração não permitida - CMODE0 10 – baixa velocidade (LS) (1 a 8MHz, tensão de alimentação de 1,8 a FLASH_LS 5,5V) 11 – alta veloc idade (HS) (1 a 16MHz, tensão de alimentação de 2,4 a FLASH_HS 5,5V, ou até 32MHz para tensões >=2,7V) Frequência de operação do oscilador interno de alta velocidade: 11000 – 64MHz (CPU a 32MHz)* CLK_64MHZ 10000 – 48MHz (CPU a 24MHz)* CLK_48MHZ FRQSEL4 01000 – 32MHz CLK_32MHZ FRQSEL3 00000 – 24MHz CLK_24MHZ FRQSEL2 FRQSEL1 01001 – 16MHz CLK_16MHZ FRQSEL0 00001 – 12MHz CLK_12MHZ 01010 – 8MHz CLK_8MHZ 01011 – 4MHz CLK_4MHZ 01101 – 1MHz CLK_1MHZ * Apenas nos modelos G14

Endereço BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0x000C3 OCDENSET 0 0 0 0 1 0 OCDERSD Escrita

Nome do Bit Descrição Símbolo C Seleção do modo de operação do depurador interno (OCD): 00 – OCD desativado DEBUG_OFF

OCDENSET 01 – configuração não permitida - 10 – OCD ativado, apaga a flash em caso de falha na autenticação OCDERSD DEBUG_ON_ERASE do security ID (modo seguro) 11 – OCD ativado, não apaga a flash em caso de falha na DEBUG_ON_NO_ERASE autenticação do security ID (modo inseguro)

A programação dos bytes de configuração pode ser feita, em linguagem C, utilizando-se #pragmas : #include "myRL78.h" // Configuração dos registradores de opção (OPTION BYTES) // Watchdog desligado

78 Microcontroladores RL78: Guia Básico

#pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Detector de baixa tensão desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador HS 4MHz #pragma location = "OPTBYTE" __root __far const char opbyte2 = CLK_HS | CLK_4MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;

Listagem 3.2

É importante declarar os bytes de configuração com o modificador __far, especialmente nos modelos G12 com 8KiB ou menos de flash e quando se utiliza o modelo near para o armazenamento de código. Nestes casos, o compilador armazenará os bytes de configuração O e security ID na RAM ao invés da flash, resultando em mal funcionamento. O uso do modificador __far permite contornar este problema, além disso, o seu uso com modelo de memória far ou com outros modelos de chip não provoca nenhum efeito colateral!

Atenção: ao programar um chip através do ambiente IAR, o byte de configuração 3 é sempre alterado automaticamente pelo compilador de forma a ativar o OCD (no modo erase, que i apaga a flash caso o security ID falhe). Caso seja necessário desativar totalmente o OCD, é necessário gerar um arquivo HEX e gravá-lo através do RFP (Renesas Flash Programmer) ou outra ferramenta de gravação!

Arquitetura e Modelo de Programação 79

80 Microcontroladores RL78: Guia Básico

4

Suporte à CPU 4. Suporte à CPU

Neste capítulo estudaremos os módulos internos que dão suporte ao funcionamento da CPU RL78. Dentre estes módulos podemos destacar: sistema de reset, sistema de clock, detector de tensão e cão de guarda.

4.1. Reset

Todo circuito digital sequencial necessita de um sinal de controle capaz de colocá-lo em um estado inicial conhecido. Este sinal é normalmente chamado de reset em eletrônica digital. Os circuitos de reset constituem um elemento importante nos microcontroladores e microprocessadores, pois garantem que os seus circuitos internos sejam corretamente inicializados após a energização do mesmo. Os microcontroladores RL78, assim como a maioria dos seus concorrentes, incluem um circuito interno de reset e um pino externo com esta função. O circuito de reset inicializa a máquina de estados responsável pela busca e decodificação de instruções, configura a direção dos pinos de E/S (no reset os pinos são configurados como entradas, exceto o P130), inicializa os registradores SFR dos periféricos internos do microcontrolador (todos os periféricos, com exceção daqueles configurados pelos bytes de configuração, são desativados após um reset).

Observe que o conteúdo da memória RAM, dos registradores GPR, do apontador da pilha (SP) i e do registrador do oscilador interno (HOCODIV) não é alterado por um reset!

O reset também provoca o desvio do programa para o endereço apontado pelo vetor de reset (endereços de memória 0x0000 e 0x0001). Existem sete diferentes fontes de reset nos RL78, ou seja, sete diferentes maneiras de se provocar a reinicialização do chip:

1. RESET : um nível lógico baixo (0) neste pino provoca o reset do chip. Isto permite que um circuito de reset externo provoque a reinicialização do microcontrolador, uma facilidade útil em sistemas com outros circuitos digitais além do microcontrolador; 2. POR - reset interno de energização: os RL78 incluem um circuito de reset POR (Power On Reset) que monitora a tensão de alimentação do chip, mantendo-o em

Suporte à CPU 81

reset quando a tensão de alimentação é menor que aproximadamente 1,5V (parâmetro VPDR ). Esta facilidade permite que, na maioria das aplicações, seja desnecessário incluir um circuito de reset externo; 3. LVD - reset por detecção de baixa tensão: um circuito interno chamado LVD (Low Voltage Detector) pode ser configurado para gerar um reset quando a tensão de alimentação cai abaixo de um valor programado (veremos que o LVD pode também gerar uma interrupção). Esta funcionalidade pode ser utilizada para, por exemplo, salvar variáveis importantes quando uma queda de alimentação é detectada; 4. WDT - reset provocado pelo watchdog: os RL78 incluem um circuito cão de guarda (watchdog) que consiste num temporizador que, ao atingir uma marca de tempo programada, provoca o reset do chip; 5. TRAP - reset por execução de opcode ilegal: este reset é gerado quando a CPU tenta executar um opcode iniciado por 0xFF. Nos RL78 não há opcodes iniciados por 0xFF e, por isso, este código é considerado ilegal (mas é perfeitamente possível utilizar 0xFF como operando e como dado); 6. IAW - reset provocado pelo acesso a um endereço ilegal: como já vimos no tópico 3.1.2, o acesso a áreas de memória não implementadas ou acessos não permitidos (como, por exemplo, tentar executar código na área de registradores SFR ou GPR), pode gerar um reset IAW caso esta opção esteja habilitada. Esta característica de segurança será vista em maiores detalhes no tópico 10.2; 7. RPE - reset provocado por falha de paridade na RAM: os RL78 incluem um circuito detector de erros baseado em bits de paridade. Cada posição da memória RAM destes microcontroladores inclui um bit adicional para controle de paridade. Nas operações de escrita na RAM, os bits de paridade são atualizados e nas operações de leitura estes bits são checados. Caso seja detectado um erro entre a paridade calculada e a paridade lida, um reset pode ser gerado. Esta característica de segurança será vista em maiores detalhes no tópico 10.2. O módulo LVD e o watchdog serão vistos em maiores detalhes mais a frente neste capítulo. Após um reset, é possível consultar o registrador RESF para identificar qual a fonte causadora do mesmo. Repare que estes flags, uma vez setados, assim permanecerão até que ocorra um reset externo (via pino RESET ), um reset interno (POR), ou ocorra a leitura do registrador.

Repare que a leitura do RESF apaga TODOS os flags simultaneamente, por esta razão, o O valor do mesmo deve ser lido para uma variável temporária e só então os flags devem ser analisados um a um!

Durante o reset, o pino P130 (disponível nos modelos com 48 pinos ou mais) é configurado como saída e mantido em nível lógico baixo, permitindo que o microcontrolador promova o reset de outros circuitos externos conectados a ele.

82 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura TRAP WDTRF RPERF IAWRF LVIRF 0 0 0 RESF Escrita - - - - - Reset * 0 0 * 0 * * * * Estes bits são apagados após a leitura do registrador RESF e após um reset POR ou pelo pino de reset. Nome do Bit Descrição Símbolo C Indicador de reset provocado pela tentativa de execução de opcode ilegal: TRAP bTRAP 0 – não houve evento de reset por TRAP 1 – um reset foi provocado por TRAP Indicador de reset causado pelo watchdog: WDTRF 0 – o watchdog não causou reset bWDTRF 1 – o watchdog provocou um reset Indicador de reset provocado por erro de paridade da RAM: RPERF 0 – não houve reset por erro de paridade bRPERF 1 – um reset foi provocado por erro de paridade Indicador de reset provocado por acesso ilegal à memória: IAWRF 0 – não houve reset IAW bIAWRF 1 – um reset foi provocado por IAW Indicador de reset provocado por baixa tensão: LVIRF 0 – não houve reset por baixa tensão bLVIRF 1 – um reset foi provocado por baixa tensão

4.2. Sistema de Clock

O sistema de clock dos microcontroladores RL78 é dividido em duas categorias: o sistema principal e o sistema secundário. No sistema de clock principal, temos dois sinais de clock, derivados de dois módulos osciladores:

1. fMX , derivado do oscilador de alta frequência, também chamado de X1 e capaz de operar a até 20MHz;

2. fIH , derivado do oscilador interno de alta frequência, também chamado de HOCO e capaz de operar a até 32MHz (64MHz nos modelos G14). A seleção entre os dois osciladores é realizada por meio do bit MCM0 do registrador CKC: com MCM0 = 0 seleciona-se o sinal f IH e com MCM0 = 1, seleciona-se o sinal f MX . O sinal selecionado passa então a ser chamado fMAIN e poderá alimentar a CPU, timers TAU, módulos de comunicação serial e conversor A/D. No sistema de clock secundário, também temos dois sinais de clock derivados de dois módulos osciladores:

Suporte à CPU 83

1. fSUB , derivado do oscilador de clock de subsistema, também chamado de XT1 e projetado para utilizar cristais de 32,768kHz (este oscilador não está disponível nos modelos com 36 pinos ou menos);

2. fIL , derivado do oscilador interno de baixa frequência, também chamado de LOCO e que opera tipicamente em 15kHz. A finalidade básica do clock secundário é suprir o clock de três módulos: o watchdog, o timer de intervalo e o RTC. Nas aplicações onde se necessita medir tempo com precisão, recomenda-se utilizar o oscilador XT1 e um cristal externo de 32,768kHz. Desta forma, o sinal fSUB pode fornecer a base de tempo para o RTC, permitindo que se construa relógios e calendários de alta precisão. O sinal de clock global que efetivamente alimenta a CPU, unidades TAU, periféricos de comunicação e o conversor A/D é chamado de fCLK . Este sinal pode ser derivado do clock principal f MAIN ou do clock secundário f SUB . Esta funcionalidade é controlada pelo bit CSS no registrador CKC: com CSS = 0 o fCLK é derivado do sinal f MAIN e com CSS = 1, o fCLK é derivado do sinal f SUB . Após um reset, o RL78 opera sempre utilizando o oscilador interno de alta frequência, conforme a configuração dos bytes de opção. Caso a aplicação utilize outra fonte de clock, ela deverá ser configurada e selecionada na inicialização do programa (ou em outro momento, se assim for desejado).

4.2.1. Oscilador X1 O oscilador principal dos RL78 possui dois pinos externos: X1/P121 e X2/P122. A eles podem ser conectados cristais ou ressonadores cerâmicos, com frequências de 1 a 20MHz. O pino X2 também pode operar como uma entrada para clock externo (EXCLK), podendo operar em frequências de 1 a 20MHz. O registrador CMC (Clock Mode Control) deve ser utilizado para configurar a operação do oscilador X1: quando o bit OSCSEL = 1 o oscilador pode operar e os pinos P121 e P122 são controlados pelo oscilador, quando OSCSEL = 0, os pinos P121 e P122 podem ser utilizados como entradas digitais. Quando OSCSEL = 1, o bit EXCLK permite configurar a utilização de um oscilador externo: quando EXCLK = 1, o pino X2/P122 opera como entrada de clock externo EXCLK e o pino P121 passa a ser uma entrada digital de uso geral, quando EXCLK = 0, o oscilador necessita de um cristal ou ressonador cerâmico. Ainda no registrador CMC, o bit AMPH permite configurar o nível de consumo do oscilador e a faixa de frequências que ele pode operar. Quando o oscilador X1 está ativo, a sua operação é controlada através do bit MSTOP no registrador CSC: quando MSTOP = 0, o oscilador pode operar normalmente e quando MSTOP = 1, o oscilador é paralisado, reduzindo o consumo de energia. Este oscilador inclui uma funcionalidade adicional que consiste num temporizador de estabilização, que pode ser utilizado para fazer com que o sinal f MX permaneça inativo até que um tempo de estabilização seja atingido, quando então o sinal de clock é liberado.

84 Microcontroladores RL78: Guia Básico

O tempo de estabilização pode ser configurado através do registrador OSTS, variando de 28 até 2 18 ciclos de clock do oscilador. A contagem deste temporizador pode ser lida através do registrador OSTC. Para utilizar o oscilador X1 como fonte de clock para a CPU é necessário configurá-lo conforme descrito acima, em seguida, o programa deve aguardar a estabilização do oscilador (monitorando o registrador OSTC) e uma vez estável, deve-se comutar o clock principal, setando-se o bit MCS no registrador CKC.

Lembre-se de que os bits CMODE1 e CMODE0 (byte de configuração 0x000C2) devem ser i configurados de acordo com a velocidade de operação da CPU!

As conexões do oscilador X1 são vistas na figura 4.1. Para garantir maior estabilidade e precisão, é importante utilizar trilhas curtas, um bom plano de terra e evitar a passagem de trilhas com sinais de alta corrente ou alta frequência passem próximas aos elementos do circuito oscilador.

Figura 4.1 4.2.2. Oscilador XT1 O oscilador secundário dos RL78, também chamado XT1 possui dois pinos externos: XT1/P123 e XT2/P124. A eles pode ser conectado um cristal de frequência igual a 32,768kHz. O pino XT2 também pode operar como uma entrada para clock externo (EXTCLK), podendo operar em frequências de 32 a 35kHz.

i Este oscilador não está presente nos chips com encapsulamentos de 36 pinos ou menos.

O registrador CMC (Clock Mode Control) deve ser utilizado para configurar a operação do oscilador XT1: quando o bit OSCSELS = 1 o oscilador pode operar e os pinos P123 e P124 são controlados pelo oscilador, quando OSCSELS = 0, os pinos P123 e P124 podem ser utilizados como entradas digitais. Quando OSCSELS = 1, o bit EXCLKS permite configurar a utilização de um oscilador externo: quando EXCLKS = 1, o pino XT2/P124 opera como entrada de clock externo EXCLKS e o pino P123 passa a ser uma entrada digital de uso geral, quando EXCLKS = 0, o oscilador necessita de um cristal externo. Este oscilador pode operar em três modos: normal, baixo consumo e ultra baixo consumo. A seleção entre os modos é feita através dos bits AMPHS1 e AMPHS0 (registrador CMC). Após um reset o modo selecionado é o de baixo consumo.

Lembre-se de que ao selecionar o modo de ultra baixo consumo, as características do circuito, distância de trilhas, qualidade dos componentes e interferências externas O passam a ser substancialmente significantes, por isso, este modo deve ser utilizado apenas após cuidadoso projeto e ensaios!

Suporte à CPU 85

Quando o oscilador XT1 está ativo, a sua operação é controlada através do bit XTSTOP no registrador CSC: quando XTSTOP = 0, o oscilador pode operar normalmente e quando XTSTOP = 1, o oscilador é paralisado, reduzindo o consumo de energia. Para selecionar o oscilador XT1 como fonte de clock para a CPU e os periféricos basta setar o bit CSS (registrador CKC). As conexões do oscilador XT1 são vistas na figura 4.2. As mesmas recomendações sugeridas para o oscilador X1 valem para o XT1, mas no caso dele, por tratarem-se de sinais de potência ainda menor e de um circuito mais sensível, o projeto deve ser ainda mais criterioso!

Figura 4.2

4.2.3. Oscilador Interno de Alta Frequência Como já vimos, os RL78 incluem um oscilador interno de alta frequência (também chamado de HOCO) capaz de operar a até 32MHz (64MHz nos modelos G14). Este oscilador apresenta também uma elevada estabilidade de frequência e precisão na ordem de 1%. O HOCO é configurado inicialmente através do byte de configuração em 0x000C2 e é sempre selecionado como fonte de clock da CPU após um reset. A frequência de operação do HOCO pode ser reconfigurada em tempo de execução, utilizando-se o registrador HOCODIV e também é possível efetuar um ajuste fino da mesma utilizando-se o registrador HIOTRM.

Lembre-se de que os bits CMODE1 e CMODE0 (byte de configuração 0x000C2) devem ser i configurados de acordo com a velocidade de operação da CPU!

A operação do HOCO é controlada pelo bit HIOSTOP no registrador CSC: quando HIOSTOP = 0, o oscilador pode operar normalmente e quando HIOSTOP = 1, o oscilador é paralisado, reduzindo o consumo de energia. Note que, no caso dos modelos G14, a frequência máxima da CPU ainda é 32MHz, mas o oscilador pode trabalhar a até 64MHz. Nos modos 48 ou 64MHz, a frequência de oscilador alimenta o timer RD e é dividida por dois antes de alimentar a CPU, desta forma a CPU opera dentro dos limites especificados.

A nota de aplicação AN1084 (R01AN1084EG0100) demonstra o procedimento de calibração do oscilador HOCO utilizando uma referência de clock externa. Através O deste procedimento é possível obter uma precisão de ±0,1% na frequência do oscilador interno!

86 Microcontroladores RL78: Guia Básico

4.2.4. Oscilador Interno de Baixa Frequência Este oscilador, que chamaremos de LOCO, opera numa frequência nominal típica de 15kHz e possui precisão de ±15%. Ele é utilizado basicamente como fonte de clock para o watchdog e opcionalmente, pode também fornecer clock para o timer de intervalo e para o RTC interno. Como este oscilador possui baixa precisão e não pode ser ajustado, o seu uso como fonte de clock para os timers deve ser considerado apenas nas aplicações em que a medição de tempo não necessita de precisão. O LOCO está sempre em operação e não pode ser desativado diretamente pelo programa, mas é desligado no modo stop quando o watchdog está desligado e não está sendo utilizado como fonte de clock pelos timers. Para selecionar o LOCO como fonte de clock do timer de intervalo e do RTC, basta setar o bit WUTMMCK0 (registrador OSMC).

i Não é possível utilizar o LOCO como fonte de clock para a CPU!

4.2.5. Registradores do Sistema de Clock

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura CLS MCS CSS MCM0 0 0 0 0 CKC Escrita - - Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Status do clock da CPU e periféricos: CLS 0 – Clock principal (X1 ou HOCO) bCLS 1 – Clock secundário (XT1)

Seleção da fonte do clock da CPU e periféricos (f CLK ): CSS 0 – Clock principal (X1 ou HOCO) bCSS 1 – Clock secundário (XT1)

Status do clock principal: MCS 0 – Oscilador interno (HOCO) bMCS 1 – Oscilador X1

Seleção da fonte do clock principal: 0 – Oscilador interno (HOCO) MCM0 bMCM0 1 – Oscilador X1 * Este bit somente pode ser alterado quando CSS=1

Suporte à CPU 87

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura EXCLK OSCSEL EXCLKS OSCSELS 0 AMPHS1 AMPHS0 AMPH CMC Escrita Reset 0 0 0 0 0 0 0 0

Atenção: o registrador CMC é do tipo write-once , ou seja, após o reset ele somente pode ser configurado uma única vez e através de uma operação de 8 bits. Caso não seja i necessário alterar o conteúdo do mesmo, o programa deve escrever 0x00 no mesmo, de forma a garantir que ele não seja alterado por algum erro no programa!

Nome do Bit Descrição Símbolo C Seleção da configuração de operação do oscilador X1: 00 – oscilador desativado (pinos P121 e P122 como entradas digitais) OSC_X1_OFF 01 – oscilador operando co m cristal ou ressonador externo conectado aos EXCLK OSC_X1_OSC OSCSEL pinos X1/P121 e X2/P122 10 – oscilador desativado (pinos P121 e P122 como entradas digitais) - 11 – entrada de clock externo via P122, pino P121 opera como entrada OSC_X1_EXT digital Seleção da configuração de operação do oscilador XT1: 00 – oscilador desativado (pinos P123 e P124 como entradas digitais) OSC_XT1_OFF 01 – oscilador operando com cristal ou ressonador externo conectado aos EXCLKS OSC_XT1_OSC OSCSELS pinos X1/P123 e X2/P124 10 – oscilador desativado (pinos P123 e P124 como entradas digitais) - 11 – entrada de clock externo via P124, pino P123 opera como entrada OSC_XT1_EXT digital Seleção do modo de operação do oscilador XT1: 00 – modo de baixa potência OSC_XT1_LP AMPHS1 AMPHS0 01 – modo normal OSC_XT1_STD 10 – modo ultra baixa potência OSC_XT1_ULP 11 – modo não permitido - Seleção da faixa de frequência de operação do oscilador X1: AMPH bAMPH 0 – 1 a 10 MHz 1 – 10,1 a 20MHz

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura MSTOP XTSTOP 0 0 0 0 0 HIOSTOP CSC Escrita Reset 1 1 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Operação do oscilador X1: MSTOP bMSTOP 0 – Oscilador pode operar 1 – Oscilador parado Operação do oscilador XT1: XTSTOP bXTSTOP 0 – Oscilador pode operar 1 – Oscilador parado Operação do oscilador HOCO: HIOSTOP bHIOSTOP 0 – Oscilador operando 1 – Oscilador parado

88 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura Estado do contador de estabilização OSTC Escrita - Reset 0 0 0 0 0 0 0 0 O valor lido neste registrador mostra o estado do contador de estabilização: 0x00 – tempo mínimo não transcorrido 0x80 – 2 8 contagens transcorridas 0xC0 – 2 9 contagens transcorridas 0xE0 – 2 10 contagens transcorridas 0xF0 – 2 11 contagens transcorridas 0xF8 – 2 13 contagens transcorridas 0xFC – 2 15 contagens transcorridas 0xFE – 2 17 contagens transcorridas 0xFF – 2 18 contagens transcorridas

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 OSTS2 OSTS1 OSTS0 OSTS Escrita Reset 0 0 0 0 0 1 1 1

Nome do Bit Descrição Símbolo C Seleção do número de ciclos de estabilização do oscilador X1: 000 - 256 ciclos do oscilador OSTS_256 001 – 512 ciclos do oscilador OSTS_512 OSTS2 010 – 1024 ciclos do oscilador OSTS_1k OSTS1 011 – 2048 ciclos do oscilador OSTS_2k OSTS0 100 – 8192 ciclos do oscilador OSTS_8k 101 – 32768 ciclos do oscilador OSTS_32k 110 – 131072 ciclos do oscilador OSTS_131k 111 – 262144 ciclos do oscilador OSTS_262k

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura RTCLPC 0 0 WUTMMCK0 0 0 0 0 OSMC Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Comportamento do clock secundário em modo stop e halt quando utilizado como fonte de clock da CPU: RTCLPC 0 – O clock secundário continua a suprir os periféricos nos modos halt e stop bRTCLPC 1 – O clock secundário é paralisado nos modos halt e stop (exceto para o RTC e timer de intervalo) Seleção da fonte de clock do RTC e do timer de intervalo: WUTMMCK0 bWUTMMCK0 0 – Oscilador XT1 1 – Oscilador LOCO

Suporte à CPU 89

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 DIV2 DIV1 DIV0 HOCODIV Escrita Reset 0 0 0 0 0 ? ? ?

Nome do Bit Descrição Símbolo C Seleção da frequência de operação do oscilador HOC O (quando o bit

FRQSEL3 = 1 no byte de configuração): 000 – 32MHz HOCO_32MHZ 001 – 16MHz HOCO_16MHZ 010 – 8MHz HOCO_8MHz 011 – 4MHz HOCO_4MHZ DIV2 100 – 2MHz HOCO_2MHZ DIV1 DIV0 101 – 1MHz HOCO_1MHz Seleção da frequência de operação do oscilador HOC O (quando o bit

FRQSEL3 = 0 no byte de configuração): 000 – 24MHz HOCO_24MHZ 001 – 12MHz HOCO_12MHZ 010 – 6MHz HOCO_6MHz 011 – 3MHz HOCO_3MHZ Outras configurações são inválidas. O oscilador interno HOCO é configurado inicialmente pelo conteúdo do byte de configuração: Endereço BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0x000C2 CMODE1 CMODE0 1 FRQSEL4 FRQSEL3 FRQSEL2 FRQSEL1 FRQSEL0 Escrita

Nome do Bit Descrição Símbolo C Frequência de operação do oscilador interno de alta velocidade: 11000 – 64MHz (CPU a 32MHz)* CLK_64MHZ 10000 – 48MHz (CPU a 24MHz)* CLK_48MHZ FRQSEL4 01000 – 32MHz CLK_32MHZ FRQSEL3 00000 – 24MHz CLK_24MHZ FRQSEL2 FRQSEL1 01001 – 16MHz CLK_16MHZ FRQSEL0 00001 – 12MHz CLK_12MHZ 01010 – 8MHz CLK_8MHZ 01011 – 4MHz CLK_4MHZ 01101 – 1MHz CLK_1MHZ * Apenas nos modelos G14

90 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura Ajuste fino do oscilador HOCO HIOTRM Escrita - Reset Varia conforme a calibração de fábrica

O valor carregado neste registrador é utilizado para ajustar o oscilador HOCO: 0 – frequência mínima ... 255 – frequência máxima

4.2.6. Exemplo O exemplo a seguir mostra como o oscilador interno HOCO pode ser configurado “on the fly” durante a execução do programa. Trata-se de um simples pisca led que alterna 10 piscadas do led operando com frequência de 32MHz e 10 piscadas com a CPU operando a 8MHz. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h" // Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0}; #define LED_D2 P7_bit.no7 void pisca(void) { unsigned char cnt; unsigned long int temp; for (cnt=10;cnt;cnt--) { LED_D2 = 0; for (temp=100000;temp;temp--); LED_D2 = 1; for (temp=100000;temp;temp--); } }

void main( void ) { PM7_bit.no7 = 0; // porta P77 como saída CMC = 0; // desativa osciladores X1 e XT1 while (1) { pisca();

Suporte à CPU 91

HOCODIV = HOCO_8MHZ; // oscilador a 8MHz pisca(); HOCODIV = HOCO_32MHZ; // oscilador a 32MHz } } Exemplo 4.1

4.3. Gerenciamento de Energia

Um dos diferenciais de projeto dos microcontroladores RL78 é o quesito consumo de energia. Como já dissemos anteriormente, o projeto destes chips levou em consideração um baixo consumo aliado a uma alta velocidade de operação, o que se traduz em alta eficiência computacional. Para se ter uma idéia, um microcontrolador RL78 consome cerca de 4,6mA quando operando com alimentação de 5V e utilizando o oscilador interno operando a 32MHz. Isto significa que o chip consume aproximadamente 23mW quando operando em velocidade máxima. Apesar de este ser um número excelente, muitas aplicações de microcontroladores são operadas a bateria ou pilha, neste caso, um consumo de 23mW pode esgotar rapidamente estas fontes de energia tão limitadas. Por esta razão, os RL78 possuem modos especiais de operação que reduzem drasticamente o consumo de energia. Além do modo totalmente operacional (o modo run, que é o modo padrão), temos o modo halt , no qual o clock da CPU é paralisado, com o restante dos periféricos podendo operar normalmente e o modo stop , no qual praticamente todas as fontes de clock do microcontrolador são paralisadas, juntamente com a CPU e os periféricos (apenas alguns poucos periféricos podem continuar operando neste modo). Lembre-se de que nos modos halt e stop o clock da CPU é paralisado e por isso, nenhum programa é executado! No entanto, se analisarmos cuidadosamente, poderemos perceber que praticamente qualquer aplicação pode se beneficiar em algum momento de um destes modos de baixo consumo. Vejamos alguns exemplos típicos do uso destes modos de economia de energia: 1. A aplicação está aguardando uma temporização ser completada. Neste caso, é possível entrar em modo halt enquanto se aguarda um timer gerar uma interrupção. Caso se utilize o RTC ou timer de intervalo, é possível inclusive utilizar o modo stop nesta situação! 2. Utilizar o modo stop para manter o equipamento em modo “desligado” e, através de teclas conectadas a pinos de interrupção retorna-se ao modo operacional quando o usuário pressiona uma delas. 3. O microcontrolador permanece em modo snooze aguardando a recepção de um dado pela porta serial ou uma conversão A/D ser completada.

O conteúdo da memória RAM, o estado das portas de E/S e dos periféricos é mantido i enquanto o chip permanece nos modos halt, stop e snooze.

92 Microcontroladores RL78: Guia Básico

4.3.1. Modo Halt O modo halt permite reduzir significativamente o consumo de energia do microcontrolador, pois ao paralisar o clock da CPU, apenas os periféricos que permanecem operando continuam a consumir corrente significativa.

Lembre-se de que estes microcontroladores utilizam circuitos CMOS. Neste tipo de circuito, quanto maior a frequência de comutação, maior a corrente consumida. Ao O desativar o clock da CPU, seus MOSFETs passam a permanecer em modo estático, com um consumo extremamente baixo de energia (basicamente a corrente de fuga dos gates dos MOSFETs)!

Como já vimos, um RL78 (R5F100LE) operando a 32MHz consome cerca de 4,6mA quando operando com alimentação de 5V. Se nas mesmas condições o microcontrolador entrar em modo halt, o consumo de energia é reduzido para cerca de 540µA! Ou seja, no modo halt o RL78 reduz o seu consumo para cerca de 11,7% do consumo em modo totalmente operacional!

Lembre-se de que o consumo total do microcontrolador irá depender de quais periféricos i estão operando! O bit RTCLPC (registrador OSMC) permite selecionar o comportamento dos periféricos quando o oscilador XT1 é utilizado como fonte de clock da CPU e dos periféricos: quando RTCLPC = 0, os periféricos podem continuar operando em modo halt e quando RTCLPC = 1, os periféricos são paralisados no modo halt. Tudo o que é necessário fazer para se entrar neste modo de operação é executar a instrução assembly HALT ou uma chamada a função __halt() em linguagem C.

O Para utilizar a função __halt(), é necessário incluir o arquivo “intrinsics.h”!

Uma vez em modo halt, a CPU permanecerá inativa até que ocorra uma interrupção ou reset. Caso as interrupções globais estejam desabilitadas (IE = 0 no PSW), ainda assim, uma interrupção de periférico poderá provocar a saída do modo halt, porém, neste caso particular, não ocorrerá desvio para o vetor de interrupção e o programa seguirá da instrução seguinte a HALT.

4.3.2. Modo Stop O modo stop garante um consumo de energia substancialmente menor que o modo halt, pois, além da CPU, praticamente todos os periféricos são paralisados. Neste modo de operação, somente os seguintes periféricos ou módulos podem continuar operando: • Oscilador secundário XT1 (desde que habilitado); • Oscilador interno de baixa frequência (desde que utilizado com o RTC, timer de intervalo ou watchdog); • Detector de baixa tensão (LVD);

Suporte à CPU 93

• Saída de clock (desde que operando com o clock de subsistema); • Interrupção externa e de teclado; • Watchdog (desde que habilitado para operar no modo stop); • Timer de intervalo (quando utilizando como fonte de clock o oscilador interno de baixa frequência); • RTC. Neste modo de operação, a corrente consumida pelo mesmo microcontrolador (R5F100LE) é reduzida tipicamente para cerca de 230nA, ou seja, no modo stop o microcontrolador consume cerca de 0,04% da corrente consumida no modo halt ou 0,005% do consumo no modo run! O bit RTCLPC (registrador OSMC) permite selecionar o comportamento dos periféricos quando o oscilador XT1 é utilizado como fonte de clock da CPU e dos periféricos: quando RTCLPC = 0, os periféricos podem continuar operando em modo stop e quando RTCLPC = 1, os periféricos são paralisados no modo stop. A entrada neste modo de operação é provocada pela execução da instrução assembly STOP ou pela chamada da função __stop() em linguagem C.

O Para utilizar a função __stop(), é necessário incluir o arquivo “intrinsics.h”!

Uma vez em modo stop, a CPU permanecerá inativa até que ocorra uma interrupção ou reset. Caso as interrupções globais estejam desabilitadas (IE = 0 no PSW), ainda assim, uma interrupção de periférico poderá provocar a saída do modo stop, porém, neste caso particular, não ocorrerá desvio para o vetor de interrupção e o programa seguirá da instrução seguinte a STOP.

Atenção: ao programar um chip através do ambiente IAR, o byte de configuração 3 é sempre alterado (pelo compilador) para ativar o OCD (no modo erase, que apaga a flash caso o security ID falhe). Caso seja necessário desativar totalmente o OCD, é necessário gerar um i arquivo HEX e gravá-lo através do RFP (Renesas Flash Programmer) ou outra ferramenta de gravação! Lembre-se de que o OCD, caso ativado no byte de configuração, aumenta consideravelmente o consumo em modo stop (cerca de 250µA)!

4.3.3. Modo Snooze Este modo é uma variação do modo stop, onde o oscilador interno de alta velocidade é mantido operando, permitindo que alguns periféricos continuem a funcionar, podendo gerar uma interrupção e o consequente retorno ao modo run. O conversor A/D e os módulos seriais CSI e UART podem ser configurados para continuar operando neste modo. No modo snooze, após a execução da instrução assembly STOP, a CPU e a maioria dos periféricos é paralisada. Caso o conversor A/D esteja configurado para operar em modo snooze (registrador ADM2), ele permanecerá operando e realizando conversões, ao completar

94 Microcontroladores RL78: Guia Básico

conversões o A/D gera uma interrupção que provoca o retorno da CPU ao modo run. No caso das interfaces seriais CSI e UART, elas permanecerão ativas desde que configuradas para operar no neste modo (registrador SSCm). Ao receber ou enviar um dado, estes módulos gerarão uma interrupção que fará com que a CPU retorne ao modo run.

4.3.4. Gerenciamento de Clock Outra funcionalidade importante no gerenciamento do consumo de energia dos RL78 é o gerenciamento de clock e energia. Através dele é possível controlar quais periféricos podem operar e quais são desligados. O controle é feito por meio do registrador PER0. Os periféricos controlados são: conversor A/D, timers TAU, interfaces seriais (SAU e I 2C) e o relógio de tempo real (RTC).

Após um reset todos os periféricos mencionados são desativados e devem ser ativados i através do registrador PER0 antes de serem utilizados!

Atenção: quando os periféricos estão desativados os seus registradores SFR não operam e i por isso não devem ser utilizados. Qualquer escrita nos mesmos é descartada.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura RTCEN IICA1EN ADCEN IICA0EN SAU1EN SAU0EN TAU1EN TAU0EN PER0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Controle do clock do RTC e do timer de intervalo: RTCEN bRTCEN 0 – Clock desativado 1 – Clock ativado Controle do clock da interface I 2C1: IICA1EN bIICA1EN 0 – Clock desativado 1 – Clock ativado Controle do clock da conversor A/D: ADCEN bADCEN 0 – Clock desativado 1 – Clock ativado Controle do clock da interface I 2C0: IICA0EN bIICA0EN 0 – Clock desativado 1 – Clock ativado Controle do clock do módulo serial SAU1: SAU1EN bSAU1EN 0 – Clock desativado 1 – Clock ativado Controle do clock do módulo serial SAU0: SAU0EN bSAU0EN 0 – Clock desativado 1 – Clock ativado Controle do clock da unidade de timers TAU1: TAU1EN bTAU1EN 0 – Clock desativado 1 – Clock ativado Controle do clock da unidade de timers TAU0: TAU0EN bTAU0EN 0 – Clock desativado 1 – Clock ativado

Suporte à CPU 95

4.3.5. Dicas para Reduzir o Consumo de Energia A entrada em modo stop reduz grandemente o consumo de energia do microcontrolador, mas para garantir o menor consumo possível devemos observar alguns detalhes importantes: 1. Desative os periféricos que não serão utilizados: lembre-se de que o watchdog, o LVD, o RTC, o timer de intervalo e o oscilador XT1 podem continuar operando no modo stop. Além disso, as interfaces seriais e o ADC também podem operar em modo snooze. Por isso, antes de entrar em modo stop, certifique-se de que todos os periféricos não utilizados estejam devidamente desligados. A tabela 4.1 ilustra o consumo típico de alguns destes módulos: Módulo Consumo (µA) ADC (5V) 1300 Referência interna 1,45V 75 Sensor de temperatura 75 Oscilador XT1 0,57 Watchdog* 0,22 RTC 0,02 Timer de intervalo 0,02 LVD 0,08 * Inclui o consumo do oscilador LOCO (15kHz) Tabela 4.1

2. Desative o OCD: o circuito de depuração interno consume algumas centenas de microampéres quando está habilitado no byte de configuração opbyte3. Na fase de desenvolvimento pode ser interessante deixá-lo desta forma, mas para produção é importante desativar o OCD para garantir um menor consumo de energia; 3. Não deixe pinos de entrada flutuando: pinos de entrada podem gastar energia desnecessária quando são deixados flutuando. Neste caso é uma boa idéia configurar como saída todos os pinos não utilizados e colocá-los em um nível lógico seguro (normalmente zero); 4. Lembre-se de que o pino P4.0/TOOL0 deve possuir um resistor externo de pull-up. Para reduzir o consumo de energia, configure este pino como entrada ou, se configurado como saída, mantenha-o em nível lógico alto antes de entrar em um modo de baixo consumo.

4.3.6. Exemplo O exemplo a seguir demonstra a utilização do modo stop. Ao ser ligada a alimentação o led D2 da placa de promoção do RL78/G13 irá piscar brevemente e em seguida a CPU irá entrar em modo stop, com o consumo reduzido para cerca de 230nA. A saída desde modo é realizada por meio do pino P5.0 que é configurado para operação como fonte de interrupção externa INTP1 com o seu resistor interno de pull-up ativado (uma tecla deve ser conectada entre este pino e o GND).

96 Microcontroladores RL78: Guia Básico

Uma transição negativa no pino (do nível “1” para nível “0”) provoca a saída do modo stop e o retorno ao modo normal de execução. Observe que o flag da interrupção é apagado por software (PIF1 = 0). Isto é necessário porque a aplicação não está com as interrupções habilitadas (IE = 0) e por isso não há uma ISR para o tratamento da mesma (o flag seria apagado automaticamente quando o programa fosse desviado para a ISR). Para a correta operação do exemplo, alguns passos devem ser observados: 1. A aplicação deve ser compilada com o depurador interno (OCD) desativado no byte de opção número 3; 2. O projeto deve ser compilado no modo “Release” dentro do ambiente EWRL78. Lembre-se de configurar as opções de projeto da mesma forma que no modo “Debug”. O linker deve ser configurado para gerar um arquivo .hex, necessário para a gravação através da ferramenta RFP, conforme mostrado no tópico 2.1.4; 3. Após a gravação do arquivo .hex gerado no passo 2, basta remover o jumper J9 para que o microcontrolador saia do reset e execute a aplicação. Para medição da corrente consumida, basta conectar um multímetro ou microamperímetro no local do jumper J3. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 4MHz flash low speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em casa de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_OFF; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED_D2 P7_bit.no7

void pisca(void) { unsigned char cnt; unsigned long int temp; for (cnt=10;cnt;cnt--) { LED_D2 = 0; for (temp=100000;temp;temp--); LED_D2 = 1; for (temp=100000;temp;temp--); } }

Suporte à CPU 97

void main (void) { P0=P1=P2=P3=P4=P5=P6=P7=P12=P14=0; // configura todos os pinos como saídas PM0=PM1=PM2=PM3=PM4=PM5=PM6=PM7=PM12=PM14=0; // configura pinos analógicos para modo digital ADPC = 1; PMC0=PMC12=PMC14=0; CMC = 0; // desativa osciladores X1 e XT1 PM5_bit.no0 = 1; // pino P5.0 como entrada PU5_bit.no0 = 1; // liga pull-up do pino P5.0 EGN0 = BIT1; // interrupção INTP1 na borda de descida PIF1 = 0; // limpa o flag da interrupção INTP1 PMK1 = 0; // habilita a interrupção INTP1 while(1) { pisca(); // pisca 10 vezes o led __stop(); // entra em modo stop // ocorreu um sinal de wake-up PIF1 = 0; // limpa o flag da interrupção } } Exemplo 4.2

4.4. Clock/Buzzer Output

Os microcontroladores RL78 incluem até dois módulos capazes de gerar sinais de onda quadrada através de pinos do chip. Os sinais gerados pelos módulos podem ser utilizados para controlar buzzers ou alto-falantes externos, fornecer referências externas de clock, etc. Estes módulos consistem em divisores de frequência capazes de dividir um dos sinais internos de clock (principal ou do oscilador XT1) por um fator fixo configurável (8 seleções para cada fonte de clock). Os sinais de saída (PCLBUZ0 e PCLBUZ1) podem ainda ser controlados (ligados ou desligados) de forma que se pode modulá-los conforme desejado. Note que nos microcontroladores com encapsulamentos de 24 ou 25 pinos, apenas um módulo está disponível (saída PCLBUZ0) e nos modelos com 20 pinos, nenhum dos módulos está presente. O sinal PCLBUZ0 está normalmente associado ao pino P140 (ou P31 quando há redirecionamento de E/S) e o pino PCLBUZ1 está normalmente associado ao pino P141 (ou P55 quando há redirecionamento de E/S). Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura CKS1 PCLOEn 0 0 0 CSELn CCSn2 CCSn1 CCSn0 Escrita CKS0 Reset 0 0 0 0 0 0 0 0 O bit PCLOEn controla a saída do módulo: em “0” a saída está desativada e em “1” a saída é controlada pelo módulo.

98 Microcontroladores RL78: Guia Básico

As tabelas a seguir mostram os valores típicos de frequências de saída para as diversas configurações dos módulos. CSELn = 0 (clock primário) f/1 f/2 f/4 f/8 f/16 f/2048 f/4096 f/8192 CCSn2 0 0 0 0 1 1 1 1 CCSn1 0 0 1 1 0 0 1 1 CCSn0 0 1 0 1 0 1 0 1 1M 1M 500k 250k 125k 62,5k 488,28 244,14 122,07 2M 2M 1M 500k 250k 125k 976,56 488,28 244,14 3M 3M 1,5M 750k 375k 187,5k 1.464,84 732,42 366,21 4M 4M 2M 1M 500k 250k 1.953,13 976,56 488,28 5M 5M 2,5M 1,25M 625k 312,5k 2.441,41 1.220,70 610,35 6M 6M 3M 1,5M 750k 375k 2.929,69 1.464,84 732,42 8M 8M 4M 2M 1M 500k 3.906,25 1.953,13 976,56 10M 10M 5M 2,5M 1,25M 625k 4.882,81 2.441,41 1.220,70 12M 12M 6M 3M 1,5M 750k 5.859,38 2.929,69 1.464,84 16M 16M 8M 4M 2M 1M 7.812,5 3.906,25 1.953,13 Clock principal (Hz) (Hz) principal Clock 20M * 10M 5M 2,5M 1,25M 9.765,63 4.882,81 2.441,41 24M * 12M 6M 3M 1,5M 11.718,75 5.859,38 2.929,69 32M * 16M 8M 4M 2M 15.625 7.812,5 3.906,25 * A frequência de saída não deve ultrapassar 16MHz!!! Tabela 4.2

CSELn=1 (clock secundário XT1) f/1 f/2 f/4 f/8 f/16 f/32 f/64 f/128 CCSn2 0 0 0 0 1 1 1 1 CCSn1 0 0 1 1 0 0 1 1 CCSn0 0 1 0 1 0 1 0 1 Saída 32.768 16.384 8.192 4.096 2.048 1.024 512 256 Tabela 4.3

4.4.1. Exemplo O exemplo a seguir demonstra como utilizar a saída PCLBUZ0 disponível no RL78/G13. O programa configura o pino P14.0 como saída e ajusta a saída PCLBUZ0 para operar com uma frequência de saída igual a 3.906,25Hz (com o clock da CPU proveniente do HOCO operando a 32MHz). #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 4MHz flash low speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em casa de falha de autenticação

Suporte à CPU 99

#pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_OFF; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

void main (void) { CMC = 0; // desativa osciladores X1 e XT1 PM14_bit.no0 = 0; // pino P14.0 como saída CKS0 = bPCLOE | 7; // ativa a saída PCLBUZ0 com clock = 3,9kHz while (1); } Exemplo 4.3

4.5. Detector de Baixa Tensão

O detector de baixa tensão ou LVD é um circuito comparador de tensão integrado ao RL78 e que monitora a tensão de alimentação do chip. O LVD pode operar em três modos distintos: • Reset: neste modo o LVD provoca o reset do chip quando a tensão de alimentação cai abaixo do valor configurado; • Interrupção: o LVD gera uma interrupção quando a tensão de alimentação cai abaixo do valor configurado; • Interrupção e reset: é um misto dos dois modos anteriores. O LVD gera uma interrupção quando a tensão de alimentação cai abaixo de um limite configurado e provoca o reset caso ela ultrapasse um limite mínimo também especificado. O módulo LVD pode ser desativado (através do byte de configuração), mas isso normalmente não deve ser realizado, já que ele garante a correta operação do microcontrolador nas flutuações de tensão e o seu consumo é muito reduzido (cerca de 80nA). Vejamos agora os detalhes de cada modo de operação do LVD.

4.5.1. Modo Reset Neste modo, o LVD provoca o reset do chip quando a tensão de alimentação cai abaixo do valor de disparo (valor de descida da coluna V LVD na tabela 4.4). Ao mesmo tempo, os bits LVIRF (registrador RESF) e LVIF (registrador LVIM) são setados. Enquanto esta situação perdurar, o sinal de reset do LVD é mantido, sendo liberado somente quando a tensão ultrapassa o valor de subida da coluna V LVD na mesma tabela. Quando isso acontece, o bit LVIF é apagado (mas o LVIRF é mantido setado).

Note que, caso a tensão de alimentação caia abaixo do valor V POR , um reset de energização é desencadeado (o bit LVIRF é apagado).

100 Microcontroladores RL78: Guia Básico

4.5.2. Modo Interrupção Neste modo, o módulo LVD gera interrupções tanto quando a tensão de alimentação cai abaixo do valor de disparo (valor de descida da coluna V LVD na tabela 4.4), quanto quando a tensão de alimentação ultrapassa o valor de subida da coluna V LVD na mesma tabela. Em qualquer dos casos o bit LVIF é setado, juntamente com o flag de interrupção LVIIF e, caso a máscara de interrupção do LVD esteja desativada (LVIMK = 0), uma interrupção será gerada.

4.5.3. Modo Interrupção e Reset Neste modo, o LVD opera inicialmente no modo de interrupção. Quando a tensão de alimentação cai abaixo do valor V LVDH , um evento de interrupção é disparado e simultaneamente o módulo passa a operar no modo reset (no registrador LVIS, os bits de seleção de modo LVIMD e de seleção de limiar LVILV são setados, selecionando o modo de reset com limiar V LVDL ). Dentro da ISR a aplicação deve seguir os seguintes passos: 1. Setar o bit LVISEN no registrador LVIM. Isto é necessário para modificar o bit LVILV no próximo passo; 2. Apagar o bit LVILV no registrador LVIS; 3. Apagar o bit LVISEN no registrador LVIM; 4. Aguardar que a estabilização do LVD seja completada (bit LVIOMSK=0 no registrador LVIM; 5. Após a estabilização, caso a tensão de alimentação esteja abaixo de VLVDH, um reset é gerado, caso contrário a aplicação deve seguir para o próximo passo; 6. O bit LVISEN (registrador LVIM) deve ser setado novamente. Isto é necessário para alterar o bit LVIMD; 7. O bit LVIMD (registrador LVIS) deve ser apagado (seleciona o modo de interrupção); 8. O bit LVISEN deve ser apagado e a aplicação retorna ao estado normal de operação, um novo evento de queda de tensão irá gerar uma nova interrupção LVD.

Neste modo de operação, o parâmetro V LVDH pode ser considerado como o limiar de interrupção e o parâmetro V LVDL pode ser considerado como o limiar de reset. Após um reset neste modo a aplicação deve sempre verificar a origem do reset (registrador RESF) e caso verifique que o reset foi provocado pelo LVD (bit LVIRF = 1), ela deve obrigatoriamente seguir os seguintes passos: 1. Setar o bit LVISEN (registrador LVIM) de forma a poder modificar o bit LVIMD; 2. Aguardar um tempo mínimo de 400µs; 3. Apagar o bit LVIMD no registrador LVIS (selecionando o modo de interrupção);

Suporte à CPU 101

4. Apagar o bit LVISEN e iniciar a operação normal do microcontrolador.

4.5.4. Registradores do LVD

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura LVIOMSK LVIF LVISEN 0 0 0 0 0 LVIM Escrita 0 0 Reset 0* 0 0 0 0 0 0* 0* * Após um reset LVD este registrador não é alterado. Nome do Bit Descrição Bit C Símbolo C Controle de escrita no registrador LVIS: LVISEN 0 – escrita desabilitada (não produz efeito) LVISEN bLVISEN 1 – escrita habilitada Máscara de estado do LVD: 0 – LVD operando normalmente LVIOMSK LVIOMSK bLVIOMSK 1 – LVD em estabilização (nenhum evento será gerado nesta situação) Indicador de status do LVD: 0 – LVD desligado ou tensão (V ) ≥ valor configurado LVIF DD LVIF bLVIF (V LVD ) 1 – tensão (V DD ) < valor configurado (V LVD )

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura LVIMD 0 0 0 0 0 0 LVILV LVIS Escrita Reset * 0 0 0 0 0 0 * * O valor após o reset depende da configuração do LVD no byte de configuração: 0x81 no modo reset, 0x01 no modo interrupção e 0x00 no modo interrupção e reset. Atenção: somente é possível escrever no registrador LVIS quando o bit LVISEN = 1 no LVIM! Nome do Bit Descrição Bit C Símbolo C Modo de operação do LVD: 0 – modo de interrupção LVIMD 1 – modo de reset LVIMD bLVIMD * somente é possível escrever 0 quando o LVD opera no modo interrupção e reset! Nível de detecção do LVD: LVILV 0 – Nível alto (V LVDH ) LVILV bLVILV 1 – Nível baixo (V LVDL )

102 Microcontroladores RL78: Guia Básico

Endereço BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0x000C1 VPOC2 VPOC1 VPOC0 1 LVIS1 LVIS0 LVIMDS1 LVIMDS0 Escrita

Nome do Bit Descrição Símbolo C Seleção do modo de operação do detector de baixa tensão (LVD): 00 – proibido - LVIMDS1 LVIMDS0 01 – modo interrupção LVD_INT_MODE 10 – modo de interrupção e reset LVD_INTRES_MODE 11 – modo de reset LVD_RESET_MODE VPOC2 VPOC1 VPOC0 Veja a tabela abaixo: Veja a tabela abaixo LVIS1 LVIS0

V /V V LVD LVDH LVDL VPOC2 VPOC1 VPOC0 LVIS1 LVIS0 Símbolo C Subida Descida Descida* 1 1,67V* 2 1,63V - 0 0 0 1 1 LVD_VMODE0 1,77V 1,73V 1,63V 0 0 0 1 0 LVD_VMODE1 1,88V* 2 1,84V - 0 0 1 1 1 LVD_VMODE2 1,88V 1,84V 1,63V 0 0 0 0 1 LVD_VMODE3 1,98V 1,94V 1,84V 0 0 1 1 0 LVD_VMODE4 2,09V 2.04V 1,84V 0 0 1 0 1 LVD_VMODE5 2,50V* 2 2,45V - 0 1 0 1 1 LVD_VMODE6 2,61V 2,55V 2,45V 0 1 0 1 0 LVD_VMODE7 2,71V 2,65V 2,45V 0 1 0 0 1 LVD_VMODE8 2,81V* 2 2,75V - 0 1 1 1 1 LVD_VMODE9 2,92V 2,86V 1,63V 0 0 0 0 0 LVD_VMODE10 2,92V 2,86V 2,75V 0 1 1 1 0 LVD_VMODE11 3,02V 2,96V 2,75V 0 1 1 0 1 LVD_VMODE12 3,13V 3,06V 1,84V 0 0 1 0 0 LVD_VMODE13 3,75V 3,67V 2,45V 0 1 0 0 0 LVD_VMODE14 4,06V 3,98V 2,75V 0 1 1 0 0 LVD_VMODE15 1 * VLVDL é a tensão de reset no modo de interrupção e reset *2 Configuração não permitida quando o LVD opera no modo de interrupção e reset Tabela 4.4

Suporte à CPU 103

4.6. Watchdog (WDT)

O watchdog ou cão de guarda é um elemento de segurança que visa garantir a correta operação da aplicação. Ele consiste num temporizador que, ao atingir o tempo máximo (também chamado de estouro de temporização), provoca o reset do microcontrolador. Para evitar que isso ocorra, inserem-se alguns comandos especiais dentro de determinadas partes do programa. Estes comandos especiais apagam e reiniciam a contagem do watchdog, impedindo que o mesmo estoure e provoque o reset do chip. A idéia é que, caso o programa entre em um estado de erro ou loop, ele deixa de executar os comandos de reinício do watchdog, fazendo com que o mesmo estoure a sua contagem e provoque o reset do microcontrolador. É claro que existem situações onde um watchdog comum pode não conseguir prevenir uma falha, como por exemplo, se a aplicação entrar em loop num trecho de código que contenha um comando para apagamento do watchdog. A solução para amenizar este problema é um watchdog com janela de tempo, como o utilizado nos RL78. Neste tipo de dispositivo, o apagamento ou reinício da contagem do watchdog é possível apenas dentro de uma faixa de tempo específica (janela de tempo), a tentativa de executar esta operação fora da janela de tempo provoca o reset do chip.

O watchdog é um dispositivo cujo uso deve ser muito bem avaliado pelo projetista ou programador. A segurança oriunda do seu uso somente terá validade se ele for corretamente configurado. A quantidade de comandos para reinício do watchdog é também tema para longas e O fervorosas discussões. Por um lado poucos comandos para reinício do watchdog podem resultar em resets inesperados, sem que exista uma falha real no software. Comandos em excesso podem resultar na perda da eficácia do dispositivo, permitindo que, mesmo com falhas, o programa continue a ser executado. Lembre-se: muitas falhas de programas são causadas pelo mal uso do watchdog!

O watchdog utilizado nos RL78 consiste num contador binário de 17 bits alimentado pelo oscilador LOCO (de 15kHz), além de alguns circuitos lógicos que controlam a janela de tempo e as condições de operação do módulo. As circunstâncias em que o watchdog pode ser ressetado são muito específicas: é necessário escrever o valor 0xAC no registrador WDTE (numa operação de 8 bits) enquanto a janela de escrita está aberta. A escrita de qualquer outro valor ou do valor correto no momento errado provoca o reset do microcontrolador. A janela de escrita no registrador WDTE pode ser configurada em três diferentes aberturas: 50%, 75% ou 100%. A seleção é feita através dos bits WINDOW1 e WINDOW0 do byte de configuração em 0x000C0. A figura 4.3 mostra a relação entre os bits e a abertura da janela.

104 Microcontroladores RL78: Guia Básico

WINDOW1 WINDOW0 25% 50% 75% 100% 0 1 Fechada Aberta 1 0 Fechada Aberta 1 1 Aberta Legenda: Janela fechada (escrita de qualquer valor no WDTE causa reset) Janela aberta (escrita de 0xAC no WDTE reinicia a contagem do watchdog) Figura 4.3

Note que, quando é selecionada uma abertura de janela igual a 100%, a funcionalidade de janela do watchdog é desativada, permitindo que ele receba comandos de reinício a qualquer momento. A temporização do watchdog pode ser configurada através dos bits WDCS2, WDCS1 e WDCS0, variando de aproximadamente 3,71ms até 3,79 segundos. Opcionalmente é possível também configurar o watchdog para gerar uma interrupção quando ele atinge 75% da sua contagem, desta forma, é possível garantir que os tempos de janela aberta sejam atendidos.

A leitura do registrador WDTE pode retornar dois valores diferentes após o reset, i dependendo da configuração do bit WDTON: quando WDTON = 0, o valor de reset do WDTE é igual a 0x1A e quando WDTON = 1, o valor de reset do WDTE é igual a 0x9A!

O watchdog também pode continuar operando quando a CPU entra em um dos modos de baixo consumo de energia (halt, stop ou snooze). Para isso, o bit WDSTBYON deve ser setado no byte de configuração. Caso WDSTBYON = 0, o watchdog é paralisado ao entrar num modo de baixo consumo e a sua contagem reinicia de zero quanto o chio retorna ao modo run.

Quando se utiliza o watchdog é uma boa idéia verificar o registrador RESF no início do programa. O bit WDTRF setado, indicará que o watchdog provocou um O reset. Esta informação pode ser utilizada para fornecer algum aviso de falha ao usuário, ou ser registrada na memória flash do microcontrolador para avaliação futura.

A nota de aplicação R01AN0603ED0100 traz muitas informações e detalhes sobre O o funcionamento e utilização do watchdog!

Observe que toda a configuração de operação é controlada pelo byte de configuração em 0x000C0, o que significa que, uma vez configurado e ativado, o watchdog não pode ser desativado pela aplicação.

Suporte à CPU 105

Endereço BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0x000C0 WDTINIT WINDOW1 WINDOW0 WDTON WDCS2 WDCS1 WDCS0 WDSTBYON Escrita

Nome do Bit Descrição Símbolo C Habilitação da interrupção do watchdog: 0 – interrupção desativada WDTINIT bWDTINIT 1 – interrupção habilitada (gera interrupção quando a contagem do watchdog chega a 75% do tempo de estouro) Seleção do período de janela aberta do watchdog: 00 – proibido - WINDOW1 WINDOW0 01 – 50% WDT_WINDOW50 10 – 75% WDT_WINDOW75 11 – 100% WDT_WINDOW100 Controle de operação do watchdog: WDTON bWDTON 0 – watchdog desativado 1– watchdog ativado Tempo de estouro do watchdog (considerando a frequência máxima de

fIL =17,25kHz) 6 000 – 2 /f IL (±3,71ms) WDT_3ms 7 001 – 2 /f IL (±7,42ms) WDT_7ms WDCS2 8 010 – 2 /f IL (±14,84ms) WDT_14ms WDCS1 9 WDCS0 011 – 2 /f IL (±29,68ms) WDT_29ms 11 100 – 2 /f IL (±118,72ms) WDT_118ms 13 101 – 2 /f IL (±474,90ms) WDT_474ms 14 110 – 2 /f IL (±0,9498s) WDT_949ms 16 111 – 2 /f IL (±3,79919s) WDT_3799ms Operação do watchdog nos modos halt ou stop: WDSTBYON bWDSTBYON 0 – watchdog parado 1 – watchdog operacional Utilize o símbolo WDT_OFF (definido em myRL78.h) para desativar o watchdog!

4.6.1. Exemplo O programa a seguir demonstra a utilização do watchdog e da interrupção dele. Na verdade nós não utilizamos a interrupção propriamente dita, mas apenas monitoramos o flag da mesma (um processo chamado de pooling). Quando o programa detecta, no loop principal, que o flag do watchdog (WDTIIF) está setado, ele apaga a contagem do watchdog e o flag, impedindo que o cão de guarda ressete o chip. Mas quando o usuário pressiona uma tecla ligada ao pino P1.0, aterrando o mesmo, o programa entra num loop de espera, deixando de tratar o watchdog, o que leva o mesmo a estourar e ressetar o chip. O if no início do programa monitora o estado do bit WDTRF e acende o led quando o reset foi causado pelo watchdog!

106 Microcontroladores RL78: Guia Básico

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog #pragma location = "OPTBYTE" __root __far const char config0 = bWDTON|bWDTINIT|WDT_WINDOW50|WDT_3799ms; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root __far const char config1 = LVD_RESET_MODE | LVD_VMODE15; // oscilador 4MHz flash low speed #pragma location = "OPTBYTE" __root __far const char config2 = FLASH_LS | CLK_4MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char config3 = DEBUG_ON_ERASE;

/* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P7_bit.no7 #define TCL P1_bit.no0 unsigned char temp;

void main(void) { CMC = 0; // desativa osciladores X1 e XT1 PM7_bit.no7 = 0; // configura LED como saída PU1_bit.no0 = 1; // liga pull up do pino P1.0 // faz a leitura do registrador RESF e salva em uma variável temporária temp = RESF; // se WDTRF = 1 liga o led, senão apaga if (temp && bWDTRF) LED = 0; else LED = 1; while(1) { // caso o flag de interrupção do WDT esteja setado if (WDTIIF) { WDTE = 0xAC; // apaga o watchdog WDTIIF = 0; // apaga o flag } while (!TCL); // se a tecla for pressionada, fica em loop } } Exemplo 4.4

Suporte à CPU 107

4.7. Regulador Interno de Tensão

Os microcontroladores RL78 incluem um regulador de tensão integrado ao chip. Este regulador fornece uma tensão de saída estabilizada para a CPU e todos os periféricos internos, reduzindo o consumo de energia e reduzindo também a emissão eletromagnética (EMI). O regulador pode operar em dois modos: • Baixa potência: neste modo o regulador fornece uma tensão de saída de 2,1V. O regulador entra neste modo quando a memória flash opera em modo HS (alta velocidade) e a CPU está em modo run. Este modo também é selecionado sempre que o depurador (OCD) está em uso; • Super baixa potência: neste modo o regulador fornece uma tensão de saída de 1,8V. O regulador entra neste modo quando a memória flash opera em modo LV (baixa potência) ou LS (baixa velocidade). Este modo também é selecionado quando a CPU entra em modo stop ou quando a CPU opera com clock secundário e os osciladores X1 e HOCO estão parados. Para operar corretamente, o regulador interno necessita que um capacitor externo (470nF a 1µF) seja conectado ao pino REGC, conforme mostra a figura 4.4.

Figura 4.4

i Alguns modelos não possuem o pino REGC e dispensam o capacitor externo!

108 Microcontroladores RL78: Guia Básico

5

Portas de Entrada e Saída 5. Portas de Entrada e Saída

As portas de entrada e saída (E/S ou em inglês I/O) são o meio pelo qual a CPU do microcontrolador pode se comunicar com o mundo exterior, controlando circuitos ou dispositivos, lendo informações, etc. Os microcontroladores RL78 possuem um conjunto de portas de E/S muito interessante, com diversas funções e capacidades integradas. Uma das características interessantes das portas de E/S destes chips é que elas permitem interface com diferentes níveis de tensão, ou seja, um microcontrolador alimentado por 5V pode se comunicar perfeitamente com um circuito alimentado por 3V.

Esta funcionalidade está disponível primariamente nos chips com pino de alimentação i EV DD . Nestes chips os circuitos internos dos pinos P20 a P27, P121 a P124, P137 e P150 a P156 são alimentados pela fonte conectada ao EV DD , desta forma, conecta-se o pino V DD do chip ao potencial de 5V e o pino EV DD ao potencial desejado (1,8 a 5V).

Muitos pinos possuem também sensibilidade selecionável (níveis CMOS ou TTL) e saída configurável (complementar ou dreno aberto), o que também facilita a interconexão com circuitos alimentados por potenciais diferentes daquele do microcontrolador. Praticamente todos os pinos possuem circuitos Schmitt trigger nas suas entradas, o que garante maior imunidade a ruídos. Lembre-se de que neste tipo de entrada, a comutação de nível lógico ocorre somente quando a tensão de entrada ultrapassa os limiares de comutação. Na zona de indeterminação, o nível lógico anterior é mantido.

Todos os pinos (exceto P60 a P63 e P137) possuem diodos de proteção (clamp) para V DD e V SS que limitam a tensão máxima nas entradas do microcontrolador. Os pinos P60 a P63 possuem somente diodos para V SS . A tabela 5.1 mostra os valores de corrente injetada máxima e média por pino e os valores globais (para todos os pinos). I máxima por pino I média por pino I máxima I média global Tipo de entrada global VIN >V DD VIN V DD VIN V DD Pinos digitais 5mA 5mA 400µA 400µA 20mA 4mA Pinos analógicos 2mA 150µA 150µA 20µA 4mA 1mA Tabela 5.1

A maioria dos pinos de E/S do RL78 podem fornecer uma corrente individual de 10mA e drenar uma corrente individual de até 20mA (os pinos P20 a P27 e P150 a P156 podem fornecer até 100µA e drenar até 400µA). Este valor de corrente depende da tensão EV DD0 e cai com o

Portas de Entrada e Saída 109

decréscimo desta. Note, entretanto, que há um limite global para os pinos: cerca de 135mA de fornecimento e 150mA de drenagem (alguns grupos de pinos possuem valores conjuntos diferentes, consulte o manual de hardware para maiores detalhes).

5.1. Registradores das Portas de E/S

As portas de E/S dos RL78 possuem largura de oito bits e cada uma possui um conjunto de registradores responsáveis pelo controle da sua operação: • Px – responsável por ler ou escrever nos pinos. A leitura da porta ou de um pino irá retornar, nos pinos configurados como entrada, o nível lógico externo, nos pinos configurados como saída, o valor lido será o último escrito no pino ou porta. A escrita na porta ou num pino irá alterar o estado dos pinos configurados como saída. Nos pinos configurados como entrada, o valor escrito é armazenado no registrador da porta apenas; • PMx – responsável por controlar a direção de cada pino da porta: 0 – o pino é uma saída digital; 1 – o pino é uma entrada digital; • PUx – responsável pelo controle dos pull-ups internos (tipicamente 20k Ω, apenas algumas portas possuem resistores de pull-up integrados, veja as tabelas 5.2 e 5.3). Os pull-ups somente podem ser ativados nos pinos configurados como entrada e quando o bit correspondente em POMx está em 0: 0 – pull-up desativado; 1 – pull-up ativado (desde que o bit correspondente em POMx esteja em 0);

Após um reset, o pull-up do pino P40/TOOL0 é ativado, os demais são desativados! Note que o pino P40/TOOL0 seleciona o modo de operação do chip após um reset: quando em i nível “0” ele seleciona o modo de gravação/depuração e quando em nível “1” ele seleciona o modo normal de operação.

• PIMx – responsável pela seleção da sensibilidade do buffer de entrada (CMOS ou TTL). Consulte as tabelas 5.2 e 5.3 para verificar quais pinos possuem esta capacidade: 0 – buffer de entrada sensível a níveis CMOS; 1 – buffer de entrada sensível a níveis TTL; • POMx – responsável pela seleção do tipo de saída do pino (complementar ou dreno aberto). Consulte as tabelas 5.2 e 5.3 para verificar quais pinos possuem esta capacidade: 0 – saída complementar (apenas se o pino estiver configurado como saída); 1 – saída em dreno aberto (apenas se o pino estiver configurado como saída); • PMCx – seleciona o modo de operação (digital ou analógico) das portas 0, 3, 10, 11, 12 e 14 (veja a tabela 5.5 para identificar os bits implementados): 0 – modo digital; 1 – modo analógico;

110 Microcontroladores RL78: Guia Básico

• ADPC – seleciona o modo de operação (digital ou analógico) das portas 2 e 15 (veja a tabela 5.4); • PIOR – controla o redirecionamento de algumas funções digitais; • GDIDIS – controle global de desativação dos buffers de entrada. As tabelas 5.2 e 5.3 apresentam os diversos pinos de E/S disponíveis nos modelos até 64 pinos da linha RL78/G13, bem como as funcionalidades presentes em cada um deles. A coluna E/S mostra as direções possíveis para o pino, a coluna pull-up indica a presença ou não de pull-up interno, a coluna dreno aberto mostra se o pino possui capacidade de saída em dreno aberto (os pinos não marcados possuem apenas a saída complementar, enquanto que os marcados possuem saída complementar ou dreno aberto, selecionável por software). A coluna TTL/CMOS indica o tipo de buffer de entrada disponível (CMOS, TTL ou ambos) e a coluna Schmitt trigger indica se a entrada possui este tipo de facilidade ou não, as demais colunas mostram as funções analógicas e digitais associadas ao pino, além da configuração padrão após um reset. Dreno TTL/ Schmitt Funções digitais Após Pino E/S Pull-up Analógico Funções digitais alternativas Aberto CMOS Trigger redirecionadas reset P00 E/S X X C X ANI17* TI00 - P00 P01 E/S X - T/C X ANI16* TO00 - P01 P02 E/S X X C X ANI17 SO10/TXD1 - ANI17 P03 E/S X X T/C X ANI16 SI10/RXD1/SDA10 - ANI16 P04 E/S X X T/C X - SCK10/SCL10 - P04 P05 E/S X - C X - TI05/TO05 - P05 P06 E/S X - C X - TI06/TO06 - P06 P10 E/S X X T/C X - SCK00/SCL00 TI07/TO07 P10 P11 E/S X X T/C X - SI00/RXD0/TOOLRXD/SDA00 TI06/TO06 P11 P12 E/S X X C X - SO00/TXD0/TOOLTXD INTP5/TI05/TO05 P12 P13 E/S X X T/C X - TXD2/SO20 SDAA0/TI04/TO04 P13 P14 E/S X X T/C X - RXD2/SI20/SDA20 SCLA0/TI03/TO03 P14 P15 E/S X X T/C X - SCK20/SCL20 TI02/TO02 P15 P16 E/S X - T/C X - TI01/TO01/INTP5 SI00/RXD0 P16 P17 E/S X X T/C X - TI02/TO02 SO00/TXD0 P17 P20 E/S - - C - ANI0/AV REFP - - ANI0 P21 E/S - - C - ANI1/AV REFM - - ANI1 P22 E/S - - C - ANI2 - - ANI2 P23 E/S - - C - ANI3 - - ANI3 P24 E/S - - C - ANI4 - - ANI4 P25 E/S - - C - ANI5 - - ANI5 P26 E/S - - C - ANI6 - - ANI6 P27 E/S - - C - ANI7 - - ANI7 P30 E/S X - C X - INTP3/RTC1HZ/SCK11/SCL11 - P30 P31 E/S X - C X - TI03/TO03/INTP4 PCLBUZ0 P31 P40 E/S X - C X - TOOL0 - P40 P41 E/S X - C X - TI07/TO07 - P41 P42 E/S X - C X - TI04/TO04 - P42 P43 E/S X - C X - - - P43 P50 E/S X X C X - INTP1/SI11/SDA11 - P50 P51 E/S X - C X - INTP2/SO11 - P51 P52 E/S X - C X - - INTP10 P52 * Nos chips com 32 pinos ou menos, os pinos P00 e P01 possuem função analógica multiplexada. Nestes chips os pinos P02 e P03 não estão implementados. Legenda: C=CMOS, T=TTL, T/C = TTL ou CMOS Tabela 5.2

Portas de Entrada e Saída 111

Dreno TTL/ Schmitt Funções digitais Após Pino E/S Pull-up Analógico Funções digitais alternativas Aberto CMOS Trigger redirecionadas reset P53 E/S X - C X - - INTP11 P53 P54 E/S X - C X - - - P54 P55 E/S X - T/C X - - PCLBUZ1/SCK00 P55 P60 E/S - X* 1 C X - SCLA0 - P60 P61 E/S - X* 1 C X - SDAA0 - P61 P62 E/S - X* 1 C X - - - P62 P63 E/S - X* 1 C X - - - P63 P70 E/S X - C X - KR0/SCK21/SCL21 - P70 P71 E/S X X C X - KR1/SI21/SDA21 - P71 P72 E/S X - C X - KR2/SO21 - P72 P73 E/S X - C X - KR3/SO01 - P73 P74 E/S X X C X - KR4/INTP8/SI01/SDA01 - P74 P75 E/S X - C X - KR5/INTP9/SCK01/SCL01 - P75 P76 E/S X - C X - KR6/INTP10 RXD2 P76 P77 E/S X - C X - KR7/INTP11 TXD2 P77 P120 E/S X - C X ANI19 - - ANI19 P121 E - - C X - X1 - P121 P122 E - - C X - X2/ECLK - P122 P123 E - - C X - XT1 - P123 P124 E - - C X - XT2/EXCLKS - P124 P130 S - - - - - *2 - P130 P137 E - - C X - INTP0 - P137 P140 E/S X - C X - PCLBUZ0/INTP6 - P140 P141 E/S X - C X - PCLBUZ1/INTP7 - P141 P146 E/S X - C X - - - P142 P147 E/S X - C X ANI18 - - ANI18 *1 Atenção: os pinos P60 a P63 quando configurados como saídas operam somente em modo dreno aberto! *2 O pino P130 é mantido em nível lógico 0 durante um reset Legenda: C=CMOS, T=TTL, T/C = TTL ou CMOS Tabela 5.3

Lembre-se que os níveis de tensão para “0” e “1” nas portas CMOS e TTL são diferentes. Os pinos configurados como entradas nos RL78 respondem aos seguintes níveis: Entradas Schmitt Trigger:

CMOS: nível “1” V IN ≥80%V DD e nível “0” V IN ≤20%V DD ≥ ≤ i TTL (V DD entre 4 e 5,5V): nível “1” V IN 2,2V e nível “0” V IN 0,5V TTL (V DD entre 3,3 e 4V): nível “1” V IN ≥2,0V e nível “0” V IN ≤0,8V

TTL (V DD entre 1,6 e 3,3V): nível “1” V IN ≥1,5V e nível “0” V IN ≤0,32V Entradas Comuns:

CMOS: nível “1” V IN ≥70%V DD e nível “0” V IN ≤30%V DD

Vejamos alguns exemplos de configuração dos registradores das portas de E/S dos RL78: 1. Configurar os pinos P10, P11 e P12 como saídas e P13 a P17 como entradas: // Porta = 1, configuração = EEEEESSS ou 11111000 ou 0xF8 PM1 = 0xF8; // configura todos os bits de uma vez Ou também é possível utilizar uma estrutura de campos de bits definida nos headers de todos os modelos de RL78. Esta estrutura mapeia os oito bits individualmente e permite acesso a qualquer SFR utilizando o seguinte formato: SFR_bit.noX, onde SFR é nome do registrador e X o número do bit (0 a 7).

112 Microcontroladores RL78: Guia Básico

typedef struct { unsigned char no0:1; unsigned char no1:1; unsigned char no2:1; unsigned char no3:1; unsigned char no4:1; unsigned char no5:1; unsigned char no6:1; unsigned char no7:1; } __BITS8;

Assim, utilizando a estrutura acima, podemos escrever: // Configura um pino de cada vez (código maior e mais lento): PM1_bit.no0 = 0; PM1_bit.no1 = 0; PM1_bit.no2 = 0; PM1_bit.no3 = 1; PM1_bit.no4 = 1; PM1_bit.no5 = 1; PM1_bit.no6 = 1; PM1_bit.no7 = 1;

2. Ligar os pull-ups das entradas P16 e P17 configuradas acima: // Porta = 1, configuração em PU1 = 11000000 ou 0xC0 POM1 = 0; // todas os pinos de P1 como saídas complementares PU1 = 0xC0; // configura todos os bits de uma vez

3. Setar o pino P11 e apagar P10 e P12: // Podemos escrever bit por bit: P1_bit.no0 = 0; // P10 = 0 P1_bit.no1 = 1; // P11 = 1 P1_bit.no2 = 0; // P12 = 0 Ou // Podemos escrever em toda a porta (somente os pinos configurados // como saída serão alterados): P1 = 2;

4. Ler o pino P17 e setar P11 caso P17 esteja setado: if (P1_bit.no7) P1_bit.no1 = 1;

5. Configurar toda a porta 7 como entrada, ler o seu estado e guardar em uma variável: PM7 = 0xFF; // todos os pinos de P7 como entradas valor = P7; // lê P7 e guarda em “valor” 6. Configurar os pinos P11 a P13 como saídas (P13 como dreno aberto) e P10 e P14 a P17 como entradas (somente P16 com pull-up interno): // Porta = 1, configuração em PM1 = EEEESSSE ou 11110001 ou 0xF1 PM1 = 0xF1; // P11 a P13 como saídas, o restante como entradas POM1 = BIT3; // somente P13 como dreno aberto PU1 = BIT6; // liga pull-up de P16

Portas de Entrada e Saída 113

Um cuidado especial deve ser dispensado aos pinos com função analógica multiplexada.

Após um reset, os pinos com função analógica multiplexada são sempre configurados como i entradas analógicas! Caso deseje utilizá-los no modo digital, é necessário modificar o registrador relacionado ao mesmo (PMCx ou ADPC).

A seguir temos a configuração do registrador ADPC. Observe que o valor carregado neste registrador configura as entradas analógicas ANI0 a ANI14, conforme indicado na tabela 5.4. Antes de utilizar as portas 2 e 15 do microcontrolador, é importante configurar este registrador de forma que os pinos sejam configurados para as suas devidas funções (analógicas ou digitais). Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 ADPC3 ADPC2 ADPC1 ADPC0 ADPC Escrita Reset 0 0 0 0 0 0 0 0 Observe ainda que, conforme demonstra a tabela 5.4, não é possível utilizar aleatoriamente qualquer pino na função analógica. Assim, caso seja necessário utilizar, por exemplo, a entrada ANI12 (pino P22) no modo analógico, os pinos P20 e P21 deverão obrigatoriamente operar também na função analógica!

Valor em ADPC ANI7/P27 ANI7/P27 ANI6/P26 ANI5/P25 ANI4/P24 ANI3/P23 ANI2/P22 ANI1/P21 ANI0/P20 ANI9/P151 ANI9/P151 ANI8/P150 ANI14/P156 ANI14/P156 ANI13/P155 ANI12/P154 ANI11/P153 ANI10/P152

0 A A A A A A A A A A A A A A A 1 D D D D D D D D D D D D D D D 2 D D D D D D D D D D D D D D A 3 D D D D D D D D D D D D D A A 4 D D D D D D D D D D D D A A A 5 D D D D D D D D D D D A A A A 6 D D D D D D D D D D A A A A A 7 D D D D D D D D D A A A A A A 8 D D D D D D D D A A A A A A A 9 D D D D D D D A A A A A A A A 10 D D D D D D A A A A A A A A A 11 D D D D D A A A A A A A A A A 12 D D D D A A A A A A A A A A A 13 D D D A A A A A A A A A A A A 14 D D A A A A A A A A A A A A A 15 D A A A A A A A A A A A A A A Tabela 5.4 Os demais pinos analógicos são controlados pelos registradores PMCx, conforme a tabela a seguir. Note que os demais bits dos registradores não estão implementados e devem ser mantidos em 1. Além disso, os registradores PMCx são carregados com o valor 0xFF após um reset.

114 Microcontroladores RL78: Guia Básico

Encapsulamento Bits Implementados (número de pinos) Porta 14 Porta 12 Porta 11 Porta 10 Porta 3 Porta 0 PMC00 20 a 25 PMC147 - - - - PMC01 PMC00 30 a 32 PMC147 PMC120 - - - PMC01 36 a 48 PMC147 PMC120 - - - - PMC02 52 a 64 PMC147 PMC120 - - - PMC03 PMC02 80 a 100 PMC147 PMC120 - PMC100 - PMC03 PMC115 PMC35 PMC02 128 PMC147 PMC120 PMC116 PMC100 PMC36 PMC03 PMC117 PMC37 Tabela 5.5

Vejamos mais alguns exemplos de configuração dos registradores das portas de E/S dos RL78: 1. Uma aplicação vai utilizar um RL78 de 20 pinos e necessita de quatro entradas analógicas. Optou-se por utilizar as entradas ANI0 a ANI2 (pinos P20 a P22) e também ANI18 (pino P147) no modo analógico, os demais pinos em modo digital: // Selecionar os pinos P20 a P22 no modo analógico: ADPC = 4; // Pino P147 no modo analógico PMC14_bit.no7 = 1; // Pinos P00 e P01 no modo digital PMC0_bit.no0 = 0; PMC0_bit.no1 = 0; 2. Configurar apenas os pinos P20 a P24 no modo analógico (chip de 64 pinos): // Configura o ADPC ADPC = 6; // Configura os demais pinos para o modo analógico PMC0 = 0xF3 // Pinos P02 e P03 no modo digital PMC12_bit.no0 = 0; // Pino P120 no modo digital PMC14_bit.no7 = 0; // Pino P147 no modo digital 3. Configurar todos os pinos para modo digital (chip de 64 pinos): // Configura o ADPC ADPC = 1; // Configura os demais pinos para o modo analógico PMC0 = 0xF3 // Pinos P02 e P03 no modo digital PMC12_bit.no0 = 0; // Pino P120 no modo digital PMC14_bit.no7 = 0; // Pino P147 no modo digital

Antes de prosseguirmos, é importante conhecer a função do registrador GDIDIS: ele é utilizado nos casos em que a tensão de alimentação das portas de E/S (através do pino EV DD ) pode ser desligada de forma independente da tensão V DD (que alimenta o restante do chip). Assim, as aplicações que podem controlar esta fonte externa de energia devem desativar o GDIDIS (fazendo GDIDIS = 1) após a desativação da alimentação do pino EV DD . Este procedimento evita que flua corrente através dos buffers de entrada neste tipo de situação, nos outros casos, GDIDIS deve estar apagado (GDIDIS = 0).

Portas de Entrada e Saída 115

5.2. Redirecionamento de Funções

Outra funcionalidade interessante disponível nos RL78 é a capacidade de redirecionar algumas funções periféricas para diferentes pinos de E/S. Isto permite que se otimize a disposição de componentes em uma placa de circuito impresso e garante uma maior flexibilidade e liberdade de projeto.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 PIOR5 PIOR4 PIOR3 PIOR2 PIOR1 PIOR0 PIOR Escrita Reset 0 0 0 0 0 0 0 0 As tabelas a seguir mostram as configurações de redirecionamento disponíveis para cada bit do registrador PIOR (os modelos de 20 e 25 pinos não possuem esta função e neles este registrador não está implementado):

128/100 pinos 80 pinos 64 pinos 52 pinos 48 pinos 44 pinos 30 a 40 pinos Função Estado do bit PIOR0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 TI02/TO02 P17 P15 P17 P15 P17 P15 P17 P15 P17 P15 P17 P15 P17 P15 TI03/TO03 P31 P14 P31 P14 P31 P14 P31 P14 P31 P14 P31 P14 P31 P14 TI04/TO04 P42 P13 P42 P13 P42 P13 - P13 - P13 - P13 - P13 TI05/TO05 P46 P12 P05 P12 P05 P12 - P12 - P12 - P12 - P12 TI06/TO06 P102 P11 P06 P11 P06 P11 - P11 - P11 - P11 - P11 TI07/TO07 P145 P10 P41 P10 P41 P10 P41 P10 P41 P10 P41 P10 - P10 Tabela 5.6

128/100 pinos 80 pinos 64 pinos 52 pinos 48 pinos 44 pinos 30 a 40 pinos Função Estado do bit PIOR1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 INTP10 P76 P110 P76 P110 P76 P52 P76 ------INTP11 P77 P111 P77 P111 P77 P53 P77 ------TXD2 P13 P77 P13 P77 P13 P77 P13 P77 P13 - P13 - P13 - RXD2 P14 P76 P14 P76 P14 P76 P14 P76 P14 - P14 - P14 - SCL20 P15 - P15 - P15 - P15 - P15 - P15 - P15 - SDA20 P14 - P14 - P14 - P14 - P14 - P14 - P14 - SI20 P14 - P14 - P14 - P14 - P14 - P14 - P14 - SO20 P13 - P13 - P13 - P13 - P13 - P13 - P13 - SCK20 P15 - P15 - P15 - P15 - P15 - P15 - P15 - TXD0 P12 P17 P12 P17 P12 P17 P12 P17 P12 P17 P12 P17 P12 P17 RXD0 P11 P16 P11 P16 P11 P16 P11 P16 P11 P16 P11 P16 P11 P16 SCL00 P10 - P10 - P10 - P10 - P10 - P10 - P10 - SDA00 P11 - P11 - P11 - P11 - P11 - P11 - P11 - SI00 P11 P16 P11 P16 P11 P16 P11 - P11 - P11 - P11 - SO00 P12 P17 P12 P17 P12 P17 P12 - P12 - P12 - P12 - SCK00 P10 P55 P10 P55 P10 P55 P10 - P10 - P10 - P10 - Tabela 5.7

116 Microcontroladores RL78: Guia Básico

128/100 pinos 80 pinos 64 pinos 52 pinos 48 pinos 44 pinos 30 a 40 pinos Função Estado do bit PIOR2 0 1 0 1 0 1 0 1 0 1 0 1 0 1 SCLA0 P60 P14 P60 P14 P60 P14 P60 P14 P60 P14 P60 P14 P60 P14 SDAA0 P61 P13 P61 P13 P61 P13 P61 P13 P61 P13 P61 P13 P61 P13 Tabela 5.8

128/100 pinos 80 pinos 64 pinos 52 pinos 48 pinos Função Estado do bit PIOR3 0 1 0 1 0 1 0 1 0 1 PCLBUZ0 P140 P31 P140 P31 P140 P31 P140 P31 P140 P31 Tabela 5.9

128/100 pinos 80 pinos 64 pinos Função Estado do bit PIOR4 0 1 0 1 0 1 PCLBUZ1 P141 P55 P141 P55 P141 P55 INTP5 P16 P12 P16 P12 P16 P12 Tabela 5.10

128/100 pinos Função Estado do bit PIOR5 0 1 INTP1 P46 P56 INTP2 P30 P57 INTP4 P31 P146 INTP6 P140 P84 INTP7 P141 P85 INTP8 P74 P86 INTP9 P75 P87 TXD1 P02 P82 RXD1 P03 P81 SCL10 P04 P80 SDA10 P03 P81 SI10 P03 P81 SO10 P02 P82 SCK10 P04 P80 Tabela 5.11

5.3. Exemplo

O exemplo a seguir mostra como efetuar a leitura de uma tecla conectada ao pino P5.0, ativando o led conectado ao pino P5.2. Na placa utilizada para testes (RSK do RL78/G13) a chave SW1 está conectada ao pino P5.0 e o led D0 está conectado ao pino P5.2. No caso da placa RSK não é necessário utilizar os resistor de pull-up interno do pino P5.0 pois já existe um resistor externo com esta função.

Portas de Entrada e Saída 117

A figura 5.1 mostra o diagrama parcial da placa RSK do RL78/G13.

Figura 5.1

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog

118 Microcontroladores RL78: Guia Básico

#pragma location = "OPTBYTE" __root __far const char config0 = WDT_OFF; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root __far const char config1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char config2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char config3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P5_bit.no2 /* LED no pino P5.2 */ #define SW1 P5_bit.no0 /* tecla no pino P5.0 */

void main(void) { CMC = 0; // desativa osciladores X1 e XT1 PM5_bit.no2 = 0; // configura LED (P5.2) como saída while (1) { // se SW1 estiver em "0" (fechada) liga o led, caso contrário desliga if (!SW1) LED=0; else LED=1; } } Exemplo 5.1

Portas de Entrada e Saída 119

6

Sistema de Interrupções 6. Sistema de Interrupções

Já vimos que um programa é uma sequência de instruções cuja ordem de execução é basicamente a mesma. Apesar de ser possível modificar o fluxo do programa, ou seja, fazer com que determinadas partes do programa sejam executadas ou não, a comunicação entre o ambiente externo ao programa e o programa ocorre sempre em momentos definidos pelo programador (o chamado pooling). Embora este método funcione razoavelmente bem, há situações onde o programa necessita tomar conhecimento de um evento imediatamente após a sua ocorrência. Interfaces de comunicação serial são exemplos típicos: suponha uma comunicação ocorrendo a uma taxa de 1Mbps. Isto equivale a 125.000 bytes por segundo, ou um byte a cada 8µs! Isto significa que a aplicação tem este tempo para detectar a chegada do novo dado e fazer a leitura do mesmo, antes da chegada de um novo! Para permitir um rápido tratamento de eventos como este é que existem as interrupções. Uma interrupção consiste basicamente em um evento externo ao programa que provoca o desvio do mesmo para uma sub-rotina ou função especificada pelo programador. Interrupções são muito similares a chamadas de função em C, de fato, podemos considerar interrupções como chamadas de função executadas pelo hardware, porém, diferentemente de uma função normal, uma função de interrupção não deve ser chamada diretamente pela aplicação. Outro exemplo interessante de aplicação de interrupções é na temporização, vamos supor que em uma aplicação, deseja-se fazer com que um led pisque a 1Hz para indicar uma condição de erro. Na abordagem tradicional de programação, as piscadas do led são controladas através de loops do programa, conforme demonstra o fluxograma da figura 6.1. Nele, os blocos “Aguarda 500ms” consistem em loops programados de forma que a sua execução completa ocorra em 500ms. Este algoritmo deve funcionar perfeitamente e fazer o led piscar como desejado, mas há um problema: a maior parte do tempo útil da CPU é gasto nos dois blocos “Aguarda 500ms”, responsáveis pela temporização do led. De fato, se considerarmos que as operações de ligar e desligar o led são executadas cada uma em 1µs, podemos concluir facilmente que para cada 1 segundo de operação, a CPU passa cerca de 999,998ms (desconsiderando o desvio para o início do loop principal) apenas aguardando a passagem do tempo, sem executar nenhuma tarefa útil.

120 Microcontroladores RL78: Guia Básico

Início

Liga led

Aguarda 500ms

Desliga led

Aguarda 500ms

Figura 6.1 – Fluxograma de um pisca led

Desta forma conclui-se que a utilização de loops de programa para temporização não é uma saída razoável e pode causar grandes impactos na aplicação.

Existem algumas soluções para este problema: uma delas consiste em utilizar um sistema operacional multitarefa (um RTOS - Real Time Operating System), capaz de executar várias tarefas através da divisão do tempo da CPU. Desta forma um algoritmo como o descrito pode ser executado livremente, ao mesmo tempo em que outras tarefas são executadas “simultaneamente”.

É claro que a adoção de um RTOS não é uma tarefa simples, a maioria deles requer uma boa quantidade de memória flash e RAM para operar. Além disso, RTOSs possuem curvas de aprendizado longas e necessitam de investimento para que possam ser efetivamente utilizados.

Outra opção substancialmente mais simples e econômica para se permitir que se aproveite melhor o tempo da CPU é o uso de interrupções.

Interrupções resolvem questões como a do algoritmo mostrado na figura 6.1 ao permitir que o programa principal possa permanecer executando e seja interrompido num determinado instante (a passagem de 500ms).

É claro que interrupções somente possuem utilidade se tiverem periféricos atrelados a elas. Os RL78 possuem diversos periféricos capazes de gerar diferentes interrupções: os timers podem interromper a CPU para sinalizar a passagem de tempo, captura de um pulso, etc., as interfaces de comunicação podem interromper a CPU ao receber ou enviar um dado, o conversor A/D pode interromper a CPU ao terminar de fazer uma conversão, etc.

Ainda com relação ao algoritmo da figura 6.1, através de um timer e do uso de interrupções, seria possível fazer toda a temporização de piscagem do led dentro de uma ISR (rotina de tratamento de interrupção), fazendo com que a CPU permanecesse liberada para outros usos cerca de 99,999% do tempo!

Sistema de Interrupções 121

6.1. Categorias de Interrupções

Podemos classificar as interrupções em duas categorias básicas: mascaráveis e não mascaráveis. Interrupções mascaráveis são aquelas que podem ser desativadas ou ignoradas pela CPU, ao passo que as não mascaráveis não podem ser desativadas e nunca são ignoradas pela CPU.

Também podemos classificar as interrupções em externas e internas: internas são as interrupções geradas pelos periféricos internos do microcontrolador e externas são aquelas geradas por eventos externos e recebidas normalmente através de pinos de interrupção.

Existe também uma categoria especial de interrupção chamada de interrupção por software. Nesta categoria a origem da interrupção não é um periférico ou pino de hardware, mas uma instrução assembly especial.

Interrupções por software são especialmente úteis na implementação de chamadas de sistema em sistemas operacionais.

6.2. Sistema de Interrupções do RL78

Os microcontroladores RL78 possuem um sistema de interrupções bastante poderoso e similar ao existente em modelos de 32 bits existentes no mercado. Ele é composto por um sistema de vetores (a maioria das interrupções possuem vetores individuais para onde o programa é desviado no caso da ocorrência de uma interrupção) e cada fonte de interrupção possui prioridade programável.

É possível selecionar um entre quatro níveis de prioridade (0 a 3) para cada interrupção, sendo que o nível 0 é o de maior prioridade e o nível 3 o de menor prioridade.

O sistema de múltiplas prioridades permite que, caso duas interrupções aconteçam simultaneamente, a de maior prioridade tenha preferência a de menor prioridade. Também é possível que uma interrupção de maior prioridade interrompa uma interrupção de menor prioridade que se encontre em tratamento.

O sistema de interrupções dos RL78 é similar ao dos seus concorrentes: temos um controle global de interrupções (bit IE no registrador PSW), controles individuais de mascaramento de interrupção (bits MK nos registradores MKxL e MKxH) e flags de interrupção (bits IF nos registradores IFxL e IFxH). A figura 6.2 mostra um diagrama funcional simplificado do controle de interrupções dos RL78.

Os flags de interrupção (localizados nos registradores IFxL e IFxH) são setados automaticamente pelos eventos de interrupção dos periféricos, por exemplo, o flag PIF0 (registrador IF0L) é setado numa transição do pino INTP0, já o flag TMIF00 (registrador IF1L) é setado quando ocorre o estouro de contagem ou captura de sinal no canal 0 do timer TAU0.

Cada flag de interrupção de periférico é aplicado a uma porta AND responsável pelo mascaramento da interrupção. O bit de mascaramento (MK) é controlado por um dos

122 Microcontroladores RL78: Guia Básico

registradores MKxL ou MKxH. Assim, nos exemplos acima, o controle de mascaramento da interrupção INTP0 é o PMK0, localizado no registrador MK0L e o controle de mascaramento da interrupção do canal 0 do TAU0 é o TMMK00, localizado no registrador MK1L.

Figura 6.2

Observe que quando o bit de mascaramento está setado (MK=1) a interrupção está mascarada (desabilitada), ao passo que quando o bit está apagado (MK=0) a i interrupção não está mascarada e está habilitada! Este controle é invertido em relação aos controles de habilitação de interrupção disponíveis em microcontroladores de outros fabricantes.

As interrupções periféricas que não se encontrem mascaradas, somente poderão interromper a CPU caso o bit IE = 1 (registrador PSW). Quando IE = 0, a CPU não pode ser interrompida, exceto por uma interrupção por software (instrução BRK, que não pode ser mascarada). Além disso, uma interrupção somente será reconhecida se o nível de prioridade dela for maior ou igual ao nível de prioridade atual (configurado nos bits ISP0 e ISP1 do PSW).

Observe também que, conforme ilustra a figura 6.2, qualquer sinal de interrupção, mesmo quando IE = 0, faz com que o microcontrolador retorne ao modo ativo (run), caso a CPU se encontre em um modo de baixo consumo de energia (halt, stop ou snooze).

Uma vez reconhecida a interrupção, ocorre o salvamento do conteúdo do PSW e do PC na pilha, o bit IE é apagado (desabilitando novas interrupções), a prioridade da interrupção que foi reconhecida é salva nos bits ISP0 e ISP1 (registrador PSW), o programa é desviado para o endereço apontado pelo respectivo vetor e o flag da interrupção é automaticamente apagado.

A rotina de tratamento de interrupção (ISR) deve ser encerrada com uma instrução RETI (para as interrupções mascaráveis) ou RETB (para a interrupção por software BRK).

As tabelas 6.1 e 6.2 a seguir apresentam os vetores de interrupção disponíveis nos RL78/G13. São apresentados os nomes dos vetores, os flags de interrupção (com os respectivos registradores que os abrigam), bits de mascaramento de interrupção (e respectivos registradores), além da descrição da fonte de cada interrupção.

Sistema de Interrupções 123

Número Endereço Nome Flag Máscara Fonte do Vetor RST - - Pino de reset POR - - POR LVD RESF:LVIRF - LVD - 0x00000 WDT RESF:WDTRF - Watchdog TRAP RESF:TRAP - Opcode ilegal IAW RESF:IAWRF IAWCTL:IAWEN Acesso ilegal a memória RPE RESF:RPERF RPECTL:RPERDIS Erro de paridade da RAM - 0x00002 DBG - - On chip debugger (OCD) 0 0x00004 INTWDTI IF0L:WDTIIF MK0L:WDTIMK Watchdog 1 0x00006 INTLVI IF0L:LVIIF MK0L:LVIMK Detecção de baixa tensão 2 0x00008 INTP0 IF0L:PIF0 MK0L:PMK0 Pino INTP0 3 0x0000A INTP1 IF0L:PIF1 MK0L:PMK1 Pino INTP1 4 0x0000C INTP2 IF0L:PIF2 MK0L:PMK2 Pino INTP2 5 0x0000E INTP3 IF0L:PIF3 MK0L:PMK3 Pino INTP3 6 0x00010 INTP4 IF0L:PIF4 MK0L:PMK4 Pino INTP4 7 0x00012 INTP5 IF0L:PIF5 MK0L:PMK5 Pino INTP5 INTST2 IF0H:STIF2 MK0H:STMK2 TX UART2 8 0x00014 INTCSI20 IF0H:CSIIF20 MK0H:CSIMK20 Transferência CSI20 INTIIC20 IF0H:IICIF20 MK0H:IICMK20 Transferência IIC20 INTSR2 IF0H:SRIF2 MK0H:SRMK2 RX UART2 9 0x00016 INTCSI21 IF0H:CSIIF21 MK0H:CSIMK21 Transferência CSI21 INTIIC21 IF0H:IICIF21 MK0H:IICMK21 Transferência IIC21 INTSRE2 IF0H:SREIF2 MK0H:SREMK2 Erro RX UART2 10 0x00018 INTTM11H IF0H:TMIF11H MK0H:TMMK11H Estouro ou captura no canal 1 do TAU1 (8 bits superiores) 11 0x0001A INTDMA0 IF0H:DMAIF0 MK0H:DMAMK0 Fim de transferência no DMA0 12 0x0001C INTDMA1 IF0H:DMAIF1 MK0H:DMAMK1 Fim de transferência no DMA1 INTST0 IF0H:STIF0 MK0H:STMK0 TX UART0 13 0x0001E INTCSI00 IF0H:CSIIF00 MK0H:CSIMK00 Transferência CSI00 INTIIC00 IF0H:IICIF00 MK0H:IICMK00 Transferência IIC00 INTSR0 IF0H:SRIF0 MK0H:SRMK0 RX UART0 14 0x00020 INTCSI01 IF0H:CSIIF01 MK0H:CSIMK01 Transferência CSI01 INTIIC01 IF0H:IICIF01 MK0H:IICMK01 Transferência IIC01 INTSRE0 IF0H:SREIF0 MK0H:SREMK0 Erro RX UART0 15 0x00022 INTTM01H IF0H:TMIF01H MK0H:TMMK01H Estouro ou captura no canal 1 do TAU0 (8 bits superiores) INTST1 IF1L:STIF1 MK1L:STMK1 TX UART1 16 0x00024 INTCSI10 IF1L:CSIIF10 MK1L:CSIMK10 Transferência CSI10 INTIIC10 IF1L:IICIF10 MK1L:IICMK10 Transferência IIC10 INTSR1 IF1L:SRIF1 MK1L:SRMK1 RX UART1 17 0x00026 INTCSI11 IF1L:CSIIF11 MK1L:CSIMK11 Transferência CSI11 INTIIC11 IF1L:IICIF11 MK1L:IICMK11 Transferência IIC11 INTSRE1 IF1L:SREIF1 MK1L:SREMK1 Erro RX UART1 18 0x00028 INTTM03H IF1L:TMIF03H MK1L:TMMK03H Estouro ou captura no canal 3 do TAU0 (8 bits superiores) 19 0x0002A INTIICA0 IF1L:IICAIF0 MK1L:IICAMK0 Fim de comunicação em IICA0 20 0x0002C INTTM00 IF1L:TMIF00 MK1L:TMMK00 Estouro ou captura no canal 0 do TAU0 21 0x0002E INTTM01 IF1L:TMIF01 MK1L:TMMK01 Estouro ou captura no canal 1 do TAU0 22 0x00030 INTTM02 IF1L:TMIF02 MK1L:TMMK02 Estouro ou captura no canal 2 do TAU0 23 0x00032 INTTM03 IF1L:TMIF03 MK1L:TMMK03 Estouro ou captura no canal 3 do TAU0 24 0x00034 INTAD IF1H:ADIF MK1H:ADMK Fim de conversão no ADC 25 0x00036 INTRTC IF1H:RTCIF MK1H:RTCMK Alarme ou período do RTC 26 0x00038 INTIT IF1H:ITIF MK1H:ITMK Estouro do timer de intervalo 27 0x0003A INTKR IF1H:KRIF MK1H:KRMK Mudança de estado nas entradas KR INTST3 IF1H:STIF1 MK1H:STMK1 TX UART3 28 0x0003C INTCSI30 IF1H:CSIIF10 MK1H:CSIMK10 Transferência CSI30 INTIIC30 IF1H:IICIF10 MK1H:IICMK10 Transferência IIC30 INTSR3 IF1H:SRIF3 MK1H:SRMK3 RX UART3 29 0x0003E INTCSI31 IF1H:CSIIF31 MK1H:CSIMK31 Transferência CSI31 INTIIC31 IF1H:IICIF31 MK1H:IICMK31 Transferência IIC31 30 0x00040 INTTM13 IF1H:TMIF13 MK1H:TMMK13 Estouro ou captura no canal 3 do TAU1 31 0x00042 INTTM04 IF1H:TMIF04 MK1H:TMMK04 Estouro ou captura no canal 4 do TAU0 32 0x00044 INTTM05 IF2L:TMIF05 MK2L:TMMK05 Estouro ou captura no canal 5 do TAU0 33 0x00046 INTTM06 IF2L:TMIF06 MK2L:TMMK06 Estouro ou captura no canal 6 do TAU0 34 0x00048 INTTM07 IF2L:TMIF07 MK2L:TMMK07 Estouro ou captura no canal 7 do TAU0 35 0x0004A INTP6 IF2L:PIF6 MK2L:PMK6 Pino INTP6 36 0x0004C INTP7 IF2L:PIF7 MK2L:PMK7 Pino INTP7 37 0x0004E INTP8 IF2L:PIF8 MK2L:PMK8 Pino INTP8 38 0x00050 INTP9 IF2L:PIF9 MK2L:PMK9 Pino INTP9 Tabela 6.1

124 Microcontroladores RL78: Guia Básico

Número Endereço Nome Flag Máscara Fonte do Vetor 39 0x00052 INTP10 IF2L:PIF10 MK2L:PMK10 Pino INTP10 40 0x00054 INTP11 IF2H:PIF11 MK2H:PMK11 Pino INTP11 41 0x00056 INTTM10 IF2H:TMIF10 MK2H:TMMK10 Estouro ou captura no canal 0 do TAU1 42 0x00058 INTTM11 IF2H:TMIF11 MK2H:TMMK11 Estouro ou captura no canal 1 do TAU1 43 0x0005A INTTM12 IF2H:TMIF12 MK2H:TMMK12 Estouro ou captura no canal 2 do TAU1 INTSRE3 IF2H:SREIF3 MK2H:SREMK3 Erro RX UART3 44 0x0005C INTTM13H IF2H:TMIF13H MK2H:TMMK13H Estouro ou captura no canal 3 do TAU1 (8 bits superiores) 45 0x0005E INTMD IF2H:MDIF MK2H:MDMK Fim de divisão ou overflow 46 0x00060 INTIICA1 IF2H:IICAIF1 MK2H:IICAMK1 Fim de comunicação em IICA1 47 0x00062 INTFL IF2H:FLIF MK2H:FLMK Utilizada pela biblioteca FSL 48 0x00064 INTDMA2 IF3L:DMAIF2 MK3L:DMAMK2 Fim de transferência no DMA2 49 0x00066 INTDMA3 IF3L:DMAIF3 MK3L:DMAMK3 Fim de transferência no DMA3 50 0x00068 INTTM14 IF3L:TMIF14 MK3L:TMMK14 Estouro ou captura no canal 4 do TAU1 51 0x0006A INTTM15 IF3L:TMIF15 MK3L:TMMK15 Estouro ou captura no canal 5 do TAU1 52 0x0006C INTTM16 IF3L:TMIF16 MK3L:TMMK16 Estouro ou captura no canal 6 do TAU1 53 0x0006E INTTM17 IF3L:TMIF17 MK3L:TMMK17 Estouro ou captura no canal 7 do TAU1 - 0x0007E BRK - - Instrução BRK Tabela 6.2

Observe que alguns vetores são compartilhados por mais de um periférico. Neste caso, somente um deles deve utilizar a sua função de interrupção! A utilização das interrupções em C é muito simples. A declaração da ISR deve ser feita da seguinte forma:

#pragma vector = NOME_DO_VETOR __interrupt void NOME_DA_FUNCAO(void) { // o código da ISR vai aqui }

Observe que o #pragma vector antes da declaração da ISR instrui o compilador sobre qual o vetor de interrupção deve ser associado à função. Em NOME_DO_VETOR o programador deverá colocar o nome (conforme a coluna “nome” nas tabelas 6.1 e 6.2) seguido do sufixo _vect. Desta forma temos INTWDTI_vect para a interrupção do watchdog, INTP0_vect para a interrupção externa do pino INTP0, INTTM00_vect para a interrupção do canal 0 do TAU0 e assim por diante. Os bits de mascaramento de interrupção podem ser configurados diretamente através dos seus nomes conforme mostrado nas tabelas 6.1 e 6.2. Assim, para habilitar a interrupção do canal 0 do TAU0 podemos escrever: TMMK00 = 0; // habilita a interrupção do canal 0 do TAU0 E para desabilitar (mascarar) a mesma interrupção podemos escrever: TMMK00 = 1; // desabilita a interrupção do canal 0 do TAU0 A habilitação global das interrupções (bit IE no registrador PSW) pode ser controlada através de duas funções intrínsecas definidas no arquivo intrinsics.h: __enable_interrupt(); // habilita interrupções (IE=1) __disable_interrupt(); // desabilita interrupções (IE=0)

Sistema de Interrupções 125

6.2.1. Sistema de Prioridades de Interrupção Como já vimos, os RL78 possuem um sistema com quatro diferentes prioridades de interrupção. O nível de prioridade de cada fonte de interrupção é selecionado através de dois bits localizados cada um num dos registradores PR0xx e PR1xx, conforme as tabelas a seguir. Lembre-se de que, após um reset, todos os bits destes registradores são setados, fazendo com que todas as interrupções possuam prioridade 3 (a mais baixa).

Bit PR10L PR00L Prioridade de interrupção do 0 WDTIPR1 WDTIPR0 Watchdog 1 LVIPR1 LVIPR0 LVD 2 PPR10 PPR00 INTP0 3 PPR11 PPR01 INTP1 4 PPR12 PPR02 INTP2 5 PPR13 PPR03 INTP3 6 PPR14 PPR04 INTP4 7 PPR15 PPR05 INTP5 Bit PR10H PR00H Prioridade de interrupção do STPR12 STPR02 TX UART2 0 CSIPR120 CSIPR020 CSI20 IICPR120 IICPR020 IIC20 SRPR12 SRPR02 RX UART2 1 CSIPR121 CSIPR021 CSI21 IICPR121 IICPR021 IIC21 SREPR12 SREPR02 Erro RX USART2 2 TMPR111H TMPR011H TAU1 canal 1 (8 bits MSB) 3 DMAPR10 DMAPR00 DMA0 4 DMAPR11 DMAPR01 DMA1 STPR10 STPR00 TX UART0 5 CSIPR100 CSIPR000 CSI00 IICPR100 IICPR000 IIC00 SRPR10 SRPR00 RX UART0 6 CSIPR101 CSIPR001 CSI01 IICPR101 IICPR001 IIC01 SREPR10 SREPR00 Erro RX USART0 7 TMPR101H TMPR001H TAU0 canal 1 (8 bits MSB) Bit PR11L PR01L Prioridade de interrupção do STPR11 STPR01 TX UART1 0 CSIPR110 CSIPR010 CSI10 IICPR110 IICPR010 IIC10 SRPR11 SRPR01 RX UART1 1 CSIPR111 CSIPR011 CSI11 IICPR111 IICPR011 IIC11 SREPR11 SREPR01 Erro RX USART1 2 TMPR103H TMPR003H TAU0 canal 3 (8 bits MSB) 3 IICAPR10 IICAPR00 IICA0 4 TMPR100 TMPR000 TAU0 canal 0 5 TMPR101 TMPR001 TAU0 canal 1 6 TMPR102 TMPR002 TAU0 canal 2 7 TMPR103 TMPR003 TAU0 canal 3 Tabela 6.3

126 Microcontroladores RL78: Guia Básico

Bit PR11H PR01H Prioridade de interrupção do 0 ADPR1 ADPR0 ADC 1 RTCPR1 RTCPR0 RTC 2 ITPR1 ITPR0 Timer de intervalo 3 KRPR1 KRPR0 Interrupção de teclado STPR13 STPR03 TX UART3 4 CSIPR130 CSIPR030 CSI30 IICPR130 IICPR030 IIC30 SRPR13 SRPR03 RX UART3 5 CSIPR131 CSIPR031 CSI31 IICPR131 IICPR031 IIC31 6 TMPR113 TMPR013 TAU1 canal 3 7 TMPR104 TMPR004 TAU0 canal 4 Bit PR12L PR02L Prioridade de interrupção do 0 TMPR105 TMPR005 TAU0 canal 5 1 TMPR106 TMPR006 TAU0 canal 6 2 TMPR107 TMPR007 TAU0 canal 7 3 PPR16 PPR06 INTP6 4 PPR17 PPR07 INTP7 5 PPR18 PPR08 INTP8 6 PPR19 PPR09 INTP9 7 PPR110 PPR010 INTP10 Bit PR12H PR02H Prioridade de interrupção do 0 PPR111 PPR011 INTP11 1 TMPR110 TMPR010 TAU1 canal 0 2 TMPR111 TMPR011 TAU1 canal 1 3 TMPR112 TMPR012 TAU1 canal 2 SREPR13 SREPR03 Erro RX USART3 4 TMPR113H TMPR013H TAU1 canal 3 (8 bits MSB) 5 MDPR1 MDPR0 Multiplicador/divisor 6 IICAPR11 IICAPR01 IICA 7 FLPR1 FLPR0 Biblioteca FSL Tabela 6.4

Vejamos como configurar a prioridade de interrupção do LVD para nível 1: LVIPR1 = 0; LVIPR0 = 1; Configurar interrupção do canal 2 do TAU1 para prioridade 0: TMPR112 = 0; TMPR012 = 0;

Atenção: caso ocorram duas ou mais interrupções de mesma prioridade e ao mesmo tempo, a primeira a ser tratada é aquela com o menor número de vetor (primeira coluna das tabelas i 6.1 e 6.2)! As demais interrupções pendentes serão tratadas cada uma após o término do tratamento da anterior.

A utilização de diferentes prioridades para as ISRs torna-se mais eficiente quando uma interrupção de maior prioridade pode interromper uma (ou mais) de menor prioridade. Para que isso seja possível nos RL78, basta habilitar as interrupções globais logo no início da(s) ISR(s) de baixa prioridade:

Sistema de Interrupções 127

#pragma vector = XXXX_vect __interrupt void trata_int_baixa_prioridade(void) { __enable_interrupt(); // esta ISR pode ser interrompida! // código da ISR }

#pragma vector = XXXX_vect __interrupt void trata_int_alta_prioridade(void) { // código da ISR }

Lembre-se que uma interrupção com prioridade 3 pode ser interrompida por outras de prioridade 0, 1, 2 ou 3, uma interrupção de prioridade 2 pode ser interrompida por outras de prioridade 0, 1 ou 2 e assim por diante. As interrupções de mais alta prioridade (0) somente podem ser interrompidas por outras interrupção de alta prioridade!

6.2.2. Latência de Interrupção

Todo microcontrolador ou microprocessador necessita de um certo tempo entre a ocorrência do evento de interrupção e o efetivo processamento da primeira instrução útil da ISR. Este intervalo de tempo é chamado de latência de interrupção. A latência de interrupção decorre de vários fatores: 1. O circuito de controle de interrupção precisa reconhecer a interrupção (verificar se a mesma está habilitada, decodificar seu vetor, etc.); 2. A CPU precisa completar a instrução em execução (salvo algumas máquinas e instruções especiais que podem ser interrompidas e retomadas posteriormente); 3. Deve ocorrer o salvamento básico de contexto (normalmente o contador e programa e registrador de status, PC e PSW no caso do RL78); Nos RL78, a latência base de interrupção varia de 9 ciclos de clock (mínimo) a 14 ciclos de clock (máximo), conforme a instrução em execução e a instrução seguinte a mesma (algumas instruções bloqueiam temporariamente as interrupções). A esta latência base, devemos considerar também o tempo necessário ao salvamento de contexto no caso (salvamento dos registradores de propósito geral da CPU), que pode acrescer de 1 a 4 ciclos de clock aos tempos supracitados.

Quanto menor a latência, mais rápida a resposta do microcontrolador aos eventos O de interrupção!

128 Microcontroladores RL78: Guia Básico

6.2.3. Utilizando os Bancos de Registradores dos RL78

Como já vimos no capítulo 3, a CPU RL78 possui quatro bancos de registradores de propósito geral, estes registradores são utilizados pelas operações cotidianas da aplicação e por isso, são sempre salvos automaticamente pelo compilador no início da ISR (salvamento de contexto) e restaurados antes do retorno da mesma (restauração de contexto). Vejamos um exemplo: suponha a ISR a seguir.

#pragma vector = INTTM00_vect __interrupt void trata_tau00(void) { teste *=3; } Ela gera o seguinte código assembly: PUSH AX PUSH BC MOVW AX, N:teste MOVW BC, #0x3 CALL N:?I_MUL_L02 MOVW N:teste, AX POP BC POP AX RETI Como o código da ISR altera os registradores AX e BC, o conteúdo prévio dos mesmos é salvo na pilha pelas duas primeiras instruções PUSH e restaurado pelas instruções POP antes de retornar da interrupção (RETI). Estas quatro instruções são executadas cada uma em apenas um ciclo de clock, mas adicionam à latência de interrupção um atraso que pode ser significativo (no caso dos dois PUSH) e aumentam o tempo de execução da ISR. Utilizando-se um banco alternativo de registradores, podemos fazer com que o compilador remova estas instruções, reduzindo a latência de interrupção e reduzindo o tempo de execução da ISR, o que se traduz em aumento da performance da aplicação. Para utilizar outro banco de registradores na ISR, basta utilizar a diretiva #pragma bank antes da declaração da mesma: #pragma bank=1 #pragma vector = XXXXXX_vect __interrupt void trata_int(void) { teste *=3; } Vejamos o código assembly gerado: SEL RB1 MOVW AX, N:teste MOVW BC, #0x3 CALL N:?I_MUL_L02 MOVW N:teste, AX RETI

Sistema de Interrupções 129

É fácil perceber que as quatro instruções de salvamento e restauração dos GPRs foram substituídas por apenas uma instrução de seleção de banco (SEL RB1), que é executada em apenas um ciclo de clock. Isto significa redução de código e aumento de performance! Veja que o banco 1 é selecionado por SEL RB1 no início da ISR, mas como o programa retorna ao banco 0 (ou o banco em que se encontrava) após a ISR? Simples: a instrução RETI restaura o PSW da pilha (ele foi salvo automaticamente pela interrupção). O banco de registradores utilizado antes da ISR está especificado nos bits RBS1 e RBS0 do PSW, fazendo com que o banco de registradores utilizado no momento da interrupção seja restaurado juntamente com o PSW!

Também é possível utilizar outros bancos (como o 2 e 3) para outras ISRs. Isto é especialmente útil quando temos ISRs de prioridades diferentes e encadeadas, onde uma ISR de alta prioridade pode interromper uma de baixa prioridade: #pragma bank=1 #pragma vector = XXXX_vect __interrupt void trata_int_baixa_prioridade(void) { __enable_interrupt(); // esta ISR pode ser interrompida! // código da ISR } #pragma bank=2 #pragma vector = XXXX_vect __interrupt void trata_int_alta_prioridade(void) { // código da ISR }

6.3. Interrupções Externas

Os microcontroladores RL78 podem incluir até doze pinos de interrupção externa, batizados de INTP0 a INTP11. Cada pino pode ser configurado para gerar uma interrupção ao detectar uma borda de subida, de descida ou ambas as bordas. Além disso, cada pino possui um vetor de interrupção individual, permitindo o rápido processamento deste tipo de interrupção. Pino Interrupção Externa P137 INTP0 P50 INTP1 P51 INTP2 P30 INTP3 P31 INTP4 P16/(P12*) INTP5 P140 INTP6 P141 INTP7 P74 INTP8 P75 INTP9 P76/(P52*) INTP10 P77/(P53*) INTP11 * Pinos alternativos (via redirecionamento de função) Tabela 6.5

130 Microcontroladores RL78: Guia Básico

A configuração dos pinos de interrupção externa é muito simples: cada pino possui dois bits de controle, EGPx e EGNx, o bit EGPx, quando setado, ativa a sensibilidade positiva (borda de subida ou transição de “0” para “1”), enquanto que o bit EGNx, quando setado, ativa a sensibilidade negativa (borda de descida ou transição de “1” para “0”). Quando os dois bits estão apagados, a função de interrupção externa está desativada e quando os dois estão setados, ocorre interrupção em quaisquer das bordas.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura EGP0 EGP7 EGP6 EGP5 EGP4 EGP3 EGP2 EGP1 EGP0 Escrita Leitura EGN0 EGN7 EGN6 EGN5 EGN4 EGN3 EGN2 EGN1 EGN0 Escrita Reset 0 0 0 0 0 0 0 0 Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura EGP1 0 0 0 0 EGP11 EGP10 EGP9 EGP8 Escrita Leitura EGN1 0 0 0 0 EGN11 EGN10 EGN9 EGN8 Escrita Reset 0 0 0 0 0 0 0 0

EGPx EGNx Modo de interrupção 0 0 Desabilitada 0 1 Borda de descida 1 0 Borda de subida 1 1 Ambas as bordas Tabela 6.6

Para configurar a interrupção de borda de subida no pino INTP2, podemos escrever: EGP0 = 0x04; // seleciona a borda de subida no INTP2 PIF2 = 0; // apaga o flag de interrupção do INTP2 PMK2 = 0; // habilita a interrupção externa INTP2 Ou EGP0 = BIT2; // seleciona a borda de subida no INTP2 PIF2 = 0; // apaga o flag de interrupção do INTP2 PMK2 = 0; // habilita a interrupção externa INTP2

Lembre-se de que após configurar a borda de sensibilidade do pino, é importante O apagar o flag da interrupção, que pode ter sido setado pela alteração da configuração do pino. Isto deve ser feito antes de se habilitar a interrupção externa!

Outro detalhe interessante acerca dos RL78: os pinos de interrupção externa podem operar neste modo inclusive quando estão configurados como saídas! Neste caso, uma interrupção externa poderá ser gerada quando um periférico ou o software alterar o estado daquele pino.

Para que uma transição seja detectada corretamente, é necessário que, após a mesma, o i sinal no pino permaneça estável por um período mínimo de 1µs!

Sistema de Interrupções 131

6.3.1. Exemplo O exemplo a seguir demonstra como utilizar as interrupções externas INTP1 e INTP2. O estado do led 3 da placa RSK é controlado por meio de duas teclas: a tecla SW1 (conectada ao pino P5.0/INTP1) acende o led e a tecla SW2 (conectada ao pino P5.1/INTP2) apaga o mesmo. Os resistores internos de pull-up não foram utilizados porque a placa provê resistores externos para esta função (vide figura 5.1).

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P6_bit.no3

#pragma vector = INTP1_vect __interrupt void trata_INTP1(void) { LED = 0; // acende led }

#pragma vector = INTP2_vect __interrupt void trata_INTP2(void) { LED = 1; // apaga led } void main(void) { PM6_bit.no3 = 0; // configura LED como saída EGN0 = BIT2 | BIT1; // INTP1 e INTP2 na borda de descida PIF1 = 0; // apaga flag da INTP1 PIF2 = 0; // apaga flag da INTP2 PMK1 = 0; // habilita INTP1 PMK2 = 0; // habilita INTP2 LED = 1; // led desligado __enable_interrupt(); // habilita interrupções globais while (1); }

Exemplo 6.1

132 Microcontroladores RL78: Guia Básico

6.4. Interrupção de Teclado

O módulo de interrupção de teclado (KR) é utilizado para gerar uma interrupção (KRIF) quando qualquer uma das suas oito entradas muda de estado (borda de descida, ou seja, mudança de nível lógico alto para nível lógico baixo). Esta facilidade é especialmente útil para se detectar o pressionamento de teclas e provocar a saída de um modo de baixo consumo. A operação do módulo KR é muito simples: cada bit do registrador KRM controla uma das entradas de interrupção. Quando o bit KRMx está apagado, o respectivo pino de E/S não gera interrupção KRIF, quando o bit KRMx está setado, então uma borda de descida no respectivo pino de E/S irá setar o flag KBIF. A tabela a seguir mostra os pinos associados ao módulo de interrupção de teclado. Pino Entrada P70 KR0 P71 KR1 P72 KR2 P73 KR3 P74 KR4 P75 KR5 P76 KR6 P77 KR7 Tabela 6.7

A seguir temos o diagrama do registrador KRM, utilizado para controlar a operação das entradas de interrupção do módulo.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura KRM7 KRM6 KRM5 KRM4 KRM3 KRM2 KRM1 KRM0 KRM Escrita Reset 0 0 0 0 0 0 0 0

É necessário que o sinal de entrada permaneça estável (em nível lógico “0”) por um período i mínimo de 250ns (para tensões de alimentação superiores a 1,8V) ou 1µs (para tensões menores que 1,8V)!

6.4.1. Exemplo O próximo exemplo mostra a implementação do exemplo 6.1 mas utilizando a interrupção de teclado ao invés das interrupções externas. O exemplo foi escrito para a placa RPB do RL78/G13 e necessita que duas teclas sejam conectadas aos pinos P7.0 e P7.1 (de cada pino para o GND). Os pull-ups internos são ativados, de forma que apenas é necessário conectar teclas a placa RPB.

Sistema de Interrupções 133

Observe que em razão de existir apenas um vetor de interrupção, é necessário testar, dentro da ISR, qual pino está em nível lógico baixo, de forma a determinar qual tecla foi pressionada. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P7_bit.no7 #define PIN_P70 P7_bit.no0 #define PIN_P71 P7_bit.no1

#pragma vector = INTKR_vect __interrupt void trata_intkr(void) { if (!PIN_P70) LED = 0; // acende led if (!PIN_P71) LED = 1; // apaga led }

void main(void) { PM7_bit.no7 = 0; // configura LED como saída PU7 = BIT1 | BIT0; // ativa pull-ups dos pinos P7.0 e P7.1 KRM = BIT1 | BIT0; // ativa entradas KR1 e KR0 no modo de interrupção KRIF = 0; // apaga flag da interrupção de teclado KRMK = 0; // habilita interrupção de teclado LED = 1; // led desligado __enable_interrupt(); // habilita interrupções globais while (1); } Exemplo 6.2

134 Microcontroladores RL78: Guia Básico

7

Periféricos de Temporização 7. Periféricos de Temporização

Neste capítulo estudaremos os periféricos de temporização encontrados nos RL78/G13. Os temporizadores ou timers formam a espinha dorsal de qualquer microcontrolador e podem ser utilizados para diversas tarefas tais como: geração de bases de tempo, medição de sinais, geração de sinais, etc. Os RL78/G13 incluem três diferentes modelos de timers: o timer de intervalo, o relógio de tempo real com calendário (RTC) e a TAU. O timer de intervalo destina-se a temporizações simples e pode ser utilizado para gerar base de tempo para uma aplicação (por exemplo, uma interrupção a cada 1ms), ele também pode ser utilizado para fazer com que o chip saia periodicamente de um modo de baixo consumo de energia. O RTC (Real Time Clock ou relógio de tempo real) é um timer mais elaborado que pode ser utilizado para fornecer bases de tempo precisas em aplicações como relógios e semelhantes. Ele inclui funcionalidades como alarme e calendário, permitindo que se implemente aplicações de controle de tempo muito eficientes. O último e mais completo timer dos RL78/G13 é a TAU (Timer Array Unit – Unidade conjunta de timers). Uma unidade TAU consiste num conjunto de 4 a 8 timers de 16 bits que podem operar de forma independente ou associados para operações complexas (como geração de sinais, inclusive PWM). Até 2 TAU de 8 canais podem estar presentes num mesmo chip (ou seja, até 16 timers de 16 bits). Estes três timers são controlados primariamente pelo registrador PER0 (já visto quando falamos do gerenciamento de clock), por isso, antes de utilizá-los é necessário habilitá-los através dos respectivos bits do registrador. Além dos timers mencionados acima, os microcontroladores da linha G14 incluem também outros timers que serão discutidos rapidamente no final deste capítulo.

Periféricos de Temporização 135

Nome Bits 7 6 5 4 3 2 1 0 Leitura RTCEN IICA1EN ADCEN IICA0EN SAU1EN SAU0EN TAU1EN TAU0EN PER0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Bit C Símbolo C Controle do clock do RTC e do timer de intervalo: RTCEN RTCEN bRTCEN 0 – Clock desativado 1 – Clock ativado Controle de clock e operação da unidade de timer TAU1: TAU1EN TAU1EN bTAU1EN 0 – TAU1 desativada 1 – TAU1 ativada Controle de clock e operação da unidade de timer TAU0: TAU0EN TAU0EN bTAU0EN 0 – TAU0 desativada 1 – TAU0 ativada

7.1. Timer de Intervalo (IT)

Este é o temporizador mais simples e básico dos RL78. Ele consiste num contador de 12 bits que pode receber clock do sistema secundário de clock, ou seja, do oscilador LOCO (fIL =15kHz) ou do oscilador secundário XT1 (fSUB =32,768kHz).

Figura 7.1

A sua operação é muito simples: o contador de 12 bits é incrementado a cada ciclo do clock secundário (f SUB ou f IL ). Quando o contador atinge o valor programado nos bits 0 a 11 do registrador ITMC, a contagem volta a zero e o flag INTIT é setado. O timer de intervalo (IT) possui também um bit de habilitação (RINTE) que deve ser setado para que o contador do timer possa efetivamente contar e gerar interrupção, quando RINTE está apagado a contagem do timer é mantida em zero.

A frequência de interrupção do timer de intervalo (f INTIT ) pode ser calculada através da seguinte fórmula: CLK f = INTIT ITMC _ VAL +1 Onde CLK é a frequência da fonte de clock do timer (15kHz quando utilizado o LOCO ou 32,768kHz quando utilizado o oscilador XT1) e ITMC_VAL corresponde aos 12 bits menos

136 Microcontroladores RL78: Guia Básico

significativos carregados no registrador ITMC. A seleção do clock é feita através do bit WUTMMCK0 localizado no registrador OSMC: WUTMMCK0 Fonte de Clock do RTC/IT 0 Oscilador XT1 1 Oscilador LOCO (15kHz) Tabela 7.1

A seguir mostramos a organização do registrador ITMC que configura o IT:

Nome Bits 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura RINTE 0 0 0 ITMC_VAL ITMC Escrita Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Lembre-se que ITMC_VAL pode assumir valores entre 0 e 4095, o que significa que a menor frequência de interrupção do timer de intervalo é igual a 3,66Hz (quando operando com o LOCO em 15kHz) ou 8Hz (quando operando com o XT1 em 32,768kHz). Caso a máscara de interrupção do timer (ITMK) esteja em zero e as interrupções estejam globalmente habilitadas (IE=1), a cada estouro do timer o flag ITIF será setado e o programa será desviado para o vetor INTIT.

Lembre-se de que antes de utilizar o timer de intervalo é necessário setar o bit RTCEN no i registrador PER0! A escrita no registrador do ITMC é ignorada quando RTCEN = 0!

Note que o timer de intervalo pode operar normalmente nos modos halt, stop e snooze (desde que a sua fonte de clock permaneça ativa), permitindo que a CPU seja mantida parada e sendo periodicamente “acordada” pelo timer. Esta técnica é útil quando se necessita que a aplicação apresente um consumo muito baixo de energia, um exemplo típico é o de sensores inteligentes, onde o microcontrolador periodicamente verifica uma entrada, realiza algum processamento e então retorna para um modo de baixo consumo, aguardando uma nova amostragem.

7.1.1. Exemplo O exemplo a seguir demonstra a utilização do timer de intervalo (IT). Ele faz com que o led D2 da placa de promoção do RL78 (YRPBRL78G13) pisque numa frequência de 5Hz. Este exemplo utiliza o oscilador interno de 15kHz (LOCO) como fonte de clock do timer, mas também é possível utilizar o oscilador XT1 para se obter mais precisão. A vantagem de se utilizar o LOCO é a redução de custo e de consumo de energia (já que o XT1 necessita de cristal externo e consome mais energia que o LOCO).

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

Periféricos de Temporização 137

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;

/* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P7_bit.no7

#pragma vector = INTIT_vect __interrupt void trata_IT(void) { LED = !LED; // inverte o estado do led }

void main(void) { PM7_bit.no7 = 0; // P7.7 como saída LED = 1; // led desligado CMC = 0; // desativa osciladores X1 e XT1 // configura o LOCO (15kHz) como fonte de clock do IT/RTC OSMC = bWUTMMCK0; // habilita o RTC e o IT RTCEN = 1; // Configura o IT para uma interrupção a cada 3000 contagens, ou seja: // 3000/15000 = 200ms -> uma interrupção a cada 200ms ITMC = bRINTE | 2999; // habilita a interrupção do IT ITMK = 0; __enable_interrupt(); // habilita as interrupções do RL78 while (1); }

Exemplo 7.1

7.2. RTC

O RTC (Real Time Clock – Relógio de tempo real) é um timer dedicado principalmente a implementação de relógios e bases de tempo de precisão. Ele inclui contadores de horas, minutos e segundos, além de calendário com marcação de dia, dia da semana, mês e ano e também alarme programável (dia da semana, hora e minuto).

138 Microcontroladores RL78: Guia Básico

Figura 7.2

O núcleo do RTC é conjunto de contadores BCD (decimal codificado em binário) responsáveis por contar as unidades de tempo. O contador de mais baixa ordem (segundos) é impulsionado por um sinal de 1Hz derivado de um contador de 16 bits que divide o sinal f RTC (que por sua vez pode ser derivado do oscilador LOCO ou do oscilador XT1) por um fator normalmente igual a 32768 (ele pode sofrer pequenos ajustes como veremos adiante). O RTC pode gerar dois tipos de interrupção: uma periódica e outra de alarme. A periódica pode ser disparada a cada 0,5 ou 1 segundo, ou ainda a cada minuto, hora, dia ou mês. A interrupção de alarme é disparada quando o valor de alarme (dia de semana, hora e minuto) coincide com o horário corrente do RTC. É possível também fazer com que o sinal de clock de 1Hz do RTC seja disponibilizado através de um pino do chip (P30, que deve ser configurado como saída digital e apenas nos modelos com 40 pinos ou mais) para medição ou utilização por outros circuitos externos ao microcontrolador. Há também uma interessante funcionalidade que é a de ajuste de precisão do timer. Através do registrador SUBCUD é possível ajustar o fator de divisão (32768) do contador de 16 bits do RTC, permitindo ajustar o clock em algumas partes por milhão (PPM), de forma a compensar erros e imprecisões do oscilador XT1. Vale lembrar que o RTC pode operar normalmente nos modos halt, stop e snooze, permitindo que a aplicação mantenha um preciso controle de horário e calendário e sem a necessidade de retornar ao modo run para tarefas de manutenção de relógio (como acontece em microcontroladores sem RTCs ou mesmo com RTCs mais simples).

Periféricos de Temporização 139

7.2.1. Configuração do RTC Vejamos então como configurar e utilizar o RTC em uma aplicação: o primeiro passo é setar o bit RTCEN no registrador PER0!

Lembre-se de que antes de utilizar o RTC é necessário setar o bit RTCEN no registrador i PER0! A escrita nos registradores do RTC é ignorada quando RTCEN = 0!

Também é importante selecionar o oscilador XT1 como fonte de clock para o RTC (e timer de intervalo). Isto é feito apagando-se o bit WUTMMCK0 no registrador OSMC. Caso este bit seja mantido setado, a fonte de clock do RTC e do timer de intervalo será o oscilador interno de baixa frequência (LOCO) e, segundo o fabricante, apenas a função de interrupção periódica pode ser utilizada neste caso, os contadores de tempo e alarme ficam desabilitados. Devemos então configurar o RTC através dos registradores RTCC0 e RTCC1. No registrador RTCC0 encontramos o bit de habilitação do RTC (RTCE) que deve ser setado para que o timer possa operar. Há também um bit (AMPM) para seleção de modo de horário (12 ou 24 horas), outro para ativação da saída de clock de 1Hz (RCLOE1) e mais três bits (CT2, CT1 e CT0) para configuração da interrupção periódica do RTC. No registrador RTCC1 encontramos os controles do alarme e de leitura ou escrita nos contadores do relógio. O bit WALE controla a ativação ou desativação do alarme, WALIE controla a interrupção do alarme e WAFG sinaliza que o alarme disparou. Temos também o bit RIFG que sinaliza a ocorrência de uma interrupção periódica do RTC. O bit RWAIT deve ser utilizado sempre que é necessário escrever ou ler qualquer um dos registradores do relógio (SEC para segundos, MIN para minutos, HOUR para horas, DAY para dia, WEEK para dia da semana, MONTH para mês e YEAR para ano). Quando RWAIT é setado, um mecanismo de bloqueio impede que ocorra a propagação do sinal de relógio para os contadores de tempo. Este bloqueio necessita de no máximo um ciclo de clock do RTC (cerca de 30,5µs) para ser completado e a sua efetivação é indicada pelo bit RWST. Esta facilidade de bloqueio permite que a aplicação faça a leitura ou escrita dos registradores sem correr o risco de que ocorra um incremento durante a operação (o que poderia resultar em erros na leitura). Sendo assim, uma vez setado o bit RWAIT a aplicação deve aguardar que RWST seja setado também antes de poder ler ou escrever nos registradores de tempo do relógio. Um detalhe importante é que a aplicação deve realizar a leitura ou escrita nos registradores do relógio em no máximo um segundo, devendo em seguida apagar RWAIT de forma que o clock do sistema seja restaurado. Deixar RWAIT setado por mais de um segundo pode provocar atrasos indesejados no relógio!

Jamais efetue o ciclo de espera pelo bit RWST dentro de uma ISR, pois isso causará a perda i de outras interrupções que poderiam ocorrer neste intervalo!

O horário de alarme pode ser programado nos registradores ALARMWM (minuto), ALARMWH (hora) e ALARMWW (dia da semana). Para programar o alarme é importante seguir os procedimentos indicados pelo fabricante, que são: 1. Desativar o alarme (WALE=0);

140 Microcontroladores RL78: Guia Básico

2. Habilitar a interrupção de alarme (WALIE=1); 3. Alterar os registradores de alarme (ALARMWM, ALARMWH e ALARMWW); 4. Habilitar o alarme (WALE=1).

A interrupção periódica do RTC e a interrupção de alarme compartilham o mesmo vetor de interrupção e setam o mesmo flag (RTCIF). A ISR do RTC (INTRTC) deve verificar a origem i da interrupção no registrador RTCC1 (flag WAFG para o alarme e RIFG para a interrupção periódica).

7.2.2. Registradores do RTC

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura RTCE 0 RCLOE1 0 AMPM CT2 CT1 CT0 RTCC0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Bit C Símbolo C Controle de operação do RTC: RTCE 0 – contadores parados RTCE bRTCE 1 – contadores operando Controle da saída de 1Hz: RCLOE1 0 – saída desabilitada RCLOE1 bRCLOE1 1 – saída habilitada Seleção do modo 12 ou 24 horas: AMPM 0 – modo 12 horas - bAMPM 1 – modo 24 horas Seleção da interrupção periódica do RTC: 000 – desativada - INT_RTC_OFF 001 – intervalos de 0,5 segundos - INT_RTC_05S CT2 010 – intervalos de 1 segundo - INT_RTC_1S CT1 CT0 011 – intervalos de 1 minuto (quando SEC=0) INT_RTC_1MIN 100 – intervalos de 1 hora (quando SEC=MIN=0) - INT_RTC_1H 101 – intervalos de 1 dia (quando SEC=MIN= HOUR=0) - INT_RTC_1D 11x – intervalos e 1 mês (todo dia 1 as 00:00:00) - INT_RTC_1M Atenção: é recomendado reescrever o bit AMPM após cada bloqueio de clock do RTC (via bit RWAIT no registrador RTCC1). Após o mascaramento da interrupção do RTC (RTCMK=1) o fabricante recomenda reescrever o conteúdo dos bits CT2 a CT0 e apagar os flags RIFG e RTCIF.

Periféricos de Temporização 141

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura WAFG RIFG RWST WALE WALIE 0 0 RWAIT RTCC1 Escrita 0 0 - Reset 0 0 0 0 0 0 0 0 * RWST é um bit somente de leitura e não pode ser modificado pelo programa, WAFG e RIFG podem ser lidos e apagados ao se escrever “0” neles. A escrita de “1” não provoca nenhum efeito e não altera o seu estado. Nome do Bit Descrição Bit C Símbolo C Controle de habilitação do alarme: WALE 0 – alarme desabilitado WALE bWALE 1 – alarme habilitado Habilitação da interrupção de alarme do RTC: WALIE 0 – interrupção desabilitada WALIE bWALIE 1 – interrupção habilitada Sinalizador de interrupção do alarme do RTC: WAFG 0 – nenhuma interrupção pendente WAFG bWAFG 1 – interrupção pendente Sinalizador de interrupção periódica do RTC: RIFG 0 – nenhuma interrupção pendente RFIG bRIFG 1 – interrupção pendente Indicador de bloqueio de clock do RTC: RWST 0 – RTC operando sem bloqueio de clock RWST bRWST 1 – clock bloqueado, RTC pode ser lido ou escrito Controle de bloqueio do clock do RTC: RWAIT 0 – RTC opera normalmente RWAIT bRWAIT 1 – solicita bloqueio do clock

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 SEC40 SEC20 SEC10 SEC8 SEC4 SEC2 SEC1 SEC Escrita Reset 0 0 0 0 0 0 0 0 Este registrador contém o valor do contador de segundos do RTC. Ele opera com valores BCD, desta forma, o seu valor máximo é igual a 0x59. Repare que 10 segundos são representados como 0x10 e não como 0x0A.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 MIN40 MIN20 MIN10 MIN8 MIN4 MIN2 MIN1 MIN Escrita Reset 0 0 0 0 0 0 0 0 Este registrador contém o valor do contador de minutos do RTC. Ele opera com valores BCD, desta forma, o seu valor máximo é igual a 0x59. Repare que 20 minutos são representados como 0x20 e não como 0x14.

142 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura HOUR20/ 0 0 HOUR10 HOUR8 HOUR4 HOUR2 HOUR1 HOUR Escrita AMPM Reset 0 0 0 0 0 0 0 0 Este registrador contém o valor do contador de horas do RTC. Ele opera com valores BCD, desta forma, o seu valor máximo (no modo 24 horas) é igual a 0x23. Quando o RTC opera em modo 12 horas o bit 5 passa a operar na função AMPM: em 0 para AM (antes do meio dia) e 1 para PM (depois do meio dia). Quando operando no modo 12 horas o valor máximo de horário é igual a 0x12 (bit 4 a bit 0). Desta forma, 10 horas da manhã será representado como 0x10 nos dois modos e 10 horas da noite será representado como 0x22 no modo 24 horas e 0x30 no modo 12 horas. Um exemplo de como ler este registrador no formato 12 horas: hora = HOUR & 0x1F; if (HOUR && BIT5) LED_AMPM=1; else LED_AMPM=0; Para escrever o horário no registrador: HOUR = hora; if (bit_AMPM) HOUR |= BIT5;

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 DAY20 DAY10 DAY8 DAY4 DAY2 DAY1 DAY Escrita Reset 0 0 0 0 0 0 0 1 Este registrador contém o valor do contador de dias do RTC. Ele opera com valores BCD, desta forma, o seu valor máximo é igual a 0x31. Após um reset ele é carregado com o valor 0x01, já que não existe dia 0!

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 WEEK4 WEEK2 WEEK1 WEEK Escrita Reset 0 0 0 0 0 0 0 0 Este registrador contém o valor do contador de dia semana do RTC. Os valores representam os dias conforme a tabela a seguir. WEEK Dia da semana 0 Domingo 1 Segunda-feira 2 Terça-feira 3 Quarta-feira 4 Quinta-feira 5 Sexta-feira 6 Sábado Tabela 7.2

Periféricos de Temporização 143

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 MONTH10 MONTH8 MONTH4 MONTH2 MONTH1 MONTH Escrita Reset 0 0 0 0 0 0 0 1 Este registrador contém o valor do contador de meses do RTC. Os valores representam os meses de 1 a 12 em BCD (outubro é representado 0x10, novembro 0x11 e dezembro 0x12).

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura YEAR80 YEAR40 YEAR20 YEAR10 YEAR8 YEAR4 YEAR2 YEAR1 YEAR Escrita Reset 0 0 0 0 0 0 0 0 Este registrador contém o valor do contador de anos do RTC. Os valores são armazenados em BCD, de 0x00 a 0x99. Para efeitos de cálculo de ano bissexto, o RTC considera que YEAR = 0x00 equivale ao ano 2000, que é um ano bissexto (fevereiro com 29 dias).

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura DEV F6 F5 F4 F3 F2 F1 F0 SUBCUD Escrita Reset 0 0 0 0 0 0 0 0 Este registrador permite corrigir o relógio para reduzir imprecisões na contagem de tempo provocadas por desvios na frequência do oscilador XT1. A correção efetuada pelo registrador SUBCUD consiste em adicionar ou subtrair um valor do fator de divisão padrão (32768) do contador de 16 bits do RTC. Esta correção é realizada a cada 20 segundos (bit DEV = 0) ou a cada minuto (bit DEV = 1). O fator de correção é especificado pelos bits F0 a F5 e o bit F6 indica se fator de correção deve ser somando ou subtraído do valor base (32768). Observe que quando F6 = 0, o fator de correção consiste no valor binário carregado em F0 a F5, subtraído de 1 e multiplicado por 2. Quando F6 = 1, o fator de correção consiste no complemento de dois do conteúdo de F0 a F5 multiplicado por 2. Através deste registrador é possível efetuar correções de ±63,1ppm (quando DEV = 1) até ±189,2ppm (quando DEV = 0)

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 WM40 WM20 WM10 WM8 WM4 WM2 WM1 ALARMWM Escrita Reset 0 0 0 0 0 0 0 0 Este registrador armazena o minuto de alarme do RTC. Assim como o registrador de minutos, este registrador também utiliza o formato BCD e pode conter valores de 0x00 a 0x59.

144 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 WH20 WH10 WH8 WH4 WH2 WH1 ALARMWH Escrita Reset 0 0 0 1 0 0 1 0 Este registrador armazena a hora de alarme do RTC. Assim como o registrador de horas, este registrador também utiliza o formato BCD e pode conter valores de 0x00 a 0x23. No modo 12 horas o bit WH20 comporta-se como AMPM e indica se o horário de alarme é antes de meio dia (WH20 = 0) ou depois do meio dia (WH20 = 1).

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 WW6 WW5 WW4 WW3 WW2 WW1 WW0 ALARMWW Escrita Reset 0 0 0 0 0 0 0 0 Este registrador controla os dias da semana onde o alarme deve ser disparado. WW0 para domingo, WW1 para segunda-feira, WW2 para terça-feira, WW3 para quarta-feira, WW4 para quinta-feira, WW5 para sexta-feira e WW6 para sábado.

7.2.3. Ajuste do RTC Como já foi dito, o RTC inclui um mecanismo que permite realizar pequenos ajustes para compensar desvios de frequência no oscilador XT1. Este mecanismo utiliza o registrador SUBCUD e atua diretamente sobre o fator de divisão do contador de 16 bits, localizado no circuito gerador de clock do RTC e responsável por dividir o sinal do oscilador XT1 (f SUB ) por 32.768, de forma a obter um sinal de 1Hz. O circuito de correção modifica periodicamente (a cada 20 ou a cada 60 segundos) o fator de divisão padrão (32.768) adicionando ou subtraindo do mesmo um valor configurável. Desta forma, garante-se a precisão da contagem de tempo do RTC ao longo do tempo. Para entendermos o conceito da correção, basta considerar que um oscilador de 32.768Hz gera 1.966.080 pulsos em um minuto de operação. Se o oscilador estiver operando fora da frequência, digamos 32.767Hz, o total de pulsos em um minuto será de 1.966.020, ou seja, 60 pulsos de clock a menos, o que significa que o relógio vai atrasar cerca 1 segundo a cada 546,13 segundos (ou cerca de um segundo a cada 9 minutos).

O valor de correção pode ser calculado da seguinte forma: N pulsosreal -Npulsos32768 = 1.966.020-1.966.080 = -60. Como o resultado é negativo, sabemos que F6 = 1 e o valor de F5 a F0 será igual a ~(60/2-1) = ~(30-1) = ~29 = 0xE2. Como apenas os seis bits menos significativos são utilizados, então o valor de F5 a F0 será igual a 0x22, F6 = 1 e DEV = 1 (já que o número de pulsos foi calculado para um minuto). O valor final de SUBCUD será igual a 0xE2. Outro exemplo: considerando que o oscilador esteja operando a 32.771Hz. Neste caso, temos uma diferença de +180 pulsos (o relógio vai adiantar). O cálculo do valor de correção será Npulsosreal -Npulsos32768 = 1.966.260-1.966.080 = +180. Como o resultado é positivo, o bit F6 = 0 e o

Periféricos de Temporização 145

valor a ser carregado em F5 a F0 será igual a (180/2)-1 = 90-1 = 89. No entanto, este valor é superior ao máximo que pode ser armazenado nos 6 bits menos significativos do SUBCUD. Isto significa que, neste caso, a correção não poderá ser feita a cada minuto e deverá ser feita a cada 20 segundos (DEV = 0). Refazendo o cálculo do número de pulsos a cada 20 segundos chegamos a uma diferença de +60 pulsos (basta dividir o valor por 3 o valor obtido para um minuto). O valor a ser carregado em F5 a F0 será igual a (60/2)-1 = 30-1 = 29 ou 0x1D, com F6 = 0 e DEV = 0! O valor final de SUBCUD será igual a 0x1D.

Lembre-se de que para medir a frequência do oscilador XT1 deve ser ativada a saída de clock do RTC (RCLOE=1) através do pino P30. Não tente medir o sinal do oscilador i diretamente nos pinos XT1 e XT2, pois qualquer carga adicional nestes pinos irá desestabilizar o oscilador, podendo causar erros de medição e até a parada de oscilação dele!

7.2.4. Exemplo O exemplo a seguir demonstra como utilizar o RTC. A aplicação utiliza a interrupção periódica do RTC, configurada para intervalos de um segundo, para alternar o estado do led D2 na placa RPB do RL78/G13. A mesma interrupção também realiza a atualização da estrutura “time” que armazena o horário atual e que também permite setar o horário do RTC. O procedimento de configuração de horário do relógio deve obedecer aos seguintes passos: 1. A aplicação deve apagar o bit “time.update”, de forma a poder alterar os demais campos da estrutura “time”; 2. Após a configuração dos campos da estrutura, a aplicação deve setar o bit “time.set”. Isto fará com que o horário do RTC seja reconfigurado com os valores da estrutura “time”. Após esta operação a atualização do horário é automaticamente habilitada (o bit “time.set” é apagado e “time.update” é setado). #include “ior5f100le.h” #include “ior5f100le_ext.h” #include “intrinsics.h” #include “myRL78.h”

// Configura watchdog = desligado #pragma location = “OPTBYTE” __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = “OPTBYTE” __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = “OPTBYTE” __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = “OPTBYTE” __root __far const char opbyte3 = DEBUG_ON_ERASE;

146 Microcontroladores RL78: Guia Básico

/* Configura security ID */ #pragma location = “SECUID” __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P7_bit.no7

struct { unsigned char hour, minute, second; unsigned char year, month, week, day; unsigned char set : 1; unsigned char update : 1; } time;

#pragma vector = INTRTC_vect __interrupt void trata_RTC(void) { LED = !LED; // inverte o estado do led // solicita o bloqueio dos contadores caso a atualização esteja ativa if (time.update) RWAIT = 1; }

void main(void) { PM7_bit.no7 = 0; // P7.7 como saída LED = 1; // led desligado CMC = OSC_XT1_OSC; // oscilador XT1 ligado no modo de baixa potência CSC = bMSTOP; // libera oscilador XT1 e mantém X1 parado OSMC = 0; // configura o XT1 como fonte de clock do IT/RTC RTCEN = 1; // habilita o RTC e o IT // habilita o RTC, modo 24 horas, interrupção periódica de 1 segundo RTCC0 = bRTCE | bAMPM | INT_RTC_1S; RTCC1 = 0; RTCMK = 0; // habilita a interrupção do RTC time.set = 0; time.update = 1; __enable_interrupt(); // habilita as interrupções do RL78 while (1) { if (time.set) { // se houver requisição de atualização de horário do RTC RWAIT = 1; // solicita bloqueio dos contadores } if (RWST) { // se o indicador de bloqueio dos contadores estiver setado if (time.set) { // setar o horário do relógio HOUR = time.hour; MIN = time.minute; SEC = time.second; YEAR = time.year; MONTH = time.month; WEEK = time.week; DAY = time.day; time.set = 0; // apaga o indicador de atualização } else { // é uma atualização do mostrador time.hour = HOUR; time.minute = MIN;

Periféricos de Temporização 147

time.second = SEC; time.year = YEAR; time.month = MONTH; time.week = WEEK; time.day = DAY; } RWAIT = 0; // desbloqueia o clock dos contadores do RTC time.update = 1; // ativa a atualização do mostrador } } } Exemplo 7.2

A figura 7.3 mostra a janela “Live Watch” de uma sessão de depur ação do IAR EWRL78. Utilizando esta janela é possível visualizar o horário do relógio sendo atualizado em tempo real! Repare que, por padrão do depurador, o RTC continua operando, mesmo quando a execução do programa é paralisada! Figura 7.3

7.3. TAU

A TAU (Timer Array Unit – unidade conjunta de timers) é a principal unidade de temporização dos RL78 e constitui um dos grandes atributos destes microcontroladores. Uma unidade TAU é composta de até oito canais, cada um contendo um contador e um registrador de recarga/captura, ambos de 16 bits. Cada canal pode operar nos seguintes modos: • Gerador de interrupções periódicas ou de ondas quadradas; • Captura de sinais externos (medição de período de sinais digitais); • Medição de ciclo ativo ou inativo de sinais; • Contador de eventos externos; • Gerador de atraso ou disparo único (o contador dispara após um evento interno ou externo e gera uma interrupção após um atraso programável). Os canais 1 e 3 também podem operar como timers de 8 bits, de forma que cada um destes canais opera como dois timers de 8 bits. Adicionalmente, na TAU0, o canal 0 pode operar como divisor de frequência e, nos modelos com 30 pinos ou mais, o canal 7 pode ser utilizado em conjunto com a UART2 para implementar comunicação LIN (Local Interconnect Network – rede de interconexão local). Também é possível agrupar canais para realizar operações complexas tais como:

148 Microcontroladores RL78: Guia Básico

• Geração de sinais PWM (Pulse Width Modulation – modulação por largura de pulso), onde um canal é responsável pela temporização do período do sinal (o canal mestre) e outros canais são responsáveis pelo ciclo ativo de cada sinal (os canais escravos); • Geração de pulsos únicos (com intervalo e duração programáveis). Uma característica muito importante e interessante da TAU é que cada canal comporta-se como um timer independente de 16 bits já que, diferentemente dos timers utilizados em outros microcontroladores, cada canal possui recarga independente e contador próprio, reduzindo drasticamente a necessidade de intervenção da CPU na geração de sinais e interrupções periódicas. Nos timers comumente encontrados em outros microcontroladores, temos um contador principal, normalmente com módulo de contagem configurável e um ou mais registradores comparadores, um para cada canal. Assim, para gerar interrupções periódicas podemos utilizar duas alternativas: configurar o módulo de contagem do contador principal, o que faz com que todos os canais devam operar dentro do mesmo range do contador principal, ou carrega-se o período de contagem no registrador comparador a cada comparação, por exemplo: se o contador principal do timer incrementa a cada 1µs então, para gerar uma comparação a cada 1ms será necessário configurar o registrador de comparação para 1000 contagens e a cada comparação deveremos somar 1000 ao mesmo de forma a obter comparações periódicas de 1ms. Como cada canal da TAU dos RL78 funciona como um timer independente, podemos configurar um canal qualquer para operar com módulo de contagem 1000 e ele gerará uma interrupção a cada 1ms, sem nenhuma necessidade de intervenção da CPU! Os demais canais podem realizar contagens em diferentes módulos sem que ocorra interferência ou dependência entre eles.

7.3.1. Visão Geral de uma Unidade TAU Antes de estudarmos em mais detalhes os diversos modos de operação dos canais da TAU, vejamos alguns detalhes gerais acerca da sua operação.

Lembre-se de que antes de utilizar uma unidade TAU é necessário setar o bit TAU0EN (para i a TAU0) ou TAU1EN (para a TAU1) no registrador PER0!

Primeiramente, é importante saber que existem quatro divisores de clock (prescalers) na TAU, batizados de CK0, CK1, CK2 e CK3. Cada um deles pode ser configurado para dividir o sinal de clock principal f CLK por fatores configurados através do registrador TPSm (onde m pode ser 0 para a unidade TAU0 ou 1 para a unidade TAU1). Estes sinais de clock podem ser utilizados como fonte de clock dos canais da TAU. Como já foi dito, cada canal possui um contador (TCRmn onde m indica a unidade TAU, 0 ou 1, e n indica o número do canal, 0 a 7) e um registrador de captura ou comparação (TDRmn), ambos com 16 bits. A configuração do modo de operação de cada canal é realizada através dos registradores TMRmn. Observe que cada contador pode contar progressiva ou regressivamente, conforme o modo de operação do canal: nos modos de captura a contagem é progressiva e nos demais modos a contagem é regressiva.

Periféricos de Temporização 149

É no registrador TMRmn que configuram-se facilidades como a operação de canais em conjunto (configurando-se um ou mais canais como mestres e outros como escravos) ou operação de canais independentes. Cada canal pode ser individualmente habilitado (registrador TE0 para a TAU0 e TE1 para a TAU1) e a sua operação é iniciada setando-se o bit de partida (registrador TSm) e pode ser paralisada a qualquer tempo setando-se o bit de parada (registrador TTm). Quando o canal está parado o contador mantém o último valor de contagem.

Observe que os registradores TSm e TTm são do tipo write-only e por isso, a leitura deles i retorna sempre o valor zero. A verificação do status de operação de um canal deve ser feita através do registrador TEm!

Adicionalmente, cada canal pode contar com um pino que pode operar como entrada (TImn), que pode ser utilizada como fonte de clock externo ou para medição de período ou ciclo ativo/inativo de sinais externos. O pino também pode operar como saída (TOmn) que pode ser utilizada para gerar sinais PWM, pulsos ou ondas quadradas. As entradas podem ser configuradas para operar com filtros digitais de ruído (registradores NFEN1 e NFEN2). No caso das saídas, os registradores TOEm, TOm, TOLm e TOMm podem ser utilizados para configurar o modo como o canal interage com os pinos de E/S do microcontrolador.

Atenção: quando o filtro de ruído está desativado o pulso aplicado na entrada do canal 1 deverá ter uma duração mínima de + 10ns para que possa ser corretamente i fMCLK identificado pelo hardware da TAU. Quando o filtro está ativado, o pulso deve permanecer ativo por um período mínimo de 2 pulsos de clock do canal (f MCLK ).

As tabelas a seguir mostram os pinos associados às unidades TAU dos RL78/G13. As células sombreadas indicam os canais disponíveis nos diversos encapsulamentos. Pino de E/S utilizado pela TAU* TAU Encapsulamento (pinos) Pino Unidade Canal Função 128 100 80 64 52 48,44 40 36,32,30 25,24 20 Alternativo 0 TI00 P00 P00 P00 P00 P00 P00 P00 P00 P00 P00 - 0 TO00 P01 P01 P01 P01 P01 P01 P01 P01 P01 P01 - 1 TI01/TO01 P16 P16 P16 P16 P16 P16 P16 P16 P16 P16 - 2 TI02/TO02 P17 P17 P17 P17 P17 P17 P17 P17 P17 P17 - 0 3 TI03/TO03 P31 P31 P31 P31 P31 P31 P31 P31 P31 - - 4 TI04/TO04 P42 P42 P42 P42 ------P13 5 TI05/TO05 P46 P46 P05 P05 ------P12 6 TI06/TO06 P102 P102 P06 P06 ------P11 7 TI07/TO07 P145 P145 P41 P41 P41 P41 P41 - - - P10 * A disponibilidade de pinos e canais varia conforme o tamanho do encapsulamento Tabela 7.3

150 Microcontroladores RL78: Guia Básico

Pino de E/S utilizado pela TAU* TAU Encapsulamento (pinos) Pino Unidade Canal Função 128 100 80 64 52 48,44 40 36,32,30 25,24 20 Alternativo 0 TI10/TO10 P64 P64 P64 ------1 TI11/TO11 P65 P65 P65 ------2 TI12/TO12 P66 P66 P66 ------3 TI13/TO13 P67 P67 P67 ------1 4 TI14/TO14 P103 ------5 TI15/TO15 P104 ------6 TI16/TO16 P105 ------7 TI17/TO17 P106 ------* A disponibilidade de pinos e canais varia conforme o tamanho do encapsulamento Tabela 7.4

Nos próximos tópicos veremos os diversos modos em que os canais das unidades TAU podem operar.

7.3.2. Operação em Modo Timer/Gerador de Onda Quadrada Neste modo de operação o contador do canal (TCRmn) conta regressivamente, iniciando a contagem com o valor carregado no registrador TDRmn. A cada pulso de clock (CK0, CK1, CK2 ou CK3) a contagem é decrementada até atingir zero, quando então o respectivo flag de interrupção é setado (TMIFmn = 1) e caso a interrupção do canal esteja habilitada (TMMKmn = 0) e IE=1, o programa é desviado para o vetor do respectivo do canal (INTTMmn_vect). No próximo pulso de clock o contador do canal é novamente carregado com o valor de TDRmn e o processo reinicia. Para operar neste modo o registrador de controle do canal (TMRmn) deve ser configurado com os bits MD3 = 0, MD2 = 0 e MD1 = 0. O bit MD0 configura a geração de interrupção no disparo do canal (MD0 = 1) ou não (MD0 = 0). Também é possível (e recomendável) utilizar o símbolo TAU_MD_TIMER para configurar o canal no modo timer sem interrupção no disparo ou o símbolo TAU_MD_TIMER_TRIG_INT para configurar o canal no modo timer com interrupção no disparo. A fonte de clock (bit CCS) deve ser sempre o clock interno (CCS=0). Observe que independentemente da configuração de interrupção no disparo, o canal irá gerar uma interrupção a cada recarga do contador! O período de interrupção (em segundos) nesta modalidade de operação pode ser calculado através da seguinte fórmula: TDRmn +1 T = INT CKx Onde: TDRmn é o valor carregado no registrador de comparação do canal e CKx é a frequência de clock do canal (sinal CK0, CK1, CK2 ou CK3, conforme selecionado no registrador de configuração do canal TMRmn).

Periféricos de Temporização 151

Neste modo de operação, utiliza-se normalmente o disparo por software (bits STS0, STS1 e STS2 em 0) e a temporização tem início quando o canal é disparado (via registrador TSm) e é paralisada via registrador TTm. A seguir temos um exemplo de configuração do canal 2 da TAU0 para geração de interrupções a cada 1ms. No exemplo utilizaremos o sinal CK0 como fonte de clock do canal e consideraremos que o chip utiliza clock interno de 32MHz. // Primeiro configuramos os divisores de clock CKx no registrador TPS0 TPS0 = TAU_CK0_DIV1; // CK0=1MHz, CK1=1MHz, CK2=16MHz e CK3=125kHz // Agora configuramos o canal, não utilizaremos interrupção no disparo TMR02 = TAU_CK0 | TAU_MODE_TIMER; // Carrega o valor de comparação (para 1ms o valor de recarga é 999) TDR02 = 999; // Agora disparamos o canal, setando o bit correspondente (2) no TS0: TS0L = TAU_CH2; // é mais eficiente escrever na parte baixa do TS0! // Para gerar interrupções, basta apagar a máscara de interrupção // e habilitar as interrupções TMMK02 = 0; __enable_interrupt(); A ISR para tratamento da interrupção do canal deverá conter o código abaixo. Lembre-se de que ela será executada a cada 1ms! O símbolo INTTM02_vect é válido para o canal 2 da TAU 0, os demais canais possuem símbolos equivalentes (veja as tabelas 6.1 e 6.2). #pragma vector = INTTM02_vect __interrupt void trata_canal02(void) { // código de tratamento de interrupção aqui! // lembre-se de que não é necessário apagar o flag de interrupção! } A qualquer momento é possível parar a contagem do canal, para isso basta setar o bit correspondente (bit 2) no registrador TT0: // Paralisa a contagem no canal 2 da TAU0 TT0L = TAU_CH2; // é mais eficiente escrever na parte baixa do TT0 Adicionalmente, além da interrupção, é possível configurar o canal para alterar o estado do pino de saída do canal a cada evento de recarga. O sinal gerado será uma onda quadrada com ciclo ativo de 50%, ou seja, o sinal permanecerá 50% do período em nível 0 e 50% em nível 1. O período do sinal poderá ser calculado através da seguinte fórmula: (TDRmn + 2*)1 T = SINAL CKx Onde: TDRmn é o valor carregado no registrador de comparação do canal e CKx é a frequência de clock do canal (sinal CK0, CK1, CK2 ou CK3, conforme selecionado no registrador de configuração do canal TMRmn). Para que o sinal seja disponibilizado na saída do canal é necessário configurar o registrador de controle de saída do canal (TOEm), setando-se o bit do respectivo canal. No exemplo mostrado anteriormente, para ativar a saída do canal 2 da TAU0 poderíamos escrever: // Configura o pino do canal (P17) para o modo de saída PM1_bit.no7 = 0; // Habilita a saída do canal 2 da TAU0 TOE0L = TAU_CH2; // é mais eficiente escrever na parte baixa do TOE0

152 Microcontroladores RL78: Guia Básico

Após a configuração acima, o pino P17 passará a gerar um sinal de frequência igual a 500Hz. A seguir temos um exemplo completo de configuração dos canais 0 e 1 da TAU0 para operação no modo temporizador. O pino P16 funciona como saída do canal 1, ao passo que o canal 0 somente gera interrupções no software (piscando o led D2 conectado ao pino P77 da Promotion Board do RL78/G13) #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;

/* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P7_bit.no7

#pragma vector = INTTM00_vect __interrupt void trata_TAU0_canal0(void) { LED = !LED; // inverte o estado do led }

void main(void) { PM1_bit.no6 = 0; // P16 como saída (canal 1 da TAU0) PM7_bit.no7 = 0; // P77 como saída TAU0EN = 1; // habilita a TAU0 TPS0 = TAU_CK0_DIV32; // CK0=1MHz, CK1=32MHz, CK2=16MHz e CK3=125kHz // configura os canais 0 e 1 da TAU0 no modo temporizador TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_TIMER; TMR01 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_TIMER; TDR00 = 49999; // uma interrupção a cada 50ms no canal 0 TDR01 = 499; // sinal de 1kHz no canal 1 TOE0L = TAU_CH1; // habilita a saída do canal 1 da TAU0 TMMK00 = 0; // habilita a interrupção do canal 0 da TAU0 TS0L = TAU_CH0 | TAU_CH1; // Dispara os canais 0 e 1 __enable_interrupt(); // habilita as interrupções do RL78 while (1); } Exemplo 7.3

Periféricos de Temporização 153

7.3.3. Operação no Modo Gerador de Atraso/Disparo Único Neste modo de operação o canal da TAU é configurado para gerar um atraso programável após receber um sinal de disparo que pode vir através do pino de entrada do canal (TImn) ou do software (registrador TSm). Após receber o sinal de disparo, o contador do canal é carregado com o conteúdo do registrador de comparação TMRmn e faz a contagem regressiva até atingir o valor zero, quando então é disparada a interrupção e o respectivo flag é setado (TMIFmn = 1). O período de atraso (em segundos) é dado pela mesma fórmula do modo timer: TDRmn +1 T = INT CKx Onde: TDRmn é o valor carregado no registrador de comparação do canal e CKx é a frequência de clock do canal (sinal CK0, CK1, CK2 ou CK3, conforme selecionado no registrador de configuração do canal TMRmn). Para que o canal opere neste modo o registrador de controle (TMRmn) deve ser configurado com os bits MD3 = 1, MD2 = 0 e MD1 = 0. O bit MD0 configura o comportamento do canal ao receber um novo disparo durante a temporização. Quando MD0 = 0, um novo disparo é ignorado e não produz efeito. Quando MD0 = 1, um novo disparo (redisparo) provoca a recarga do contador e uma nova temporização tem início. A interrupção somente é disparada ao término da temporização. Também é possível (e recomendável) utilizar o símbolo TAU_MD_ONECOUNT para configurar o canal para operar neste modo (novos disparos ignorados) ou TAU_MD_ONECOUNT_TRIG para permitir o redisparo. A fonte de clock (bit CCS) deve ser sempre o clock interno (CCS=0). O tipo de disparo é selecionado através dos bits STS2, STS1 e STS0, localizados no registrador TMRmn. Basicamente o disparo pode ocorrer por software ou pelo pino de entrada do canal TImn. A tabela 7.4 mostra as configurações possíveis dos bits STS2, STS1 e STS0. STS2 STS1 STS0 Fonte de disparo Símbolo C (myRL78.h) 0 0 0 Software TAU_TRIG_SOFT* 0 0 1 Pino TAU_TRIG_VALID_EDGE * o símbolo TAU_TRIG_SOFT pode ser omitido já que equivale ao valor 0. Tabela 7.5 No disparo por sinal externo, o software deve armar o canal setando o bit de disparo correspondente no registrador TSm. Uma vez armado, somente ao ser detectada a borda no pino de entrada TImn é que a contagem do canal tem início. No disparo por software, o software deve armar o canal setando o bit de disparo correspondente no registrador TSm e a contagem tem início imediatamente após o bit de disparo do canal ser setado no registrador TSm, ou seja, primeiro o canal é armado e depois disparado. A configuração da borda de sensibilidade é feita através dos bits CIS1 e CIS0, localizados no registrador TMRmn. É possível configurar o canal para que o disparo ocorra na borda de descida, de subida ou em ambas as bordas do sinal aplicado ao pino TImn. A tabela 7.5 mostra as configurações possíveis para os bits CIS1 e CIS0.

154 Microcontroladores RL78: Guia Básico

CIS1 CIS0 Borda de Sensibilidade Símbolo C (myRL78.h) 0 0 Descida TAU_EDGE_FALLING* 0 1 Subida TAU_EDGE_RISING 1 0 Ambas TAU_EDGE_BOTH * o símbolo TAU_EDGE_FALLING pode ser omitido já que equivale ao valor 0. Tabela 7.6 Quando se utiliza o disparo por transição no pino, é possível ativar o filtro interno de ruído, de forma a reduzir a interferência provocada pela presença eventual de ruídos. Os registradores NFEN1 e NFEN2 controlam a ativação/desativação do filtro em cada entrada das duas unidades TAU. O exemplo a seguir utiliza o canal 1 para gerar atrasos de 25ms. Neste exemplo o canal 0 é configurado para operar como temporizador, gerando uma interrupção a cada 300ms. Na ISR do canal 0 o led D2 da Promotion Board do RL78/G13 é aceso e o canal 1 é disparado, gerando um atraso de 25ms. Após o atraso a ISR do canal 1 apaga o led e o canal permanece aguardando um novo disparo. O resultado final é que o led pisca em pulsos rápidos. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h" // Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P7_bit.no7

#pragma vector = INTTM00_vect __interrupt void trata_TAU0_canal0(void) { LED = 0; // liga o led TS0L = TAU_CH1; // dispara o canal 1, inicia a temporização do atraso }

#pragma vector = INTTM01_vect __interrupt void trata_TAU0_canal1(void) { LED = 1; // desliga o led }

void main(void) { PM7_bit.no7 = 0; // P77 como saída

Periféricos de Temporização 155

TAU0EN = 1; // habilita a TAU0 // CK1=1MHz, CK2=16MHz e CK0=CK3=125kHz TPS0 = TAU_CK0_DIV256 | TAU_CK1_DIV32; // configura o canal 0 no modo temporizador TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_TIMER; // configura o canal 1 no modo atraso/disparo único TMR01 = TAU_CK1 | TAU_TRIG_SOFT | TAU_MD_ONECOUNT ; TDR00 = 37499; // canal 0 gera uma interrupção a cada 300ms TDR01 = 24999; // canal 1 gera um atraso de 25ms TS0L = TAU_CH0; // dispara o canal 0 TMMK00 = 0; // habilita a interrupção do canal 0 da TAU0 TMMK01 = 0; // habilita a interrupção do canal 1 da TAU0 __enable_interrupt(); // habilita as interrupções do RL78 while (1); } Exemplo 7.4

7.3.4. Operação em Modo Contador de Eventos Quando um canal da TAU está configurado no modo contador de eventos, o clock do contador do canal é derivado do pino de entrada do canal (TImn). A cada borda de subida ou de descida (configurável por software) do sinal no pino (TImn), o contador do canal é decrementado em um. O valor inicial do contador é determinado pelo registrador de comparação TDRmn. Quando a contagem do contador do canal atinge o valor zero, um evento de interrupção é disparado e o respectivo flag é setado (TMIFmn = 1). Ao mesmo tempo o contador é recarregado com o valor de TDRmn. Caso o valor do registrador TDRmn seja alterado, ele somente irá afetar a contagem no início do próximo ciclo, ou seja, após a contagem atual chegar a zero. O número de contagens para se gerar uma interrupção é igual a TDRmn + 1. A seleção deste modo de operação é feita através do registrador de controle (TMRmn), que deve ser configurado com os bits MD3 = 0, MD2 = 1, MD1 = 1 e MD0 = 0. É possível utilizar o símbolo TAU_MD_EVENTCOUNT para configurar o canal para operação nesta modalidade. O bit CCS deve ser setado de forma a selecionar o pino TImn como fonte de clock e a origem de disparo deve ser o software (todos os bits STS em zero). A configuração da borda de sensibilidade do sinal de clock é feita através dos bits CIS1 e CIS0, localizados no registrador TMRmn. É possível configurar o canal para que a contagem decremente a cada borda de descida, de subida ou com qualquer borda do sinal aplicado ao pino TImn. A tabela 7.5 mostra as configurações possíveis para os bits CIS1 e CIS0. Para iniciar a operação de contagem, o software deve armar o canal setando o bit de disparo correspondente no registrador TSm, o contador do canal (TCRmn) é carregado com o valor inicial (lido do TDRmn) e o contador permanece parado. A cada borda válida no pino TImn, o contador será decrementado conforme descrito.

156 Microcontroladores RL78: Guia Básico

Também é possível ativar o filtro interno de ruído, de forma a reduzir a interferência provocada pela presença eventual de ruídos. Os registradores NFEN1 e NFEN2 controlam a ativação/desativação do filtro em cada entrada das duas unidades TAU.

Atenção: A frequência máxima de entrada (com filtro de ruído desativado) é de i aproximadamente 12MHz.

7.3.5. Operação como Divisor de Frequência A operação como divisor de frequência é muito similar ao modo contador de eventos, com a diferença de que a saída do canal (P01/TO00) tem o seu estado invertido a cada recarga do contador, ou seja, a cada vez que o contador atinge o valor zero ele é recarregado com o valor de TDR00. A configuração do registrador TMR00 deve ser feita da mesma forma mostrada para o modo contador de eventos. A tabela 7.5 mostra as configurações possíveis para os bits CIS1 e CIS0 que configuram a borda de sensibilidade válida para o pino TI00. Quando o canal está configurado para operar somente com borda de descida ou somente com borda de subida, a frequência de saída em TO00 é dada pela seguinte fórmula: f f = 00TI 00TO TDR( 00 + 2*)1 Quando o canal está configurado para decrementar em ambas as bordas, a frequência de saída em TO00 é dada pela seguinte fórmula: f f = 00TI 00TO TDR 00 +1 Neste caso, o período de saída do sinal em TO00 pode exibir um erro de ±1 ciclo de clock (o clock aplicado em TI00) em virtude de erros de amostragem. Para iniciar a operação de contagem, o software deve armar o canal setando o bit de disparo (bit 0) no registrador TS0, o contador do canal (TCR00) é carregado com o valor inicial (lido do TDR00) e o contador permanece parado. A cada borda válida no pino TI00, o contador será decrementado conforme descrito e ao chegar a zero, o estado do pino TO00 é invertido e TCR00 é recarregado com o valor de TDR00. Caso o valor do TDR00 seja alterado, ele somente irá afetar a contagem no início do próximo ciclo, ou seja, após a contagem atual chegar a zero. Também é possível ativar o filtro interno de ruído, de forma a reduzir a interferência provocada pela presença eventual de ruídos. O bit 0 do registrador NFEN1 permite ativar a funcionalidade do filtro de entrada.

i Atenção: A frequência máxima de entrada (sem filtro) é de aproximadamente 12MHz.

Periféricos de Temporização 157

7.3.6. Operação no Modo de Captura de Período Este modo de operação permite utilizar um canal qualquer da TAU para realizar a medição do período de um sinal digital aplicado ao pino de entrada do canal. Nesta modalidade de operação o contador do canal opera em modo crescente, iniciando sua contagem de zero e incrementando a cada ciclo da fonte de clock selecionada (CK0, CK1, CK2 ou CK3, conforme os bits CKS1 e CKS0 do registrador TMRmn). Ao ser detectada uma borda (selecionada através dos bits CIS1 e CIS0) a contagem atual do contador (TCRmn) é captura (armazenada) no registrador TDRmn. Ao mesmo tempo o bit OVF (registrador TSRmn) é atualizado, de forma a indicar se houve estouro da contagem antes da captura ou não), a contagem do TCRmn retorna a zero e o flag de interrupção do canal (TMIFmn) é setado. O período do sinal capturado será igual a: (TDRmn + )1 T = SINAL CKx Onde: TDRmn é o valor capturado pelo canal e CKx é a frequência de clock do canal (sinal CK0, CK1, CK2 ou CK3, conforme selecionado no registrador de configuração do canal TMRmn). Apesar do manual do fabricante informar que é possível realizar a medição do período capturado com OVF=1 (quando o valor medido é igual a TDRmn + 0x10001), esta prática deve ser evitada, pois não há garantia de que apenas um overflow de contagem ocorreu durante a medição. De fato, OVF é setado sempre que ocorre um ou mais estouros da contagem do TCRmn! De maneira geral o bit OVF deve ser utilizado apenas como um indicador de erro, sinalizando que o período do sinal foi maior que a capacidade de medição do canal. A aplicação deve então tomar as providências cabíveis como, por exemplo, reduzir a frequência de clock do canal (aumentando consequentemente a faixa de medição). Para operar no modo de captura de período, o registrador TMRmn deve ter os seus bits de seleção de modo configurados para 0100 (MD3=0, MD2=1, MD1=0 e MD0=0). Observe que quando MD0=0, o sinal de interrupção é disparado a cada captura e quando MD0=1, o sinal de interrupção é disparado com a partida do contador e também a cada captura. O símbolo TAU_MD_CAPTURE pode ser utilizado para configurar o canal neste modo de operação (com MD0=0) ou TAU_MD_CAPTURE_TRIG_INT para selecionar o modo de captura com MD0=1. A fonte de clock (bit CCS) deve ser sempre o clock interno (CCS=0). A seleção da borda de captura é realizada por meio dos bits CIS1 e CIS0, conforme a tabela 7.5. É possível selecionar a captura nas bordas de subida, descida ou ambas (neste caso mede-se os semiciclos de cada período continuamente). Os bits de seleção do modo de disparo (STS2, STS1 e STS0) devem ser configurados para STS2=0, STS1=0 e STS0=1 (borda válida no pino TImn). Depois de configurado o canal, a operação de captura é iniciada setando-se o respectivo bit de disparo do canal (registrador TSm). Esta operação provoca a carga do valor 0x0000 no

158 Microcontroladores RL78: Guia Básico

registrador de captura (TDRmn) e inicia a contagem crescente do contador do canal (TCRmn). Ao detectar uma borda válida no pino TImn, a contagem atual do TCRmn é armazenada no registrador TDRmn, o flag de interrupção INTTMmn é setado, o flag OVF (registrador TSRmn) é atualizado e a contagem do TCRmn é reiniciada de zero. Uma particularidade interessante é que após a partida inicial do canal, uma captura pode ser disparada tanto pela borda válida no pino TImn quanto por um disparo por software (setando novamente o bit TSmn). A figura 7.4 mostra uma típica operação de captura de borda de subida (CIS1=0 e CIS0=1). Se considerarmos que o clock do canal é igual a 1MHz, teremos que o período do sinal é igual a 100µs (99+1). TSmn

TEmn

TImn

TCRmn 0 1 2 ... 48 49 0 1 2 3 ... 48 49 50 51 ... 97 98 99 0 1 2 3 ... 48 49 50 51 ... 97 98 99 0 1 2 ...

TDRmn 0 49 99 99

INTTMmn Figura 7.4

A primeira captura após o disparo inicial do canal deve normalmente ser desprezada, pois é necessário um ciclo completo do sinal na entrada TImn para que a medição seja feita corretamente.

7.3.7. Operação no Modo de Captura de Ciclo O modo de captura de ciclo é uma variação do modo de captura de período, porém neste modo, a contagem do canal é iniciada somente ao detectar uma borda previamente configurada no pino TImn e a captura ocorre na borda oposta. Desta forma, o período medido não é do sinal, mas do semiciclo. Nesta modalidade de operação o contador do canal opera em modo crescente, incrementando a contagem a cada ciclo da fonte de clock selecionada (CK0, CK1, CK2 ou CK3, conforme os bits CKS1 e CKS0 do registrador TMRmn). Ao ser detectada uma borda (selecionada através dos bits CIS1 e CIS0) a contagem do canal é iniciada (partindo de zero) e ao detectar a borda oposta, a contagem atual do contador (TCRmn) é captura (armazenada) no registrador TDRmn. Ao mesmo tempo o bit OVF (registrador TSRmn) é atualizado, de forma a indicar se houve estouro da contagem antes da captura ou não), a contagem do TCRmn retorna a zero e o flag de interrupção do canal (TMIFmn) é setado. O período do sinal capturado será igual a: (TDRmn + )1 T = SINAL CKx

Periféricos de Temporização 159

Onde: TDRmn é o valor capturado pelo canal e CKx é a frequência de clock do canal (sinal CK0, CK1, CK2 ou CK3, conforme selecionado no registrador de configuração do canal TMRmn). As mesmas considerações já feitas para o bit OVF valem para este modo de operação. Para operar no modo de captura de ciclo ativo/inativo, o registrador TMRmn deve ter os seus bits de seleção de modo configurados para 1100 (MD3=1, MD2=1, MD1=0 e MD0=0 ou através o símbolo TAU_MD_CAPTURE_LEVEL). A fonte de clock (bit CCS) deve ser sempre o clock interno (CCS=0). A seleção da borda de captura é realizada por meio dos bits CIS1 e CIS0, conforme a tabela 7.6. É possível selecionar a captura nas bordas de subida, descida ou ambas (neste caso mede-se os semiciclos de cada período continuamente). CIS1 CIS0 Borda de Partida Borda de Captura Símbolo C (myRL78.h) 1 0 Descida Subida TAU_EDGE_FALL_RISE 1 1 Subida Descida TAU_EDGE_RISE_FALL Tabela 7.7

Os bits de seleção do modo de disparo (STS2, STS1 e STS0) devem ser configurados para STS2=0, STS1=1 e STS0=0 (qualquer borda válida no pino TImn). Após configurado o canal, a operação de captura é iniciada setando-se o respectivo bit de disparo do canal (registrador TSm). Esta operação provoca a carga do valor 0x0000 no registrador de captura (TDRmn). Ao detectar uma borda de partida no pino TImn, o contador do canal inicia a contagem e ao detectar a borda de captura a contagem atual do TCRmn é armazenada no registrador TDRmn, o flag de interrupção INTTMmn é setado, o flag OVF (registrador TSRmn) é atualizado e a contagem do TCRmn retorna a zero. A figura 7.5 mostra uma típica operação de captura de ciclo ativo (CIS1=1 e CIS0=1). Podemos verificar que a contagem do TCRmn é iniciada de zero a cada borda de subida de TImn e a contagem é capturada na borda de descida do mesmo. Se considerarmos que o clock do canal é igual a 1MHz, teremos que o período do ciclo ativo é igual a 50µs (49+1). TSmn

TEmn

TImn

TCRmn 0 0 1 2 3 ... 48 49 0 0 1 2 3 ... 48 49 0 0 1 2 3 ...

TDRmn 0 49 49

INTTMmn Figura 7.5

7.3.8. Operação no Modo de Pulso Configurável Neste modo de operação utilizam-se dois canais de uma TAU para gerar um pulso único com atraso e duração programáveis. O canal mestre é responsável pela temporização do atraso antes do pulso e o canal escravo é responsável pela temporização do pulso. Ambos operam no modo de contagem única regressiva, partindo do valor de TDRmn e decrementando até zero.

160 Microcontroladores RL78: Guia Básico

O disparo da operação pode se dar através de um pulso na entrada TImn do canal mestre ou via software e a saída do pulso ocorre pelo pino TOmn do canal escravo. O tempo de atraso antes do pulso é definido pela seguinte fórmula: TDRmestre + 2 T = ATRASO CKx Onde: TDRmestre é o valor carregado no registrador de comparação do canal mestre e CKx é a frequência de clock do canal (sinal CK0 ou CK1, conforme selecionado no registrador de configuração do canal TMRmn). A duração do pulso é definida pela seguinte fórmula: TD Re scravo T = PULSO CKx Onde: TDRescravo é o valor carregado no registrador de comparação do canal escravo e CKx é a frequência de clock do canal (sinal CK0 ou CK1, conforme selecionado no registrador de configuração do canal TMRmn).

O domínio de clock do canal mestre e do escravo deve ser o mesmo. Isto significa que a i seleção do prescaler CKx feita para o canal escravo deve ser exatamente a mesma do canal mestre!

Para operar nesta modalidade, o registrador TMRmn do canal mestre deve ter o seu bit MASTER=1 (exceto quando se trata do canal 0) e os seus bits de seleção de modo MDx configurados para 1000 binário (MD3=1, MD2=0, MD1=0 e MD=0, símbolo TAU_MD_ONECOUNT no arquivo myRL78.h), os bits de seleção de fonte de disparo STSx devem estar configurados para disparo por software (STS2=0, STS1=0 e STS0=0) ou disparo por borda válida no pino TImn (STS2=0, STS1=0 e STS0=1), neste caso a borda válida é selecionada através dos bits CIS1 e CIS0, conforme a tabela 7.7 a seguir. CIS1 CIS0 Borda de Sensibilidade Símbolo C (myRL78.h) 0 0 Descida TAU_EDGE_FALLING* 0 1 Subida TAU_EDGE_RISING 1 0 Ambas TAU_EDGE_BOTH * o símbolo TAU_EDGE_FALLING pode ser omitido já que equivale ao valor 0. Tabela 7.8

No caso do canal escravo, o registrador TMRmn deve ter os seus bits de seleção de modo MDx configurados para 1000 binário (MD3=1, MD2=0, MD1=0 e MD=0, símbolo TAU_MD_ONECOUNT no arquivo myRL78.h) e os bits de seleção de fonte de disparo STSx devem estar configurados para disparo por interrupção do mestre (STS2=1, STS1=0 e STS0=0). A fonte de clock (bit CCS) do canal mestre e do escravo deve ser sempre o clock interno (CCS=0). Adicionalmente, os registradores de controle de saída da TAU devem ser configurados da seguinte forma: nos registradores TOEm (habilitação da saída do canal) e TOMm (controle da saída do canal) os bits relativos ao canal escravo devem estar setados, fazendo com que o pino de

Periféricos de Temporização 161

E/S seja controlado pelo canal e ativado/desativado sob controle do canal mestre e do escravo. A polaridade de saída do pulso é determinada através do registrador TOLm. Quando o bit relativo ao canal escravo está em zero, o pulso no pino TOmn tem polaridade positiva (o pulso é ativo em um) e quando o bit está setado, o pulso no pino TOmn tem polaridade negativa (o pulso é ativo em zero). TSmestre

TEmestre

TSescravo

TEescravo

TImestre

TCRmestre 0xFFFF X X-1 X-2 ... 0 0xFFFF X X-1 X-2 ... 0

TDRmestre X

INTTMmestre

TCRescravo 0xFFFF Y Y-1 Y-2 ... 0 0xFFFF Y Y-1 Y-2 ... TDRescravo Y

INTTMescravo

Pino TOescravo (TOL=0) X+2 Y X+2

Pino TOescravo (TOL=1) X+2 Y X+2 Figura 7.6

Observe que somente canais pares (2, 4 ou 6) podem ser configurados para o modo mestre. O canal escravo a ser utilizado será aquele de numeração imediatamente superior a do mestre, assim, caso o mestre seja o canal 0, o escravo deverá ser o canal 1, caso o mestre seja o canal 2, o escravo deverá ser o canal 3 e assim por diante.

Atenção: o canal zero pode operar como mestre mas o bit MASTER do registrador TMRm0 i deve ser mantido SEMPRE em zero!

Após a configuração dos canais mestre e escravo (registradores TMRmn), a aplicação deve configurar o atraso inicial (registrador TDR do canal mestre) e largura do pulso (registrador TDR do canal escravo). Feito isso, a operação é iniciada setando-se os bits de disparo (registrador TSm) dos dois canais (mestre e escravo) simultaneamente. Esta operação faz com que os registradores TCR dos canais mestre e escravo sejam carregados com 0xFFFF e inicia a detecção de borda válida na entrada TImn do canal mestre. Ao detectar uma borda válida o contador TCR do mestre é carregado com o valor do respectivo TDR e inicia uma contagem regressiva até zero. Durante esta contagem a saída TOmn do escravo é mantida inativa. No instante em que a contagem do mestre atinge o valor zero é gerado um evento de interrupção no canal (que pode ou não ser utilizado pela aplicação) e a contagem do mestre é suspensa, aguardando novamente um pulso de disparo na entrada TImn. O evento de interrupção do canal mestre provoca a carga do contador TCR do escravo com o valor do respectivo registrador TDR, a contagem regressiva do canal do canal escravo é iniciada e a saída TOmn do escravo é colocada no estado ativo.

162 Microcontroladores RL78: Guia Básico

No instante em que a contagem do escravo atinge o valor zero é gerado um evento de interrupção no canal (que pode ou não ser utilizado pela aplicação) e a contagem do escravo é suspensa, aguardando um novo disparo do canal mestre. Ao mesmo tempo, a saída TOmn do escravo é colocada no estado inativo.

A alteração do tempo de atraso (TDR mestre) e da duração do pulso (TDR escravo) deve ser O feita preferivelmente logo após o evento de interrupção de cada canal.

É possível associar mais de um canal escravo ao mestre e com isso gerar múltiplos pulsos com larguras diferentes após um atraso comum. Desta forma, uma aplicação poderia O utilizar, por exemplo, o canal 2 como mestre e os canais 3 e 4 como escravos, gerando dois pulsos de larguras diferentes após um intervalo comum determinado pelo canal 2!

Enquanto o canal mestre permanece aguardando uma borda válida no pino TImn, é possível provocar um disparo através do software. Para isso, basta setar o bit de disparo do canal mestre (registrador TSm). O exemplo a seguir dispara um pulso no pino P16 com atraso de 10ms e duração de 500µs, após detectar uma borda de descida no pino P00 (entrada do canal 0 da TAU0).

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;

/* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

void main(void) { PM1_bit.no6 = 0; // P16 como saída PU0_bit.no0 = 1; // liga pull-up do pino P00 TAU0EN = 1; // habilita a TAU0 TPS0 = TAU_CK0_DIV32; // CK0=1MHz, CK1=32MHz, CK2=16MHz e CK3=125kHz // configura o canal 0 no modo de atraso/disparo único TMR00 = TAU_CK0 | TAU_TRIG_VALID_EDGE | TAU_EDGE_FALLING | TAU_MD_ONECOUNT; // configura o canal 1 no modo de atraso/disparo único controlado pelo mestre TMR01 = TAU_CK0 | TAU_TRIG_MASTER | TAU_MD_ONECOUNT; TDR00 = 9999; // atraso de 10ms TDR01 = 499; // pulso de 500us TOE0L = TAU_CH1; // habilita a saída do canal 1

Periféricos de Temporização 163

TOM0L = TAU_CH1; // configura a saída do canal 1 para operar no modo TS0L = TAU_CH0 | TAU_CH1; // dispara os canais 0 e 1 while (1); }

Exemplo 7.5 A figura 7.7 mostra o comportamento da saída do canal 1 em função da entrada do canal 0.

TI00 (P00)

TO01 (P16) 10ms 0,5ms Figura 7.7

7.3.9. Operação em Modo PWM

No modo PWM utilizam-se dois ou mais canais de uma TAU para gerar um ou mais (até 7) sinais modulados em largura de pulso (PWM). Sinais PWM são amplamente utilizados em controle de motores, controle de brilho e iluminação, etc. O PWM na TAU utiliza o canal mestre como responsável pela temporização do período do sinal e operando no modo de intervalo (contagem regressiva), enquanto que os canais escravos são responsáveis pela temporização do ciclo ativo e operam no modo de contagem única (regressiva). A saída dos sinais PWM é realizada através dos pinos TOmn dos canais escravos. O período do sinal PWM é definido pela seguinte fórmula: TDRmn +1 T = PWM CKx Onde: TDRmn é o valor carregado no registrador de comparação do canal mestre e CKx é a frequência de clock do canal (sinal CK0 ou CK1, conforme selecionado no registrador de configuração do canal TMRmn). A largura do ciclo ativo é definida pela seguinte fórmula: TDRmn T = CICLO _ ATIVO CKx Onde: TDRmn é o valor carregado no registrador de comparação do canal escravo e CKx é a frequência de clock do canal (sinal CK0 ou CK1, conforme selecionado no registrador de configuração do canal TMRmn).

O domínio de clock do canal mestre e dos escravos deve ser o mesmo. Isto significa que a i seleção do prescaler CKx feita para os canais escravos deve ser exatamente a mesma do canal mestre! Um ciclo ativo de 0% é obtido configurando-se o registrador TDR do canal escravo para o valor zero. Um ciclo ativo de 100% é obtido configurando-se o registrador TDR do canal escravo para um valor maior ou igual ao do TDR do mestre mais um.

164 Microcontroladores RL78: Guia Básico

O cálculo do ciclo ativo (em %) pode ser realizado através da seguinte fórmula: TD Re scravo CICLO _ ATIVO (%) = 100* (TDRmestre + )1

A resolução do sinal PWM será de 16 bits quando o período (TDR mestre) for igual a i 0xFFFF, para outros valores do TDR mestre a resolução será reduzida conforme o número de contagens do período do sinal.

Em cada TAU é possível ter um conjunto de até 7 canais PWM sincronizados (utilizando o canal 0 como mestre). Também é possível utilizar outros canais (2, 4 ou 6) como mestres de forma a ter diferentes grupos com diferentes frequências de sinal PWM. Nos RL78, um canal mestre pode ter como escravos apenas os canais de numeração superior a sua, assim, o canal 0 pode ter como escravos todos os demais canais, o canal 2 pode ter como escravos os canais 3, 4, 5, 6 e 7, o canal 4 pode ter como escravos os canais 5, 6 e 7 e o canal 6 pode ter como escravo somente o canal 7. Também é possível ter canais operando de forma independente dos grupos de PWM, por exemplo, uma aplicação poderia ter um grupo de dois canais PWM utilizando o canal 0 como mestre e os canais 1 e 2 como escravos e outro grupo de dois canais PWM utilizando o canal 4 como mestre e os canais 5 e 6 como escravos. Neste caso, os canais 3 e 7 poderiam ser configurados para operar de forma independente dos grupos PWM.

Atenção: o canal zero pode operar como mestre mas o bit MASTER do registrador TMRm0 i deve ser mantido SEMPRE em zero!

Para operar nesta modalidade, o registrador TMRmn do canal mestre deve ter o seu bit MASTER=1 (exceto quando se trata do canal 0) e os seus bits de seleção de modo MDx configurados para 0001 binário (MD3=0, MD2=0, MD1=0 e MD=1 ou utilizando o símbolo TAU_MD_TIMER_TRIG_INT), a fonte de clock (bit CCS) deve ser o clock interno (CCS=0), os bits de seleção de fonte de disparo STSx devem estar configurados para disparo por software (STS2=0, STS1=0 e STS0=0) e os bits CIS1 e CIS0 devem ser mantidos em zero. No caso dos canais escravos, cada registrador TMRmn deve ter os seus bits de seleção de modo MDx configurados para 1001 binário (MD3=1, MD2=0, MD1=0 e MD=1 ou utilizando o símbolo TAU_MD_ONECOUNT_TRIG), a fonte de clock (bit CCS) deve ser o clock interno (CCS=0), os bits de seleção de fonte de disparo STSx devem estar configurados para disparo por interrupção do mestre (STS2=1, STS1=0 e STS0=0) e os bits CIS1 e CIS0 devem ser mantidos em zero. Adicionalmente, os registradores de controle de saída da TAU devem ser configurados da seguinte forma: nos registradores TOEm (habilitação da saída do canal) e TOMm (controle da saída do canal) os bits relativos aos canais escravos devem estar setados, fazendo com que os pinos de E/S sejam controlado pelos canais e ativados/desativados sob controle do canal mestre e dos escravos. A polaridade de saída dos sinais é determinada pelo registrador TOLm. Quando o bit relativo ao canal está em zero, o sinal no pino TOmn tem polaridade positiva (ciclo ativo em nível um) e quando o bit está setado, o sinal no pino TOmn tem polaridade negativa (ciclo ativo em nível zero).

Periféricos de Temporização 165

TSmestre

TEmestre

TSescravo

TEescravo

TCRmestre X X-1 X-2 ... 3 2 1 0 X X-1 X-2 ... 3 2 1 0 X X-1 X-2 ... 3 2 1 0 X X-1 X-2 ... 3 2 1 0

TDRmestre X

INTTMmestre

TCRescravo Y Y-1 ... 1 0 Y Y-1 ... 1 0 Y Y-1 ... 1 0 Y Y-1 ... 1 0

TDRescravo Y

INTTMescravo

Pino TOescravo (TOL=0) Ciclo ativo Ciclo ativo Ciclo ativo Ciclo ativo

Pino TOescravo (TOL=1) Ciclo ativo Ciclo ativo Ciclo ativo Ciclo ativo Figura 7.8

Após a configuração dos canais mestre e escravos (registradores TMRmn), a aplicação deve configurar o período do sinal PWM (registrador TDR do canal mestre) e largura do ciclo ativo de cada canal (registradores TDR dos canais escravos). Feito isso, a operação é iniciada setando-se os bits de disparo (registrador TSm) de todos os canais envolvidos (mestre e escravos) simultaneamente. Esta operação faz com que os registradores TCR dos canais mestre e escravos sejam carregados com o conteúdo dos respectivos TDRs e inicia a contagem regressiva nos canais. No instante em que um canal escravo atinge a contagem zero, a respectiva saída (TOmn) é invertida e permanece desta forma até que o canal mestre atinja a contagem zero, quando então todos os canais escravos têm as suas saídas configuradas para o estado de repouso (conforme a configuração do registrador TOLm).

A alteração do período do sinal PWM (TDR mestre) e do ciclo ativo (TDR dos escravos) O deve ser feita preferivelmente logo após o evento de interrupção de cada canal.

O exemplo a seguir demonstra como configurar os canais 1 e 2 para operar no modo escravo controlando o ciclo ativo de sinais PWM, tendo o canal 0 como mestre, controlando o período do sinal. O exemplo gera dois sinais de 1kHz, com ciclo ativo de 10% no canal 1 (pino P16) e de 90% no canal 2 (pino P17), conforme mostra a figura 7.9. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE"

166 Microcontroladores RL78: Guia Básico

__root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

void main(void) { PM1 = 0x3F; // P17 e P16 como saídas (canais 1 e 2 da TAU0) TAU0EN = 1; // habilita a TAU0 TPS0 = TAU_CK0_DIV32; // CK0=1MHz, CK1=32MHz, CK2=16MHz e CK3=125kHz // configura o canal 0 no modo mestre para PWM TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_TIMER_TRIG_INT; // configura os canais 1 e 2 no modo escravo para PWM TMR01 = TAU_CK0 | TAU_TRIG_MASTER | TAU_MD_ONECOUNT_TRIG; TMR02 = TAU_CK0 | TAU_TRIG_MASTER | TAU_MD_ONECOUNT_TRIG; TDR00 = 999; // período do sinal PWM = 1kHz TDR01 = 100; // canal 1 = 10% de ciclo ativo TDR02 = 900; // canal 2 = 90% de ciclo ativo TOE0L = TAU_CH2 | TAU_CH1; // habilita a saída dos canais 1 e 2 da TAU0 // saída dos canais 1 e 2 controladas pelo mestre/escravo TOM0L = TAU_CH2 | TAU_CH1; // dispara os canais mestre e escravos TS0L = TAU_CH0 | TAU_CH1 | TAU_CH2; while (1); } Exemplo 7.6

TO02 (P17)

TO01 (P16) 1ms Figura 7.9

7.3.10. Registradores das TAU Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura PRS PRS PRS PRS PRS PRS PRS PRS PRS PRS PRS PRS 0 0 0 0 TPSm Escrita m31 m30 m21 m20 m13 m12 m11 m10 m03 m02 m01 m00 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *m corresponde ao número da TAU (0 ou 1) Nome do Bit Descrição Símbolo C Seleção do divisor do CK3 da TAU:

00 - f clk dividido por 256 TAU_CK3_DIV256 PRSm31 PRSm30 01 - f clk dividido por 1024 TAU_CK3_DIV1024 10 - f clk dividido por 4096 TAU_CK3_DIV4096

11 - f clk dividido por 16384 TAU_CK3_DIV16384 Seleção do divisor do CK2 da TAU:

00 - f clk dividido por 2 TAU_CK2_DIV2 PRSm21 PRSm20 01 - f clk dividido por 4 TAU_CK2_DIV4 10 - f clk dividido por 16 TAU_CK2_DIV16

11 - f clk dividido por 64 TAU_CK2_DIV64

Periféricos de Temporização 167

Seleção do divisor do CK0 e CK1 da TAU:

0000 - fclk (nenhuma divisão) TAU_CKx_DIV1

0001 - f clk dividido por 2 TAU_CKx_DIV2

0010 - f clk dividido por 4 TAU_CKx_DIV4

0011 - f clk dividido por 8 TAU_CKx_DIV8

PRSm13 0100 - f clk dividido por 16 TAU_CKx_DIV16 PRSm12 0101 - f dividido por 32 TAU_CKx_DIV32 PRSm11 clk PRSm10 0110 - f clk dividido por 64 TAU_CKx_DIV64

0111 - f clk dividido por 128 TAU_CKx_DIV128 PRSm03 1000 - f dividido por 256 TAU_CKx_DIV256 PRSm02 clk PRSm01 1001 - f clk dividido por 512 TAU_CKx_DIV512

PRSm00 1010 - f clk dividido por 1024 TAU_CKx_DIV1024

1011 - f clk dividido por 2048 TAU_CKx_DIV2048

1100 - f clk dividido por 4096 TAU_CKx_DIV4096

1101 - f clk dividido por 8192 TAU_CKx_DIV8192

1110 - f clk dividido por 16384 TAU_CKx_DIV16384

1111 - f clk dividido por 32768 TAU_CKx_DIV32768 Nota: x pode ser 0 ou 1, por exemplo, TAU_CK0_DIV1 para o CK0 ou TAU_CK1_DIV1 para o CK1

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura MAS TER/ CKS1 CKS0 0 CCS STS2 STS1 STS0 CIS1 CIS0 0 0 MD3 MD2 MD1 MD0 SPLI TMRmn Escrita T Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *m corresponde ao número da TAU (0 ou 1) e n corresponde ao canal (0 a 7) Nome do Bit Descrição Símbolo C Seleção da fonte de clock do canal: 00 – prescaler CK0 TAU_CK0 CKS1 CKS0 01 – prescaler CK2 (somente nos canais 1 e 3) TAU_CK2 10 – prescaler CK1 TAU_CK1 11 – prescaler CK3 (somente nos canais 1 e 3) TAU_CK3 Seleção da fonte de clock do canal: 0 – o clock do canal é derivado de um dos 4 prescalers da TAU CCS bTAU_CCS 1 – o clock do canal é derivado da entrada externa do canal (pi no TImn) Nos canais 2, 4 e 6, este bit c onfigura o canal para operação independente ou combinada: 0 – canal operando de forma independente ou como escravo de MASTER bTAU_MASTER outro canal 1 – canal operando como mestre de outros canais * nos canais 0, 5 e 7 este bit deve ser mantido em zero! Nos canais 1 e 3, este bit configura o canal para operar em 8 ou 16 bits: SPLIT bTAU_8BIT 0 – canal operando em 16 bits 1 – canal operando em 8 bits

168 Microcontroladores RL78: Guia Básico

Nome do Bit Descrição Símbolo C Seleção do modo de disparo e de captura do canal: 000 – disparo somente por software TAU_TRIG_SOFT 001 – uma borda válida no pino TImn provoca o disparo e a TAU_TRIG_VALID_EDGE STS2 captura STS1 010 – qualquer transição no pino TImn provoca o disparo e a TAU_TRIG_BOTH_EDGE STS0 captura 100 – disparo e c aptura gerados por um sinal de interrupção do TAU_TRIG_MASTER canal mestre Outras configurações não são permitidas - Seleção da borda válida para entrada no pino TImn: 00 – borda de descida TAU_EDGE_FALLING

CIS1 01 – borda de subida TAU_EDGE_RISING CIS0 10 – ambas as bordas (disparo ocorre na descida, captura na TAU_EDGE_FALL_RISE subida), medição de ciclo inativo TAU_EDGE_BOTH 11 – ambas as bordas (disparo ocorre na subida, captura na TAU_EDGE_RISE_FALL descida), medição de ciclo ativo Seleção do modo de operação do canal da TAU: 0000 – modo de timer de intervalo (não gera interrupção no TAU_MD_TIMER disparo do canal) 0001 – modo de timer de intervalo (gera interrupção no disparo TAU_MD_TIMER_TRIG_INT do canal) 0100 – modo de captura de período de sinal (não gera MD3 TAU_MD_CAPTURE MD2 interrupção no disparo do canal) MD1 0101 – modo de captura de período de sinal (gera interrupção no TAU_MD_CAPTURE_TRIG_INT MD0 disparo do timer) 0110 – modo de contagem de eventos (não gera interrupçã o no TAU_MD_EVENTCOUNT disparo do timer) 1000 – modo de contagem única (não permite re-disparo) TAU_MD_ONECOUNT 1001 – modo de contagem única (re-disparo reinicia a contagem) TAU_MD_ONECOUNT_TRIG 1100 – modo de captura de ciclo ativo/inativo TAU_MD_CAPTURE_LEVEL

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 OVF TSRmn Escrita Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 * m corresponde ao número da TAU (0 ou 1) e n corresponde ao canal (0 a 7) * Os 8 bits menos significativos podem ser acessados através do registrador TSRmnL O bit OVF é setado nos modos de captura quando o contador do canal (TCRmn) estoura a contagem sem que tenha ocorrido uma captura. Ele é automaticamente apagado quando ocorre uma captura sem estouro da contagem do canal.

Periféricos de Temporização 169

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 TEH TEH Leitura 0 0 0 0 0 0 TEm7 TEm6 TEm5 TEm4 TEm3 TEm2 TEm1 TEm0 m3 m1 TEm Escrita ------Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *m corresponde ao número da TAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador TEmL

Nome do Bit Descrição Símbolo C Indicador de operação da parte alta do canal 3 (modo de 8 bits): TEHm3 0 – desabilitado TAU_CH3_8BIT 1 – habilitado Indicador de operação da parte alta do canal 1 (modo de 8 bits): TEHm1 0 – desabilitado TAU_CH1_8BIT 1 – habilitado TEm7 Indicador de operação dos canais 0 a 7 da TAU: TAU_CH7 TEm6 0 – desabilitado TAU_CH6 TEm5 1 – habilitado TAU_CH5 TEm4 TAU_CH4 TEm3 TAU_CH3 TEm2 TAU_CH2 TEm1 TAU_CH1 TEm0 TAU_CH0

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura TSH TSH 0 0 0 0 0 0 TSm7 TSm6 TSm5 TSm4 TSm3 TSm2 TSm1 TSm0 TSm Escrita m3 m1 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *m corresponde ao número da TAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador TSmL Nome do Bit Descrição Símbolo C Controle de disparo da parte alta do canal 3 (modo de 8 bits) TSHm3 0 – sem efeito TAU_CH3_8BIT 1 – inicia contagem (modo timer) Controle de disparo da parte alta do canal 1 (modo de 8 bits) TSHm1 0 – sem efeito TAU_CH1_8BIT 1 – inicia contagem (modo timer) TSm7 Controle de disparo dos canais 0 a 7 da TAU: TAU_CH7 TSm6 0 – sem efeito TAU_CH6 TSm5 1 – inicia a operação conforme o modo selecionado TAU_CH5 TSm4 TAU_CH4 TSm3 TAU_CH3 TSm2 TAU_CH2 TSm1 TAU_CH1 TSm0 TAU_CH0

170 Microcontroladores RL78: Guia Básico

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura TTH TTH 0 0 0 0 0 0 TTm7 TTm6 TTm5 TTm4 TTm3 TTm2 TTm1 TTm0 TTm Escrita m3 m1 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *m corresponde ao número da TAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador TTmL Nome do Bit Descrição Símbolo C Controle de parada da parte alta do canal 3 (modo de 8 bits): TTHm3 0 – sem efeito TAU_CH3_8BIT 1 – para a contagem do canal Controle de parada da parte alta do canal 1 (modo de 8 bits): TTHm1 0 – sem efeito TAU_CH1_8BIT 1 – para a contagem do canal TTm7 Controle de parada dos canais 0 a 7 da TAU: TAU_CH7 TTm6 0 – sem efeito TAU_CH6 TTm5 1 – para a contagem do canal TAU_CH5 TTm4 TAU_CH4 TTm3 TAU_CH3 TTm2 TAU_CH2 TTm1 TAU_CH1 TTm0 TAU_CH0

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 TIS02 TIS01 TIS00 TIS0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Seleção da entrada de clock externo do canal 5 da TAU0: 000 – Pino TI05 TIS_TI05 TIS02 001 – Pino TI05 - TIS01 010 – Pino TI05 - TIS00 011 – Pino TI05 - 100 – Oscilador LOCO (15kHz) TIS_LOCO 101 – Oscilador XT1 TIS_XT1

Periféricos de Temporização 171

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura TOE TOE TOE TOE TOE TOE TOE TOE 0 0 0 0 0 0 0 0 TOEm Escrita m7 m6 m5 m4 m3 m2 m1 m0 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da TAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador TOEmL Nome do Bit Descrição Símbolo C TOEm7 Controle de habilitação das saídas dos canais 0 a 7 da TAU: TAU_CH7 TOEm6 0 – saída desabilitada TAU_CH6 TOEm5 1 – saída habilitada e controlada pelo canal TAU_CH5 TOEm4 TAU_CH4 TOEm3 TAU_CH3 TOEm2 TAU_CH2 TOEm1 TAU_CH1 TOEm0 TAU_CH0

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura TOm TOm TOm TOm TOm TOm TOm TOm 0 0 0 0 0 0 0 0 TOm Escrita 7 6 5 4 3 2 1 0 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da TAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador TOmL Nome do Bit Descrição Símbolo C TOm7 Controle das saídas dos canais 0 a 7 da TAU (somente quando TOEmn = 0): TAU_CH7 TOm6 0 – saída em nível zero TAU_CH6 TOm5 1 – saída em nível um TAU_CH5 TOm4 TAU_CH4 TOm3 TAU_CH3 TOm2 TAU_CH2 TOm1 TAU_CH1 TOm0 TAU_CH0

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura TOL TOL TOL TOL TOL TOL TOL 0 0 0 0 0 0 0 0 0 TOLm Escrita m7 m6 m5 m4 m3 m2 m1 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da TAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador TOLmL Nome do Bit Descrição Símbolo C TOLm7 Controle de polaridade da saída dos canais 0 a 7 da TAU (somente TAU_CH7 TOLm6 quando TOEmn = 1 e com o canal operando como escravo nos modos TAU_CH6 TOLm5 PWM ou pulso único (TOMmn = 0)): TAU_CH5 TOLm4 0 – lógica positiva (ativo em nível um) TAU_CH4 TOLm3 1 – lógica negativa (ativo em nível zero) TAU_CH3 TOLm2 TAU_CH2 TOLm1 TAU_CH1

172 Microcontroladores RL78: Guia Básico

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura TOM TOM TOM TOM TOM TOM TOM 0 0 0 0 0 0 0 0 0 m7 m6 m5 m4 m3 m2 m1 TOMm Escrita Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *m corresponde ao número da TAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador TOMmL Nome do Bit Descrição Símbolo C TOMm7 Seleção do modo de controle do canal (mestre ou escravo). Este TAU_CH7 TOMm6 registrador soment e tem função quando o pino TOmn é controlado pelo TAU_CH6 TOMm5 canal (bit TOEmn = 1). TAU_CH5 TOMm4 0 – modo mestre – a saída do canal é controlada pelo canal mestre TAU_CH4 TOMm3 1 – modo escravo – a saída do canal é setada pelo canal mestre e TAU_CH3 TOMm2 apagada pelo escravo (este canal). O nível lógico da saída depende TAU_CH2 TOMm1 da polaridade selecionada no registrador TOLm TAU_CH1

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 0 ISC1 ISC0 ISC Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Seleção da entrada do canal 7 da TAU0 (apenas nos modelos com 30 pinos ou mais): ISC1 bISC1 0 – entrada via pino TI07 1 – entrada do canal conectada ao RxD2 (para operação LIN) Seleção da entrada de interrupção externa INTP0: ISC0 0 – sinal de interrupção derivado do pino INTP0 bISC0 1 – sinal de interrupção derivado de RxD2 (para operação LIN)

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura TNFEN07 TNFEN06 TNFEN05 TNFEN04 TNFEN03 TNFEN02 TNFEN01 TNFEN00 NFEN1 Escrita Reset 0 0 0 0 0 0 0 0 Leitura TNFEN17 TNFEN16 TNFEN15 TNFEN14 TNFEN13 TNFEN12 TNFEN11 TNFEN10 NFEN2 Escrita Reset 0 0 0 0 0 0 0 0 Estes registradores permitem ativar os filtros de ruído existentes nas entradas dos canais das unidades TAU. Quando ativados (TNFENxx = 1), o sinal de entrada (via pino TImn) precisa estar estável por dois ciclos f CLK para que ele seja detectado pelo timer. Nome do Bit Descrição Símbolo C Controle do filtro de ruído do pino TI17/TO17/P106: TNFEN17 0 – filtro desligado bTNFEN17 1 – filtro ligado

Periféricos de Temporização 173

Nome do Bit Descrição Símbolo C Controle do filtro de ruído do pino TI16/TO16/P105: TNFEN16 0 – filtro desligado bTNFEN16 1 – filtro ligado Controle do filtro de ruído do pino TI15/TO15/P104: TNFEN15 0 – filtro desligado bTNFEN15 1 – filtro ligado Controle do filtro de ruído do pino TI14/TO14/P103: TNFEN14 0 – filtro desligado bTNFEN14 1 – filtro ligado Controle do filtro de ruído do pino TI13/TO13/P67: TNFEN13 0 – filtro desligado bTNFEN13 1 – filtro ligado Controle do filtro de ruído do pino TI12/TO12/P66: TNFEN12 0 – filtro desligado bTNFEN12 1 – filtro ligado Controle do filtro de ruído do pino TI11/TO11/P65: TNFEN11 0 – filtro desligado bTNFEN11 1 – filtro ligado Controle do filtro de ruído do pino TI10/TO10/P64: TNFEN10 0 – filtro desligado bTNFEN10 1 – filtro ligado Controle do filtro de ruído do pino TI07/TO07/P145 ou entrada RxD2/P14 (conforme bit ISC1): TNFEN07 bTNFEN7 0 – filtro desligado 1 – filtro ligado Controle do filtro de ruído do pino TI06/TO06/P102: TNFEN06 0 – filtro desligado bTNFEN6 1 – filtro ligado Controle do filtro de ruído do pino TI05/TO05/P46: TNFEN05 0 – filtro desligado bTNFEN5 1 – filtro ligado Controle do filtro de ruído do pino TI04/TO04/P04: TNFEN04 0 – filtro desligado bTNFEN4 1 – filtro ligado Controle do filtro de ruído do pino TI03/TO03/P31: TNFEN03 0 – filtro desligado bTNFEN3 1 – filtro ligado Controle do filtro de ruído do pino TI02/TO02/P17: TNFEN02 0 – filtro desligado bTNFEN2 1 – filtro ligado Controle do filtro de ruído do pino TI01/TO01/P16: TNFEN01 0 – filtro desligado bTNFEN1 1 – filtro ligado Controle do filtro de ruído do pino TI00/TO00/P00: TNFEN00 0 – filtro desligado bTNFEN0 1 – filtro ligado

174 Microcontroladores RL78: Guia Básico

7.4. Outros Timers

Além dos timers vistos até aqui, alguns modelos de RL78 (como os G14) incluem outros timers com funções especiais: Timer RJ: timer de 16 bits que pode ser utilizado para geração de pulsos, medição de largura e período de pulsos e contagem de eventos externos, ele também pode receber clock do módulo ELC (Event Link Controller). Timer RD: composto por dois timers de 16 bits e capaz de operar a até 64MHz (utilizando o clock interno dos RL78/G14). Possui dois grupos de 4 canais que podem ser utilizados no modo temporizador, captura de sinais (medição de período), comparação (geração de sinais periódicos) e diversos modos PWM para controle de motores (até 6 canais com dead time e modulação). Timer RG: timer de 16 bits com duas entradas e dois pinos de E/S (para captura, comparação ou PWM). Este timer inclui um modo especial para decodificação de encoders bifásicos.

Periféricos de Temporização 175

176 Microcontroladores RL78: Guia Básico

8

Periféricos Analógicos 8. Periféricos de Analógicos

O conversor A/D (Analógico/Digital) ou simplesmente ADC, é o dispositivo eletrônico que permite ao microcontrolador realizar a leitura de sinais do mundo analógico, em especial tensões, provenientes das mais variadas fontes: sensores, transdutores, etc. Na área de microcontroladores, encontramos chips com conversor integrado e outros que dependem de conversores externos. Nos modelos que possuem conversor integrado, eles apresentam resoluções típicas de 10 bits (alguns modelos possuem conversores mais simples, de 8 bits, enquanto outros possuem conversores de maior precisão, com 12 ou 16 bits). Neste capítulo iremos conhecer o conversor A/D integrado aos RL78/G13. Este conversor possui uma resolução de 10 bits (podendo também operar com apenas 8 bits) e pode ser encontrado em todos os modelos das linhas RL78/G10, G12, G13 e G14, desde os modelos menores, com apenas 10 pinos, até os maiores, com 128 pinos.

8.1. Detalhes Gerais do Conversor A/D

O conversor A/D ou simplesmente ADC dos RL78 é do tipo SAR, o que significa que ele utiliza um registrador de aproximações sucessivas para fazer a conversão de grandezas analógicas para grandezas digitais. Não vamos discutir neste livro a operação do conversor SAR (que é bastante simples), basta dizer que ele é substancialmente mais rápido que outros tipos de conversores, como o de rampa digital, garantindo ótima velocidade e baixo custo. Como já foi dito, o conversor A/D dos RL78 pode operar com 8 ou 10 bits de resolução, ou seja, para um sinal de entrada na faixa de 0 a 5V, com uma resolução de 10 bits, cada bit irá representar uma tensão de cerca de 4,88mV ou 19,53mV no caso de uma resolução de 8 bits. O ADC é composto por diversos blocos: • Seletor analógico: responsável por selecionar um dos canais (pinos ou referências internas) a ser convertido pelo ADC; • Circuito de amostragem e retenção: responsável por armazenar (num pequeno capacitor) a tensão a ser medida, de forma a garantir que ela não mude durante a conversão; • Comparador analógico: responsável por comparar a tensão desconhecida a ser convertida com a tensão proveniente do SAR/DAC, gerando uma saída de erro que alimenta o SAR;

Periféricos Analógicos 177

• DAC: converte a saída digital do SAR em uma tensão analógica que pode ser comparada com a tensão desconhecida no comparador analógico; • SAR: o “cérebro” do conversor, responsável pelo algoritmo de aproximação que, utilizando a realimentação do comparador analógico, permite ao mesmo convergir digitalmente para o valor da tensão desconhecida. Note que apesar do conversor possuir diversos canais de entrada, somente um deles pode ser selecionado, amostrado e convertido num dado instante. Isto significa que não é possível realizar múltiplas conversões simultaneamente. Os procedimentos para operação do ADC são bastante simples. Em primeiro lugar é necessário ativar o conversor, o que é feito através do já conhecido registrador PER0: Nome Bits 7 6 5 4 3 2 1 0 Leitura RTCEN IICA1EN ADCEN IICA0EN SAU1EN SAU0EN TAU1EN TAU0EN PER0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Bit C Símbolo C Controle de clock e operação do conversor analógico/digital: ADCEN ADCEN bADCEN 0 – ADC desativado 1 – ADC ativado Uma vez ativado o conversor, a aplicação deve configurar os pinos que serão utilizados pelo ADC para operar como entradas no modo analógico. A configuração dos pinos como entrada é feita nos registradores PMx, ao passo que a seleção do modo analógico é feita através dos registradores ADPC (para as entradas ANI0 a ANI14) e PMCx (para as entradas ANI16 a ANI26). Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 ADPC3 ADPC2 ADPC1 ADPC0 ADPC Escrita Reset 0 0 0 0 0 0 0 0

Valor em ADPC ANI7/P27 ANI7/P27 ANI6/P26 ANI5/P25 ANI4/P24 ANI3/P23 ANI2/P22 ANI1/P21 ANI0/P20 ANI9/P151 ANI9/P151 ANI8/P150 ANI14/P156 ANI14/P156 ANI13/P155 ANI12/P154 ANI11/P153 ANI10/P152

0 A A A A A A A A A A A A A A A 1 D D D D D D D D D D D D D D D 2 D D D D D D D D D D D D D D A 3 D D D D D D D D D D D D D A A 4 D D D D D D D D D D D D A A A 5 D D D D D D D D D D D A A A A 6 D D D D D D D D D D A A A A A 7 D D D D D D D D D A A A A A A 8 D D D D D D D D A A A A A A A 9 D D D D D D D A A A A A A A A 10 D D D D D D A A A A A A A A A

178 Microcontroladores RL78: Guia Básico

Valor em ADPC ANI7/P27 ANI7/P27 ANI6/P26 ANI5/P25 ANI4/P24 ANI3/P23 ANI2/P22 ANI1/P21 ANI0/P20 ANI9/P151 ANI9/P151 ANI8/P150 ANI14/P156 ANI14/P156 ANI13/P155 ANI12/P154 ANI11/P153 ANI10/P152

11 D D D D D A A A A A A A A A A 12 D D D D A A A A A A A A A A A 13 D D D A A A A A A A A A A A A 14 D D A A A A A A A A A A A A A 15 D A A A A A A A A A A A A A A Tabela 8.1

As entradas ANI16 a ANI26 são controlados pelos registradores PMCx, conforme a tabela a seguir. Note que os demais bits dos registradores não estão implementados e devem ser mantidos em 1. Além disso, os registradores PMCx são carregados com o valor 0xFF após um reset.

Encapsulamento Bits Implementados (número de pinos) Porta 14 Porta 12 Porta 11 Porta 10 Porta 3 Porta 0 PMC00 20 a 25 PMC147 - - - - PMC01 PMC00 30 a 32 PMC147 PMC120 - - - PMC01 36 a 48 PMC147 PMC120 - - - - PMC02 52 a 64 PMC147 PMC120 - - - PMC03 PMC02 80 a 100 PMC147 PMC120 - PMC100 - PMC03 PMC115 PMC35 PMC02 128 PMC147 PMC120 PMC116 PMC100 PMC36 PMC03 PMC117 PMC37 Tabela 8.2

A tabela a seguir relaciona os pinos com as entradas analógicas do conversor A/D. Canal Pino Canal Pino 0 P20/AV REFP 13 P155 1 P21/AV REFM 14 P156 2 P22 16 P03 *1 3 P23 17 P02 *2 4 P24 18 P147 5 P25 19 P120 6 P26 20 P100 7 P27 21 P37 8 P150 22 P36 9 P151 23 P35 10 P152 24 P117 11 P153 25 P116 12 P154 26 P115 *1 Nos chips com 32 pinos ou menos, este canal está conectado ao pino P01 *2 Nos chips com 32 pinos ou menos, este canal está conectado ao pino P00 Tabela 8.3

Periféricos Analógicos 179

Depois de configurados os pinos de E/S para operação como entradas analógicas, a aplicação deve configurar o conversor A/D através dos seus três registradores de controle: ADM0, ADM1 e ADM2. O registrador ADM0 configura o clock do conversor, habilitação e início de conversão, além do modo de operação (um canal ou uma varredura de quatro canais). O bit ADCE controla a atividade do comparador analógico de tensão dentro do conversor, quando este bit está setado, o comparador está ligado e o conversor pode realizar uma conversão, quando ADCE=0 o conversor está desativado. A seleção do clock do conversor é feita através dos bits FR2, FR1 e FR0, eles controlam o fator de divisão aplicado ao sinal de clock global fCLK (que, conforme já vimos no tópico 4.2, pode ser derivado do oscilador interno, do oscilador X1 ou do oscilador XT1) e que origina o sinal de clock do A/D, chamado de fAD . A tabela a seguir mostra as configurações possíveis para os bits FRx.

FR2 FR1 FR0 Clock do ADC (f AD ) Tempo de atraso (f CLK ) Símbolo C (myRL78.h) 0 0 0 fclk/64 63 ADCLK_DIV64 0 0 1 fclk/32 31 ADCLK_DIV32 0 1 0 fclk/16 15 ADCLK_DIV16 0 1 1 fclk/8 7 ADCLK_DIV8 1 0 0 fclk/6 5 ADCLK_DIV6 1 0 1 fclk/5 4 ADCLK_DIV5 1 1 0 fclk/4 3 ADCLK_DIV4 1 1 1 fclk/2 1 ADCLK_DIV2 Tabela 8.4

Observe que a tabela mostra também uma coluna “Tempo de atraso”, este tempo é utilizado em alguns modos de disparo do conversor, conforme será detalhado mais adiante. Um ciclo de conversão A/D é iniciado quando o conversor recebe um sinal de disparo. Existem duas fontes de disparo para iniciar uma conversão: um comando de software ou um sinal de interrupção derivado do hardware (interrupção do canal 1 da TAU0, interrupção do RTC ou interrupção do timer de intervalo). Após o atraso mencionado o conversor inicia a amostragem do sinal, ou seja, a tensão analógica a ser medida é conectada ao capacitor de amostragem do conversor, que irá se carregar até os níveis serem equalizados. O período de amostragem pode ser de 5 ou 7 ciclos de clock f AD conforme a configuração dos bits LV1 e LV0 (registrador ADM0). Tempo de Tempo Total FR2 FR1 FR0 LV1, LV0 f Amostragem Conversão AD Estabilização de Conversão 0 0 0 fclk/64 1344/fclk 0 0 1 fclk/32 672/fclk 0 1 0 fclk/16 336/fclk 0 1 1 fclk/8 168/fclk 00 2 f 7 f 12 f 1 0 0 fclk/6 AD AD AD 126/fclk 1 0 1 fclk/5 105/fclk 1 1 0 fclk/4 84/fclk 1 1 1 fclk/2 42/fclk Tabela 8.5

180 Microcontroladores RL78: Guia Básico

Tempo de Tempo Total FR2 FR1 FR0 LV1, LV0 f Amostragem Conversão AD Estabilização de Conversão 0 0 0 fclk/64 1728/fclk 0 0 1 fclk/32 864/fclk 0 1 0 fclk/16 432/fclk 0 1 1 fclk/8 216/fclk 00 8 f 7 f 12 f 1 0 0 fclk/6 AD AD AD 162/fclk 1 0 1 fclk/5 135/fclk 1 1 0 fclk/4 108/fclk 1 1 1 fclk/2 54/fclk 0 0 0 fclk/64 1216/fclk 0 0 1 fclk/32 608/fclk 0 1 0 fclk/16 304/fclk 0 1 1 fclk/8 152/fclk 01 2 f 5 f 12 f 1 0 0 fclk/6 AD AD AD 114/fclk 1 0 1 fclk/5 96/fclk 1 1 0 fclk/4 76/fclk 1 1 1 fclk/2 38/fclk 0 0 0 fclk/64 1600/fclk 0 0 1 fclk/32 800/fclk 0 1 0 fclk/16 400/fclk 0 1 1 fclk/8 200/fclk 01 8 f 5 f 12 f 1 0 0 fclk/6 AD AD AD 150/fclk 1 0 1 fclk/5 125/fclk 1 1 0 fclk/4 100/fclk 1 1 1 fclk/2 50/fclk 0 0 0 fclk/64 1216/fclk 0 0 1 fclk/32 608/fclk 0 1 0 fclk/16 304/fclk 0 1 1 fclk/8 152/fclk 10 - 7 f 12 f 1 0 0 fclk/6 AD AD 114/fclk 1 0 1 fclk/5 96/fclk 1 1 0 fclk/4 76/fclk 1 1 1 fclk/2 38/fclk 0 0 0 fclk/64 1088/fclk 0 0 1 fclk/32 544/fclk 0 1 0 fclk/16 272/fclk 0 1 1 fclk/8 136/fclk 11 - 5 f 12 f 1 0 0 fclk/6 AD AD 102/fclk 1 0 1 fclk/5 85/fclk 1 1 0 fclk/4 68/fclk 1 1 1 fclk/2 34/fclk Tabela 8.6

Após a amostragem do sinal, o capacitor de amostragem é desconectado do sinal a ser medido e conectado ao conversor e o processo de conversão A/D propriamente dito tem início. A conversão necessita de 10 ciclos f AD (para uma resolução de 8 bits) ou 12 ciclos (para uma resolução de 10 bits) para ser completada. A seleção da resolução é feita por meio do bit ADTYP (registrador ADM2): quando ADTYP=0, o conversor opera com 10 bits, quando ADTYP=1, o conversor opera com 8 bits. O tempo total necessário para completar uma conversão pode ser determinado pela seguinte fórmula:

Periféricos Analógicos 181

TTOTAL _ CONV = TATRASO + TESTAB + TAMOSTRAGEM + TCONVERSÃO Onde:

TATRASO é o tempo de atraso conforme a tabela 8.4 (válido para disparo por software e para o disparo por hardware sem atraso, no caso do disparo por hardware com atraso, este tempo é igual a um ciclo). Este atraso é medido em ciclos f CLK .

TESTAB é o tempo de estabilização. Ele pode ser de 2 ou 8 ciclos f AD no modo de disparo por hardware com atraso. Nos modos de disparo por software e disparo por hardware sem atraso, o tempo de estabilização é igual a 0.

TAMOSTRAGEM é o tempo de amostragem (5 ou 7 ciclos f AD ) conforme mostra as tabelas 8.5 e 8.6.

TCONVERSÃO é o tempo de conversão SAR (10 ciclos f AD para 8 bits ou 12 ciclos f AD para 10 bits).

Os tempos T ATRASO e T ESTAB são utilizados na primeira conversão após um sinal de disparo. i Quando se utiliza o modo de varredura ou o modo de conversões múltiplas, estes tempos são utilizados apenas na primeira conversão, mas não nas posteriores.

Completada a conversão, o resultado é comparado com os registradores de comparação digital ADUL (valor limite superior) e ADLL (valor limite inferior). A operação do comparador digital é controlada pelo bit ADRCK (registrador ADM2). Quando ADRCK=0, o comparador gera uma interrupção INTAD e atualiza o registrador ADCR quando o resultado da conversão (8 bits mais significativos) é menor ou igual ao valor do registrador ADUL e maior ou igual ao valor do registrador ADLL, ou seja, dentro da faixa entre ADLL e ADUL. Quando ADRCK=1, o comparador gera uma interrupção INTAD e atualiza o registrador ADCR quando o resultado da conversão (8 bits mais significativos) é maior que ao valor do registrador ADUL ou menor que valor do registrador ADLL, ou seja, fora da faixa entre ADLL e ADUL.

O comparador digital efetua uma comparação de 8 bits! Quando o conversor opera com i resolução de 10 bits a comparação é efetuada apenas com os 8 bits superiores do resultado.

Quando o conversor opera em modo de 8 bits, o resultado da conversão pode ser lido no registrador de 8 bits ADCRH. Quando o conversor opera no modo de 10 bits, o resultado da conversão deve ser lido no registrador de 16 bits ADCR. Neste caso, o resultado é alinhado à esquerda e os 6 bits menos significativos são mantidos em zero (para obter o resultado real basta dividir o conteúdo do ADCR por 64). O resultado da conversão poderá ser calculado através da seguinte equação (é considerada uma resolução de 10 bits, no caso de 8 bits, basta substituir o valor 1024 por 256 na equação):    VAIN − AV REFM  RESULTADO 10 BITS = INT  *1024 + 5,0   AV REFP − AV REFM 

Onde: V AIN é a tensão analógica de entrada, AV REFP é a tensão de referência positiva e AV REFP é a tensão de referência negativa. INT consiste na função matemática que retorna a parte inteira do argumento (a parte fracionária é desprezada).

182 Microcontroladores RL78: Guia Básico

A seleção da referência positiva do conversor é feita através dos bits ADREFP1 e ADREFP0 (registrador ADM2) conforme a tabela a seguir. ADREFP1 ADREFP0 Referência Positiva Símbolo C (myRL78.h)

0 0 Alimentação positiva (V DD ) ADC_REFP_VDD 0 1 Entrada ANI0 ADC_REFP_PIN 1 0 Referência interna de 1,45V ADC_REFP_INT * o símbolo ADC_REFP_VDD pode ser omitido já que equivale ao valor 0. Tabela 8.7

i A tensão de referência positiva externa não pode ser inferior a 1,6V e nem superior a tensão de alimentação do chip (V DD )!

A seleção da tensão de referência negativa é feita por meio do bit ADREFM do registrador ADM2: quando ADREFM=0, a referência negativa é o pino V SS (0V) e quando ADREFM=1, a referência negativa é obtida por uma tensão analógica externa fornecida através da entrada ANI1. Lembre-se de que a referência negativa não pode ser menor que V SS . Caso a interrupção do ADC esteja habilitada (ADMK = 0) e as interrupções globais estejam habilitadas (IE=1), o sinal de interrupção INTAD provocará o desvio do programa para o vetor de interrupção do ADC (INTAD_vect).

8.2. Modos de Operação

Neste tópico veremos os diversos modos de operação disponíveis no conversor A/D dos RL78. O modo de operação está relacionado a três configurações básicas: 1. Conversão simples ou múltipla; 2. Conversão de um canal ou varredura de canais; 3. Tipo de disparo: por software e por hardware com ou sem atraso.

8.2.1. Conversão Simples ou Múltipla Esta configuração de operação do A/D determina se após um disparo o conversor vai realizar uma única conversão (one-shot na terminologia do fabricante) ou iniciar conversões sucessivas. Esta facilidade é controlada pelo bit ADSCM no registrador ADM1: quando ADSCM=1, ao receber um sinal de disparo o conversor realiza apenas uma conversão e após completada ele aguarda um novo disparo. Quando ADSCM=0, ao receber um sinal de disparo o conversor inicia uma nova conversão e após ela ser completada outra conversão é automaticamente iniciada, neste caso ele permanecerá fazendo conversões indefinidamente até que o software determine a sua parada (escrevendo 0 no bit ADSC).

Periféricos Analógicos 183

8.2.2. Conversão de Um Canal ou Varredura de Canais O conversor A/D dos RL78 inclui a facilidade de efetuar a varredura automática de canais (scan na terminologia do fabricante), ou seja, o conversor efetua 4 conversões em sequência, iniciando do canal especificado pelo programador (através do registrador ADS) e continuando pelos 3 canais seguintes. Desta forma, após um único sinal de disparo, o conversor irá realizar quatro conversões completas em quatro canais sequenciais. Caso o modo de múltiplas conversões esteja habilitado (ADSCM=0), após completar uma varredura dos quatro canais o conversor reiniciará um novo ciclo (com os mesmos quatro canais) e permanecerá repetindo a varredura até que seja desativado pelo software (pela escrita de 0 no bit ADSC). Esta facilidade é configurada pelo bit ADMD no registrador ADM0: quando ADMD=0, o conversor A/D opera no modo de canal único, ou seja, após um disparo é feita uma conversão (ou sucessivas se o bit ADSCM=0) do canal selecionado pelo registrador ADS. Quando ADMD=1, o conversor opera no modo de varredura de canais.

Atenção: no modo de varredura não é permitido selecionar canais superiores ao décimo i primeiro!

Como não há uma forma de identificar qual canal foi convertido num determinado instante, ao utilizar o modo de varredura é interessante configurar o bit ADRCK=0 (registrador O ADM2), ADLL=0 e ADUL=0xFF, desta forma garante-se que todas as quatro conversões irão gerar interrupções, permitindo que o software possa rastreá-las corretamente!

8.2.3. Formas de Disparo do Conversor Uma vez que o conversor esteja devidamente configurado e o canal a ser convertido tenha sido selecionado no registrador ADS, ele permanecerá em standby, aguardando um sinal de disparo para que a conversão seja efetivamente iniciada. Como já foi dito anteriormente, uma conversão pode ser disparada de duas formas distintas: pelo software ou pelo hardware. Além disso, um disparo por hardware pode incluir ou não um tempo de atraso para estabilização do sinal. A seleção do tipo de disparo é feita através dos bits ADTMD1 e ADTMD0 localizados no registrador ADM1. A tabela 8.8 mostra as configurações possíveis. ADTMD1 ADTMD0 Fonte de Disparo Símbolo C (myRL78.h) 0 0 Software ADC_TRIG_SOFT 0 1 Software - 1 0 Hardware (sem atraso) ADC_TRIG_HARD_NO_WAIT 1 1 Hardware (com atraso) ADC_TRIG_HARD_WAIT * o símbolo ADC_TRIG_SOFT pode ser omitido já que equivale ao valor 0. Tabela 8.8

Atenção: é necessário aguardar um tempo de no mínimo 1µs entre a habilitação inicial do i conversor (ADCE=1) e o disparo da conversão. Este tempo é necessário para a estabilização do circuito do conversor.

184 Microcontroladores RL78: Guia Básico

8.2.3.1. Disparo por Software

Quando o conversor está configurado para disparo por software (bit ADTMD1=0 no registrador ADM1), uma nova conversão tem início sempre que o bit ADCS (registrador ADM0) é setado pelo programa. Após setado o bit ADCS o conversor irá aguardar um tempo de atraso de 1 a 63 ciclos de clock f CLK . Este tempo é selecionado de acordo com a configuração dos bits FR2, FR1 e FR0 (registrador ADM0) conforme mostra a tabela 8.4. Nos modos de múltiplas conversões e de varredura, o tempo de atraso é utilizado somente na primeira conversão. Completada a conversão, o bit ADCS é automaticamente apagado pelo hardware (exceto quando o modo de múltiplas conversões está selecionado, neste caso ADCS permanece setado).

Redisparar o conversor ou selecionar outro canal no registrador ADS enquanto uma i conversão está em andamento, faz com que a conversão atual seja descartada e uma nova conversão seja iniciada!

8.2.3.2. Disparo por Hardware

É possível configurar o conversor para iniciar uma conversão após receber um sinal de disparo proveniente do hardware. A seleção do módulo de hardware responsável por disparar o conversor é feita pelos bits ADTRS1 e ADTRS0 (registrador ADM1). A tabela 8.8 mostra as configurações possíveis. ADTRS1 ADTRS0 Fonte de Disparo Símbolo C (myRL78.h) 0 0 Canal 1 da TAU0 ADC_TRIG_TAU 1 0 RTC ADC_TRIG_RTC 1 1 Timer de Intervalo (IT) ADC_TRIG_IT * o símbolo ADC_TRIG_TAU pode ser omitido já que equivale ao valor 0. Tabela 8.9 O disparo pela TAU pode ser utilizado para sincronizar as conversões A/D com a geração de sinais (PWM, por exemplo), ou para obter taxas taxas de amostragem específicas. O RTC e o IT podem ser utilizados para disparar conversões quando o microcontrolador está em modo halt, stop ou snooze. Desta forma o sistema pode permanecer em modo de baixo consumo e ainda assim realizar conversões A/D periodicamente. Podemos citar como exemplo de aplicação a amostragem periódica de sensores em sistemas movidos à bateria. O disparo por hardware pode incluir ou não um tempo de estabilização. O modo ADC_TRIG_HARD_WAIT inclui um tempo de estabilização de 2 ou 8 ciclos fAD antes do início da conversão. No modo ADC_TRIG_HARD_NO_WAIT o conversor não utiliza tempo de estabilização, mas antes da conversão ele aguarda o tempo de atraso da mesma forma que no disparo por software. Este tempo é determinado pelos bits FR2, FR1 e FR0 (registrador ADM0) conforme mostra a tabela 8.4.

Periféricos Analógicos 185

Os tempos de estabilização e de atraso são utilizados na primeira conversão após um sinal i de disparo. Quando se utiliza o modo de varredura ou o modo de conversões múltiplas, estes tempos são utilizados apenas na primeira conversão, mas não nas posteriores.

8.3. Referência Interna de Tensão

Um dos canais do conversor A/D dos RL78 está conectado a uma referência interna de tensão com valor típico de saída de 1,45V. Esta referência interna pode ser utilizada para calibrar o conversor e permite também a medição indireta da tensão de alimentação do chip.

A medição indireta do V DD é possível porque a conversão A/D depende da tensão de referência positiva e, quando utilizamos V DD como referência positiva, a conversão torna-se dependente da tensão de alimentação. Por exemplo, se considerarmos que a tensão de alimentação é igual a 5V teremos:

 45,1  RES = INT  *1024 + 5,0  = 297 REF INT_  5 

Se a tensão V DD variar para 4,95V o resultado da conversão da tensão da referência interna será igual a:

 45,1  RES REF INT_ = INT  *1024 + 5,0  = 300  95,4 

A fórmula a seguir mostra como calcular V DD a partir do valor medido para a referência interna de tensão. *45,1 1024 V = DD RES Para selecionar a referência interna como o canal de entrada do conversor é necessário configurar o registrador ADS com o valor 0x81 (símbolo ADC_CH_REF no arquivo myRL78.c).

Após selecionar a referência interna como entrada do conversor, o resultado da primeira i conversão deve ser descartado, apenas os resultados seguintes devem ser utilizados pela aplicação!

8.4. Sensor de Temperatura

Os microcontroladores RL78 incluem um sensor interno de temperatura que pode ser lido através do conversor A/D. Este sensor apresenta uma tensão típica de 1,05V quando submetido a uma temperatura de 25 oC, apresenta um coeficiente de temperatura de -3,6mV/ oC e uma precisão de aproximadamente ±3 oC quando calibrado.

186 Microcontroladores RL78: Guia Básico

A tensão de saída (em Volts) para uma temperatura T pode ser calculada através da seguinte fórmula:

VSENSOR = 05,1 + T( − − mV6,3*)25 Isto significa que o sensor apresentará uma tensão de saída de 1,14V quando submetido a uma temperatura de 0 oC e 780mV quando submetido a uma temperatura de 100oC.

Lembre-se de que os RL78 com faixa de temperatura comercial podem operar entre -40 e i +85ºC ao passo que os modelos com faixa de temperatura industrial podem chegar a 105ºC!

A temperatura do sensor (em oC) pode ser calculada através da seguinte fórmula: ADCR V* DD −1075 2, Temperatur a = 25 − 64 6864,3 Para selecionar o sensor de temperatura como o canal de entrada do conversor é necessário configurar o registrador ADS com o valor 0x80 (símbolo ADC_CH_TEMP no arquivo myRL78.c).

Após selecionar o sensor de temperatura como entrada do conversor, o resultado da i primeira conversão deve ser descartado, apenas os resultados seguintes devem ser utilizados pela aplicação!

8.5. Operação em Modo Snooze

O conversor A/D pode operar em modo snooze, realizando conversões periódicas enquanto a CPU e o restante do microcontrolador permanecem em modo stop. Para isso, é necessário utilizar o disparo por hardware em modo de conversão simples (one-shot) e selecionar o RTC ou timer de intervalo como fonte do disparo. Lembre-se de que o periférico selecionado deverá estar configurado para operar no modo stop! Também é necessário setar o bit AWC (registrador ADM2) para que o conversor possa operar em modo snooze.

Atenção: o bit AWC deve ser setado apenas antes da entrada no modo stop, esta operação deve ser feita com o conversor desabilitado (ADCE=0). Ao sair do modo stop e retornar ao i modo run a aplicação deve apagar o bit AWC. Caso o bit AWC permaneça setado durante a operação normal do conversor, as conversões podem não ser iniciadas corretamente.

A operação neste modo requer também que o oscilador HOCO seja selecionado como fonte de clock da CPU e periféricos. O modo snooze não deve ser utilizado se outro oscilador estiver operando como fonte de clock para a CPU e periféricos. Existem algumas vantagens na utilização do modo snooze na operação do conversor A/D, em especial podemos destacar a redução do consumo de energia e o aumento da precisão do conversor.

Periféricos Analógicos 187

A redução de consumo ocorre porque, ao utilizar as facilidades do comparador digital, é possível programar o ADC para somente “acordar” a CPU quando a tensão medida ultrapasse um determinado limite especificado pelos registradores ADUL e ADLL. Neste caso, a interrupção do ADC pode ser utilizada para provocar a saída do modo snooze e o retorno ao modo ativo, permitindo que a aplicação faça o processamento do resultado da conversão. O aumento da precisão decorre do fato de que quando o chip está em modo snooze, a grande maioria dos seus circuitos internos está parada, reduzindo o ruído elétrico dentro do chip. Esta redução de ruído permite obter leituras mais confiáveis.

8.6. Registradores do ADC

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura ADCS ADMD FR2 FR1 FR0 LV1 LV0 ADCE ADM0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Bit C Símbolo C Controle de operação do conversor A/D: Numa operação de escrita: 0 – para a conversão ADCS 1 – habilita a conversão ADCS bADCS Numa operação de leitura: 0 – conversão parada 1 – conversão em andamento Modo de conversão: ADMD 0 – um canal - bADMD 1 – sequência de canais Seleção do clock do conversor e tempo de início de conversão

(T IC ):

000 – f CLK /64 – T IC = 63 f CLK - ADCLK_DIV64

001 – f CLK /32 – T IC = 31 f CLK - ADCLK_DIV32

FR2 010 – f CLK /16 – T IC = 15 f CLK - ADCLK_DIV16 FR1 FR0 011 – f CLK /8 – T IC = 7 f CLK - ADCLK_DIV8 100 – f CLK /6 – T IC = 5 f CLK - ADCLK_DIV6

101 – f CLK /5 – T IC = 4 f CLK - ADCLK_DIV5

110 – f CLK /4 – T IC = 3 f CLK - ADCLK_DIV4

111 – f CLK /2 – T IC = 1 f CLK - ADCLK_DIV2 ADC_LV0 LV1 ADC_LV1 Seleção do tempo de estabilização (vide tabelas 8.5 e 8.6) - LV0 ADC_LV2 ADC_LV3 Controle do comparador de tensão do ADC: ADCE 0 – desativa o comparador analógico ADCE bADCE 1 – ativa o comparador analógico

188 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura ADTMD1 ADTMD0 ADSCM 0 0 0 ADTRS1 ADTRS0 ADM1 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Seleção do modo de disparo do conversor A/D: ADTMD1 00, 01 – disparo por software (bit ADCS) ADC_TRIG_SOFT ADTMD0 10 – disparo por hardware (sem tempo de estabilização) ADC_TRIG_HARD_NO_WAIT 11 – disparo por hardware (com tempo de estabilização) ADC_TRIG_HARD_WAIT Modo de conversão: ADSCM 0 – conversões sequenciais bADSCM 1 – conversão única Seleção da fonte de disparo por hardware: ADTRS1 00 – interrupção do canal 1 da TAU0 ADC_TRIG_TAU ADTRS0 10 – interrupção do RTC ADC_TRIG_RTC 11 – interrupção do timer de intervalo (IT) ADC_TRIG_IT

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura ADREFP1 ADREFP0 ADREFM 0 ADRCK AWC 0 ADTYP ADM2 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Seleção da referência positiva do conversor:

ADREFP1 00 – V REF+ proveniente do V DD ADC_REFP_VDD ADREFP0 01 – V REF+ proveniente da entrada ANI0 ADC_REFP_PIN

10 – V REF+ proveniente da referência interna de 1,45V ADC_REFP_INT Seleção da referência negativa do conversor: ADREFM bADREFM 0 – pino VSS 1 – pino P21/ANI1 Checagem de limites do resultado da conversão: 0 – A interrupção INTAD é disparada quando o resultado da ADRCK conversão está dentro da faixa entre ADLL e ADUL bADRCK 1 – A interrupção INTAD é disparada quando o resultado da conversão é menor que ADLL ou maior que ADUL Habilitação de operação do conversor no modo snooze: AWC 0 – ADC não opera no modo snooze ADC_SNOOZE_ENABLE 1 – ADC pode operar no modo snooze Número de bits do resultado da conversão: ADTYP 0 – 10 bits ADC_8BIT 1 – 8 bits

Periféricos Analógicos 189

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura ADISS 0 0 ADS4 ADS3 ADS2 ADS1 ADS0 ADS Escrita Reset 0 0 0 0 0 0 0 0 Este registrador seleciona o canal a ser convertido no próximo disparo do conversor: Canal selecionado Símbolo C Canal selecionado Símbolo C ANI0/P20 ADC_CH0 ANI14/P156 ADC_CH14 ANI1/P21 ADC_CH1 ANI16/P03 ADC_CH16 ANI2/P22 ADC_CH2 ANI17/P02 ADC_CH17 ANI3/P23 ADC_CH3 ANI18/P147 ADC_CH18 ANI4/P24 ADC_CH4 ANI19/P120 ADC_CH19 ANI5/P25 ADC_CH5 ANI20/P100 ADC_CH20 ANI6/P26 ADC_CH6 ANI21/P37 ADC_CH21 ANI7/P27 ADC_CH7 ANI22/P36 ADC_CH22 ANI8/P150 ADC_CH8 ANI23/P35 ADC_CH23 ANI9/P151 ADC_CH9 ANI24/P117 ADC_CH24 ANI10/P152 ADC_CH10 ANI25/P116 ADC_CH25 ANI11/P153 ADC_CH11 ANI26/P115 ADC_CH26 ANI12/P154 ADC_CH12 Sensor de temperatura ADC_CH_TEMP ANI13/P155 ADC_CH13 Referência interna de 1,45V ADC_CH_REF * Os canais 15 (0x0F) e 27 em diante (0x1B e acima) não são permitidos

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura Resultado da conversão 0 0 0 0 0 0 ADCR Escrita - Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Este registrador armazena o resultado da conversão (desde que ela esteja dentro da faixa programada nos registradores de comparação). Quando o conversor opera no modo de 8 bits (ADTYP = 1), o resultado da conversão pode ser lido no registrador ADCRH. Neste caso, a leitura do registrador ADCR irá retornar o resultado de 8 bits no byte superior, com os 8 bits inferiores mantidos em zero.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura Limiar superior do comparador digital ADUL Escrita Reset 1 1 1 1 1 1 1 1 Leitura Limiar inferior do comparador digital ADLL Escrita Reset 0 0 0 0 0 0 0 0

Os registradores ADUL e ADLL armazenam os limiares de comparação do circuito comparador digital do conversor A/D. Quando ADRCK=0, a interrupção INTAD é disparada quando o resultado da conversão está dentro da faixa entre ADLL e ADUL (inclusive). Quando ADRCK=1, a interrupção INTAD é disparada quando o resultado da conversão é menor que ADLL ou maior que ADUL.

190 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 0 ADTES1 ADTES0 ADTES Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Modo de teste do conversor A/D: ADTES1 00 – Teste desativado ADC_TEST_OFF ADTES0 10 – Converte a entrada AV REFM ADC_TEST_REFM

11 – Converte a entrada AV REFP ADC_TEST_REFP

8.7. Exemplo

O exemplo a seguir demonstra a operação do conversor A/D do RL78/G13. O programa monitora a tensão do cursor do trimpot R15 da placa YRPBRL78G13, ligando o led quando o valor lido no ADC é maior que 511 (o equivalente a aproximadamente 2,5V). #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED P7_bit.no7

#pragma vector = INTAD_vect __interrupt void trata_ADC(void) { unsigned int result; result = ADCR >> 6; // lê o resultado da conversão if (result>511) LED = 0; else LED = 1; }

void main(void) { PM7_bit.no7 = 0; // pino P77 como saída LED = 0; // apaga o led

Periféricos Analógicos 191

ADPC = 4; // pinos P20, P21 e P22 no modo analógico ADCEN = 1; // habilita o ADC // Configura o ADC (conversões múltiplas, um canal, disparo por software) ADM0 = ADCLK_DIV64 | ADC_LV0 | bADCE; ADM1 = ADC_TRIG_SOFT; ADS = ADC_CH2; // seleciona o canal 2 ADMK = 0; // habilita interrupção do ADC __enable_interrupt(); // habilita as interrupções do RL78 ADCS = 1; // inicia uma conversão while (1); } Exemplo 8.1

8.8. Outros Periféricos Disponíveis

Algumas linhas de RL78 possuem outros periféricos analógicos que substituem ou coexistem com o conversor A/D de 10 bits apresentado neste capítulo. A seguir mostramos alguns destes periféricos.

8.8.1. Comparador Analógico Os microcontroladores da linha G14 incluem dois comparadores analógicos que podem ser utilizados para comparar tensões analógicas externas ou fazer comparação de tensões externas com a referência interna de 1,45V. Estes comparadores possuem também filtros digitais em suas saídas, que podem ser utilizados para reduzir ruídos de saída. O sinal de saída dos comparadores pode ser disponibilizado em pinos de E/S, pode gerar interrupção e também alimentar o módulo ELC (Event Link Controller).

8.8.2. Conversor A/D de 12 bits Os microcontroladores RL78/G1A possuem um conversor A/D de 12 bits ao invés do conversor de 10 bits mostrado neste capítulo, mas que opera de forma muito similar ao mostrado neste livro. As diferenças básicas residem no fato de que o bit ADTYP (registrador ADM2) seleciona entre o modo de 12 bits (ADTYP=0) e o modo de 8 bits (ADTYP=1). Além disso, o registrador de resultado da conversão (ADCR) é alinhado à direita ao invés da esquerda como mostrado neste livro. Para maiores detalhes, consulte o manual de hardware desta linha de chips.

8.8.3. Conversor D/A Alguns modelos da linha G14 incluem um ou dois módulos conversores digital para analógico (DAC) de 8 bits. Estes conversores podem ser utilizados para gerar tensões analógicas sob o controle do microcontrolador.

192 Microcontroladores RL78: Guia Básico

9

Periféricos de Comunicação 9. Periféricos de Comunicação

Neste capítulo apresentamos as interfaces de comunicação disponíveis nos microcontroladores RL78/G13 e em outras linhas da família RL78. Além dos periféricos descritos neste capítulo, a linha RL78/G1C inclui também interface USB 2.0 capaz de operar em modo full speed (12Mbps) e low speed (1,5Mbps).

9.1. Unidades SAU

Uma unidade SAU (Serial Array Unit – unidade conjunta serial) é o elemento básico de comunicação serial dos RL78. Cada unidade SAU pode conter até quatro canais seriais e podem existir até duas unidades SAU num mesmo microcontrolador. Um canal da SAU é composto por um registrador de deslocamento responsável pela conversão serial/paralelo e outros circuitos adjacentes. Cada canal pode operar em três modos distintos: • CSI – modo de comunicação síncrono similar ao SPI 3 fios e utilizado para comunicação de alta velocidade com memórias seriais (normalmente flash e EEPROM), conversores A/D, cartões de memória MMC, SD e SDIO e outros dispositivos. Cada canal pode ser configurado para transmitir 7 ou 8 bits de dados, com palavras iniciando pelo MSB ou pelo LSB, com controle de fase do clock e de polaridade do clock e dos dados. Neste modo cada canal da SAU utiliza três pinos: SOxx para saída de dados seriais, SIxx para entrada de dados seriais e SCKxx para entrada de clock (modo escravo) ou saída de clock (modo mestre); • I2C simplificado – modo I 2C mestre com algumas limitações (não há suporte a múltiplos mestres, nem a arbitragem de barramento e nem solicitação de espera pelo escravo). Este modo pode ser utilizado para comunicação com virtualmente qualquer dispositivo I 2C, como por exemplo: RTCs, memórias EEPROM, flash e RAM seriais, conversores A/D e D/A, etc. Cada canal pode ser configurado para transmissão ou recepção em modo mestre, o hardware inclui controle para geração e detecção do bit de reconhecimento (ACK), mas a geração das condições de partida e de parada deve ser providenciada pela aplicação; • UART – modo de comunicação assíncrona, disponível apenas nos canais 0 e 2 das unidades SAU. Pode operar com 7, 8 ou 9 bits e inclui gerador/detector de paridade,

Periféricos de Comunicação 193

inversão de polaridade dos dados e detecção de erros (paridade, quadro e de sobrescrita). O modo UART utiliza dois canais da SAU, assim, quando o canal 0 opera como UART o canal 1 fica indisponível e quando o canal 2 opera como UART o canal 3 fica indisponível da mesma forma. Adicionalmente, a UART2 pode operar em modo LIN e conjunto com a TAU e a interrupção externa INTP0. Isto significa que nos modelos com 80, 100 e 128 pinos é possível dispor de até 8 canais CSI (SPI), ou 8 canais I 2C simplificado ou até 4 canais UART. A tabela a seguir mostra a disponibilidade de canais das unidades SAU nos diversos modelos de encapsulamentos encontrados na linha RL78/G13. Disponibilidade de Canais SAU SAU (número de pinos do encapsulamento) Unidade Canal 128,100,80 64 52,48 44,40,36 32,30 25,24,20 CSI00 CSI00 CSI00 CSI00 CSI00 CSI00 0 IIC00 IIC00 IIC00 IIC00 IIC00 IIC00 UART0 UART0 UART0 UART0 UART0 UART0 CSI01 CSI01 CSI01 1 - - - IIC01 IIC01 IIC01 0 CSI10 CSI10 2 IIC10 IIC10 UART1 UART1 UART1 UART1 UART1 UART1 CSI11 CSI11 CSI11 CSI11 CSI11 CSI11 3 IIC11 IIC11 IIC11 IIC11 IIC11 IIC11 CSI20 CSI20 CSI20 CSI20 CSI20 0 IIC20 IIC20 IIC20 IIC20 IIC20 - UART2 UART2 UART2 UART2 UART2 CSI21 CSI21 CSI21 CSI21 1 - - IIC21 IIC21 IIC21 IIC21 1 CSI30 2 IIC30 - - - - - UART3 CSI31 3 - - - - - IIC31 Tabela 9.1

A tabela a seguir mostra as funções dos canais SAU e os pinos de E/S associados a elas. Encapsulamento (pinos) Função 128 100 80 64 52,48 44,40,36 32,30 25,24 20 SI00/SDA00/RxD0 P11/P16 P11/P16 P11/P16 P11/P16 P11/P16 P11/P16 P11/P16 P11 P11 SO00/TxD0 P12/P17 P12/P17 P12/P17 P12/P17 P12/P17 P12/P17 P12/P17 P12 P12 SCK00/SCL00 P10/P55 P10/P55 P10 P10 P10 P10 P10 P10 P10 SI01/SDA01 P44 P44 P44 P74 P74 - - - - SO01 P45 P45 P45 P73 P73 - - - - SCK01/SCL01 P43 P43 P43 P75 P75 - - - - SI10/SDA10/RxD1 P03/P81 P03/P81 P03 P03 P01 P01 P01 P01 P01

194 Microcontroladores RL78: Guia Básico

Encapsulamento (pinos) Função 128 100 80 64 52,48 44,40,36 32,30 25,24 20 SO10/TxD1 P02/P82 P02/P82 P02 P02 P00 P00 P00 P00 P00 SCK10/SCL10 P04/P80 P04/P80 P04 P04 - - - - - SI11/SDA11 P50 P50 P50 P50 P50 P50 P50 P50 P17 SO11 P51 P51 P51 P51 P51 P51 P51 P17 P16 SCK11/SCL11 P30 P30 P30 P30 P30 P30 P30 P30 P30 SI20/SDA20/RxD2 P14/P76 P14/P76 P14/P76 P14 P14 P14 P14 - - SO20/TxD2 P13/P77 P13/P77 P13/P77 P13 P13 P13 P13 - - SCK20/SCL20 P15 P15 P15 P15 P15 P15 P15 - - SI21/SDA21 P71 P71 P71 P71 P71 P71 - - - SO21 P72 P72 P72 P72 P72 P72 - - - SCK21/SCL21 P70 P70 P70 P70 P70 P70 - - - SI30/SDA30/RxD3 P143 P143 P143 ------SO30/TxD3 P144 P144 P144 ------SCK30/SCL30 P142 P142 P142 ------SI31/SDA31 P53 P53 P53 ------SO31 P52 P52 P52 ------SCK31/SCL31 P54 P54 P54 ------Tabela 9.2

Adicionalmente, o canal 0 (e o canal 2 nos modelos com 64 pinos ou mais) de cada unidade SAU pode continuar operando em modo snooze (quando operando no modo CSI ou UART), permitindo que o microcontrolador receba dados seriais enquanto permanece em modo de baixo consumo de energia. Funcionalmente uma unidade SAU apresenta muitas similaridades em relação a TAU, os registradores possuem formato parecido, com um controle geral de divisor de clock (registrador SPSm), registradores de configuração independentes para cada canal (SMRmn e SCRmn), registradores de disparo (SSm), de parada (STm) e de indicação de habilitação (SEm). Também estão presentes registradores para o controle dos pinos de saída dos canais (SOEm, SOm e SOLm), além dos registradores ISC (para utilização de LIN) e NFEN0 (para ativação dos filtros digitais nas entradas dos canais da SAU). As unidades SAU também incluem registradores de status para indicação de erros (SSRmn) e para o apagamento dos indicadores de erro (SIRmn). Os dados transmitidos/recebidos são controlados através do registrador SDRmn. Este registrador também controla (através dos seus 7 bits mais significativos) o fator de divisão final que determina o baud rate da comunicação (neste livro chamaremos este fator de FDC). A seguir veremos os registradores relacionados às unidades SAU e nos tópicos seguintes estudaremos cada um dos três modos de operação dos seus canais.

Periféricos de Comunicação 195

9.1.1. Registradores das SAU

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura PRS PRS PRS PRS PRS PRS PRS PRS 0 0 0 0 0 0 0 0 m13 m12 m11 m10 m03 m02 m01 m00 SPSm Escrita Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *m corresponde ao número da unidade SAU (0 ou 1) * Os 8 bits menos significativos podem ser acessados através do registrador SPSmL Nome do Bit Descrição Símbolo C Seleção do divisor do CK0 e CK1 da SAU:

0000 - f clk (nenhuma divisão) SAU_CKx_DIV1

0001 - f clk dividido por 2 SAU_CKx_DIV2

0010 - f clk dividido por 4 SAU_CKx_DIV4

0011 - f clk dividido por 8 SAU_CKx_DIV8

PRSm13 0100 - f clk dividido por 16 SAU_CKx_DIV16 PRSm12 0101 - f clk dividido por 32 SAU_CKx_DIV32 PRSm11 PRSm10 0110 - f clk dividido por 64 SAU_CKx_DIV64

0111 - f clk dividido por 128 SAU_CKx_DIV128 PRSm03 1000 - f dividido por 256 SAU_CKx_DIV256 PRSm02 clk PRSm01 1001 - f clk dividido por 512 SAU_CKx_DIV512

PRSm00 1010 - f clk dividido por 1024 SAU_CKx_DIV1024

1011 - f clk dividido por 2048 SAU_CKx_DIV2048

1100 - f clk dividido por 4096 SAU_CKx_DIV4096

1101 - f clk dividido por 8192 SAU_CKx_DIV8192

1110 - f clk dividido por 16384 SAU_CKx_DIV16384

1111 - f clk dividido por 32768 SAU_CKx_DIV32768

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura CKS CCS STS SIS MD MD MD 0 0 0 0 0 0 1 0 0 SMRmn Escrita mn mn mn mn0 mn2 mn1 mn0 Reset 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 *m corresponde ao número da SAU (0 ou 1) , n corresponde ao número do canal da SAU (0 a 3) Nome do Bit Descrição Símbolo C Seleção do prescaler associado ao canal SAU (CK0 ou CK1): CKSmn 0 – seleciona o prescaler 0 da SAU bSAU_CKS 1 – seleciona o prescaler 1 da SAU Seleção da fonte de clock do canal: CCSmn 0 – clock interno f CLK (utiliza o fator FDC do SDRmn) SAU_CLK_EXT 1 – clock externo via pino SCK do canal Seleção da fonte de disparo de partida: STSmn 0 – software (para modo CSI, I 2C simplificado ou transmissão UART) bSAU_STS 1 – borda válida no pino RxD do canal (para o modo de recepção UART)

196 Microcontroladores RL78: Guia Básico

Nome do Bit Descrição Símbolo C Controle de inversão da linha de recepção da UART: SISmn0 0 – bit de partida detectado na borda de descida, recepção normal SAU_RX_INV 1 – bit de partida detectado na borda de subida, recepção invertida Seleção do modo de operação do canal SAU: MDmn2 00 – modo CSI SAU_MD_CSI MDmn1 01 – modo UART SAU_MD_UART 10 – modo I 2C simplificado SAU_MD_I2C Seleção do modo de interrupção do canal SAU: MDmn0 0 – interrupção ao final da transferência SAU_INT_BUFFER 1 – interrupção no esvaziamento do buffer

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura TXE RXE DAP CKP EOC PTCm PTCm DIR SLC SLC DLS DLS 0 0 0 1 SCRmn Escrita mn mn mn mn mn n1 n0 mn mn1 mn0 mn1 mn0 Reset 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 1

*m corresponde ao número da SAU (0 ou 1) , n corresponde ao número do canal da SAU (0 a 3) Nome do Bit Descrição Símbolo C Configuração do modo de operação do canal n: 00 – comunicação desabilitada SAU_COMM_DISABLE TXEmn RXEmn 01 – somente recepção SAU_COMM_RX 10 – somente transmissão SAU_COMM_TX 11 – transmissão e recepção SAU_COMM_TXRX Seleção da polaridade do clock e fase do sinal em modo CSI (nos modos UART e I 2C estes bits devem ser configurados para 0): 00 – clock ativo em nível baixo, dado amostrado na borda SAU_CSI_CLKMODE0 de subida do clock DAPmn 01 – clock ativo em nível alto, dado amostrado na borda CKPmn SAU_CSI_CLKMODE1 de descida do clock 10 – clock ativo em nível baixo, dado amostrado na borda SAU_CSI_CLKMODE2 de descida do clock 11 – clock ativo em nível alto, dado amostrado na borda SAU_CSI_CLKMODE3 de subida do clock Habilitação da interrupção de erro INTSRE (válido apenas no modo UART): EOCmn SAU_INTSRE_ENABLE 0 – interrupção de erro desabilitada 1 – interrupção de erro habilitada Seleção da paridade no modo UART: 00 – paridade desativada SAU_NO_PARITY PTCmn1 PTCmn0 01 – paridade mantida sempre em zero SAU_PARITY_ZERO 10 – paridade par SAU_PARITY_EVEN 11 – paridade ímpar SAU_PARITY_ODD

Periféricos de Comunicação 197

Nome do Bit Descrição Símbolo C Ordem de transferência dos dados no modo CSI e UART: DIRmn 0 – comunicação inicia pelo bit MSB SAU_LSB_FIRST 1 – comunicação inicia pelo bit LSB Número de bits de parada no modo UART: SLCmn1 00 – nenhum bit de parada (somente modo CSI) SAU_NO_STOP SLCmn0 01 – um bit de parada SAU_ONE_STOP 10 – dois bits de parada (apenas canal 0 e 2) SAU_TWO_STOP Seleção do tamanho da palavra no modo CSI e UART: DLSmn1 01 – 9 bits (somente modo UART) SAU_9BITS DLSmn0 10 – 7 bits SAU_7BITS 11 – 8 bits SAU_8BITS

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura Dado recebido (7, 8 ou 9 bits) FDC SDRmn Escrita Dado a ser transmitido (7, 8 ou 9 bits) Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) , n corresponde ao número do canal da SAU (0 a 3) O campo FDC (fator de divisão do clock) determina o baud rate da comunicação. O baud rate é igual a fMCLK /f CK /(FDC*2+2) (pode ir de 2 até 256). O campo FDC somente pode ser lido ou escrito no registrador SDR quando o canal da SAU está parado (bit SEmn = 0). Quando o canal está em operação normal (SEmn=1), um dado escrito no SDR altera somente os bits 0 a 8 e a leitura do SDR retorna os o campo FDC (bits 9 a 15) em zero.

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura FECT PECT OVCT 0 0 0 0 0 0 0 0 0 0 0 0 0 SIRmn Escrita mn mn mn Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) , n corresponde ao número do canal da SAU (0 a 3) * os 8 bits inferiores podem ser acessados através do registrador SIRmnL

Nome do Bit Descrição Símbolo C Apagamento do flag de erro de quadro: FECTmn 0 – não apaga o flag bFECT 1 – apaga o flag FEFmn no registrador SSRmn Apagamento do flag de erro de paridade: PECTmn 0 – não apaga o flag bPECT 1 – apaga o flag PEFmn no registrador SSRmn Apagamento do flag de erro de sobrescrita: OVCTmn 0 – não apaga o flag bOVCT 1 – apaga o flag OVFmn no registrador SSRmn

198 Microcontroladores RL78: Guia Básico

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 TSF BFF FEF PEF OVF Leitura 0 0 0 0 0 0 0 0 0 0 0 mn mn mn mn mn SSRmn Escrita ------Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) , n corresponde ao número do canal da SAU (0 a 3) * os 8 bits inferiores podem ser acessados através do registrador SSRmnL Nome do Bit Descrição Símbolo C Indicador de estado de comunicação do canal: TSFmn 0 – comunicação parada ou suspensa bTSF 1 – comunicação em andamento Indicador de estado do buffer do canal: BFFmn 0 – não há dado válido no SDRmn bBFF 1 – há um dado válido no SDRmn Indicador de erro de quadro: 0 – nenhum erro FEFmn bFEF 1 – erro de quadro detectado (no modo UART, indica falha na detecção do bit de parada) Indicador de erro de paridade ou NACK: 0 – nenhum erro PEFmn bPEF 1 – erro de paridade detectado (modo UART) ou NACK recebido do escravo (modo I 2C) Indicador de erro de sobrescrita: 0 – nenhum erro OVFmn bOVF 1 – um novo dado foi recebido antes de o anterior ser lido no SDRmn

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SSm Escrita 0 0 0 0 0 0 0 0 0 0 0 0 SSm3 SSm2 SSm1 SSm0 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) * os 8 bits inferiores podem ser acessados através do registrador SSmL

Nome do Bit Descrição Símbolo C SSm3 SAU_CH3 Inicia a operação do canal (o canal da SAU passa a SSm2 SAU_CH2 aguardar o início da comunicação e o bit SEmn SSm1 SAU_CH1 correspondente é setado) SSm0 SAU_CH0

Periféricos de Comunicação 199

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 STm Escrita 0 0 0 0 0 0 0 0 0 0 0 0 STm3 STm2 STm1 STm0 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) * os 8 bits inferiores podem ser acessados através do registrador STmL

Nome do Bit Descrição Símbolo C STm3 SAU_CH3 STm2 Para a operação do canal (a comunicação é encerrada e o SAU_CH2 STm1 bit SEmn correspondente é apagado) SAU_CH1 STm0 SAU_CH0

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura 0 0 0 0 0 0 0 0 0 0 0 0 SEm3 SEm2 SEm1 SEm0 SEm Escrita - Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) * os 8 bits inferiores podem ser acessados através do registrador SEmL

Nome do Bit Descrição Símbolo C SEm3 SAU_CH3 Indicador de estado de operação do canal da SAU: SEm2 SAU_CH2 0 – operação paralisada SEm1 SAU_CH1 1 – operação normal SEm0 SAU_CH0

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura SOE SOE SOE SOE 0 0 0 0 0 0 0 0 0 0 0 0 SOEm Escrita m3 m2 m1 m0 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) * os 8 bits inferiores podem ser acessados através do registrador SOEmL * Só é permitido alterar este registrador com o canal paralisado (SEmn=0) Nome do Bit Descrição Símbolo C SOEm3 SAU_CH3 Habilitação da saída do canal n: SOEm2 SAU_CH2 0 – saída desativada SOEm1 SAU_CH1 1 – saída ativada SOEm0 SAU_CH0

200 Microcontroladores RL78: Guia Básico

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura CKO CKO CKO CKO SO SO SO SO 0 0 0 0 0 0 0 0 SOm Escrita m3 m2 m1 m0 m3 m2 m1 m0 Reset 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1

*m corresponde ao número da SAU (0 ou 1) * os 8 bits inferiores podem ser acessados através do registrador SOmL * somente é permitido alterar os bits CKO e SO quando a saída do canal está desativada (registrador SOEm) Nome do Bit Descrição Símbolo C CKOm3 SAU_CKO3 Estado da saída de clock do canal n: CKOm2 SAU_CKO2 0 – linha de clock em “0” CKOm1 SAU_CKO1 1 – linha de clock em “1” CKOm0 SAU_CKO0 SOm3 SAU_CH3 Estado da saída de dados do canal n: SOm2 SAU_CH2 0 – saída desativada SOm1 SAU_CH1 1 – saída ativada SOm0 SAU_CH0

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura SOL SOL 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SOLm Escrita m2 m0 Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) * os 8 bits inferiores podem ser acessados através do registrador SOLmL Nome do Bit Descrição Símbolo C Inversão do sinal transmitido do canal n: SOLm2 SAU_CH2 0 – sinal não invertido SOLm0 SAU_CH0 1 – sinal invertido

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Leitura SSEC SWC 0 0 0 0 0 0 0 0 0 0 0 0 0 0 SSCm Escrita m m Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

*m corresponde ao número da SAU (0 ou 1) * os 8 bits inferiores podem ser acessados através do registrador SSCmL Nome do Bit Descrição Símbolo C Mascaramento da interrupção de erro INTSRE no modo snooze: SSECm 0 – interrupção habilitada bSSEC 1 – interrupção desabilitada Controle do modo snooze: SWCm 0 – desativado bSWC 1 – ativado

Periféricos de Comunicação 201

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 0 ISC1 ISC0 ISC Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Seleção da entrada do canal 7 da TAU0 (a penas nos modelos com 30 pinos ou mais): ISC1 bISC1 0 – entrada via pino TI07 1 – entrada do canal conectada ao RxD2 (para operação LIN) Seleção da entrada de interrupção externa INTP0: ISC0 0 – sinal de interrupção derivado do pino INTP0 bISC0 1 – sinal de interrupção derivado de RxD2 (para operação LIN)

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 SNFEN30 0 SNFEN20 0 SNFEN10 0 SNFEN00 NFEN0 Escrita Reset 0 0 0 0 0 0 0 0 Estes registradores permitem ativar os filtros de ruído existentes nas entradas dos canais das unidades SAU. Quando ativados (SNFENxx = 1), o sinal RxD do respectivo canal precisa estar estável por dois ciclos fCLK para que ele seja detectado pelo timer. Nome do Bit Descrição Símbolo C Controle do filtro de ruído do pino RxD3/SDA30/SI30/P143: SNFEN30 bSNFEN30 0 – filtro desligado 1 – filtro ligado Controle do filtro de ruído do pino RxD2/SDA20/SI20/P14: SNFEN20 bSNFEN20 0 – filtro desligado 1 – filtro ligado Controle do filtro de ruído do pino RxD1/ANI16/SI10/SDA10/P03: SNFEN10 bSNFEN10 0 – filtro desligado 1 – filtro ligado Controle do filtro de ruído do pino RxD0/TOOLRxD/SDA00/SI00/ P11: SNFEN00 bSNFEN00 0 – filtro desligado 1 – filtro ligado

Nome Bits 7 6 5 4 3 2 1 0 Leitura RTCEN IICA1EN ADCEN IICA0EN SAU1EN SAU0EN TAU1EN TAU0EN PER0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Bit C Símbolo C Controle de clock e operação da SAU1: SAU1EN SAU1EN bSAU1EN 0 – SAU1 desativada 1 – SAU1 ativada Controle de clock e operação da SAU0: SAU0EN SAU0EN bSAU0EN 0 – SAU0 desativada 1 – SAU0 ativada

202 Microcontroladores RL78: Guia Básico

9.1.2. Modo UART O modo UART permite implementar comunicação serial assíncrona, sendo muito utilizado na comunicação com computadores e outros dispositivos. Por ser um modo assíncrono, não há um sinal de clock comum para sincronizar os dados entre o transmissor e o receptor, ao invés disso, utiliza-se uma frequência conhecida para se efetuar o deslocamento dos dados através do registrador de deslocamento de transmissão/recepção (baud rate). A sincronização entre transmissor e receptor é garantida pela utilização de uma sinalização específica para marcar o início e o fim de uma transmissão (bits de partida e de parada). A figura 9.1 mostra um típico quadro serial assíncrono. Chamamos quadro pois ele contém a informação mais os bits de controle (partida e parada).

Partida D0 D1 D2 D3 D4 D5 D6 D7* D8* Parada Figura 9.1

É fácil perceber que o receptor detecta o início de uma transmissão quando ocorre uma borda de descida no sinal (início do bit de partida). Após a partida, os dados são lidos e amostrados pelo registrador de deslocamento utilizando uma frequência (baud rate) conhecida pelo transmissor e pelo receptor. Após os bits de dados, o bit de parada serve exclusivamente para fazer com que a linha de comunicação retorne ao seu estado inativo, de forma que um novo bit de partida possa ser detectado. Quando operando no modo UART é possível configurar a polaridade do sinal serial, a ordem de deslocamento (início pelo bit menos significativo ou pelo bit mais significativo), o número de bits de dados transmitido em cada quadro (7, 8 ou 9) e o número de bits de parada (1 ou 2). Também é possível adicionar um bit de paridade (par, ímpar ou sempre zero), de forma que se efetue um controle básico de erros (feito automaticamente pelo hardware quando a paridade é utilizada). A seleção do modo UART é feita pela configuração dos bits MD2=0 e MD1=1 (símbolo SAU_MD_UART no arquivo myRL78.h) no registrador de controle de modo do canal (SMRmn). O bit MD0 permite configurar o evento que gera uma interrupção conforme mostra a tabela 9.3. MD0 Canal Descrição do Evento de Interrupção Um caractere foi recebido, a aplicação deve fazer a leitura do mesmo no registrador 0 Recepção RXDu Um caractere foi transmitido, para outra transmissão a aplicação deve escrever no 0 Transmissão novo dado no registrador TXDu O buffer de recepção está cheio, a aplicação deve ler os dados no registrador RXDu 1 Recepção até que o indicador de buffer cheio seja apagado (bit BFF no registrador SSRmn) O buffer de transmissão está vazio, a aplicação deve escrever novos dados no 1 Transmissão registrador TXDu até que o indicador de buffer cheio seja setado (bit BFF no registrador SSRmn) Tabela 9.3

É importante destacar que para a operação da UART no modo full duplex (transmissão e recepção simultâneas) é necessário configurar um dos canais como transmissor (bit TXE = 1 no

Periféricos de Comunicação 203

registrador SCRmn) e o outro como receptor (bit RXE = 1 no registrador SCRmn). No modo UART, é possível utilizar os símbolos TXDu e RXDu para acessar a parte menos significativa do SDRmn, assim, utiliza-se o registrador TXDu para envio de dados pela UART “u” e o registrador RXDu para leitura dos dados recebidos pela UART “u”. A tabela a seguir mostra a organização e configuração dos canais UART nas SAU dos RL78/G13. SAU Canal UART Modo STSmn *1 TXE *2 RXE *2 Registrador de Dados 0 TX 0 1 0 TXD0 0 1 RX 1 0 1 RXD0 0 2 TX 0 1 0 TXD1 1 3 RX 1 0 1 RXD1 0 TX 0 1 0 TXD2 2 1 RX 1 0 1 RXD2 1 2 TX 0 1 0 TXD3 3 3 RX 1 0 1 RXD3 *1 Registrador SMRmn *2 Registrador SCRmn Tabela 9.4

A configuração dos canais da SAU deve seguir os seguintes passos: 1. Habilitação da SAU (registrador PER0); 2. Configuração dos divisores de clock da SAU (registrador SPSm); 3. Configuração dos canais conforme a UART a ser utilizada;

No modo UART, os canais da SAU devem operar sempre com clock interno, além disso, não i é permitido configurar a UART para operar sem bits de parada. Os bits DAPmn e CKPmn não possuem função no modo UART e devem ser mantidos em zero.

4. Configuração do baud rate do transmissor e do receptor no campo FDC dos registradores SDRmn (é possível ter baud rates diferentes para o transmissor e para o receptor). A configuração do baud rate será vista em detalhes no próximo tópico; 5. Configuração dos registradores de controle de E/S da SAU (SOm, SOLm e SOEm) conforme modo de operação desejado. Normalmente é necessário apenas ativar a saída (pino TxD) do canal no registrador SOEm e configurar o estado da saída no registrador SOm. A inversão de dados (registrador SOLm) é usada apenas em algumas aplicações específicas; 6. Ativar o filtro digital de ruído na entrada RxD correspondente (registrador NFEN0); 7. Habilitar as interrupções utilizadas INTSTn para transmissão, INTSRn para recepção e INTSREn para erros de recepção); 8. Disparar os canais para dar início ao processo de comunicação (registrador SSm). Feito isso, uma escrita no registrador TXDu provoca o início de uma transmissão e os dados recebidos pelo receptor são armazenados no registrador RXDu.

204 Microcontroladores RL78: Guia Básico

A transmissão de dados irá gerar um evento de interrupção de transmissão, setando o flag STIFx. Caso a interrupção de transmissão esteja habilitada (STMKx=0) o programa será desviado para o vetor (INTSTx_vect (x corresponde ao número da UART). A recepção de dados irá gerar um evento de interrupção de recepção, setando o flag SRIFx. Caso a interrupção de recepção esteja habilitada (SRMKx=0) o programa será desviado para o vetor INTSRx_vect (x corresponde ao número da UART).

Observe que o evento gerador da interrupção de transmissão e da interrupção de recepção i será aquele determinado pelo configuração do bit MD0 no registrador de configuração do canal SMRmn.

Adicionalmente, cada canal da SAU possui um registrador de status (SSRmn) que abriga alguns bits sinalizadores da operação do canal. O bit TSFmn indica se há comunicação em andamento no canal (transmissão ou recepção, conforme a configuração do canal), BFFmn indica se há um dado válido armazenado no buffer SDRmn (TXDu/RXDu) e os bits FEFmn, PEFmn e OVFmn indicam condições de erro conforme abaixo: • FEFmn – erro de quadro. Este bit é setado quando a UART (modo de recepção) não detecta corretamente o bit de parada; • PEFmn – erro de paridade. Quando a paridade está configurada, este bit é setado pelo hardware quando o dado recebido possui paridade diferente da calculada; • OVFmn – erro de sobrescrita. Este erro ocorre quando o dado presente no buffer do canal (SDRmn) é sobrescrito por um novo dado; Lembre-se de que os bits indicadores de erros são atualizados a cada novo caractere recebido. Estes bits podem ser apagados através do registrador SIRmn. No caso dos erros de quadro e de paridade, o caractere lido do registrador RXDu deve ser descartado. No caso da ocorrência de um dos três erros citados o flag de erro SREIFx será setado e caso a interrupção de erro de recepção da UART esteja habilitada (EOC=1 no registrador SCRmn e a máscara SREMKx correspondente a UART esteja em zero), o programa será desviado para o vetor de interrupção INTSREx_vect (x corresponde ao número da UART).

9.1.2.1. Configuração do Baud Rate

A configuração da velocidade de comunicação dos canais da UART é realizada através de três registradores: SPSm e os registradores SDRmn relativos aos canais de transmissão e de recepção. O baud rate final pode ser calculado através da seguinte fórmula:

fMCLK Baudrate = CKx FDC 2* + 2 Onde: Baudrate é a velocidade em bits por segundo (bps);

Periféricos de Comunicação 205

CKx é o fator de divisão do prescaler da SAU (CK0 ou CK1) configurado no registrador SPSm; FDC é o valor configurado no campo FDC do registrador SDRmn. As tabelas 9.4 e 9.5 mostram as configurações ideais para os divisores de clock CK0 e CK1 (registrador SPSm) e o fator de divisão FDC para diversas frequências de clock e baud rates comumente utilizados. 32MHz 24MHz Baud rate CKx FDC Baud rate real Erro CKx FDC Baud rate real Erro 300 512 103 300,48 0,16% 512 77 300,48 0,16% 600 512 51 600,96 0,16% 512 38 600,96 0,16% 1200 512 25 1201,92 0,16% 128 77 1201,92 0,16% 2400 512 12 2403,85 0,16% 128 38 2403,85 0,16% 4800 32 103 4807,69 0,16% 32 77 4807,69 0,16% 9600 32 51 9615,38 0,16% 32 38 9615,38 0,16% 19200 32 25 19230,77 0,16% 8 77 19230,77 0,16% 38400 32 12 38461,54 0,16% 8 38 38461,54 0,16% 57600 4 68 57971,01 0,64% 8 25 57692,31 0,16% 115200 2 68 115942,03 0,64% 8 12 115384,62 0,16% Mínimo 32768 127 3,81 - 32768 127 2,86 - Máximo 4 0 4M - 4 0 3M - 20MHz 16MHz Baud rate CKx FDC Baud rate real Erro CKx FDC Baud rate real Erro 300 512 64 300,48 0,16% 256 103 300,48 0,16% 600 256 64 600,96 0,16% 256 51 600,96 0,16% 1200 128 64 1201,92 0,16% 256 25 1201,92 0,16% 2400 64 64 2403,85 0,16% 256 12 2403,85 0,16% 4800 32 64 4807,69 0,16% 16 103 4807,69 0,16% 9600 16 64 9615,38 0,16% 16 51 9615,38 0,16% 19200 8 64 19230,77 0,16% 16 25 19230,77 0,16% 38400 4 64 38461,54 0,16% 16 12 38461,54 0,16% 57600 2 85 58139,53 0,94% 2 68 57971,01 0,64% 115200 2 42 116279,07 0,94% 2 33 117647,06 2,12% Mínimo 32768 127 2,38 - 32768 127 1,91 - Máximo 2 0 5M - 2 0 4M - 12MHz 10MHz Baud rate CKx FDC Baud rate real Erro CKx FDC Baud rate real Erro 300 256 77 300,48 0,16% 256 64 300,48 0,16% 600 256 38 600,96 0,16% 128 64 600,96 0,16% 1200 64 77 1201,92 0,16% 64 64 1201,92 0,16% 2400 64 38 2403,85 0,16% 32 64 2403,85 0,16% 4800 16 77 4807,69 0,16% 16 64 4807,69 0,16% 9600 16 38 9615,38 0,16% 8 64 9615,38 0,16% 19200 4 77 19230,77 0,16% 4 64 19230,77 0,16% 38400 4 38 38461,54 0,16% 2 64 38461,54 0,16% 57600 4 25 57692,31 0,16% 1 85 58139,53 0,94% 115200 4 12 115384,62 0,16% 1 42 116279,07 0,94% Mínimo 32768 127 1,43 - 32768 127 1,19 - Máximo 2 0 3M - 1 0 5M - Tabela 9.5

206 Microcontroladores RL78: Guia Básico

8MHz 6MHz Baud rate CKx FDC Baud rate real Erro CKx FDC Baud rate real Erro 300 128 103 300,48 0,16% 128 77 300,48 0,16% 600 128 51 600,96 0,16% 128 38 600,96 0,16% 1200 128 25 1201,92 0,16% 32 77 1201,92 0,16% 2400 16 103 2403,85 0,16% 32 38 2403,85 0,16% 4800 16 51 4807,69 0,16% 8 77 4807,69 0,16% 9600 16 25 9615,38 0,16% 8 38 9615,38 0,16% 19200 16 12 19230,77 0,16% 2 77 19230,77 0,16% 38400 1 103 38461,54 0,16% 2 38 38461,54 0,16% 57600 1 68 57971,01 0,64% 2 25 57692,31 0,16% 115200 1 33 117647,06 2,12% 2 12 115384,62 0,16% Mínimo 32768 127 0,95 - 32768 127 0,72 - Máximo 1 0 4M - 1 0 3M - 4MHz 2MHz Baud rate CKx FDC Baud rate real Erro CKx FDC Baud rate real Erro 300 64 103 300,48 0,16% 32 103 300,48 0,16% 600 64 51 600,96 0,16% 16 103 600,96 0,16% 1200 16 103 1201,92 0,16% 16 51 1201,92 0,16% 2400 16 51 2403,85 0,16% 16 25 2403,85 0,16% 4800 16 25 4807,69 0,16% 16 12 4807,69 0,16% 9600 16 12 9615,38 0,16% 1 103 9615,38 0,16% 19200 1 103 19230,77 0,16% 1 51 19230,77 0,16% 38400 1 51 38461,54 0,16% 1 25 38461,54 0,16% 57600 1 33 58823,53 2,12% 1 16 58823,53 2,12% 115200 1 16 117647,06 2,12% 1 7 125000,00 8,51% Mínimo 32768 127 0,48 - 32768 127 0,24 - Máximo 1 0 2M - 1 0 1M - Tabela 9.6

Observe que o valor constante no campo FDC das tabelas deve ser carregado no registrador SDRmn com um deslocamento de 9 bits à esquerda. Assim, supondo que se deseje configurar o transmissor da UART0 para operar numa velocidade de 19200bps com clock principal de 32MHz, a configuração do baud rate deverá ser feita da seguinte forma (utilizando os símbolos do arquivo myRL78.h):

// Supondo que utilizaremos o CK0 como clock da UART SPS0 = SAU_CK0_DIV32; // prescaler CK0 da SAU0 dividindo por 32 ... SDR00 = 25<<9;

Periféricos de Comunicação 207

9.1.2.2. Operação em Modo Snooze

As UARTs 0 e 2 podem ser configuradas para operar em modo snooze, desta forma elas podem acordar a CPU ao receber dados. A operação em modo snooze é controlada pelo registrador SSCm. Na SAU0, o bit AWC0 configura a operação em modo snooze para a UART0 e na SAU1, o bit AWC1 configura a mesma função para a UART2. Quando o bit AWC está setado, a UART é habilitada para operar em modo snooze e quando o mesmo está apagado, a operação em modo snooze é desabilitada.

Atenção: no modo snooze a velocidade máxima de operação da UART é 9600bps, enquanto i que a velocidade mínima é de 4800bps! A operação fora destas velocidades pode provocar erros de comunicação e perda de dados.

9.1.2.3. LIN

A UART2 pode ser utilizada para implementar comunicação em protocolo LIN (Local Interconnect Network), um protocolo bastante utilizado na indústria automotiva. Para operar em modo LIN, é necessário utilizar a interrupção externa INTP0 para detecção do pulso de wakeup e o canal 7 da TAU0 (no modo de captura de ciclo) para medir o quadro de break e (no modo de captura de período) medir os pulsos do quadro de sincronismo. O registrador ISC permite associar os sinais INTP0 e TI07 a entrada RxD2 da UART, tornando desnecessário fazer estas conexões externamente. O manual de hardware do microcontrolador mostra em maiores detalhes a configuração e operação da UART2 em modo LIN.

9.1.2.4. API Applilet

O Applilet3 oferece uma série de funções que podem ser utilizadas para implementar a comunicação serial utilizando qualquer uma das UARTs disponíveis: • R_UARTx_Start() – para disparar a UARTx, esta função também habilita as interrupções da UART; • R_UARTx_Stop() – para encerrar a comunicação da UARTx, as interrupções da mesma são também desabilitadas; • R_UARTx_Send(uint8_t *txbuf, uint16_t txnum) – para envio de dados pela UARTx. Esta função transmite “txnum” caracteres armazenados no buffer (array) indicado por “txbuf”. Esta função retorna imediatamente após a chamada (a função R_UARTx_Callback_SendEnd é chamada automaticamente quando a transmissão é completada); • R_UARTx_Receive(uint8_t *rxbuf, uint16_t rxnum) – para recepção de dados pela UARTx. Esta função armazena no buffer “rxbuf” os “rxnum” caracteres

208 Microcontroladores RL78: Guia Básico

recebidos pela UART. Esta função retorna imediatamente após a chamada (a função R_UARTx_Callback_ReceiveEnd é chamada automaticamente quando a recepção é completada); As funções de callback a seguir podem ser definidas pelo usuário (no arquivo r_cg_serial_user.c): • R_UARTx_Callback_SendEnd() – esta função é chamada automaticamente quando todos os dados do buffer de transmissão (especificado na função R_UARTx_Send) foram transmitidos; • R_UARTx_Callback_ReceiveEnd() – esta função é chamada automaticamente quando o buffer de recepção (especificado na função R_UARTx_Receive) está cheio; • R_UART_Callback_Error() – esta função é chamada sempre que ocorre um erro de recepção na UART; • R_UART_Callback_SoftwareOverRun(uint8_t rxdata) – esta função é chamada quando novos dados são recebidos e o buffer de recepção (especificado por R_UARTx_Receive) está cheio. A variável “rxdata” contém o dado recebido.

9.1.2.5. Exemplo

O exemplo a seguir demonstra como configurar a UART do RL78/G13. A aplicação utiliza a UART2 conectada através da COM virtual integrada a placa de promoção do RL78/G13 (YRPBRL78G13) para realizar a comunicação com um computador através da porta USB. Os caracteres enviados pelo computador são lidos e o programa retorna pela serial o caractere seguinte, assim, ao receber “a” é retornado “b”, ao receber “c” é retornado “d” e assim por diante. Adicionalmente, ao receber “a” o led D2 é ligado e ao receber “b” o led D2 é desligado. Para executar este programa é necessário que, após o download do mesmo, os jumpers J6 a J9 sejam colocados na posição 2-3, de forma que os pinos da UART2 (TxD2 e RxD2) sejam conectados aos pinos RX e TX da conversor USB-serial da placa. Após isso é possível utilizar um programa de terminal serial (como o Termite, disponível em http://www.compuphase.com/software_termite.htm) para fazer a comunicação com a placa. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ;

Periféricos de Comunicação 209

// debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define __9600BPS 51 << 9 #define LED P7_bit.no7

#pragma vector = INTSR2_vect __interrupt void trata_rx_UART2(void) { unsigned char temp; temp = RXD2; // lê o caractere recebido TXD2 = temp+1; // envia o caractere (seguinte) if (temp=='a') LED = 0; // se recebeu "a", liga o led if (temp=='b') LED = 1; // se recebeu "b", desliga o led } #pragma vector = INTST2_vect __interrupt void trata_tx_UART2(void) { }

void MCU_init(void) { PM1_bit.no3 = 0; // P13/TXD2 como saída P1_bit.no3 = 1; // coloca TXD2 em 1 (importante!!!) PM1_bit.no4 = 1; // P14/RXD2 como entrada PM7_bit.no7 = 0; // P77 como saída (led) LED = 1; // desliga o led SAU1EN = 1; // ativa a SAU1 // Clock CK0 da SAU1 = 32MHz / 32 = 1MHz SPS1 = SAU_CK0_DIV32; // Configura o canal 0 da SAU1 (transmissão da UART2) SMR10 = SAU_MD_UART | SAU_INT_BUFFER; SCR10 = SAU_COMM_TX | SAU_NO_PARITY | SAU_LSB_FIRST | SAU_ONE_STOP | SAU_8BITS; SDR10 = __9600BPS; // seta o baud rate do transmissor // Configura o canal 1 da SAU1 (recepção da UART2) SMR11 = bSAU_STS | SAU_MD_UART; SCR11 = SAU_COMM_RX | SAU_NO_PARITY | SAU_LSB_FIRST | SAU_ONE_STOP | SAU_8BITS; SDR11 = __9600BPS; // seta o baud rate do receptor SOE1 = SAU_CH0; // habilita a saída da UART2 SO1 = SAU_CH0; // seta a saída TXD2 NFEN0 = SNFEN20; // ativa o filtro digital da entrada RXD2 // Dispara os canais 0 e 1 da SAU1 SS1 = SAU_CH1 | SAU_CH0; SRMK2 = 0; // habilita a interrupção de recepção da UART __enable_interrupt(); // habilita as interrupções do RL78 }

void main(void) { MCU_init(); while (1); } Exemplo 9.1

210 Microcontroladores RL78: Guia Básico

9.1.3. Modo CSI O modo CSI (Clocked Serial Interface) permite o envio e recepção de dados seriais através de uma interface de 3 fios: SI (entrada de dados seriais), SO (saída de dados seriais) e SCK (entrada ou saída de clock). Diferentemente da SPI (Serial Peripheral Interface) a CSI não inclui uma linha de seleção de periférico (normalmente chamada de SS – Slave Select no dispositivo mestre e CS – Chip Select no dispositivo escravo), por isso, esta funcionalidade deve ser implementada pelo software. Note que na terminologia SPI, o sinal SO é chamado MOSI (Master Out Slave In) e o sinal SI é chamado MISO (Master In Slave Out). A figura 9.2 mostra o esquema típico de ligação da interface CSI com um periférico. O dispositivo mestre inicia e controla a comunicação, sendo o responsável por gerar o sinal de clock (SCK) que sincroniza a transferência de dados. Para cada bit enviado serialmente pela saída SO, outro bit é recebido pela entrada SI. Ao final de sete ou oito pulsos de clock (conforme a configuração da CSI) o dado do mestre é enviado para o escravo e o dado presente no escravo é recebido pelo mestre.

SS CS

SI Mestre SO SI Escravo SO

SCK SCK Figura 9.2

A tabela 9.7 mostra a nomenclatura das unidades CSI disponíveis (consulte a tabela 9.1 para a disponibilidade de canais SAU conforme a pinagem do microcontrolador). SAU Canal Número do canal (p) Unidade CSI 0 00 CSI00 1 01 CSI01 0 2 10 CSI10 3 11 CSI11 0 20 CSI20 1 21 CSI21 1 2 30 CSI30 3 31 CSI31 Tabela 9.7

A frequência máxima de operação da CSI em modo mestre é de f MCLK /2 (com fMCLK ≤24MHz e apenas na CSI00) ou f MCLK /4 (com f MCLK ≤24MHz e válido para os demais canais das SAU). No modo escravo a frequência máxima é igual f MCLK /6. O modo CSI é selecionado configurando-se os bits MD2=0 e MD1=0 (símbolo SAU_MD_CSI no arquivo myRL78.h) no registrador de controle de modo do canal (SMRmn). Neste modo pode-se utilizar o símbolo SIOp (onde p é o número da unidade CSI de acordo com a

Periféricos de Comunicação 211

tabela 9.7) para acessar a parte menos significativa do SDRmn, de forma a ler os dados recebidos pela CSI ou escrever novos dados a serem transmitidos (conforme o modo de operação). A interface CSI pode operar em seis modos distintos, de acordo com a configuração dos bits TXE, RXE (registrador SCRmn) e CCS (registrador SMRmn). A tabela 9.8 mostra as diferentes configurações possíveis.

CCS TXE RXE Modo de Operação 0 1 0 Modo mestre, somente transmissão 0 0 1 Modo mestre, somente recepção 0 1 1 Modo mestre, transmissão e recepção 1 1 0 Modo escravo, somente transmissão 1 0 1 Modo escravo, somente recepção 1 1 1 Modo escravo, transmissão e recepção Tabela 9.8

O bit MD0 (registrador SMRmn) permite configurar o evento que gera uma interrupção, conforme mostra a tabela 9.9. MD0 Modo Descrição do Evento de Interrupção Um caractere foi recebido, a aplicação deve fazer a leitura do 0 Recepção mesmo no registrador SIO do canal Um caractere foi transmitido, para outra transmissão a aplicação 0 Transmissão deve escrever no novo dado no registrador SIO do canal Transmissão/ Um caractere foi transmitido e outro foi recebido durante a última 0 transferência, a aplicação deve escrever um novo dado em SIO do Recepção canal para iniciar uma nova transmissão O buffer está cheio, a aplicação deve ler os dados no registrador SIO 1 Recepção do canal até que o indicador de buffer cheio seja apagado (bit BFF no registrador SSRmn) O buffer está vazio, a aplicação deve escrever novos dados no 1 Transmissão registrador SIO do canal até que o indicador de buffer cheio seja setado (bit BFF no registrador SSRmn) O buffer está cheio, a aplicação deve ler o dado recebido no Transmissão/ registrador SIO e em seguida escrever o novo dado a ser transmitido 1 Recepção no SIO. Novos dados podem ser escritos no SIO até que o bit BFF seja setado, indicando que o buffer está cheio Tabela 9.9

Também é possível configurar a ordem de deslocamento (iniciando pelo MSB ou pelo LSB), a polaridade do sinal de clock, a fase do sinal de dados e o tamanho da palavra transmitida (7 ou 8 bits).

Atenção: no modo CSI a controle de paridade deve estar desativado (bits PTC1 e PTC0 = 0 i no registrador SCRmn) e a opção de bits de parada deve ser desativada (bits SLC1 e SLC0 = 0 no registrador SCRmn)!

Dois bits do registrador SCRmn configuram a polaridade do clock e a fase dos dados enviados/recebidos. O controle de polaridade de clock (CKP) permite selecionar se o sinal de clock é ativo em nível baixo (CKP=0) ou ativo em nível alto (CKP=1). O controle de fase dos

212 Microcontroladores RL78: Guia Básico

dados (DAP) seleciona se o dado é amostrado na segunda borda do clock (DAP=0) ou na primeira borda (DAP=1).

Note que os bits CKP e DAP possuem polaridade invertida em relação aos bits equivalentes O em outras interfaces SPI encontradas no mercado!

A figura 9.3 mostra os quatro modos possíveis selecionados através dos bits DAP e CKP, nela é possível identificar o instante em que o receptor amostra o sinal de entrada serial (linha tracejada em SI) e o instante em que o transmissor coloca um novo dado na saída serial (SO). SCK (CKP=1)

SI (DAP=1)

SO (DAP=1) D0 D1 D2 D3 D4 D5 D6 D7

SCK (CKP=1)

SI (DAP=0)

SO (DAP=0) D0 D1 D2 D3 D4 D5 D6 D7

SCK (CKP=0)

SI (DAP=1)

SO (DAP=1) D0 D1 D2 D3 D4 D5 D6 D7

SCK (CKP=0)

SI (DAP=0)

SO (DAP=0) D0 D1 D2 D3 D4 D5 D6 D7 Figura 9.3

A tabela 9.10 mostra a equivalência entre os modos de operação CSI e os modos de operação SPI. CKP DAP Modo CSI Modo SPI Símbolo C (myRL78.h) 1 1 3 0 SAU_CSI_CLKMODE3 1 0 2 1 SAU_CSI_CLKMODE2 0 1 1 2 SAU_CSI_CLKMODE1 0 0 0 3 SAU_CSI_CLKMODE0 Tabela 9.10 – Modos SPI

A configuração de um canal da SAU para operar no modo CSI deve seguir os seguintes passos: 1. Habilitação da SAU (registrador PER0); 2. Configuração dos divisores de clock da SAU (registrador SPSm); 3. Configuração do canal: no registrador SMRmn somente a seleção do clock, o modo de operação do canal e a seleção do prescaler devem ser alterados. Algumas possibilidades de configuração são mostradas a seguir: // Modo mestre, clock CK0, interrupção na transferência SMRmn = SAU_MD_CSI; // Modo mestre, clock CK1, interrupção buffer cheio/vazio SMRmn = bSAU_CKS | SAU_MD_CSI | SAU_INT_BUFFER; // Modo escravo, clock CK0, interrupção na transferência SMRmn = SAU_CLK_EXT | SAU_MD_CSI;

Periféricos de Comunicação 213

4. No registrador SCRmn somente a seleção TX/RX, modo de operação CSI, ordem dos dados e largura da palavra devem ser alterados. Algumas possibilidades de configuração são mostradas a seguir: // Transmissor, CSI modo 0, 8 bits iniciando pelo MSB SCRmn= SAU_COMM_TX | SAU_CSI_CLKMODE0 | SAU_8BITS; // Receptor, CSI modo 2, 8 bits iniciando pelo MSB SCRmn= SAU_COMM_RX | SAU_CSI_CLKMODE2 | SAU_8BITS; // TX/RX, CSI modo 3, 8 bits iniciando pelo LSB SCRmn= SAU_COMM_TXRX | SAU_CSI_CLKMODE3 | SAU_LSB_FIRST | SAU_8BITS; 5. Configuração da velocidade da CSI no campo FDC do registrador SDRmn. A configuração do baud rate será vista em detalhes no próximo tópico; 6. Configuração dos registradores de controle de E/S da SAU (SOm, SOLm e SOEm) conforme modo de operação desejado. Normalmente é necessário apenas ativar a saída (pino SO) do canal no registrador SOEm e configurar o estado da saída no registrador SOm (lembre-se de configurar a saída correspondente ao pino SCK para o nível inativo, caso contrário a comunicação não ocorrerá); 7. Habilitar a interrupção da CSI (INTCSIp onde p é o número da unidade CSI de acordo com a tabela 9.7); 8. Disparar o canal para dar início ao processo de comunicação (registrador SSm). Cada canal CSI dispõe de um único vetor de interrupção (INTCSIp_vect, onde p é o número da unidade CSI de acordo com a tabela 9.7) para onde o programa é desviado quando o flag CSIIFp é setado e a interrupção do canal está habilitada (CSIMKp=0). O flag CSIIFp é setado sempre que uma transferência é completada, o buffer de transmissão está vazio ou o buffer de recepção está cheio. a condição é determinada pelo bit MD0 do registrador de configuração do canal (SMRmn) e também depende do modo de operação do canal (transmissão, recepção ou transmissão/recepção). Caso um novo dado seja armazenado no registrador SIOp antes que o anterior tenha sido lido pela aplicação o indicador de erro OVFmn (registrador SSRmn) é setado.

Alguns chips disponíveis no mercado utilizam uma única linha bidirecional para entrada e saída de dados digitais, operando num modo chamado de SPI a três fios (DATA, SCK e CE). É possível utilizar um canal da CSI para comunicação com este tipo de periférico, para isso, O basta conectar as linhas SI e SO da CSI à linha de dados bidirecional do chip escravo e utilizar o modo de transmissão/recepção mestre. Lembre-se de desativar a saída SO quando o escravo enviar dados para o mestre!

9.1.3.1. Configuração do Baud Rate

A configuração da velocidade de comunicação dos canais CSI é realizada através de dois registradores: SPSm e o registrador SDRmn relativo ao canal da CSI. O baud rate final pode ser calculado através da seguinte fórmula:

fMCLK Baudrate = CKx FDC 2* + 2

214 Microcontroladores RL78: Guia Básico

Onde: Baudrate é a velocidade em bits por segundo (bps); CKx é o fator de divisão do prescaler da SAU (CK0 ou CK1) configurado no registrador SPSm; FDC é o valor configurado no campo FDC do registrador SDRmn. Observe que o valor FDC deve ser carregado no registrador SDRmn com um deslocamento de 9 bits à esquerda. Assim, supondo que se deseje configurar o transmissor da CSI00 para operar numa velocidade de 1Mbps com clock de 32MHz, poderemos utilizar um fator de divisão de 16 para CK0 e manter FDC em zero. A configuração do baud rate deverá ser feita da seguinte forma (utilizando os símbolos do arquivo myRL78.h): // Supondo que utilizaremos o CK0 como clock da CSI00 SPS0 = SAU_CK0_DIV16; ... SDR00 = 0;

No modo escravo o FDC deve ser igual a zero e o clock do canal (registrador SPSm) deve i ser configurado para no mínimo metade da frequência do clock de comunicação enviado pelo mestre.

9.1.3.2. API Applilet

O Applilet3 oferece uma série de funções que podem ser utilizadas para implementar a comunicação serial síncrona utilizando qualquer um dos canais CSI disponíveis (a letra p especifica um dos canais CSI conforme a tabela 9.7): • R_CSIp_Start() – para disparar a CSIp, esta função também habilita a interrupção do canal; • R_CSIp_Stop() – para encerrar a comunicação da CSIp, a interrupção do canal também é desabilitada; • R_CSIp_Send(uint8_t *txbuf, uint16_t txnum) – quando o canal é configurado para o modo de transmissão, esta função transmite “txnum” caracteres armazenados no buffer (array) indicado por “txbuf”. Esta função retorna imediatamente após a chamada (a função r_csip_callback_sendend é chamada automaticamente quando a transmissão é completada); • R_CSIp_Receive(uint8_t *rxbuf, uint16_t rxnum) – quando o canal é configurado para o modo de recepção, esta função fará com que os dados recebidos pela CSI sejam armazenados no buffer “rxbuf” até que o número especificado por “rxnum” de caracteres sejam recebidos. Esta função retorna imediatamente após a chamada (a função re_csip_callback_receiveend é chamada automaticamente quando a recepção é completada); • R_CSIp_Send_Receive(uint8_t *txbuf, uint16_t txnum, uint8_t *rxbuf) – quando o canal é configurado para o modo de transmissão/recepção, esta função transmite “txnum” caracteres armazenados no buffer (array) indicado por “txbuf” ao mesmo

Periféricos de Comunicação 215

tempo em que recebe a mesma quantidade de caracteres armazenando-os no buffer especificado por “rxbuf”. Esta função retorna imediatamente após a chamada (esta função chama automaticamente as funções r_csip_callback_sendend e r_csip_callback_receiveend para ao completar a transferência); As funções de callback a seguir podem ser definidas pelo usuário (no arquivo r_cg_serial_user.c): • r_csip_callback_sendend() – esta função é chamada automaticamente quando todos os dados do buffer de transmissão (especificado na função R_CSIp_Send) foram transmitidos; • r_csip_callback_error() – esta função é chamada sempre que ocorre um erro de recepção na CSI; • r_csip_callback_receiveend() – esta função é chamada automaticamente quando o buffer de recepção (especificado na função R_CSIp_Receive) está cheio;

9.1.4. Modo I 2C O protocolo I2C ( Inter-Integrated Comunication – Comunicação inter-integrados) é um protocolo serial síncrono half-duplex a dois fios desenvolvido pela Philips Holandesa para auxiliar na modularização das placas de controle dos seus aparelhos de TV. O I 2C é um protocolo do tipo mestre-escravo e possui como grande vantagem a característica de permitir que múltiplos dispositivos possam compartilhar o mesmo barramento e ser endereçados individualmente, sem a necessidade de linhas de controle ou habilitação auxiliares. Como desvantagem do I 2C podemos citar a sua maior complexidade e menor velocidade (quando comparado com outros protocolos síncronos como o SPI, por exemplo). Eletricamente o protocolo é baseado numa configuração do tipo coletor aberto (dreno aberto nos dispositivos CMOS), o que significa que nenhum dispositivo pode manter uma linha ativamente em nível lógico “1”. Duas linhas são utilizadas para se efetuar a comunicação: SDA (Serial Data, utilizada para o tráfego bidirecional de dados) e SCL (Serial Clock, utilizada para sincronização entre o mestre e o escravo). A figura 9.4 mostra um típico barramento I 2C com um mestre (master1) e vários escravos (slave1, slave2, slaveN). Observe também a existência dos resistores de pull-up RP, necessários ao funcionamento do barramento.

Figura 9.4 – Barramento I 2C

216 Microcontroladores RL78: Guia Básico

O protocolo I 2C prevê regras simples que devem ser seguidas durante a comunicação: 1. Nenhum dispositivo pode forçar ativamente a linha em nível lógico “1”; 2. Não é permitido alterar o estado da linha SDA durante a fase alta do sinal de clock (SCL); 3. Uma borda de descida da linha SDA durante a fase alta de SCL é considerada uma condição de partida (início da comunicação); 4. Uma borda de subida da linha SDA durante a fase alta de SCL é considerada uma condição de parada (fim da comunicação).

Condição de partida Condição de parada

Figura 9.5 – Condição de partida e de parada

5. Após o envio de um byte o transmissor (que pode ser o mestre ou o escravo) deve sempre enviar um novo pulso de clock para que o receptor responda com o bit de reconhecimento (bit de acknowledgement ou ACK). ACK = 0 indica que o receptor reconheceu o dado, ao passo que ACK = 1 indica que o receptor não reconheceu o mesmo;

SCL

SDA

Partida 0 0 1 0 0 1 1 0 ACK Parada Figura 9.6 – Um típico quadro I 2C

6. Uma comunicação I 2C deve ser sempre precedida de um quadro de endereçamento. A função do mesmo é especificar o endereço do escravo com o qual o mestre deseja se comunicar e a natureza da operação (leitura ou escrita). O bit R/W especifica se a operação é de escrita (R/W=0) ou leitura (R/W=1). A figura 9.7 mostra um típico quadro de endereçamento I 2C (endereços de 7 bits); Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 START A6 A5 A4 A3 A2 A1 A0 R/W ACK 0-escrita 0-ACK Endereço do escravo (7 bits) 1-leitura 1-NACK Figura 9.7 – Quadro de endereçamento I 2C

7. Quando o bit R/W do quadro de endereçamento é igual a 0 (escrita), o dispositivo mestre envia dados para o escravo. Nesta situação o mestre opera como transmissor e o escravo como receptor. A cada byte enviado pelo mestre o escravo deve responder com um bit ACK (0 ou 1). Após enviar todos os dados ao escravo o mestre deve gerar uma condição de parada para que a comunicação seja encerrada e o barramento liberado;

Periféricos de Comunicação 217

8. Quando o bit R/W do quadro de endereçamento é igual a 1 (leitura), o dispositivo mestre irá receber dados do escravo. Nesta situação o mestre atua como receptor e o escravo como transmissor. Após cada byte enviado pelo escravo o mestre deverá responder com um bit ACK (0 ou 1). Quando todos os bytes forem recebidos, o mestre encerra a comunicação com uma condição de parada, liberando o barramento; 9. É possível também que ocorram múltiplas inversões no sentido da comunicação dentro de uma mesma transferência, neste caso, o mestre envia um quadro de endereçamento com R/W=0 (escrita) seguido por um ou mais quadros de dados (conforme necessário pelo dispositivo escravo), em seguida o mestre deve gerar uma nova condição de partida (chamada de repeated start ou partida repetida na terminologia I 2C) com um novo quadro de endereçamento, desta vez com o bit R/W=1 (leitura) e aí a sentido de comunicação será invertido e o mestre poderá receber tantos bytes do escravo quanto for necessário. Eventualmente é possível realizar outras inversões no sentido da comunicação seguindo o mesmo processo descrito acima. Após enviar/receber todos os dados, o mestre deve encerrar a comunicação com uma condição de parada, liberando o barramento. O protocolo I 2C prevê também uma série de endereços pré-definidos para alguns tipos de circuitos integrados e aplicações conforme mostra a tabela 9.11. Note a presença de um endereço especial para chamada geral (broadcast) o qual todos os dispositivos devem responder, um endereço especial para o modo mestre de alta velocidade (até 3,4Mbps) e um endereço especial para utilização de endereçamento de 10 bits (ao invés dos tradicionais 7). Endereço R/W Descrição 0000000 0 Endereço de chamada geral (broadcast) 0000000 1 Byte de partida (para dispositivos lentos) 0000001 x Endereço CBUS 0000010 x Reservado para outros formados de barramento 0000011 x Reservado para propósitos futuros 00001xx x Modo mestre de alta velocidade (até 3,4Mbps) 0010xxx x Sintetizadores de voz 0011xxx x Interfaces de audio PCM 0100xxx x Geradores de audio 0111xxx x Displays LED/LCD 1000xxx x Interfaces de video 1001xxx x Conversores A/D e D/A 1010xxx x Memórias 1100xxx x Sintetizadores de RF 1101xxx x Calendários/relógios 11111xx x Reservado para propósitos futuros 11110xx x Modo de endereçamento de 10 bits Tabela 9.11 – Alguns endereços reservados da I 2C

9.1.4.1. I2C Simplificado na SAU

A implementação do protocolo I 2C na SAU consiste numa solução mista de hardware e software, permitindo uma grande economia de recursos e aumento da velocidade de transferência quando comparada a uma solução inteiramente por software. Conforme já foi dito anteriormente, este modo de operação consiste numa simplificação do I 2C, apresentando como limitações principais:

218 Microcontroladores RL78: Guia Básico

1. Operação apenas em modo mestre; 2. Não é permitida a presença de outro mestre no barramento (não há suporte para arbitramento de barramento); 3. Não é suportada a funcionalidade de clock stretching, que permite que um dispositivo aguarde por outro escravo lento. Estas limitações não constituem um grande problema pois a maioria das aplicações do I 2C em sistemas microcontrolados envolve comunicação apenas de um mestre (o microcontrolador) com um ou mais escravos (tipicamente memórias EEPROM ou flash, relógios de tempo real, etc.), o que é perfeitamente atendido pelo modo I 2C simplificado. Nos demais casos é possível utilizar a interface IICA para implementação de comunicação I 2C sem as limitações impostas pela SAU. A tabela 9.12 mostra a nomenclatura das unidades I 2C disponíveis nos RL78. Consulte a tabela 9.1 para a disponibilidade de canais nos diversos encapsulamentos e a tabela 9.2 para a pinagem dos canais no modo I 2C. SAU Canal Número do Canal (p) Unidade I 2C Simplificado 0 00 IIC00 1 01 IIC01 0 2 10 IIC10 3 11 IIC11 0 20 IIC20 1 21 IIC21 1 2 30 IIC30 3 31 IIC31 Tabela 9.12

Os pinos utilizados no modo I 2C são o SCK/SCL (clock) e SI/SDA (dados), estes pinos devem ser configurados para operar como saídas dreno aberto (registrador POMx). O pino de saída de dados do canal (SO) não é utilizado neste modo (mas internamente a entrada e saída do registrador de deslocamento do canal são conectadas ao pino DAS). A velocidade máxima de transferência no modo I 2C simplificado é de 1Mbps (1MHz) quando operando no modo rápido melhorado, 400kbps (400kHz) no modo rápido ou 100kbps (100kHz) no modo padrão. No modo I2C simplificado o registrador para leitura/escrita de dados na interface é representado pelo símbolo SIOp (onde p é o número do canal conforme mostrado na tabela 9.12). A seleção do modo I 2C simplificado é feita configurando-se os bits MD2=1 e MD1=0 no registrador SMRmn. O bit MD0 deve ser mantido em zero neste modo de operação (geração de interrupção ao final de cada transferência). Ainda no registrador SMRmn, a fonte de clock deve ser interna (CCS=0), o disparo deve ser por software (STS=0) e a recepção não deve ser invertida (SIS=0). No registrador SCRmn, é necessário configurar os bits SLC1=0 e SLC0=1 (um bit de parada) pois o bit de parada no modo I 2C é utilizado na função ACK, também é necessário

Periféricos de Comunicação 219

selecionar o tamanho do caractere para 8 bits (DLS1=DLS0=1), a ordem dos dados deve ser primeiro o MSB (bit DIR=0) e os bits TXE e RXE devem ser configurados de acordo com o modo do mestre (transmissor ou receptor). A configuração de um canal da SAU para operar no modo I2C simplificado deve seguir os seguintes passos: 1. Habilitação da SAU (registrador PER0); 2. Configuração dos divisores de clock da SAU (registrador SPSm); 3. Configuração do canal: no registrador SMRmn somente o modo de operação do canal e a seleção do prescaler devem ser alterados. Algumas possibilidades de configuração são mostradas a seguir: // Modo I2C com prescaler CK0 SMRmn = SAU_MD_I2C; // Modo I2C com prescaler CK1 SMRmn = bSAU_CKS | SAU_MD_I2C; 4. No registrador SCRmn basicamente alteramos somente a seleção TX/RX, a paridade deve ser nenhuma, um bit de parada (que é utilizado como ACK) e palavra de 8 bits. As possibilidades de configuração são mostradas a seguir: // I2C como transmissor SCRmn= SAU_COMM_TX | SAU_ONE_STOP | SAU_8BITS; // I2C como receptor SCRmn= SAU_COMM_RX | SAU_ONE_STOP | SAU_8BITS; 5. Configuração do baud rate da I 2C no campo FDC do registrador SDRmn. A configuração do baud rate será vista em detalhes no próximo tópico; 6. Os registradores POMm relativos aos pinos SDA e SCL devem ser configurados para o modo de saída em dreno aberto; 7. Configuração dos registradores de controle de E/S da SAU (SOm, SOLm e SOEm). O bit relativo ao pino SDA no registrador SOEm deve ser mantido em “0”. Os bits relativos ao canal no registrador SOm devem ser mantidos em “1” (tanto o CKO quanto o SO), isto garante que, após a inicialização do canal, os pinos SDA e SCL permaneçam no estado inativo (nível lógico “1” mantido por pull-up externo); 8. Habilitar a interrupção do canal (INTIICp, onde p é o número do canal conforme a tabela 9.12); 9. No modo I 2C o canal não é disparado na inicialização, o disparo deve ocorrer apenas após a geração da condição de partida.

Lembre-se de instalar resistores de pull-up nas linhas SDA e SCL! Não é possível utilizar os O resistores internos já que, ao configurar os pinos para o modo dreno aberto, os resistores internos dos pinos são automaticamente desabilitados.

220 Microcontroladores RL78: Guia Básico

9.1.4.2. Configuração do Baud Rate

A configuração da velocidade de comunicação dos canais I2C é realizada através de dois registradores: SPSm e o registrador SDRmn relativo ao canal da I2C. O baud rate final pode ser calculado através da seguinte fórmula:

fMCLK Baudrate = CKx FDC 2* + 2 Onde: Baudrate é a velocidade em bits por segundo (bps); CKx é o fator de divisão do prescaler da SAU (CK0 ou CK1) configurado no registrador SPSm; FDC é o valor configurado no campo FDC do registrador SDRmn. Observe que o valor FDC deve ser carregado no registrador SDRmn com um deslocamento de 9 bits à esquerda. Assim, supondo que se deseje configurar o transmissor da IIC00 para operar numa velocidade de 1Mbps com clock de 32MHz, poderemos utilizar um fator de divisão de 8 para CK0 e utilizar FDC = 1. A configuração do baud rate deverá ser feita da seguinte forma (utilizando os símbolos do arquivo myRL78.h): // Supondo que utilizaremos o CK0 como clock da CSI00 SPS0 = SAU_CK0_DIV8; ... SDR00 = 1<<9; 9.1.4.3. Comunicação I 2C

Depois de inicializado o canal da SAU, a comunicação I 2C deverá obedecer aos seguintes passos: 1. Partida : o início de uma transferência I 2C é sinalizado pela condição de partida, que consiste numa borda de descida da linha SDA enquanto a linha SCL permanece inativa (nível lógico “1” fornecido por pull-up externo). Na SAU a condição de partida é gerada por software, através dos seguintes passos: a. Inicialmente a aplicação deve escrever “0” no bit correspondente ao pino SDA do registrador SOm e aguardar por um período mínimo de metade do clock de comunicação; b. Em seguida a linha SCK deve ser colocada em zero, para isso, a aplicação deve escrever “0” no bit correspondente (CKO) do registrador SOm; c. Feito isso a aplicação deve habilitar a saída SDA (registrador SOEm) e em seguida disparar o canal (registrador SSm) para que a comunicação tenha início (transmissão do quadro de endereçamento); 2. Quadro de endereçamento : após uma condição de partida (ou partida repetida) o primeiro quadro a ser transmitido pela I 2C deve ser o e endereçamento. A aplicação

Periféricos de Comunicação 221

deve escrever o byte de endereçamento (7 bits do endereço do escravo mais o bit R/W, como mostra a figura 9.7) no registrador SIO do canal para que a transmissão tenha início; 3. Quando a transmissão for completada, uma interrupção INTIICp (onde p é o número do canal conforme a tabela 9.12) será gerada. A ISR deverá verificar o estado do bit PEF (registrador SSRm) para determinar o resposta (ACK) enviada pelo escravo: se PEF=0, significa que houve reconhecimento pelo escravo (ACK=0), neste caso o mestre deve prosseguir com a comunicação. Se PEF=1, não houve resposta do escravo (possivelmente porque o endereço não existe ou o escravo não está pronto) e a aplicação deverá providenciar uma nova tentativa ou tratar o erro; 4. Transmissão de dados : caso o mestre tenha enviado um quadro de endereçamento com R/W=0 e o escravo tenha respondido com ACK=0, então a aplicação deverá providenciar o envio dos dados ao escravo. Para isso basta escrever o dado no registrador SIO do canal e aguardar pela interrupção INTIICp; 5. A ISR deverá verificar o estado do ACK (através do bit PEF, registrador SSRm), caso PEF=0, houve reconhecimento e um novo dado pode ser transmitido, caso contrário, um processamento de erro deve ser executado (isto varia conforme o tipo de escravo). Caso não haja mais dados a serem transmitidos o mestre deve encerrar a comunicação, enviando uma condição de parada (passo 9); 6. Recepção de dados: caso o mestre tenha enviado um quadro de endereçamento com R/W=1 e tenha recebido um ACK=0 do escravo, então a aplicação deverá preparar- se para receber dados do escravo, devendo o mestre ser configurado para o modo de recepção. Para isso, o canal deve ser paralisado (registrador STm), de forma que se possa modificar o registrador SCRmn (o bit TXE deve ser apagado e o bit RXE setado). Em seguida o canal deve ser disparado novamente (registrador SSm) e um valor qualquer (por exemplo 0xFF) deve ser escrito no registrador SIO do canal (isto força a SAU a iniciar uma transferência, mas nenhum dado será transmitido, apenas recebido); 7. Ao ser completada a transferência a SAU gera automaticamente um ACK=0 e a interrupção INTIICp é disparada. A ISR deve então efetuar a leitura do dado recebido no registrador SIO do canal. Caso ainda existam dados a serem recebidos, o mestre deve fazer uma nova escrita (qualquer valor) no registrador SIO para que outra transferência tenha início. Caso o mestre não deseje mais receber dados, uma condição de parada deve ser gerada (passo 9); 8. Partida Repetida (repeated start) : caso o mestre necessite modificar o sentido da comunicação, é necessário gerar uma nova condição de partida (partida repetida). Para isso, é necessário seguir os seguintes passos: a. Desabilitar o canal (via registrador STm); b. Desabilitar a saída da I 2C (via registrador SOEm); c. Configurar a linha SCL para o estado inativo (nível lógico “1” mantido por pull-up externo) através do respectivo bit CKO (registrador SOm);

222 Microcontroladores RL78: Guia Básico

d. Configurar a linha SDA para o estado inativo (nível lógico “1” mantido por pull-up externo) através do respectivo bit SO (registrador SOm); e. Iniciar a nova geração de uma condição de partida (passo 1); 9. Parada : para encerrar uma transferência I 2C é necessário que o mestre gere uma condição de parada no barramento, que consiste numa borda de subida da linha de dados (SDA) enquanto a linha de clock (SCL) está em inativa (nível lógico “1” mantido pelo pull-up externo). Para gerar a condição de parada na SAU, a aplicação deve seguir os seguintes passos: a. Paralisar a comunicação (setando o bit correspondente no registrador STm); b. Desativar a saída (apagando o bit do registrador SOEmn). Se o mestre já se encontra em modo de recepção, este bit já deverá estar apagado; c. Forçar a linha SDA em nível “0” (apagando o bit SO correspondente no registrador SOm); d. Forçar a linha SCL no estado inativo (setando o bit CKO correspondente no registrador SOm) e aguardar por um período mínimo de metade do clock de comunicação; e. Forçar a linha SDA no estado inativo (setando o bit SO correspondente no registrador SOm).

9.1.4.4. API Applilet

O Applilet3 oferece uma série de funções que podem ser utilizadas para implementar a comunicação serial síncrona utilizando qualquer um dos canais I2C disponíveis (onde p é o número do canal conforme a tabela 9.12): • R_IICp_StartCondition() – gera uma condição de partida no barramento I 2C. Esta função é chamada automaticamente pelas funções R_IICp_Master_Send() e R_IICp_Master_Receive() ; • R_IICp_Master_Send(uint8_t adr, uint8_t *txbuf, uint16_t txnum) – transmite “txnum” caracteres armazenados no buffer (array) indicado por “txbuf” para o escravo no endereço “adr”. Esta função retorna imediatamente após a chamada (a função r_iicp_callback_master_sendend é executada automaticamente quando a transmissão é completada). As condições de partida e de parada são geradas automaticamente; • R_IICp_Master_Receive(uint8_t adr, uint8_t *rxbuf, uint16_t rxnum) – recebe um bloco de dados através da interface I 2C armazenando-os no buffer especificado por “rxbuf” até que o número especificado por “rxnum” de caracteres sejam recebidos. Esta função retorna imediatamente após a chamada (a função r_iicp_callback_master_receiveend é executada automaticamente quando a recepção é completada). As condições de partida e de parada são geradas automaticamente;

Periféricos de Comunicação 223

• R_IICp_StopCondition() – gera uma condição de parada no barramento I 2C. Esta função é chamada automaticamente pelas funções R_IICp_Master_Send() e R_IICp_Master_Receive() ao término da comunicação; • R_IICp_Stop() – para encerrar a comunicação da IICp, a interrupção do canal também é desabilitada; As funções de callback a seguir podem ser definidas pelo usuário (no arquivo r_cg_serial_user.c): • r_iicp_callback_master_sendend() – esta função é chamada automaticamente quando todos os dados do buffer de transmissão (especificado na função R_IICp_Master_Send) foram transmitidos; • r_iicp_callback_master_receiveend() – esta função é chamada automaticamente quando o buffer de recepção (especificado na função R_IICp_Master_Receive) está cheio; • r_iicp_callback_master_error(MD_STATUS flag) – esta função é chamada sempre que ocorre um erro na I2C (normalmente a recepção de um NACK vindo do escravo).

9.2. Unidades IICA (I 2C)

As unidades I2C avançadas (IICA) consistem em interfaces de comunicação I 2C plenas que podem operar tanto no modo mestre quanto no modo escravo (ou seja, podem endereçar e ser endereçadas por outros dispositivos mestre no barramento). As unidades IICA apresentam as seguintes características: • Operação em modo mestre (com suporte a arbitramento do barramento) ou modo escravo; • Velocidade de comunicação de até 1MHz (quando a CPU opera acima de 10MHz); • Suporte a chamada geral (broadcast); • Pode operar em modo stop (como escravo), acordando a CPU ao ser endereçada por um mestre; • Suporte a clock stretching: permite que o receptor mantenha a comunicação em espera até que processado o dado recebido. A tabela 9.13 mostra a quantidade de canais IICA disponíveis conforme o encapsulamento dos RL78/G13. 20 a 64 80 a 128 IICA pinos pinos Número de Canais 1 2 Tabela 9.13

224 Microcontroladores RL78: Guia Básico

9.2.1. Operação da IICA A interface IICA possui todos os automatismos necessários para processar uma transferência I 2C completa, sem a necessidade de grandes intervenções da aplicação. Para utilizar uma das unidades IICA é necessário inicialmente ativá-la no registrador PER0, conforme a seguir.

Nome Bits 7 6 5 4 3 2 1 0 Leitura RTCEN IICA1EN ADCEN IICA0EN SAU1EN SAU0EN TAU1EN TAU0EN PER0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Bit C Símbolo C Controle de clock e operação da IICA1: IICA1EN IICA1EN bIICA1EN 0 – IICA1 desativada 1 – IICA1 ativada Controle de clock e operação da IICA0: IICA0EN IICA0EN bIICA0EN 0 – IICA0 desativada 1 – IICA0 ativada Uma vez ativada no registrador PER0, também é necessário habilitar a interface setando- se o bit IICE no registrador IICCTLn0. A IICA possui um registrador para transferência de dados (IICAn) que pode ser utilizado para o envio de dados (quando a interface opera como transmissor) ou para leitura dos dados recebidos (quando a interface opera como receptor). Há também um registrador específico (SVAn) para armazenamento do endereço local da interface. Este endereço é utilizado pela IICA para detectar quando ela está sendo endereçada por um dispositivo mestre do barramento.

i O registrador SVAn somente é utilizado quando a IICA opera em modo escravo!

Lembre-se de que o primeiro byte enviado após uma condição de partida (ou partida O repetida) é sempre o byte de endereçamento, contendo o endereço do escravo que deve receber a comunicação e o bit R/W indicador do tipo de transferência.

A velocidade de comunicação é controlada através de dois registradores: IICWLn que controla a fase baixa do sinal de clock e IICWHn que controla a fase alta do sinal de clock. A condição de partida, que sinaliza o início de uma transferência I 2C é gerada setando-se o bit STT (registrador IICCTLn0), este bit é apagado automaticamente pela interface após a geração da condição de partida. Adicionalmente, a aplicação pode verificar o estado do bit STD (registrador IICSn). Este bit indica quando uma condição de partida foi detectada no barramento. Após a condição de partida o mestre deve enviar o campo de endereçamento. Isto é feito escrevendo-se os 7 bits do endereço do escravo mais o bit R/W no registrador de dados da interface (IICAn). De acordo com o estado do bit R/W a interface passa a operar como transmissora (se R/W=0) ou receptora (se R/W=1). A qualquer instante isto pode ser verificado através do bit TRC (registrador IICSn).

Periféricos de Comunicação 225

Após o envio de dados pelo transmissor deve verificar se a transmissão foi reconhecida pelo receptor (ACK). O estado do ACK pode ser lido através do bit ACKD no registrador IICSn. Caso a transmissão tenha sido reconhecida o novo dado a ser transmitido deve ser escrito no registrador IICAn e após isso o bit ACKD deve ser verificado para determinar se houve reconhecimento ou não por parte do receptor. A IICA inclui a facilidade de clock stretching, permitindo o controle de fluxo dos dados entre o transmissor e o receptor e que funciona da seguinte forma: o receptor, caso precise de tempo para processar os dados recebidos do transmissor, pode manter a linha de clock (SCL) em nível “0” após oitavo ou nono pulso de clock, desta forma o transmissor irá aguardar que a linha de clock retorne ao estado inativo, ou seja, que ela seja liberada pelo receptor, de forma a prosseguir com a comunicação. Este sistema de controle de fluxo ou estado de espera está sempre ativo na IIAC e pode ser configurado para ocorrer após o oitavo ciclo de clock (no bit ACK) ou após o nono pulso de clock (após o bit ACK). Esta seleção é realizada através do bit WTIM no registrador IICCTLn0. Quando a IICA está em estado de espera, ele é liberado de uma das seguintes formas: • Através de uma escrita no registrador IICAn; • Setando o bit de liberação de modo de espera (WREL) no registrador IICCTLn0; • Pela geração de uma condição de partida ou de parada (apenas no modo mestre). No caso de operação como recepção, cada byte recebido pela interface é armazenado no registrador IICAn e no nono pulso de clock um ACK é enviado de acordo com o estado do bit ACKE no registrador IICCTLn0. A cada transferência completada (seja de transmissão ou de recepção) é gerado um evento de interrupção INTIICAn. O instante em que o sinal de interrupção é gerado (oitavo ou nono pulso de clock) irá depender da configuração do bit WTIM no registrador IICCTLn0. Também é possível configurar a IICA para gerar uma interrupção ao detectar uma condição de parada no barramento, setando-se o bit SPIE no registrador IICCTLn0.

9.2.2. API Applilet O Applilet3 oferece uma série de funções que podem ser utilizadas para implementar a comunicação serial síncrona utilizando uma das interfaces IICA disponíveis (a letra n especifica uma das unidades IICA): • R_IICAn_Master_Send(uint8_t adr, uint8_t *txbuf, uint16_t txnum, uint8_t wait) – transmite “txnum” caracteres armazenados no buffer (array) indicado por “txbuf” para o escravo no endereço “adr”. O parâmetro “wait” especifica um tempo de espera para a geração da condição de partida. Esta função retorna imediatamente após a chamada (a função r_iican_callback_master_sendend é executada automaticamente quando a transmissão é completada). Esta função também realiza automaticamente a geração das condições de partida e de parada;

226 Microcontroladores RL78: Guia Básico

• R_IICAn_Master_Receive(uint8_t adr, uint8_t *rxbuf, uint16_t rxnum, uint8_t wait) – recebe um bloco de dados através da interface I 2C armazenando-os no buffer especificado por “rxbuf” até que o número especificado por “rxnum” de caracteres sejam recebidos. O parâmetro “wait” especifica um tempo de espera para a geração da condição de partida. Esta função retorna imediatamente após a chamada (a função r_iican_callback_master_receiveend é executada automaticamente quando a recepção é completada). As condições de partida e de parada são geradas automaticamente; • R_IICAn_StopCondition() – gera uma condição de parada no barramento I 2C; • R_IICAn_Slave_Send(uint8_t *txbuf, uint16_t txnum) – transmite para o mestre os “txnum” caracteres armazenados no buffer (array) indicado por “txbuf”. Esta função retorna imediatamente após a chamada (a função r_iican_callback_slave_sendend é executada automaticamente quando a transmissão é completada); • R_IICAn_Slave_Receive(uint8_t *rxbuf, uint16_t rxnum) – recebe um bloco de dados através da interface I 2C armazenando-os no buffer especificado por “rxbuf” até que o número especificado por “rxnum” de caracteres sejam recebidos. Esta função retorna imediatamente após a chamada (a função r_iican_callback_slave_receiveend é executada automaticamente quando a recepção é completada); • R_IICAn_Stop() – para encerrar a comunicação da interface IICAn, a interrupção da interface também é desabilitada; As funções de callback a seguir podem ser definidas pelo usuário (no arquivo r_cg_serial_user.c): • r_iican_callback_master_sendend() – esta função é chamada automaticamente quando todos os dados do buffer de transmissão (especificado na função R_IICAn_Master_Send) foram transmitidos; • r_iican_callback_master_receiveend() – esta função é chamada automaticamente quando o buffer de recepção (especificado na função R_IICAn_Master_Receive) está cheio; • r_iican_callback_master_error(MD_STATUS flag) – esta função é chamada sempre que ocorre um erro na interface (uma detecção de condição de parada inesperada ou recepção de um NACK); • r_iican_callback_slave_sendend() – esta função é chamada automaticamente quando todos os dados do buffer de transmissão (especificado na função R_IICAn_Slave_Send) foram transmitidos; • r_iican_callback_slave_receiveend() – esta função é chamada automaticamente quando o buffer de recepção (especificado na função R_IICAn_Slave_Receive) está cheio; • r_iican_callback_slave_error(MD_STATUS flag) – esta função é chamada sempre que ocorre um erro na interface (endereço inválido ou recepção de um NACK).

Periféricos de Comunicação 227

9.2.3. Registradores IICA

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura Dado recebido pela interface I 2C IICAn Escrita Dado a ser transmitido pela interface I 2C Reset 0 0 0 0 0 0 0 0

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura A6 A5 A4 A3 A2 A1 A0 0 SVAn Escrita Reset 0 0 0 0 0 0 0 0 Este registrador armazena o endereço da interface IICA quando ela opera como escrava. O bit 0 deve ser mantido sempre apagado.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura IICEn LRELn WRELn SPIEn WTIMn ACKEn STTn SPTn IICCTLn0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Habilitação da operação I 2C: IICEn bIICE 0 – desativa a interface 1 – ativa a interface Solicitação de encerramento de comunicação: 0 – nenhuma solicitação LRELn 1 – encerra a comunicação, coloca as linhas SCLA e SDAA em alta bLREL impedância e força a interface para mo do standby, após a execução do comando este bit é apagado automaticamente Solicitação de cancelamento de espera: 0 – nenhuma solicitação WRELn bWREL 1 – cancela um estado de espera. Após o cancelamento este bit é apagado automaticamente Habilitação da interrupção de recepção de condição de parada: SPIEn bSPIE 0 – interrupção desabilitada 1 – interrupção habilitada Controle da geração d o tempo de espera (clock stretching) e da interrupção de transferência: 0 – interrupção gerada na borda de de scida do oitavo pulso de clock, após o WTIMn bWTIM oitavo clock a condição de espera é ativada 1 – interrupção gerada na borda de descida do nono pulso de clock, após o nono clock a condição de espera é ativada Controle de envio de reconhecimento (ACK ou NACK) na próxima transferência: ACKEn bACKE 0 – envia NACK (não reconhecimento) 1 – envia ACK (reconhecimento)

228 Microcontroladores RL78: Guia Básico

Nome do Bit Descrição Símbolo C Disparo de condição de partida (START): 0 – não gera START 1 – Gera uma condição de partida (START) ou reinício (RESTART). Caso o STTn bSTT barramento este ja ocupado por outro mestre, uma condição de partida somente será gerada após a liberação do barramento e caso a função de reserva de comunicação esteja ativada (IICRSVn=0) Disparo de condição de parada (STOP): 0 – não gera STOP SPTn bSPT 1 – gera uma con dição de parada, encerrando a transferência I2C. Este bit somente pode ser setado no modo mestre

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura MSTSn ALDn EXCn COIn TRCn ACKDn STDn SPDn IICSn Escrita - Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Indicador de modo de comunicação (mestre/escravo): MSTSn 0 – modo escravo ou em standby bMSTS 1 – modo mestre Indicador de perda de arbitragem de barramento: ALDn 0 – não ocorreu perda de arbitragem bALD 1 – o mestre perdeu a arbitragem e passou para modo escravo (MSTS=0) Indicador de recepção de código de extensão: EXCn 0 – nenhum código de extensão recebido bEXC 1 – código de extensão recebido Indicador de detecção de endereçamento do escravo (quando a interface I 2C operando em modo escravo é endereçada por um mestre externo): COIn bCOI 0 – não houve detecção de endereçamento 1 – a interface foi endereçada por um mestre externo Indicador de estado de transmissão ou recepção: TRCn 0 – modo de recepção bTRC 1 – modo de transmissão Indicador de reconhecimento (ACK ou NACK): ACKDn 0 – foi recebido um NACK bACKD 1 – foi recebido um ACK Indicador de condição de partida (START): STDn 0 – nenhuma partida foi detectada bSTD 1 – condição de partida detectada, transferência em andamento Indicador de condição de parada (STOP): 0 – nenhuma parada foi detectada SPDn bSPD 1 – condição de parada detectada, transferência completada, o barramento é liberado

Periféricos de Comunicação 229

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura STCFn IICBSYn 0 0 0 0 STCENn IICRSVn IICFn Escrita - - Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Indicador de geração da condição de partida (START): STCFn 0 – condição de partida gerada com sucesso (STTn = 1) bSTCF 1 – condição de partida não foi gerada (STTn = 0) Indicador de estado do barramento I 2C: IICBSYn bIICBSY 0 – barramento liberado 1 – barramento ocupado Disparo da habilitação inicial da interface após a habilitação da mes ma (IICEn = 1): 0 – permite gerar uma condição de partida após detectar uma condição de STCENn bSTCEN parada 1 – permite gerar uma condição de partida sem detectar uma condição de parada Controle de desabilitação da função de reserva de comunicação: IICRSVn 0 – reserva de comunicação habilitada bIICRSV 1 – reserva de comunicação desabilitada

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura WUPn 0 CLDn DADn SMCn DFCn 0 PRSn IICCTLn1 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Controle da detecção de endereçamento em modo stop: WUPn 0 – detecção de endereçamento desabilitada em modo stop bWUP 1 – detecção de endereçamento habilitada em modo stop Indicador de estado do pino SCLAn (somente quando IICEn=1): CLDn 0 – pino em nível baixo bCLD 1 – pino em nível alto Indicador de estado do pino SDAAn (somente quando IICEn=1): DADn 0 – pino em nível baixo bDAD 1 – pino em nível alto Seleção do modo de operação: SMCn 0 – padrão (até 100kbps) bSMC 1 – alta velocidade (até 1Mbps) Controle do filtro digital: DFCn 0 – filtro desligado bDFC 1 – filtro ligado Seleção do clock de operação: PRSn 0 – f CLK bPRS 1 – f CLK /2 (clock acima de 20MHz)

230 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura Configuração do ciclo inativo do clock SCLAn IICCWLn Escrita Reset 1 1 1 1 1 1 1 1

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura Configuração do ciclo ativo do clock SCLAn IICCWHn Escrita Reset 1 1 1 1 1 1 1 1

Periféricos de Comunicação 231

232 Microcontroladores RL78: Guia Básico

10

Tópicos Avançados 10. Tópicos Avançados

Neste capítulo iremos estudar algumas funcionalidades avançadas dos RL78 tais como o ajuste BCD, sistemas de segurança e de proteção de memória, hardware de multiplicação e divisão, gravação e apagamento da memória flash e dataflash e módulo de acesso direto a memória (DMA). No final do capítulo também são abordadas algumas técnicas de programação voltadas aos RL78.

10.1. Ajuste BCD

O sistema de ajuste BCD consiste numa pequeno bloco de hardware encarregado de corrigir o resultado de uma operação de adição ou subtração envolvendo dados codificados em BCD (Binary Coded Decimal). Caso o leitor não se recorde, BCD é uma técnica de representação que utiliza apenas os dígitos decimais para codificação em binário. Assim, utilizando a representação hexadecimal natural, um byte pode representar valores entre 0x00 e 0xFF, num total de 256 combinações. Utilizando BCD temos apenas as codificações de 0x00 a 0x99 e cada grupo de quatro dígitos binários (um nibble) representa uma posição decimal. Desta forma, o número 0x19 se codificado em BCD irá representar o número 19 decimal e o incremento dele deve resultar em 0x20 (o equivalente BCD a 20 decimal). O problema com a codificação BCD é que, apesar de ela ser natural para o ser humano, não é natural para os computadores digitais. Assim, numa CPU digital como a do RL78, a adição de 1 ao valor 0x19 irá sempre resultar em 0x1A, que não é um número BCD válido. Para contornar isso a Renesas incluiu um pequeno circuito de correção BCD que atua com o registrador A e os flags CY e AC (registrador PSW) produzindo um resultado no registrador BCDADJ que consiste no valor de A ajustado para BCD conforme o estado dos flags CY e AC. A utilização do ajuste BCD em linguagem assembly é muito simples. No exemplo citado (0x19 + 1), o código seria o seguinte: MOV A,#0x19 ; A = 0x19 ADD A,#1 ; A = 0x1A ADD A,!BCDADJ ; A = 0x20 Infelizmente não há uma forma simples de utilizar o ajuste BCD em linguagem C, já que não há como garantir que uma determinada variável seja armazenada no registrador A da CPU, por isso, é sempre necessário utilizar código assembly.

Tópicos Avançados 233

O exemplo a seguir demonstra como utilizar instruções assembly dentro de um programa em C para implementar uma adição BCD. Observe que este programa deve ser testado diretamente no hardware já que o simulador (ao menos no EWRL78 versão 1.10) não implementa o circuito de ajuste BCD. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

volatile unsigned char va_BCD, vb_BCD;

unsigned char bcd_add(unsigned char va, unsigned char vb) { __asm("ADD A,B"); __asm("ADD A,0xF00FE"); // 0xF00FE é o endereço do registrador BCDADJ } unsigned char bcd_sub(unsigned char va, unsigned char vb) { __asm("SUB A,B"); __asm("SUB A,0xF00FE"); // 0xF00FE é o endereço do registrador BCDADJ } void main(void) { va_BCD = 0x19; vb_BCD = bcd_add(va_BCD,1); // vb_BCD = 0x20 va_BCD = 0x32; vb_BCD = bcd_sub(va_BCD,3); // vb_BCD = 0x29 while (1); } Exemplo 10.1

10.2. Funções de Segurança

Aplicações microcontroladas estão sujeitas a falhas: interferências causadas por ruídos elétricos ou campos elétricos intensos podem provocar alterações indesejadas no conteúdo das memórias e registradores, causando, em alguns casos, falhas que podem ser catastróficas (como em aplicações aeroespaciais, automotivas relacionadas a sistemas de segurança tais como: airbags, ABS, controle do motor, câmbio, etc.).

234 Microcontroladores RL78: Guia Básico

A Comissão Eletrotécnica Internacional (IEC) criou alguns padrões (IEC60335, IEC60730 e IEC61508) que estabelecem conjuntos de testes e algoritmos de detecção de falhas que podem evitar que falhas de software ou hardware afetem a aplicação de forma a causar danos sérios ou prejuízos a vida. A Associação para Confiabilidade de Software na Indústria Automotiva (MISRA) também definiu uma série de regras (MISRA-C) que devem ser seguidas para garantir maior confiabilidade às aplicações envolvendo software automotivo (inclusive disponível dentro do ambiente EWRL78 da IAR). Os microcontroladores RL78 incluem uma série de facilidades de hardware que permitem garantir a correta operação da aplicação e o atendimento aos padrões IEC, são elas: • Checagem de CRC da memória flash: para detecção de falhas na memória flash; • Checagem de paridade da memória RAM: para detecção de erros simples na área da RAM; • Sistema de guarda: evita alterações indevidas em registradores chave do microcontrolador; • Execução de opcode ilegal: detecta a tentativa de executar uma instrução não implementada; • Acesso ilegal à memória: detecta acessos a áreas de memória inválidas ou não permitidas; • Verificação do ADC e do Clock: permite detectar se estes módulos estão operando dentro das especificações da aplicação. Alguns outros testes especificados nos padrões IEC60730 e IEC61508 são implementados inteiramente por software. A Renesas possui uma nota de aplicação que detalha as funções de uma biblioteca de auto teste específica para a norma IEC60730. A AN0749 demonstra a implementação de diversos testes e a utilização do hardware de segurança interno no suporte de segurança da aplicação. 10.2.1. Checagem de CRC da Flash A checagem de CRC da memória flash utiliza um circuito de alta velocidade (high speed CRC) que realiza o cálculo do CRC (polinomial CRC16 do CCITT) a uma taxa de 32 bits por ciclo de clock. Isto permite que o cálculo do CRC de uma área de 64KiB de memória (como no R5F100LE utilizado na maioria dos exemplos deste livro) seja completado em 512µs (quando operando com um clock de 32MHz). A utilização desta facilidade é muito simples: 1. A aplicação deve habilitar o módulo (bit CRC0EN) e configurar a faixa de endereços a ser verificada (registrador CRC0CTL); 2. Em seguida é necessário inicializar o registrador PGCRCL com o valor 0x0000; 3. O CRC inicia a sua operação quando a instrução HALT é executada (na RAM); 4. A CPU permanece no modo halt enquanto o cálculo do CRC estiver em andamento, ao término do mesmo a CPU é acordada automaticamente e o valor final do CRC pode ser lido no registrador PGCRCL.

Tópicos Avançados 235

Normalmente o resultado do cálculo do CRC deverá ser comparado com um valor previamente armazenado (o CRC calculado previamente para a mesma área de memória) e caso o resultado seja diferente, a aplicação deve entrar em um estado de erro.

Atenção: a instrução HALT deve ser executada na memória RAM! Isso pode ser feito através de um pequeno código (HALT seguido por RET) que deve ser colocado armazenado na RAM i e chamado através de uma instrução CALL (ou CALLT). Além disso, caso a depuração esteja ativada, o resultado do CRC será diferente daquele feito com a depuração desativada.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura CRC0EN 0 FEA5 FEA4 FEA3 FEA2 FEA1 FEA0 CRC0CTL Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Controle de operação da checagem de CRC da memória flash: CRC0EN 0 – checagem desativada bCRC0EN 1 – checagem ativada (durante a execução da instrução HALT) FEA5 Seleção da faixa de endereços da checagem de CRC. A faixa de endereços vai FEA4 de 0x00000 até o endereço final determinado pela fórmula: FEA3 END_FINAL=16379+16384*FEA - FEA2 Assim, quando FEA = 4, o endereço final será igual a 81915 ou 0x13FFB. FEA1 O maior valor para o campo FEA é 31 (para um chip com 512K iB de FEA0 memória)

10.2.2. Checagem de Paridade da RAM Os microcontroladores RL78 incluem um bit de paridade para cada byte de memória RAM, ou seja, toda a memória RAM destes chips é dotada de um nono bit de paridade. Esta característica é bastante incomum e raramente vista em microcontroladores do mesmo nível do RL78. A verificação de paridade encontra-se sempre ativa e pode ser verificada através do bit RPEF no registrador RPECTL, caso ocorra um erro de paridade o microcontrolador é automaticamente ressetado. Opcionalmente, é possível desabilitar o reset por erro de paridade, para isso, basta setar o bit RPERDIS no registrador RPECTL. Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura RPERDIS 0 0 0 0 0 0 RPEF RPECTL Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Mascaramento do reset por erro de paridade da RAM: RPERDIS 0 – reset por erro de paridade habilitado bRPERDIS 1 – reset por erro de paridade desabilitado Indicador de erro de paridade da RAM: RPEF 0 – nenhum erro de paridade bRPEF 1 – foi detectado um erro de paridade

236 Microcontroladores RL78: Guia Básico

10.2.3. Bloqueio de Registradores e da RAM Outra característica importante acerca da segurança dos microcontroladores RL78 é a possibilidade de bloquear a alteração (proteção contra escrita) de grupos de registradores SFR e áreas da RAM, evitando desta forma que, uma aplicação em estado anômalo de execução, possa alterar inadvertidamente registradores ou áreas importantes de memória. Esta funcionalidade é controlada pelos bits GRAM1, GRAM0, GPORT, GINT e GCSC do registrador IAWCTL. Os bits GRAM1 e GRAM0 controlam o bloqueio da RAM. Até 512 bytes da RAM podem ser protegidos contra escrita (sempre contando-se do endereço mais baixo para o mais alto). O bit GPORT permite proteger contra escrita os registradores associados às portas de E/S: PMxx, PUxx, PIMxx, POMxx, PMCxx, ADPC e PIOR. Note que os registradores de leitura e escrita nas portas (Pxx) não são protegidos por esta função e continuam podendo ser lidos ou escritos livremente. O bit GINT permite proteger contra escrita os registradores associados ao sistema de interrupção: IFxx, MKxx, PRxx, EGPx e EGNx. O bit GCSC permite proteger contra escrita os registradores associados ao sistema de clock: CMC, CSC, PSTS, CKC, PERx, OSMC, LVIM, LVIS e RPECTL.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura IAWEN 0 GRAM1 GRAM0 0 GPORT GINT GCSC IAWCTL Escrita 1 Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Controle de reset por acesso a área de memória inválida: 0 – reset desabilitado 1 – reset habilitado IAWEN bIAWEN Uma vez setado, este bit não pode ser apagado por software! Escrever “0” no mesmo não produz efeito. Proteção contra a escrita na RAM (RAM Guard): 00 – RAM Guard desabilitada, toda a RAM pode ser escrita RAMGUARD_DIS GRAM1 01 – primeiros 128 bytes da RAM protegidos GRAM0 RAMGUARD_128 10 – primeiros 256 bytes da RAM protegidos RAMGUARD_256 11 – primeiros 512 bytes da RAM protegidos RAMGUARD_512 Proteção contra a escrita nos SFRs das portas (PMxx, PUxx, PIMxx, POMxx, PMCxx, ADPC e PIOR): GPORT bGPORT 0 – proteção desabilitada, SFRs pode ser escritos livremente 1 – proteção contra escrita ativada nos SFRs Pr oteção contra a escrita nos SFRs de interrupção (IFxx, MKxx, PRxx, EGPx e EGNx): GINT bGINT 0 – proteção desabilitada, SFRs pode ser escritos livremente 1 – proteção contra escrita ativada nos SFRs Proteção contra a escrita nos SFRs do sistema de clock, L VD e controle de paridade da RAM (CMC, CSC, PSTS, CKC, PERx, OSMC, LVIM, LVIS e RPECTL): GCSC bGCSC 0 – proteção desabilitada, SFRs pode ser escritos livremente 1 – proteção contra escrita ativada nos SFRs

Tópicos Avançados 237

10.2.4. Execução de Opcode Ilegal (Trap) Outro mecanismo de proteção existente nos RL78 é o reset por execução de opcode ilegal. O único opcode não implementado nos RL78 é o de código hexadecimal 0xFF, assim, caso a CPU tente executar uma instrução cujo primeiro byte é iniciado por este valor, um reset será gerado e o bit TRAP no registrador RESF será setado.

10.2.5. Acesso Ilegal à Memória (IAW) Também é possível configurar o RL78 para gerar um reset caso a CPU tente fazer um acesso a área de memória não implementada ou de acesso não permitido. No RL78, considera-se um acesso não permitido a tentativa de executar instruções na área de registradores SFR ou dataflash, além da tentativa de escrita na área de dataflash ou flash de programa. As áreas não implementadas são aquelas marcadas como “reservadas” na figura 3.1. Qualquer acesso (leitura ou escrita) a áreas não implementadas irá provocar um reset IAW. O reset IAW deve ser habilitado por software, escrevendo-se “1” no bit IAWEN do registrador IAWCTL. Uma vez habilitado, não é possível desabilitar o reset IAW por software!

10.2.6. Verificação do A/D O conversor A/D dos RL78 possui um registrador especial destinado a realização de testes. Através do registrador ADTES, é possível configurar o conversor para realizar conversões utilizando como entrada a tensão de referência externa positiva (AV REFP) ou negativa (AV REFM ). Quando os bits ADTES1=1 e ADTES0=0 no registrador ADTES, o conversor irá converter a entrada AV REFM . Neste caso, se o conversor estiver operando corretamente, o resultado deverá ser igual a zero. Quando os bits ADTES1=1 e ADTES0=1 no registrador ADTES, o conversor irá converter a entrada AV REFP . Neste caso, se o conversor estiver operando corretamente, o resultado deverá ser igual a 0xFF (modo de 8 bits) ou 0x3FF (modo de 10 bits).

10.2.7. Verificação do Clock É possível utilizar o canal 5 da TAU0 para efetuar a medição do período do sinal do oscilador LOCO (15kHz) ou do oscilador XT1 (32768Hz). Desta forma a aplicação pode determinar se o clock principal (seja ele derivado do oscilador interno HOCO ou do oscilador externo X1) está dentro ou fora de uma faixa de valores aceitáveis.

238 Microcontroladores RL78: Guia Básico

Para fazer esta medição, basta configurar o canal 5 da TAU0 para operar no modo de medição de período e utilizar o registrador TIS0 para selecionar o LOCO ou o XT1 como fonte de sinal para o canal.

Caso seja utilizado o LOCO (15kHz) como fonte de sinal do canal, lembre-se de que este oscilador possui uma baixa precisão (±15%) e, portanto, a aplicação deverá tolerar O variações de medição incluindo este valor e mais a tolerância do oscilador principal (HOCO ou X1).

É possível realizar a calibração do oscilador HOCO utilizando-se o oscilador externo XT1 como fonte de clock do canal. Através do valor medido para o período de XT1 a aplicação O pode determinar o erro do oscilador HOCO e atuar sobre o registrador HIOTRM de forma que o valor medido se aproxime o máximo possível do valor calculado.

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura 0 0 0 0 0 TIS02 TIS01 TIS00 TIS0 Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Seleção da entrada de clock externo do canal 5 da TAU0: 000 – Pino TI05 TIS_TI05 TIS02 001 – Pino TI05 - TIS01 010 – Pino TI05 - TIS00 011 – Pino TI05 - 100 – Oscilador LOCO (15kHz) TIS_LOCO 101 – Oscilador XT1 TIS_XT1

10.3. CRC de Uso Geral

Os microcontroladores da linha G13 incluem um circuito de cálculo de CRC (checagem de redundância cíclica) que pode ser utilizado para calcular CRC (16 bits com polinomial CCITT) de maneira simples e rápida. A utilização do módulo CRC é bastante simples: basta inicializar o registrador de dados do CRC (CRCD) com o valor 0x0000, em seguida, utiliza-se o registrador CRCIN para inserir os dados de 16 bits com os quais deseja-se calcular o CRC, após isso, basta ler o valor do CRC no registrador CRCD. A seguir temos um pequeno fragmento de programa que demonstra o cálculo do CRC dos valores 0x12, 0x34 e 0x56: CRCD = 0; CRCIN = 0x12; CRCIN = 0x34; CRCIN = 0x56; crc_final = CRCD;

Tópicos Avançados 239

10.4. Gravação e Apagamento da Flash e DataFlash

Os microcontroladores RL78 incluem os circuitos internos necessários para gravação e apagamento da memória flash de programa e de dados. A utilização desta funcionalidade se dá através do uso de bibliotecas especiais de software fornecidas pelo fabricante. Estão disponíveis três bibliotecas, que deve ser utilizadas de acordo com o tipo de memória (flash ou dataflash) e o tipo de uso (dados ou programa): FSL – Flash Self-programming Library, utilizada para apagamento e programação da memória flash de programa; FDL – Flash Data Library, utilizada para apagamento e programação da memória dataflash (utilizada exclusivamente para dados não voláteis); EEL – EEPROM Emulation Library, utilizada para emulação de EEPROM na memória dataflash. Cada uma destas bibliotecas possui uma API (Application Programming Interface) composta de uma série de funções C utilizadas para inicialização, apagamento, programação e controle da memória.

10.4.1. FSL A biblioteca FSL pode ser utilizada para apagamento e programação da área de memória flash de programa. Ela pode ser utilizada tanto por bootloaders (programas especiais que permitem apagar e reprogramar a memória flash com outras aplicações) quanto para armazenamento de grandes quantidades de dados não voláteis. A desvantagem do uso da memória de programa para o armazenamento de dados não voláteis é que ela possui uma menor capacidade de ciclos de apagamento/gravação (um mínimo de 1.000 ciclos para retenção de 20 anos, enquanto a dataflash apresenta uma capacidade de 10.000 ciclos para o mesmo tempo de retenção). A tabela a seguir apresenta as principais características da FSL (o tamanho da FSL na memória flash depende das funções utilizadas). Tamanho Flash Buffer na RAM Pilha Capacidades da FSL (bytes) (bytes) (bytes) Básicas: apagamento, gravação, verificação e Mínimo 570 5 a 256 56 proteção de área Médio 870 5 a 256 56 Todas, exceto as relacionadas ao bloco duplo de boot Completo 1.350 5 a 256 56 Todas Tabela 10.1

Nos RL78 a memória flash somente pode ser apagada em blocos, cada um com tamanho de 1024 bytes. A figura 3.2 mostra a organização dos blocos de memória flash. O tempo mínimo de apagamento de um bloco é de 4.880 ciclos de clock mais 163µs (cerca de 5,04ms com clock de 1MHz ou 315µs com clock de 32MHz). O tempo máximo é de 73.342 ciclos de clock mais 255.366µs (cerca de 328,71ms com clock de 1MHz ou 257,66ms com clock de 32MHz).

240 Microcontroladores RL78: Guia Básico

No tocante a gravação, em razão da disposição dos barramentos internos da memória flash, somente é possível gravar palavras de 32 bits (4 bytes) de cada vez. O tempo máximo de gravação de uma palavra de 32 bits é de 4.283 ciclos de clock mais 627µs (cerca de 4,91ms com clock de 1MHz ou 760,84µs com clock de 32MHz). No caso de palavras posteriores gravadas dentro do mesmo ciclo de gravação, o tempo máximo de gravação é de 1153 ciclos de clock mais 561µs (cerca de 1,72ms com clock de 1MHz ou 597µs com clock de 32MHz). A biblioteca FSL pode operar de duas formas: checagem de status automática ou checagem de status pelo usuário. Na checagem de status automática (SCI) a chamada a uma função FSL somente retorna após a execução completa do comando, ou seja, enquanto o comando é executado a aplicação permanece parada. Na checagem de status pelo usuário (SCU), a chamada a uma função FSL retorna imediatamente e a FSL opera no chamado modo background (segundo plano). Neste caso, a verificação do status cabe a aplicação (através da função FSL_StatusCheck). Note que neste modo a FSL deve ser executada em RAM o que faz com que a ocupação de RAM, pelo programa, seja maior. A API da FSL define algumas estruturas e tipos de dados utilizados pelas mesmas. A seguir apresentamos as principais funções e os seus tempos de execução máximos no modo de checagem de status automática. FSL_Init(const __far fsl_descriptor_t __far* descriptor_pstr) – inicializa a FSL conforme o descritor passado como parâmetro. O descritor é uma estrutura composta de três campos: fsl_flash_voltage_u08 : especifica a faixa de tensões no qual a flash vai operar. Pode assumir dois valores: 0 – operação em alta velocidade (tensões de 3 a 5,5V); outros valores – operação em ampla faixa de tensão. fsl_frequency_u08 – s eleção da frequência de operação do chip (cada unidade vale 1MHz). Para 32MHz o valor deve ser 32, para 20MHz o valor deve ser 20 e assim por diante. A FSL não suporta operação abaixo de 1MHz! fsl_auto_status_check_u08 – seleção do modo de operação da FSL. Pode assumir dois valores: 0 – checagem pelo usuário (funções retornam imediatamente) Outros valores – checagem interna (funções retornam somente após a execução) Esta função retorna um dado do tipo fsl_u08: 0 – FSL inicializada (símbolo FSL_OK); 5 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); Tempo de execução: 5021 ciclos de clock. FSL_Open() – inicia uma sessão FSL. Esta função somente pode ser executada após a FSL estar inicializada corretamente. Tempo de execução: 10 ciclos de clock. FSL_Close() – encerra uma sessão FSL. Tempo de execução: 10 ciclos de clock.

Tópicos Avançados 241

FSL_PrepareFunctions() – ativa as funções básicas da FSL ( FSL_BlankCheck, FSL_Erase, FSL_Write, FSL_IVerify, FSL_StatusCheck, FSL_StandBy e FSL_WakeUp). Esta função somente pode ser chamada dentro de uma sessão FSL já aberta por FSL_Open() . Somente após a sua execução é que as funções mencionadas podem ser executadas. Tempo de execução: 2465 ciclos de clock.

FSL_BlankCheck(fsl_u16 block_u16) – verifica se o bloco especificado está apagado. block_u16 : especifica um bloco de 1024 bytes da memória (começando do endereço 0). Esta função retorna um dado do tipo fsl_u08: 0 – FSL inicializada (símbolo FSL_OK); 0x05 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); 0x1A – erro de apagamento (símbolo FSL_ERR_ERASE); 0x1B – erro de verificação de apagamento (símbolo FSL_ERR_BLANKCHECK); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW); 0xFF – FSL ocupada, comando em execução (símbolo FSL_BUSY). Tempo de execução: 4844 ciclos de clock + 164µs.

FSL_IVerify(fsl_u16 block_u16) – verifica o estado do bloco especificado (verificação interna da FSL com o objetivo de determinar se as células de memória estão gravadas de forma a atingir a máxima retenção de dados). block_u16 : especifica um bloco de 1024 bytes da memória (começando do endereço 0). Esta função retorna um dado do tipo fsl_u08: 0 – bloco apagado e com retenção máxima garantida (símbolo FSL_OK); 0x05 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); 0x1B – erro de verificação (símbolo FSL_ERR_IVERIFY); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW); 0xFF – FSL ocupada, comando em execução (símbolo FSL_BUSY). Tempo de execução: 10476 ciclos de clock + 1107µs.

FSL_Erase(fsl_u16 block_u16) – apaga o bloco de memória especificado. block_u16 : especifica um bloco de 1024 bytes da memória (começando do endereço 0). Esta função retorna um dado do tipo fsl_u08: 0 – bloco apagado (símbolo FSL_OK); 0x05 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); 0x10 – bloco protegido, apagamento não permitido (símbolo FSL_ERR_PROTECTION) 0x1A – erro de apagamento (símbolo FSL_ERR_ERASE); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW); 0xFF – FSL ocupada, comando em execução (símbolo FSL_BUSY). Tempo de execução: 73342 ciclos de clock + 255366µs.

242 Microcontroladores RL78: Guia Básico

FSL_Write(__near fsl_write_t __near* write_pstr) – escreve palavras (32 bits) no endereço especificado. Os parâmetros da função são passados atravé s de uma estrutura contendo os seguintes campos: fsl_data_buffer_p_u08 : ponteiro para o buffer (array) contendo os dados a serem escritos; fsl_destination_address_u32 : endereço da flash onde os dados devem ser escritos (deve ser um múltiplo de 4); fsl_word_count_u08 : número de palavras (32 bits) a serem escritas (1 a 256). Esta função retorna um dado do tipo fsl_u08: 0 – dados gravados (símbolo FSL_OK); 0x05 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); 0x10 – bloco protegido, gravação não permitida (símbolo FSL_ERR _PROTECTION) 0x1C – erro de gravação (símbolo FSL_ERR_WRITE); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW); 0xFF – FSL ocupada, comando em execução (símbolo FSL_BUSY). Tempo de execução: 3130 ciclos de clock+66µs+(1153 ciclos+561µs)*número de palavras. FSL_StatusCheck() – retorna o status de execução de um comando (especialmente útil no modo de checagem de status pelo usuário). Esta função retorna um dado do tipo fsl_u08: 0 – FSL inicializada (símbolo FSL_OK); 0x1A – erro de apagamento (símbolo FSL_ERR_ERASE); 0x1B – erro de verificação de apagamento (símbolo FSL_ERR_BLANKCHECK); 0x1C – erro de escrita (símbolo FSL_ERR_WRITE); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW); 0x30 – nenhum comando em execução (símbolo FSL_ERR_IDLE); 0xFF – FSL ocupada com um comando em execução (símbolo FSL_BUSY). Tempo de execução: veja documentação da FSL. FSL_StandBy() – suspende um comando em execução (escrita, apagamento, etc.). Esta função somente pode ser utilizada n o modo de checagem de status pelo usuário. Esta função retorna um dado do tipo fsl_u08: 0 – comando suspenso corretamente (símbolo FSL_OK); 0x1A – apagamento suspenso com erro (símbolo FSL_ERR_ERASE); 0x1B – verificação de apagamento suspensa com erro (sím bolo FSL_ERR_BLANKCHECK); 0x1C – escrita suspensa com erro (símbolo FSL_ERR_WRITE); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW); 0x30 – nenhum comando em execução (símbolo FSL_ERR_IDLE); 0x43 – comando já suspenso (símbolo FSL_SUSPEND). Tempo de execução: veja documentação da FSL.

Tópicos Avançados 243

FSL_WakeUp() – resume um comando previamente suspenso por FSL_StandBy. Esta função somente pode ser utilizada no modo de checagem de status pelo usuário. Esta função retorna um dado do tipo fsl_u08: 0 – comando resumido e executado com sucesso (símbolo FSL_OK); 0x1A – apagamento resumido com erro (símbolo FSL_ERR_ERASE); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW); 0xFF – comando resumido em execução (símbolo FSL_BUSY). Tempo de execução: veja documentação da FSL.

FSL_PrepareExtFunctions() – ativa as funções estendidas da FSL (FSL_SetXXXProtectFlag, FSL_InvertBootFlag, FSL_SetFlashShieldWindow, FSL_SwapBootCluster e FSL_SwapActiveBootCluster) além das funções básicas de FSL_Prepa reFunctions(). Esta função somente pode ser chamada dentro de uma sessão FSL já aberta por FSL_Open() . Somente após a sua execução é que as funções mencionadas podem ser executadas. Tempo de execução: 1221 ciclos de clock.

FSL_GetBlockEndAddr (__near fsl_getblockendaddr_t* getblockendaddr_pstr) – retorna o último endereço do bloco especificado. Os parâmetros da função são passados através de uma estrutura contendo os seguintes campos: fsl_destination_address_u32 : após a execução da função, este parâmetro irá conter o último endereço do bloco especificado; fsl_block_u16 : contém o número do bloco a ser pesquisado. Esta função retorna um dado do tipo fsl_u08: 0 – comando executado com sucesso (símbolo FSL_OK); 0x05 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW). Tempo de execução: 368 ciclos de clock.

FSL_GetFlashShieldWindow(__near fsl_fsw_t __near* getfsw_pstr) – retorna o bloco inícial e final da área de janela da flash. Os parâmetros da função são passados através de uma estrutura contendo os seguintes campos: fsl_start_block_u16 : número do primeiro bloco da área de janela da flash; fsl_end_block_u16 : número do último bloco da área de janela da flash. Esta função retorna um dado do tipo fsl_u08: 0 – comando executado com sucesso (símbolo FSL_OK); 0x05 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW). Tempo de execução: 307 ciclos de clock.

244 Microcontroladores RL78: Guia Básico

FSL_SetFlashShieldWindow(__near fsl_fsw_t __near* getfsw_pstr) – configura o bloco inicial e final da área de janela da flash. Os parâmetros da função são passados através de uma estrutura contendo os seguintes campos: fsl_start_block_u16 : número do primeiro bloco da área de janela da flash; fsl_end_block_u16 : número do último bloco da área de janela da flash. Esta função retorna um dado do tipo fsl_u08: 0 – comando executado com sucesso (símbolo FSL_OK); 0x05 – erro de parâmetro (símbolo FSL_ERR_PARAMETER); 0x1F – erro de fluxo (símbolo FSL_ERR_FLOW). Tempo de execução: veja documentação da FSL.

10.4.1.1. Utilização da FSL

Para utilizar a FSL em uma aplicação é necessário primeiramente baixar o instalador da biblioteca, disponível no site da Renesas: www.renesas.com. O instalador irá apresentar uma janela na qual o programador deverá selecionar o microcontrolador e o compilador utilizado para desenvolver a aplicação (figura 10.1).

Figura 10.1

O instalador irá gerar uma pasta no local selecionado. Esta pasta irá conter duas subpastas: Lib – com os arquivos da biblioteca FSL que devem ser incluídos no projeto (fsl.h, fsl_types.h e fsl.r87); Smp – com dois arquivos de configuração do linker. Estes arquivos devem ser utilizados como base, substituindo o arquivo de configuração do linker no projeto. Observe que apenas um dos arquivos deve ser utilizado. A seleção deverá considerar o modo de operação da FSL: caso seja utilizada a checagem de status interna, seleciona-se o arquivo de linker fsl_sample_linker_file_SCI.xcl e caso seja utilizada a checagem de status pelo usuário, seleciona- se o arquivo de linker fsl_sample_linker_file_SCU.xcl. Observe que o arquivo de configuração do linker irá conter uma seção destinada aos segmentos de memória necessários para a operação da FSL (neles são armazenadas as funções da API da FSL). A seguir temos um trecho do arquivo gerado para o R5F100LE:

Tópicos Avançados 245

// FSL // ======-Z(CODE)FSL_FCD=[2800-FFFF]/10000 -Z(CODE)FSL_FECD=[2800-FFFF]/10000 -Z(CODE)FSL_BCD=[2800-FFFF]/10000 -Z(CODE)FSL_BECD=[2800-FFFF]/10000 -Z(CODE)FSL_RCD=[2000-FFFF]/10000 Conforme a aplicação pode ser necessário modificar a área destinada ao armazenamento da FSL e da aplicação. A seguir apresentamos um exemplo de utilização da FSL. Trata-se uma aplicação simples que memoriza (na flash do chip) o último estado do led (aceso ou apagado), desta forma, ao se desligar e religar a placa, o estado do led é mantido. Este exemplo também demonstra como configurar o linker de forma a criar uma área dedicada ao armazenamento de dados não voláteis na memória de programa. Note que o arquivo fsl.r87 deve ser incluído dentro do projeto, pois ele contém o código compilado da biblioteca FSL. Para inserir o arquivo no projeto clique no menu principal: Projects > Add files, selecione a pasta do projeto, em tipo de arquivos selecione “Library/Object files” e então selecione e adicione o arquivo fsl.r87. A figura 10.2 mostra a aparência que o projeto deve ter após a inclusão do arquivo. O arquivo do linker (fsl_sample_linker_ file_SCI.xcl) deverá ser selecionado na janela de opções do projeto, categoria “linker”, aba Figura 10.2 “config”, conforme mostra a figura 10.3.

Figura 10.3

246 Microcontroladores RL78: Guia Básico

Neste exemplo precisamos armazenar apenas o estado do led (ligado ou desligado), o que significa apenas um bit de informação. No entanto, devido ao fato de que o menor bloco de memória apagável no RL78 é de 1024 bytes, seremos obrigados a reservar todo um bloco de 1024 bytes de memória de programa para armazenar o estado do led. Este bloco de memória deverá ser incluído no arquivo de configuração do linker, assim, utilizando como base o arquivo fsl_sample_linker_file_SCI.xcl gerado pelo instalador da FSL, faremos as modificações mostradas em negrito, conforme a seguir: -Z(FARCONST)FAR_ID=02FFF-FBFF -Z(FARDATA)FAR_I=FF700-FFEDF

// FSL // ======-Z(CODE)FSL_FCD=[2800-FBFF ]/10000 -Z(CODE)FSL_FECD=[2800-FBFF ]/10000 -Z(CODE)FSL_BCD=[2800-FBFF ]/10000 -Z(CODE)FSL_BECD=[2800-FBFF ]/10000 -Z(CODE)FSL_RCD=[2000-FBFF ]/10000

//------// Startup, Runtime-library, Near, Interrupt // and CALLT functions code segment. //------Z(CODE)RCODE,CODE=01000-FBFF -Z(DATA)FLASH_DATA=FBFF-FFFF

//------// Far functions code segment. //------Z(CODE)XCODE=[01000-FBFF ]/10000

//------// Data initializer segments. //------Z(CONST)NEAR_ID=[02000-FBFF ]/10000 -Z(CONST)SADDR_ID=[02000-FBFF ]/10000 -Z(CONST)DIFUNCT=[02000-FBFF ]/10000

//------// Constant segments //------Z(CONST)NEAR_CONST=_NEAR_CONST_LOCATION_START-_NEAR_CONST_LOCATION_END -P(CONST)FAR_CONST=[02000-FBFF ]/10000 -Z(CONST)SWITCH=02000-FBFF -Z(CONST)FSWITCH=[02000-FBFF ]/10000 Listagem 10.1

Basicamente, as modificações dizem respeito à inclusão dos segmentos destinados ao código da FSL e a delimitação da área destinada a código e constantes (até o endereço 0xFBFF da flash). O segmento destinado ao armazenamento dos dados não voláteis da aplicação é alocado nos últimos 1024 bytes da flash (0xFC00 a 0xFFFF) através do comando: -Z(DATA)FLASH_DATA=FBFF-FFFF O código de manipulação da flash foi separado em um arquivo próprio (flash.c), devendo o mesmo ser incluído no projeto O seu conteúdo é mostrado na listagem 10.2. #include "fsl_types.h" #include "fsl.h"

#pragma location = "FLASH_DATA"

Tópicos Avançados 247

__no_init __far unsigned char flash_data[1024];

static fsl_u08 my_fsl_status; static fsl_descriptor_t fsl_descr;

// Escreve uma palavra de 32 bits num endereço de 32 bits da flash void flash_write32(unsigned long data, unsigned long int address) { unsigned long int array[1]; fsl_write_t my_fsl_write_str; array[0] = data; my_fsl_write_str.fsl_data_buffer_p_u08 = (fsl_u08 __near*)array; my_fsl_write_str.fsl_word_count_u08 = 0x01; my_fsl_write_str.fsl_destination_address_u32 = address; my_fsl_status = FSL_Write((fsl_write_t __near*)&my_fsl_write_str); }

// lê um byte da flash unsigned char flash_read8(unsigned long addr) { return(*(__far char *)addr); }

// Apaga o bloco de dados não voláteis na flash void flash_erase(void) { FSL_Erase(63); // apaga o bloco 63 (0xFC00 a 0xFFFF) }

void flash_init(void) { // Inicialização da FSL fsl_descr.fsl_flash_voltage_u08 = 0; // full speed mode fsl_descr.fsl_frequency_u08 = 32; // 32MHz // Modo da FSL = SCI - checagem de status interna fsl_descr.fsl_auto_status_check_u08 = 0x01; // Inicializa a FSL FSL_Init((__far fsl_descriptor_t*)&fsl_descr); FSL_Open(); // abre uma sessão FSL FSL_PrepareFunctions(); // inicializa funções básicas FSL } Listagem 10.2 Repare que a função de apagamento do bloco da flash realiza o apagamento do bloco de número 63. Este valor pode ser obtido através das fórmulas mostradas no tópico 3.1.2. Foi também criado um array chamado flash_data. Através do mesmo é possível acessar diretamente qualquer um dos 1024 bytes localizados no bloco FLASH_DATA (definido no arquivo do linker).

Lembre-se de que o RL78 armazena os dados em formato little endian )! Isto significa que O após a execução de flash_write32(0x12345678,0xFC00), o endereço 0xFC00 irá receber o valor 0x78, 0xFC01 irá receber 0x56, 0xFC02 irá receber 0x34 e 0xFC03 irá receber 0x12!

A seguir temos o código fonte do restante da aplicação.

248 Microcontroladores RL78: Guia Básico

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h" #include "flash.c"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define LED3_RSK P6_bit.no3 #define LED_RPB P7_bit.no7 #define SW1 P5_bit.no0 // Tempo para debounce da tecla 5 = 50ms #define KEY_TIMER 5

volatile unsigned char save_status;

#pragma vector = INTIT_vect __interrupt void trata_IT(void) { static unsigned char debounce_counter, key_release; // faz o debounce da tecla SW1 if (!SW1) { // se a tecla está pressionada if (debounce_counter) debounce_counter--; else { if (key_release) // se a tecla estava liberada { LED3_RSK = !LED3_RSK; // inverte o estado do led LED_RPB = !LED_RPB; // inverte o estado do led key_release = 0; // tecla não liberada } save_status = 1; // solicita salvamento do estado do led } } else { // se a tecla não está pressionada debounce_counter = KEY_TIMER; // novo tempo de debounce key_release = 1; // tecla está liberada } }

void MCU_init(void) { PM7_bit.no7 = 0; // P7.7 como saída

Tópicos Avançados 249

PM6_bit.no3 = 0; // P6.3 como saída LED_RPB = 1; // led da RPB desligado LED3_RSK = 1; // led 3 da RSK desligado // configura o LOCO (15kHz) como fonte de clock do IT/RTC OSMC = bWUTMMCK0; RTCEN = 1; // habilita o RTC e o IT // Configura o IT para uma interrupção a cada 150 contagens, ou seja: // 150/15000 = 10ms -> uma interrupção a cada 10ms ITMC = bRINTE | 149; ITMK = 0; // habilita a interrupção do IT __enable_interrupt(); // habilita as interrupções do RL78 // restaura o estado do led conforme o conteúdo da flash if (flash_read8(0xFC00)==0) LED_RPB = LED3_RSK = 0; else LED_RPB = LED3_RSK = 1; }

void main(void) { MCU_init(); // inicializa o microcontrolador flash_init(); // inicializa a FSL while (1) { if (save_status) // se há requisição de salvamento na flash { save_status = 0; // limpa a requisição flash_erase(); // apaga a flash // se o led está ligado, salva 0 no endereço 0xFC00 // se o led está desligado, o endereço 0xFC00 permanece com 0xFF if (!LED_RPB) flash_write32(0,0xFC00); } } } Exemplo 10.2 A figura 10.4 mostra a aparência do ambiente EWRL78 durante uma sessão de depuração deste exemplo. Observe que o programa foi parado (botão break). Antes da paralisação do programa a tecla SW1 havia sido pressionada, fazendo com que o led 3 da placa acendesse.

Figura 10.4

250 Microcontroladores RL78: Guia Básico

A janela memory foi configurada para apresentar o endereço 0xFC00 (opção Goto 0xFC00) e o conteúdo das quatro primeiras posições (0xFC00 a 0xFC03) é zero, demonstrando que o conteúdo da flash foi efetivamente alterado. Para se verificar isso, basta executar a aplicação (botão run) pressionar o botão SW1 novamente (o led 3 irá se apagar) e paralisar novamente a aplicação (botão break): o conteúdo das posições 0xFC00 a 0xFC03 deverá ter sido alterado para 0xFF!

10.5. Hardware de Multiplicação e Divisão

Como já foi dito na parte introdutória deste livro, os microcontroladores RL78/G13 incluem hardware interno para multiplicação e divisão. Este hardware permite realizar operações de multiplicação inteira com e sem sinal (16 bits por 16 bits, com resultado de 32 bits), multiplicação inteira e acúmulo (MAC) com e sem sinal (16 bits por 16 bits mais 32 bits, com resultado de 32 bits) e divisão inteira sem sinal (32 bits por 32 bits, com resultado e resto de 32 bits). A operação de multiplicação é completada em um ciclo de clock, a operação de multiplicação e acúmulo necessita de dois ciclos para ser completada e a divisão necessita de dezesseis ciclos. É possível utilizar este hardware de duas formas: 1. Transparente: habilitando-se a opção de utilização do multiplicador por hardware na janela de opções do projeto (vide figura 10.1) o compilador IAR irá utilizar o hardware para acelerar as operações de multiplicação e divisão feitas em C. O aumento de performance é muito significativo, mas o consumo de flash é aumentado em cerca de 260 bytes em razão da adição de funções para manipulação do multiplicador. Vale lembrar que não é possível utilizar a modalidade de multiplicação e acúmulo diretamente em C (ou seja, ao se escrever uma declaração do tipo x += y * z o compilador utilizará o hardware apenas para a multiplicação, mas o acúmulo será feito por software e não por hardware). Operações de multiplicação e acúmulo inteiramente por hardware somente são possíveis manipulando-se diretamente o hardware multiplicador, conforme veremos a seguir. Lembre-se de que neste caso a opção de utilização do hardware multiplicador pelo compilador não deve ser utilizada!

Figura 10.5

Tópicos Avançados 251

2. Manual: a aplicação deve manipular diretamente os registradores do multiplicador. Nesta modalidade as operações de multiplicação e divisão em C continuam sendo feitas inteiramente por software e cabe ao programador escrever código para utilizar o hardware multiplicador. Esta opção é útil para se obter o máximo de performance, especialmente em aplicações DSP (processamento digital de sinais). A manipulação direta do hardware de multiplicação é feita utilizando-se os registradores MDAH, MDAL, MDBH, MDBL, MDCH, MDCL e MDUC. Nas operações de multiplicação com ou sem sinal, o multiplicando de 16 bits é carregado no registrador MDAL e o multiplicador de 16 bits é carregado no registrador MDAH, após um ciclo de clock o resultado da multiplicação (32 bits) pode ser lido nos registradores MDBH (16 bits mais significativos) e MDBL (16 bits menos significativos). Nas operações de multiplicação e acúmulo (MAC) com ou sem sinal, o multiplicando de 16 bits é carregado no registrador MDAL e o multiplicador de 16 bits é carregado no registrador MDAH, após dois ciclos de clock o resultado da multiplicação (32 bits) pode ser lido nos registradores MDBH (16 bits mais significativos) e MDBL (16 bits menos significativos) e o resultado acumulado é armazenado nos registradores MDCH (16 bits mais significativos) e MDCL (16 bits menos significativos). Após uma operação MAC os bits MACOF e MACSF do registrador MDUC são modificados de acordo com o resultado da operação: MACOF indica se houve ou não overflow (estouro) do valor representado no acumulador (MDC). Nas operações sem sinal este bit é setado quando o resultado acumulado ultrapassa o valor 0xFFFFFFFF. Nas operações sinalizadas este bit é setado quando o resultado é menor que 0x80000000 ou maior que 0x7FFFFFFF. MACSF é o indicador de sinal do valor acumulado (MDC). Nas operações de divisão de 32 por 32 bits, o dividendo de 32 bits deve ser carregado nos registradores MDA (MDAH com os 16 bits mais significativos e MDAL com os 16 bits menos significativos) e o divisor carregado nos registradores MDB (MDBH com os 16 bits mais significativos e MDBL com os 16 bits menos significativos). Após dezesseis ciclos de clock o resultado da divisão é armazenado nos registradores MDA (MDAH com os 16 bits mais significativos e MDAL com os 16 bits menos significativos) e o resto da divisão é armazenado nos registradores MDC (MDCH com os 16 bits mais significativos e MDCL com os 16 bits menos significativos). A seleção da operação a ser realizada pelo multiplicador deve ser feita no registrador MDUC antes de carregar os operandos nos registradores MDA/MDB. No caso das operações de multiplicação e multiplicação e acúmulo, a operação selecionada no MDUC é iniciada automaticamente depois de carregados os dois operandos nos registradores MDA/MDB (a ordem de carga dos operandos não é importante). No caso da operação de divisão, os operandos devem ser carregados nos registradores MDA e MDB e a operação é iniciada setando-se o bit DIVST no registrador MDUC.

252 Microcontroladores RL78: Guia Básico

Quando a operação de divisão é completada (dezesseis ciclos de clock depois) o bit DIVST é apagado pelo hardware e opcionalmente o flag MDIF é setado e uma interrupção INTMD é gerada (conforme o modo de divisão selecionado). Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura DIVMODE MACMODE 0 0 MDSM MACOF MACSF DIVST MDUC Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Símbolo C Seleção do modo de operação do multiplicador por hardware: 000 – multiplicação sem sinal MAC_MUL_UNS DIVMODE 001 – multiplicação com sinal MAC_MUL_SIG MACMODE 010 – multiplicação e acúmulo (MAC) (sem sinal) MAC_MAC_UNS MDSM 011 – multiplicação e acúmulo (MAC) (com sinal) MAC_MAC_SIG 100 – divisão (com interrupção INTMD) MAC_DIV_INT 110 – divisão (sem interrupção INTMD) MAC_DIV_NOINT Indicador de estouro do resultado acumulado (modo MAC): 0 – não houve estouro MACOF 1 – houve estouro (no modo sem sinal, significa que o resultado foi maior bMACOF que 0xFFFFFFFF, no modo com sinal, significa que o resultado foi maior que 0x7FFFFFFF ou menor que 0x80000000) Indicador do sinal do resultado acumulado: MACSF 0 – positivo bMACSF 1 – negativo Indicador de andamento da operação de divisão: DIVST 0 – operação completada bDIVST 1 – operação em andamento

10.6. DMA

O acesso direto à memória (DMA) é um circuito que permite que um periférico acesse diretamente os barramentos de dados e de endereços, de forma a transferir dados de/para a memória RAM. O DMA permite automatizar operações que, de outra forma, ocupariam a CPU desnecessariamente, tomando tempo precioso que poderia ser gasto com trabalho útil para a aplicação. Um exemplo típico é a comunicação serial: suponha um protocolo de comunicação composto de quadros de 8 bytes e com velocidade de comunicação assíncrona de 115.200bps. A esta velocidade, um caractere (8 bits de dados, mais um bit de partida e outro de parada) é recebido em 86,8µs. Se num quadro os dados forem transmitidos em uma sequencia contínua, isto significa que a CPU é interrompida a cada caractere recebido ou aproximadamente a cada 86,8µs. A cada interrupção a CPU efetua a transferência do caractere recebido para um buffer em memória. Somente após receber 8 caracteres é que a aplicação pode analisar o quadro e efetivamente fazer processamento útil do protocolo.

Tópicos Avançados 253

É fácil perceber que em altas velocidades de comunicação a CPU é ocupada desnecessariamente com trabalho bruto, ou seja, movimentar os dados recebidos da UART para um buffer em memória. Neste caso, o uso do DMA pode liberar a CPU para efetuar processamento em outras áreas da aplicação, pois a transferência dos dados recebidos para um buffer em memória é feita automaticamente pelo DMA e, somente após a recepção de 8 caracteres é que o DMA irá gerar uma interrupção, notificando a CPU do término da transferência. Isto significa que uma interrupção será gerada somente após 694,4µs e não a cada 86,8µs! O controlador DMA dos RL78 é construído de forma que pode movimentar 8 ou 16 bits por ciclo de transferência e cada transferência necessita de dois ciclos de clock para ser completada. Durante uma transferência a CPU é mantida paralisada, prosseguindo com sua operação normal assim que a transferência é completada. As transferências DMA podem ser feitas em duas direções: de um registrador SFR (periférico) para a RAM e da RAM para um registrador SFR. É possível configurar o DMA para realizar até 1024 transferências e, depois de completado este valor uma interrupção DMA (INTDMA) é gerada. Após habilitado o canal de DMA, o disparo de uma transferência pode ser realizado por software ou por um sinal de interrupção vindo de um dos seguintes periféricos (conversor A/D, canais 0, 1, 2 e 3 da TAU0 e TAU1, interrupções de transmissão ou de recepção das UARTs ou interrupções de transferência de qualquer um dos canais CSI).

Tipicamente a interrupção do periférico que irá provocar o disparo da transferência DMA O deverá estar desabilitada! O disparo da transferência ocorre independentemente da interrupção estar habilitada ou não.

A tabela 10.2 mostra a disponibilidade de canais DMA nos microcontroladores da linha RL78/G13. 80 a 128 20 a 64 DMA pinos pinos Número de Canais 4 2 Tabela 10.2

Os passos para configuração do DMA são muito simples: 1. O canal de DMA deve ser habilitado (o bit DEN no registrador DRCn deve ser setado);

i Não é possível alterar os registradores do canal de DMA quando o bit DEN está apagado!

2. No registrador DSAn deve ser configurado o endereço do registrador SFR que será a fonte ou destino da transferência. Para atribuir o endereço de um registrador SFR ao registrador DSA podemos escrever: DSAn=(char)® onde REG é no nome do registrador SFR desejado. Vejamos alguns exemplos:

254 Microcontroladores RL78: Guia Básico

DSA2 = (char)&TXD0; // atribui o endereço do TXD0 ao DSA2 DSA0 = (char)&TDR01; // atribui o endereço do TDR01 ao DSA0 3. No registrador DRAn deve ser configurado o endereço da primeira posição de memória RAM onde os dados serão armazenados ou lidos. Para atribuir um endereço da RAM ao registrador DRAn podemos escrever: DRAn=(int)&MEM onde MEM é a variável na memória RAM. Como normalmente se utiliza um array para o armazenamento do bloco de memória a ser transferido pelo DMA, a atribuição assume a seguinte forma: DRAn=(int)array onde “array” é o nome da array utilizada na transferência. Vejamos alguns exemplos: // atribui o endereço da variável “var” ao DRA1 DRA1 = (int)&var;

// atribui o endereço da array “buffer” ao DRA3 unsigned char buffer[16]; ... DRA3 = (int)buffer;

Lembre-se que a referência apenas ao nome de um array retorna o endereço do seu primeiro O elemento!

4. O número total de transferências que o canal deverá fazer deve ser configurado no registrador DBCn;

O array que irá armazenar os dados transferidos pelo DMA deve ser dimensionado de acordo com o número total de transferências configurado no registrador DBCn! Caso o O array seja menor que o número de transferências, poderão ocorrer problemas de corrupção de memória.

5. Configura-se, no registrador DMCn as características de operação do DMA: a. Direção (de um SFR para a RAM ou da RAM para um SFR); b. Tamanho (8 bits ou 16 bits);

O array que irá armazenar os dados transferidos pelo DMA deve declarado conforme o O tamanho da transferência: char para transferências de 8 bits e int para transferências de 16 bits!

c. Tipo de disparo (por software ou por hardware); d. Fonte de disparo (no caso do hardware): ADC, TAU, CSI. 6. Em seguida o bit DST (registrador DRCn) deve ser setado, de forma que o DMA entre no modo de transferência de dados; 7. Quando um periférico é utilizado como destino da transferência, pode ser necessário iniciar a mesma através de um disparo por software. Isto pode ser feito setando-se o bit STG (registrador DMCn). O bit DST (registrador DRCn) pode ser utilizado para monitorar o andamento da operação do DMA: quando em “0” indica que as transferências foram completadas e quando em “1” indica

Tópicos Avançados 255

que a operação do DMA ainda não foi completada (o número de transferências programadas no registrador DBCn ainda não foi atingido). Quando o DMA está habilitado e há transferências pendentes (DST=1), a aplicação pode cancelar as operações pendentes escrevendo “0” em DST. Quando todas as transferências programadas foram completadas o canal de DMA irá gerar uma interrupção INTDMA e a ISR deverá providenciar a desativação do mesmo (DEN=0) ou a reconfiguração do canal para novas transferências (seguindo-se os passos mostrados acima). A seguir apresentamos os registradores associados aos canais de DMA dos RL78.

10.6.1. Registradores dos Canais de DMA

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura Endereço do registrador SFR (8 bits inferiores da faixa compreendida entre 0xFFF00 e 0xFFFFF) DSAn Escrita Reset 0 0 0 0 0 0 0 0 * n é o número do canal de DMA (0 a 3) A alteração deste registrador somente pode ser realizada quando uma transferência não está em andamento.

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura Endereço de memória RAM alvo/destino da transferência DMA DRAn Escrita Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *n corresponde ao número do canal de DMA (0 a 3) Este registrador contém o endereço da RAM onde será escrito ou lido o dado na próxima transferência DMA. O conteúdo do registrador é automaticamente incrementado após cada transferência (incrementado em um para transferências de 8 bits ou 2 para transferências de 16 bits). A alteração deste registrador somente pode ser realizada quando uma transferência não está em andamento.

Nome BIT 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 Leitura 0 0 0 0 0 0 Número de transferências DMA DBCn Escrita Reset 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *n corresponde ao número do canal de DMA (0 a 3) Este registrador armazena o número de transferências a serem realizadas pelo DMA. O conteúdo do mesmo é automaticamente decrementado após cada transferência e ao atingir zero uma interrupção INTDMA é gerada. Caso este registrador esteja carregado com zero no instante em que o canal de DMA é habilitado, serão realizadas 1024 transferências até que seja gerada uma interrupção. A leitura deste registrador permite que a aplicação determine o número de transferências já realizadas. A alteração deste registrador somente pode ser realizada quando uma transferência não está em andamento.

256 Microcontroladores RL78: Guia Básico

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura STGn DRSn DSn DWAITn IFCn3 IFCn2 IFCn1 IFCn0 DMCn Escrita Reset 0 0 0 0 0 0 0 0 *n corresponde ao número do canal de DMA (0 ou 1)

Nome do Bit Descrição Bit C Símbolo C Disparo por software da transferência DMA: STGn 0 – nenhum disparo STGn bSTG 1 – dispara a transferência Seleção da direção da transferência DMA: DRSn 0 – do periférico para a RAM DRSn bDRS 1 – da RAM pra o periférico Tamanho de cada transferência do DMA: DSn 0 – 8 bits DSn bDS 1 – 16 bits Controle de paralisação da transferência DMA: 0 – executa a transferência DMA quando ocorre a DWAITn solicitação DWAITn bDWAIT 1 – paralisa a transferência, DWAIT deve ser apagado para que a transferência ocorra normalmente Seleção da fonte de disparo do DMA: 0000 – disparo por software - DMA_TRIG_SOFT 0001 – disparo pelo ADC - DMA_TRIG_ADC 0010 – disparo pelo canal 0 da TAU0 - DMA_TRIG_T00 0011 – disparo pelo canal 1 da TAU0 - DMA_TRIG_T01 IFCn3 0100 – disparo pelo canal 2 da TAU0 - DMA_TRIG_T02 IFCn2 IFCn1 0101 – disparo pelo canal 3 da TAU0 - DMA_TRIG_T03 IFCn0 0110 – disparo pela UART0 (TX) ou CSI00 - DMA_TRIG_TX0 0111 – disparo pela UART0 (RX) ou CSI01 - DMA_TRIG_RX0 1000 – disparo pela UART1 (TX) ou CSI10 - DMA_TRIG_TX1 1001 – disparo pela UART1 (RX) ou CSI11 - DMA_TRIG_RX1 1010 – disparo pela UART2 (TX) ou CSI20 - DMA_TRIG_TX2 1011 – disparo pela UART2 (RX) ou CSI21 - DMA_TRIG_RX2

Tópicos Avançados 257

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura STGn DRSn DSn DWAITn IFCn3 IFCn2 IFCn1 IFCn0 DMCn Escrita Reset 0 0 0 0 0 0 0 0 *n corresponde ao número do canal de DMA (2 ou 3)

Nome do Bit Descrição Bit C Símbolo C Disparo por software da transferência DMA: STGn 0 – nenhum disparo STGn bSTG 1 – dispara a transferência Seleção da direção da transferência DMA: DRSn 0 – do periférico para a RAM DRSn bDRS 1 – da RAM pra o periférico Tamanho de cada transferência do DMA: DSn DSn bDS 0 – 8 bits 1 – 16 bits Controle de paralisação da transferência DMA: 0 – executa a transferência DMA quando ocorre a DWAITn solicitação DWAITn bDWAIT 1 – paralisa a transferência, DWAIT deve ser apagado para que a transferência ocorra normalmente Seleção da fonte de disparo do DMA: 0000 – disparo por software - DMA_TRIG_SOFT 0001 – disparo pelo ADC - DMA_TRIG_ADC 0010 – disparo pelo canal 0 da TAU1 - DMA_TRIG_T10 0011 – disparo pelo canal 1 da TAU1 - DMA_TRIG_T11 IFCn3 0100 – disparo pelo canal 2 da TAU1 - DMA_TRIG_T12 IFCn2 IFCn1 0101 – disparo pelo canal 3 da TAU1 - DMA_TRIG_T13 IFCn0 0110 – disparo pela UART3 (TX) ou CSI30 - DMA_TRIG_TX3 0111 – disparo pela UART3 (RX) ou CSI31 - DMA_TRIG_RX3 1000 – disparo pela UART1 (TX) ou CSI10 - DMA_TRIG_TX1 1001 – disparo pela UART1 (RX) ou CSI11 - DMA_TRIG_RX1 1010 – disparo pela UART2 (TX) ou CSI20 - DMA_TRIG_TX2 1011 – disparo pela UART2 (RX) ou CSI21 - DMA_TRIG_RX2

Nome BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 Leitura DENn 0 0 0 0 0 0 DSTn DRCn Escrita Reset 0 0 0 0 0 0 0 0

Nome do Bit Descrição Bit C Símbolo C Controle de habilitação do canal DMA: DENn DENn bDEN 0 – DMA desabilitado 1 – DMA habilitado Indicador de transferência DMA: DSTn 0 – transferência DMA completada DSTn bDST 1 – transferência DMA em andamento

258 Microcontroladores RL78: Guia Básico

10.6.2. Exemplo O exemplo a seguir demonstra como utilizar um canal de DMA para automatizar a transmissão de dados com a UART. Um buffer de 32 bytes é utilizado para o armazenamento dos dados a serem transmitidos. A função tx_UART2() é utilizada para escrever uma string no buffer e configurar o DMA para realizar a transferência dos dados através da UART2. Toda a transferência é realizada automaticamente pelo DMA, ou seja, após cada caractere ser transmitido o flag de transmissão da UART2 (STIF2) é setado, provocando o disparo do DMA que transfere um novo caractere do buffer para o registrador TXD2. Este processo segue até que todos os caracteres tenham sido transmitidos (registrador DBC0 chegue a zero e bit DST seja apagado no registrador DRC0). Adicionalmente a aplicação também responde aos caracteres recebidos pela UART2, invertendo o estado do led D2 da placa RPB a cada caractere recebido e enviando a string “Teste!” ao receber o caractere ‘t’ e “RL78!” ao receber o caractere ‘r’. Os procedimentos de configuração da placa RPB e teste da aplicação são os mesmos vistos para o exemplo 9.1. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h"

// Configura watchdog = desligado #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão = desligado #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define __9600BPS 51 << 9 #define LED P7_bit.no7 #define TX_BUF_SIZE 32

unsigned char tx_buffer[TX_BUF_SIZE];

void tx_UART2(unsigned char *string);

#pragma vector = INTSR2_vect __interrupt void trata_rx_UART2(void) { unsigned char temp;

Tópicos Avançados 259

temp = RXD2; // lê o caractere recebido // se recebeu 't' envia "Teste!" if (temp=='t') tx_UART2("Teste!\r\n"); // se recebeu 'r' envia "RL78!" if (temp=='r') tx_UART2("RL78!\r\n"); LED = !LED; // a cada caractere recebido, inverte o estado do led }

#pragma vector = INTDMA0_vect __interrupt void trata_DMA_tx_uart2(void) { DEN0 = 0; // desabilita o DMA }

void MCU_init(void) { PM1_bit.no3 = 0; // P13/TXD2 como saída P1_bit.no3 = 1; // coloca TXD2 em 1 (importante!!!) PM1_bit.no4 = 1; // P14/RXD2 como entrada PM7_bit.no7 = 0; // P77 como saída (led) LED = 1; // desliga o led SAU1EN = 1; // ativa a SAU1 // Clock CK0 da SAU1 = 32MHz / 32 = 1MHz SPS1 = SAU_CK0_DIV32; // Configura o canal 0 da SAU1 (transmissão da UART2) SMR10 = SAU_MD_UART; SCR10 = SAU_COMM_TX|SAU_NO_PARITY|SAU_LSB_FIRST|SAU_ONE_STOP|SAU_8BITS; SDR10 = __9600BPS; // seta o baud rate do transmissor // Configura o canal 1 da SAU1 (recepção da UART2) SMR11 = bSAU_STS | SAU_MD_UART; SCR11 = SAU_COMM_RX|SAU_NO_PARITY|SAU_LSB_FIRST|SAU_ONE_STOP|SAU_8BITS; SDR11 = __9600BPS; // seta o baud rate do receptor SOE1 = SAU_CH0; // habilita a saída da UART2 SO1 = SAU_CH0; // seta a saída TXD2 NFEN0 = SNFEN20; // ativa o filtro digital da entrada RXD2 // Dispara os canais 0 e 1 da SAU1 SS1 = SAU_CH1 | SAU_CH0; SRMK2 = 0; // habilita a interrupção de recepção da UART DMAMK0 = 0; // habilita a interrupção do DMA0 __enable_interrupt(); // habilita as interrupções do RL78 }

// envia uma string pela UART2 utilizando o DMA void tx_UART2(unsigned char *string) { unsigned char index; index = 0; // copia a string para o buffer de transmissão while (string) { tx_buffer[index++] = *string++; // se atingiu o final da string ou o tamanho do buffer, encerra a cópia if (index==TX_BUF_SIZE || !*string) break; } // se o buffer contém caracteres, configura o DMA para a transferência if (index) { DRC0 = bDEN; // habilita o DMA0 DBC0 = index; // configura o número de bytes a transferir

260 Microcontroladores RL78: Guia Básico

DSA0 = (char)&TXD2; // configura o endereço do registrador alvo DRA0 = (int)tx_buffer; // configura o endereço do buffer com os dados DMC0 = bDRS | DMA_TRIG_TX2; // configura o canal de DMA DRC0 = bDEN | bDST; // seta DST para iniciar a transferência STG0 = 1; // dispara o DMA e inicia a transferência } }

void main(void) { MCU_init(); // transmite uma string de saudação tx_UART2("Teste da UART com DMA!"); while (1); // aguarda uma interrupção } Exemplo 10.3

10.7. Otimizando Aplicações para o RL78

Neste tópico veremos algumas técnicas de programação e características especiais do compilador que permitem extrair maior desempenho e eficiência das aplicações utilizando os microcontroladores RL78.

10.7.1. Tamanho do Dado A arquitetura dos RL78 privilegia os dados com tamanho de 1, 8 e 16 bits, por isso, é interessante que a aplicação utilize, sempre que possível, variáveis de no máximo 16 bits. O uso de variáveis inteiras de 32 bits pode ser feito sem problemas, mas é importante considerar que a aplicação funcionará melhor e mais rapidamente se for possível utilizar variáveis de 16 bits ou menos. A figura a seguir demonstra o código assembly gerado para operações comuns no cotidiano (atribuição e incremento) para variáveis de 8, 16 e 32 bits. unsigned char v8; unsigned int v16; unsigned long v32; v8 = 5; v16 = 5; v32 = 5; MOV N:v8,#5 (4) MOV X,#5 (2) MOVW HL,#0xEF0A (3) v8++; MOVW N:v16,AX (3) MOVW [HL],AX (1) INC N:v8 (3) v16++; CLRW AX (1) INCW N:v16 (3) MOVW [HL+2],AX (2) V32++; MOVW BC,N:0xEF0C (3) MOVW AX,N:v32 (3) ADDW AX,#1 (3) SKNC (2) INCW BC (1) MOVW [HL],AX (1) MOVW AX,BC (1) MOVW N:0xEF0C,AX (3) Figura 10.6

Perceba que a atribuição e incremento de um variável de 8 bits consomem 7 bytes de flash, ao passo que para uma variável de 16 bits as mesmas operações consomem 8 bytes e no caso de uma variável de 32 bits o consumo de memória flash aumenta para 24 bytes!

Tópicos Avançados 261

No caso das variáveis de ponto flutuante (float e double), o seu uso é totalmente desencorajado e deve ser evitado ao máximo, pois implica em grande aumento no tamanho do código e significativa redução na performance.

10.7.2. Endereçamento Rápido Como já vimos no tópico 3.1.3 os microcontroladores possuem um modo de endereçamento especial que acelera o acesso a uma pequena porção da memória RAM e SFRs. Este modo de endereçamento, chamado de “short address”, possibilita que as instruções sejam menores e com isso mais eficientes. A limitação deste modo de endereçamento é que ele pode ser utilizado apenas para os endereços compreendidos na faixa entre 0xFFE20 e 0xFFF1F. Considerando que a memória RAM disponível para o usuário termina no endereço 0xFFEDF, conclui-se que há 192 bytes de RAM disponíveis para utilização neste modo de endereçamento. Apesar de o compilador utilizar esta área naturalmente, sem a necessidade de utilização de diretivas especiais, ele não utilizará o modo de endereçamento rápido para as variáveis alocadas nesta região, a menos que o programador o instrua para tal. Para instruir o compilador a armazenar uma variável na região de endereçamento rápido, basta utilizar o modificador de atributo __saddr antes da declaração da variável: __saddr unsigned char myvar; Observe que o aumento na eficiência de código (especialmente na redução do espaço ocupado em flash) ao se utilizar este modo de endereçamento é substancial: __saddr unsigned char va; unsigned char va; va = 10; va = 10; CD200A MOV S:va,#0x0A (3 bytes) CF0AEF0A MOV N:va,#0x0A (4 va++; bytes) A420 INC S:va (2 bytes) va++; A00AEF INC N:vb (3 bytes) Figura 10.7

10.7.3. Campos de Bit O conjunto de instruções dos RL78 favorece a utilização de variáveis com tamanho de um bit, como no caso das estruturas com campos de bit. Para obter a máxima eficiência de código é importante utilizar campos de bit com tamanho de apenas um bit e utilizar o modificador __saddr para forçar estas estruturas a serem armazenadas na área de endereçamento rápido. Desta forma, o compilador consegue traduzir atribuições de bits em apenas uma instrução assembly (CLR1 para apagar um bit e SET1 para setar um bit). O teste de bit também é traduzido em uma única instrução assembly (BF), garantindo o máximo de eficiência de código. Observe que por padrão o compilador IAR irá armazenar os membros de uma estrutura da bits iniciando do bit menos significativo para o mais significativo. Por exemplo:

262 Microcontroladores RL78: Guia Básico

__saddr struct { unsigned char primeiro : 1; unsigned char segundo : 1; unsigned char terceiro : 1; } bits; Na estrutura acima, o elemento “primeiro” será armazenado no bit 0 da posição de memória alocada para a estrutura “bits”. O elemento “segundo” será armazenado no bit 1 e assim por diante. É possível utilizar a diretiva #pragma bitfields=reversed para forçar o compilador a armazenar a estrutura iniciando pelo bit mais significativo, assim o elemento “primeiro” seria armazenado no bit 7 da posição de memória alocada para a estrutura “bits”, seguido pelo elemento “segundo” no bit 6 e assim por diante. Para retornar ao método de alocação padrão para campos de bits, utiliza-se a diretiva #pragma bitfields=default .

10.7.4. Funções CALLT Como já vimos no tópico 3.1.3 os microcontroladores RL78 incluem uma área de 64 bytes destinada ao armazenamento de uma tabela de endereços de funções. Esta tabela pode ser acessada através das instruções assembly CALLT e permite que se faça a chamada de funções de uma forma mais eficiente, já que as instruções CALLT são menores, porém um pouco mais lentas (uma instrução CALLT ocupa dois bytes e executa em cinco ciclos de clock, ao passo que uma instrução CALL ocupa tipicamente três bytes e executa em três ciclos de clock). A principal utilidade das instruções CALLT é na redução do tamanho do código e o seu uso é recomendado no caso das funções que são chamadas com muita frequência. Para instruir o compilador a utilizar estas instruções, tudo o que é necessário fazer é declarar a função utilizando o modificador __callt antes da declaração da variável: __callt void minha_func(void); A seguir mostramos uma comparação do código assembly gerado com e sem a utilização deste modificador. __callt void teste(void) void teste(void) ...... teste(); teste(); 6184 CALLT [__T_teste] (2 FD2C01 CALL N:teste (3 bytes) bytes) Figura 10.8

Note que a função modificada com __callt deverá ser obrigatoriamente alocada nos primeiros 64k de flash do microcontrolador (isso é feito automaticamente pelo compilador). No mais, funções __callt podem retornar qualquer tipo de dado e receber qualquer quantidade de parâmetros (como qualquer outra função C tradicional).

Tópicos Avançados 263

10.8. Utilizando o Applilet3

O Applilet3 for RL78 é uma aplicação desenvolvida pela Renesas para facilitar a criação de código para o RL78. A tela inicial do Applilet pode ser vista na figura 10.9. A vantagem de se utilizar o Applilet é que ele facilitar grandemente a utilização dos periféricos internos do RL78, gerando todo o código para inicialização e tratamento de interrupções.

Figura 10.9

Para iniciar um novo projeto no Applilet, basta clicar em File>New no menu principal. Será apresentada a janela da figura 10.10A. Selecione o microcontrolador desejado (no caso da Promotion board do RL78, devemos selecionar o R5F100LE), o compilador (Build Tool), que no nosso caso é o IAR , o nome do projeto e o local onde ele será salvo (figura 10.10B).

Figura 10.10A Figura 10.10B Clicando-se em OK, o novo projeto será criado e será apresentada a tela da figura 10.11. Inicialmente a ferramenta espera que o usuário selecione a função primária dos pinos com

264 Microcontroladores RL78: Guia Básico

capacidade de redirecionamento de função (aba Pin Assignment). Esta seleção deve ser feita e não poderá mais ser alterada no decorrer do projeto.

Figura 10.11

Nos exemplos deste livro não será necessário nenhum redirecionamento de função. Todas as caixas de seleção nesta aba devem ser mantidas desmarcadas. Pressione o botão FIX SETTINGS para que a configuração seja armazenada. Nas outras abas desta tela é possível configurar outras opções do microcontrolador, como o sistema de clock (aba Clock setting), depurador interno (aba On-chip debug setting), geração de função para identificação da fonte de reset (aba Confirming reset source) e funções de segurança avançadas (aba Safety functions). No painel da esquerda é possível selecionar os diversos módulos internos do microcontrolador (dentro de Peripheral): Clock generator (a tela inicial), Port (para configuração dos pinos de E/S, Interrupts (para configuração das interrupções externas INTPx e de teclado), Serial (para configuração das unidades SAU e IICA), A/D Converter (para configuração do conversor A/D), Timer (para configuração das unidades TAU), etc. Para selecionar uma das opções é necessário um duplo clique do mouse (ou selecioná-la no na entrada Peripheral no menu principal). Uma vez que o usuário tenha configurado todas as opções e periféricos desejados, basta clicar no botão “Generate Source Code” para que o Applilet gere automaticamente um projeto para o IAR contendo todo o código de inicialização e funções necessárias para programação em alto nível do microcontrolador e dos seus periféricos. Os arquivos gerados pelo Applilet estarão armazenados dentro da pasta applilet_src. A estrutura de arquivos irá conter um arquivo principal da aplicação (r_main.c), um arquivo principal de inicialização do microcontrolador (r_systeminit.c) e outros arquivos relacionados aos módulos e periféricos do chip. É interessante notar que o Applilet normalmente gera dois arquivos para cada módulo ou periférico do chip: um arquivo contém as funções internas utilizadas para inicialização e operação do periférico e o outro contém as funções que podem ser programadas pelo usuário e que irão formar a aplicação propriamente dita. Como exemplo podemos citar o módulo CGC (gerador de clock), o Applilet gera dois arquivos para o mesmo, r_cg_cgc.c e r_cg_cgc_user.c. O primeiro arquivo contém a função

Tópicos Avançados 265

R_CGC_Create() utilizada para inicialização do sistema de clock, ao passo que o segundo contém a função R_CGC_Get_ResetSource() que pode ser modificada pelo usuário para identificar a origem do reset e executar alguma ação. O código padrão desta função pode ser visto a seguir: void R_CGC_Get_ResetSource(void) { uint8_t reset_flag = RESF; /* Start user code. Do not edit comment generated here */ /* End user code. Do not edit comment generated here */ } Observe que há dois comentários dentro da função, o primeiro marca o ponto inicial para entrada de código do usuário e o segundo marca o ponto final para entrada de código do usuário. O código da função deve ser inserido entre os dois comentários (mantendo os comentários conforme gerados pelo Applilet).

Atenção: somente modifique ou adicione código dentro da área compreendida entre os dois comentários mostrados acima! O Applilet está configurado para preservar tudo o que é i escrito nestas áreas, mesmo quando o usuário reconfigurar um projeto já existente. Caso o programador opte por inserir código fora das áreas permitidas, o projeto não poderá ser modificado posteriormente no Applilet!

Uma outra característica importante acerca do Applilet é que a inicialização principal do microcontrolador é administrada automaticamente pelo Applilet na função R_Systeminit() que é chamada dentro da função __low_level_init() . Esta última é chamada automaticamente pelo compilador imediatamente antes do controle do programa ser passado para a função main() .

10.8.1. Configuração do Timer de Intervalo Como primeiro exemplo do uso do Applilet veremos como implementar um pisca-pisca utilizando o timer de intervalo (IT) e o led D2 da placa de promoção do RL78/G13. Primeiramente é necessário criar um novo projeto no Applilet. Após fixar as configurações de redirecionamento de E/S (mantendo a configuração padrão), verifique na aba “Clock setting” se o oscilador interno High Speed está selecionado e o clock está ajustado para 32MHz (padrão no Applilet). Na aba “On-chip debug setting”, configure “On-chip debug operation setting” para “Used” e caso queira configurar algum código de segurança, insira-o no campo Security ID. Em seguida devemos configurar a pino de E/S ao qual o led D2 está conectado. Na Promotion board do RL78/G13 o led D2 está conectado ao pino P7.7 e, portanto, o mesmo deve ser configurado como saída. Um duplo-clique sobre o item “Port” (listado na caixa à esquerda) irá abrir as abas de configuração dos pinos de E/S (figura 10.4). Selecione a aba “Port7” e configure P77 como saída (Out). Opcionalmente é possível clicar na caixa ao lado direito, onde aparece o número “1”, isto fará com que o estado inicial do pino seja “1”. Caso a caixa permaneça desmarcada o estado inicial será “0”.

266 Microcontroladores RL78: Guia Básico

Figura 10.12

Em seguida devemos configurar o timer de intervalo do RL78 para controlar a frequência de piscadas do led, gerando interrupções a cada 100ms. Para configurá-lo, dê um duplo-clique sobre o item “Interval Timer” e ajuste as opções conforme a figura 10.13.

Figura 10.13

Feito isso, basta clicar no botão GENERATE CODE para que o Applilet3 gere o código necessário para configurar a CPU e os periféricos da nossa aplicação. Agora podemos abrir o projeto no EWRL78 e inserir o código necessário para que a nossa aplicação pisque o led. A figura 10.14 mostra a janela do EWRL78 com o projeto gerado pelo Applilet aberto. Perceba a estrutura de arquivos gerada para a aplicação (dentro de applilet_src), ela contém arquivos para o módulo CGC (gerador de clock), IT (timer de intervalo), Port (portas

Tópicos Avançados 267

de E/S), WDT (watchdog), além do arquivo r_main.c (arquivo principal da aplicação) e r_systeminit.c (que contém a inicialização principal do microcontrolador). Para a nossa aplicação, deveremos fazer três alterações no código gerado pelo Applilet: a primeira é inserir no arquivo r_main.c uma chamada a função R_IT_Start() , responsável por iniciar o temporizador de intervalo. Esta chamada, conforme ilustra a figura 10.14 deve ser realizada antes do while na função main().

Figura 10.14

A outra alteração consiste em inserir uma linha de código no arquivo r_cg_it_user.c, que contém a função de tratamento da interrupção do timer de intervalo. Este código ( LED_D2 = !LED_D2 ) deve ser inserido conforme ilustra a figura 10.15.

Figura 10.15

A terceira e última alteração consiste em definir o símbolo LED_D2. Preferencialmente, devemos definir os símbolos e variáveis globais do programa no arquivo r_cg_userdefine.h. A figura 10.16 ilustra o ponto onde deve ser inserida a linha de código #define LED_D2 P7_bit.no7 no arquivo citado.

Figura 10.16

268 Microcontroladores RL78: Guia Básico

Depois de realizadas todas as alterações mencionadas, basta compilar o programa e fazer o download para a Promotion board para observar o seu correto funcionamento! Lembre-se de configurar o depurador para “TK” nas opções do projeto.

10.8.2. Configuração da UART Neste exemplo mostramos como utilizar o Applilet para configurar e utilizar a UART2 da placa de promoção do RL78/G13 (YRPBRL78G13). Após criar um novo projeto no Applilet, a tela de configuração inicial das unidades SAU e IICA é acessada com um duplo clique sobre a entrada “Serial” na árvore de projeto (project tree). Feito isso, basta selecionar a unidade SAU1 e clicar na aba Channel para configurar os canais da SAU1. A figura 10.17 mostra esta etapa.

Figura 10.17

Após selecionar o modo UART2 no canal 0 da SAU1 e configurá-la para transmissão e recepção, o próximo passo é fazer as configurações de transmissão e de recepção da UART, para isso basta clicar na aba UART2. Será apresentada a tela da figura 10.18A. Nas telas mostradas nas figuras 10.18A e 10.18B o programador pode configurar as diversas características das etapas de recepção e transmissão da UART: velocidade, número de bits, sentido, polaridade, paridade, etc. Também é possível configurar o Applilet para gerar funções de callback para o fim de recepção, erro de recepção e fim de transmissão.

Figura 10.18A Figura 10.18B Após a configuração da UART (e do pino P7.7 como saída) basta clicar no botão “Generate code” para que o Applilet gere o projeto C com o código fonte de inicialização e utilização da UART. Conforme já visto no tópico 9.1.2.4, o Applilet irá gerar automaticamente um conjunto de funções para manipulação da UART2: • R_UART2_Start() – para disparar a UART2;

Tópicos Avançados 269

• R_UART2_Send() – para envio de dados pela UART2; • R_UART2_Receive() – para recepção de dados pela UART2. Após a geração do código, é necessário abrir, no IAR, o projeto criado pelo Applilet e alterar a função main() do arquivo r_main.c conforme mostrado a seguir. Este código fará com que a string “Teste” seja transmitida periodicamente através da UART, ao mesmo tempo em que o led D2 troca de estado. void main(void) { /* Start user code. Do not edit comment generated here */ unsigned long int temp; R_UART2_Start(); while (1U) { R_UART2_Send("Teste\r\n",7); for (temp=0;temp<2000000;temp++); P7_bit.no7 = !P7_bit.no7; } /* End user code. Do not edit comment generated here */ } Feito isso, basta compilar o projeto no IAR e fazer o download para a placa. Observe que para testar o exemplo é necessário sair da depuração e modificar a posição dos jumpers J6, J7, J8 e J9 para a posição 2-3 de forma a conectar o RL78/G13 ao computador através da porta COM virtual integrada a placa de promoção. Após modificar os jumpers, um programa de terminal serial (como o Termite, disponível em http://www.compuphase.com/ software_termite.htm) deverá ser aberto e configurado para acessar a porta COM virtual criada pelo driver da Renesas (no presente caso a porta COM criada foi a COM8). A figura a seguir mostra o resultado final da aplicação.

Figura 10.19

270 Microcontroladores RL78: Guia Básico

11

Exemplos de Aplicação 11. Exemplos de Aplicação

Neste último capítulo apresentamos alguns exemplos de aplicação dos RL78. Estes exemplos possuem caráter apenas didático e foram desenvolvidos para demonstrar e aplicar os conhecimentos apresentados neste livro

11.1. Utilização de Módulos LCD Alfanuméricos

Os módulos LCD são elementos de apresentação de dados muito versáteis e com custo bastante reduzido, por esta razão são encontrados nos mais variados equipamentos eletrônicos. Os módulos dividem-se em duas categorias básicas: os alfanuméricos, que podem apresentar textos e números e os gráficos que podem apresentar textos, números e gráficos a cores ou em preto e branco. Os módulos alfanuméricos consistem num controlador (normalmente o HD44780, KS0066 ou equivalente), drivers e um display de cristal líquido (LCD). Estes displays são encontrados em diversos tamanhos e com capacidades de apresentação deste 8 caracteres em uma linha até algumas dezenas de caracteres e várias linhas. Nos próximos exemplos veremos como utilizar um módulo LCD de 8 caracteres por 2 linhas para apresentar alguns dados. Pino Nome RL78 Função 1 VSS - Terra 2 VDD - +5V 3 VO - Contraste 4 RS P5.5 Seleção do registro: comandos (0) ou dados (1) 5 WR/ - Operação de leitura (1) os escrita (0) 6 E P5.4 Pino de habilitação (quando E=1 o display pode receber comandos ou dados) 7 DB0 - Bit 0 comando/dados. Não utilizado no modo de 4 bits 8 DB1 - Bit 1 comando/dados. Não utilizado no modo de 4 bits 9 DB2 - Bit 2 comando/dados. Não utilizado no modo de 4 bits 10 DB3 - Bit 3 comando/dados. Não utilizado no modo de 4 bits 11 DB4 P7.4 Bit 4 comando/dados 12 DB5 P7.5 Bit 5 comando/dados 13 DB6 P7.6 Bit 6 comando/dados 14 DB7 P7.7 Bit 7 comando/dados Tabela 11.1 – Pinagem do módulo LCD ACM0802

A tabela 11.1 mostra a pinagem do módulo ACM0802 da AZ Displays, utilizado na placa RSK RL78/G13. Este módulo encontra-se conectado ao RL78 através da porta 7 (barramento de dados de 4 bits) e dos pinos P5.5 e P5.4 (RS e ENABLE respectivamente).

Exemplos de Aplicação 271

A comunicação do microcontrolador com o módulo LCD deve seguir um protocolo definido pelo fabricante do chip controlador. A linha RS permite definir se a informação presente no barramento de dados é um dado (RS=1) ou comando (RS=0), R/W permite definir se a operação é uma escrita no display (R/W=0) ou leitura do mesmo (R/W=1) e a linha ENABLE é utilizada para controlar o fluxo de dados com o display.

A tabela 11.2 apresenta a lista de comandos possíveis. No caso da placa RSK, o pino WR/ do display está conectado a um resistor pull-down de 1k Ω, de forma que o módulo somente pode operar no modo de escrita, não sendo possível ler dados do mesmo. Tempo de Comando RS R/W D7 D6 D5 D4 D3 D2 D1 D0 Descrição Execução Apaga o display e retorna o cursor para a primei ra Apaga o display 0 0 0 0 0 0 0 0 0 1 1.64ms coluna da primeira linha Retorna o cursor a primeira coluna da primeira Retorno ao início 0 0 0 0 0 0 0 0 1 x linha e cancela qualquer deslocamento de 1.64ms mensagem I/D – seleciona a direção de de slocamento do display: 1 – desloca o cursor à direita a cada caractere Seleção do modo escrito. 0 0 0 0 0 0 0 1 I/D S 40 µs inicial 0 – desloca o cursor à esquerda a cada caractere escrito. S – liga (S=1) ou desliga (S=0) o deslocamento do display a cada leitura da DDRAM. Liga (D=1) ou desliga (D=0) o display, liga (C=1) Liga/desliga o 0 0 0 0 0 0 1 D C B ou desliga (C=0) o cursor e habilita (B=1) ou 40 µs display desabilita (B=0) a piscagem do cursor. S/C – seleciona entre o deslocamento do cur sor (S/C=0) e o deslocamento do cursor e mensagem Deslocamento do 0 0 0 0 0 1 S/C R/L x x (S/C=1). 40 µs display ou cursor R/L – direção do deslocamento: direita (R/L=1) ou esquerda (R/L=0). DL – largura do barramento: 8 bits (DL=1) ou 4 bits (DL=0). N – número de linhas: uma lin ha (N=0) ou duas Configuração 0 0 0 0 1 DL N F x x 40 µs linhas (N=1). F – tamanho do caractere: 8x5 (F=0) ou 10x5 (F=1). Seta endereço Especifica o endereço corrente de 6 bits da 0 0 0 1 A A A A A A 40 µs CGRAM CGRAM. Seta endereço Especifica o endereço corrente d 7 bits da 0 0 1 A A A A A A A 40 µs DDRAM DDRAM Lê o conteúdo do contador de endereços (AC) e o Lê o contador de AC AC AC AC AC AC AC estado do busy flag (BF): endereços (AC) e 0 1 BF 40 µs 6 5 4 3 2 1 0 BF = 1, controlador ocupado. o busy flag BF = 0, controlador disponível. Escreve um dado Escreve um dado no endereço atual da CGRAM na DDRAM ou 1 0 D7 D6 D5 D4 D3 D2 D1 D0 40 µs ou DDRAM apontada pelo registrador AC. CGRAM Lê um dado da Lê um dado do endereço atual da CGRAM ou DDRAM ou 1 1 D7 D6 D5 D4 D3 D2 D1 D0 40 µs DDRAM apontada pelo registrador AC. CGRAM Tabela 11.2 – Comandos do controlador HD44780

272 Microcontroladores RL78: Guia Básico

Figura 11.1

A figura 11.1 apresenta a tabela padrão de caracteres disponível na maioria dos módulos LCD vendidos no Brasil. Observe que a maioria dos caracteres possui o mesmo código da tabela ASCII. Os caracteres com códigos 0x00 a 0x0F são gerados conforme os dados armazenados na RAM do gerador de caracteres (CGRAM). Mais adiante veremos como programar caracteres e símbolos especiais nestas posições O controlador HD44780 e os seus compatíveis apresentam uma pequena quantidade de memória RAM interna destinada ao armazenamento dos dados a serem apresentados (DDRAM) e ao gerador de caracteres de usuário (CGRAM). A figura 11.2 apresenta a organização dos endereços da DDRAM e a sua relação com a tela do display.

Exemplos de Aplicação 273

Linha Endereço

0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

1 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

2 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

3 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 Figura 11.2 – Endereços da DDRAM

Para apresentar um caractere na segunda linha e terceira coluna do display é necessário configurar o endereço da DDRAM (através do registrador AC do controlador) para o endereço 66 decimal. Para facilitar a utilização do módulo LCD, incluímos um conjunto de funções dedicadas especificamente ao controle do display. Este conjunto de funções encontra-se dentro do arquivo “lcd_8x2.c” que é utilizado por outros exemplos no decorrer deste capítulo. Este arquivo deve estar localizado na mesma pasta onde encontra-se o código fonte da aplicação. //************************************************************************ //* LCD.C - Biblioteca de manipulação de módulo LCD no RL78 //* Autor: Fábio Pereira //************************************************************************

// As definições a seguir são utilizadas para acesso aos pinos do display #ifndef PIN_LCD_EN #define PIN_LCD_EN P5_bit.no4 // pino enable do LCD #define PIN_LCD_EN_DIR PM5_bit.no4 // direção do pino enable #define PIN_LCD_RS P5_bit.no5 // pino rs do LCD #define PIN_LCD_RS_DIR PM5_bit.no5 // direção do pino rs #define PORT_LCD_DATA4 P7 #define PORT_LCD_DATA4_DIR PM7 #endif

#define CPU_CLOCK 32000

// Endereço da segunda linha na RAM do LCD #define LCD_LIN2 0x40

// Definições utilizadas para configuração do display #define CURSOR_ON 2 #define CURSOR_OFF 0 #define CURSOR_BLINK 1 #define CURSOR_FIXED 0 #define DISPLAY_ON 4 #define DISPLAY_OFF 0 #define DISPLAY_8x5 0 #define DISPLAY_10x5 4 #define _2LINES 8 #define _1LINE 0

//************************************************************************** //* Função de atraso (aproximadamente em ms) //************************************************************************** void LCD_delay_ms(unsigned char time) { unsigned int temp;

274 Microcontroladores RL78: Guia Básico

for (;time;time--) for (temp=CPU_CLOCK/9;temp;temp--) __no_operation(); }

//************************************************************************** //* Função de envio de um nibble para o display //************************************************************************** void LCD_send4(char data) { // coloca os quatro bits nas saídas PORT_LCD_DATA4 = data & 0x0F; // pulsa a linha enable PIN_LCD_EN = 1; PIN_LCD_EN = 0; }

//************************************************************************** //* Escreve um byte no display //************************************************************************** //* Argumentos de chamada: //* char endereco : 0 se instrução, 1 se dado //* char dado : dado ou comando a ser escrito //************************************************************************** void LCD_send8(char addr, char data ) { // configura a linha rs dependendo do modo selecionado PIN_LCD_RS = addr; LCD_delay_ms(1); // envia a primeira parte do byte LCD_send4(data >> 4); // envia a segunda parte do byte LCD_send4(data & 0x0f); }

//************************************************************************** //* Inicializa o display //************************************************************************** //* Argumentos de chamada: //* char modo1 : modo do display (número de linhas e tamanho dos caracteres //* char modo2 : modo do display (estado do cursor e do display) //************************************************************************** void LCD_init(char md1, char md2 ) { unsigned char temp; // configura os pinos como saídas PIN_LCD_EN_DIR = 0; PIN_LCD_RS_DIR = 0; PORT_LCD_DATA4_DIR = 0xF0; // coloca os pinos em nível lógico 0 PORT_LCD_DATA4 = 0; PIN_LCD_RS = 0; PIN_LCD_EN = 0; LCD_delay_ms(15); // envia uma seqüência de 3 vezes 0x03 e depois 0x02 para configurar o // módulo no modo de 4 bits for(temp=3;temp;temp--) { LCD_send4(3); LCD_delay_ms(5); }

Exemplos de Aplicação 275

LCD_send4(2); // envia códigos de inicialização do display LCD_send8(0,0x20 | md1); LCD_send8(0,0x08 | md2); LCD_send8(0,1); LCD_send8(0,6); }

//************************************************************************** //* Posiciona o cursor no display //************************************************************************** //* Argumentos de chamada: //* char x : coluna a ser posicionado o cursor (iniciando de 0) //* char y : linha a ser posicionado o cursor (0 ou 1) //************************************************************************** void LCD_pos_xy(char x, char y) { unsigned char addr; addr = y * 64 + x; LCD_send8(0,0x80|addr); }

//************************************************************************** //* Função de escrita de um caractere no display //************************************************************************** //* Argumentos de chamada : //* char c : caractere a ser escrito //************************************************************************** //* Observações : //* \f apaga o conteúdo do display //* \n e \r retornam o cursor para a primeira coluna da segunda linha //************************************************************************** void LCD_write_char(char data) // envia um caractere para o display { switch (data) { case '\f' : LCD_send8(0,1); LCD_delay_ms(5); break; case '\n' : case '\r' : LCD_pos_xy(1,2); break; default : LCD_send8(1,data); } }

//************************************************************************** //* Escreve uma string no display //************************************************************************** //* Argumentos de chamada: //* char *c : um ponteiro para um caractere //************************************************************************** void LCD_write_string (char *data) { while (*data)

276 Microcontroladores RL78: Guia Básico

{ LCD_write_char(*data); data++; } }

Listagem 11.1 – Arquivo lcd_8x2.c A seguir apresentamos um pequeno exemplo de utilização das funções para manipulação do display LCD da placa RSK do RL78/G13. Este exemplo demonstra como inicializar o display e apresentar mensagens no mesmo.

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h" #include "lcd_8x2.c"

// Configura watchdog #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;

/* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

void main(void) { LCD_init(DISPLAY_8x5|_2LINES,DISPLAY_ON|CURSOR_OFF|CURSOR_FIXED); LCD_write_string("RL78/G13"); LCD_pos_xy(0,1); LCD_write_string("LCD 8x2"); while(1); }

Exemplo 11.1

Também é possível configurar uma área de memória RAM do controlador de forma a se construir caracteres e símbolos definidos pelo usuário. Esta área de RAM é chamada de CGRAM e é composta de 64 bytes. Cada conjunto de 8 bytes forma um caractere, resultando num máximo de 8 caracteres programáveis pelo usuário. A tabela 11.3 mostra os endereços da CGRAM para cada um dos possíveis caracteres definidos pelo usuário.

Exemplos de Aplicação 277

Caractere do Usuário Código do Primeiro endereço Último endereço Caractere CGRAM CGRAM 0 ou 8 0 7 1 ou 9 8 15 2 ou 10 16 23 3 ou 11 24 31 4 ou 12 32 39 5 ou 13 40 47 6 ou 14 48 55 7 ou 15 56 63 Tabela 11.3 – Endereços da CGRAM

A programação de um caractere definido pelo usuário consiste basicamente em se setar o apontador de endereços do controlador de display (AC) para o endereço inicial do caractere desejado e em seguida enviar-se os oito bytes com a representação binária do mesmo. Bits Dado 7 6 5 4 3 2 1 0 0x1F 0 0 0 1 1 1 1 1 0x1F 0 0 0 1 1 1 1 1 0x1F 0 0 0 1 1 1 1 1 0x1F 0 0 0 1 1 1 1 1 0x1F 0 0 0 1 1 1 1 1 0x1F 0 0 0 1 1 1 1 1 0x1F 0 0 0 1 1 1 1 1 0x1F 0 0 0 1 1 1 1 1 Figura 11.3 – Um caractere definido pelo usuário

11.2. Mostrador Analógico no LCD

O próximo exemplo mostra como utilizar caracteres definidos pelo usuário para construir um mostrador em barra com um “visual analógico”. O gráfico é atualizado a cada 125ms, utilizando o canal 0 da TAU0 e apresenta um barra com tamanho proporcional ao valor lido no canal 6 do conversor A/D. Na placa RSK do RL78/G13 esta entrada está conectada a um trimpot (RV1). Variando-se a posição do mesmo podemos variar o tamanho da barra apresentada no display. Note que um caractere totalmente preenchido é composto de 5 colunas com todas as 8 linhas preenchidas (como mostra a figura 11.3). Lembre-se de cada caractere é desenhado numa matriz de 5 colunas por 7 linhas (a última linha é normalmente mantida em branco, pois é dedicada ao cursor, que não é utilizado neste exemplo). O exemplo também demonstra a utilização de um canal DMA configurado para transferir 16 leituras do ADC para um buffer de amostras. Após cada transferência completa do DMA a aplicação calcula a média das mesmas para apresentação no display. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h" #include "lcd_8x2.c"

278 Microcontroladores RL78: Guia Básico

// Configura watchdog #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE; /* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

volatile __saddr struct { unsigned char display_update : 1; } bits;

unsigned int samples[16], result; const char custom_char[] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, // uma coluna 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, // duas colunas 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, // três colunas 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, // quatro colunas 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F // cinco colunas };

#pragma vector = INTDMA0_vect __interrupt void trata_DMA_ADC(void) { unsigned char aux; DRC0 = bDEN; // habilita o DMA0 DBC0 = 16; // número de palavras a transferir DSA0 = (char)&ADCR; // endereço do registrador fonte DRA0 = (int)samples; // endereço do buffer para as amostras // configura o canal de DMA: 16 bits, do SFR para a RAM, disparo pelo ADC DMC0 = bDS | DMA_TRIG_ADC; DRC0 = bDEN | bDST; // seta DST para iniciar a transferência result = 0; // soma todas as amostras (deslocando-as 6 bits à esquerda) for (aux=0; aux<16; aux++) { result += samples[aux]>>6; } result >>= 4; // divide o resultado por 16 }

#pragma vector = INTTM00_vect __interrupt void trata_TAU0_canal0(void) { bits.display_update = 1; // atualiza o display a cada 125ms }

/*

Exemplos de Aplicação 279

Desenha um gráfico de barra no display LCD alfanumérico utilizando os caracteres especiais criados: | || ||| |||| e ||||| O parâmetro pix é o número de pixels a desenhar */ void LCD_bargraph(unsigned char pix) { char cnt = 8; // número máximo de colunas while (pix) { if (pix>=5) // se restar mais de 5 pixels a desenhar { LCD_write_char(4); // desenha um bloco preto cnt--; // uma coluna a menos pix -= 5; // cinco pixels a menos } else // se restar menos de 5 colunas a desenhar { LCD_write_char(pix-1); // desenha um bloco parcial pix = 0; // não há mais pixels restantes cnt--; // uma coluna a menos } } // preenche as colunas restantes com espaços while (cnt--) LCD_write_char(' '); }

void init(void) { unsigned char aux; ADPC = 8; // pinos P20, P21 e P22 no modo analógico ADCEN = 1; // habilita o ADC // Configura o ADC (conversões múltiplas, um canal, disparo por software) ADM0 = ADCLK_DIV16 | ADC_LV0 | bADCE; ADM1 = ADC_TRIG_SOFT; ADS = ADC_CH6; // seleciona o canal 6 como entrada do ADC ADCS = 1; // inicia uma conversão DRC0 = bDEN; // habilita o DMA0 DBC0 = 16; // número de palavras a transferir DSA0 = (char)&ADCR; // endereço do registrador fonte DRA0 = (int)samples; // endereço do buffer para as amostras // configura o canal de DMA: 16 bits, do SFR para a RAM, disparo pelo ADC DMC0 = bDS | DMA_TRIG_ADC; DRC0 = bDEN | bDST; // seta DST para iniciar a transferência TAU0EN = 1; // habilita a TAU0 TPS0 = TAU_CK0_DIV1024; // CK0=31250Hz, CK1=32MHz, CK2=16MHz e CK3=125kHz // configura o canal 0 da TAU0 no modo temporizador TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_TIMER; TDR00 = 3905; // uma interrupção a cada 125ms no canal 0 TS0L = TAU_CH0; // Dispara o canal 0 LCD_init(DISPLAY_8x5|_2LINES,DISPLAY_ON|CURSOR_OFF|CURSOR_FIXED); // configura os caracteres especiais na CGRAM LCD_send8(0,0x40); // aponta para a área da CGRAM for (aux=0; aux

280 Microcontroladores RL78: Guia Básico

void main(void) { init(); LCD_write_char('\f'); // apaga o display LCD_pos_xy(0,0); // cursor na coluna 0 da linha 0 LCD_write_string("RL78/G13"); while(1) { if (bits.display_update) { bits.display_update = 0; // apaga o indicador de atualização LCD_pos_xy(0,1); // cursor na coluna 0 da linha 1 LCD_bargraph(result/25); // desenha o gráfico de barras } } }

Exemplo 11.2

11.3. Termômetro Digital

Neste exemplo demonstramos como utilizar o sensor interno de temperatura do RL78/G13. A aplicação configura o ADC para operar no modo contínuo, convertendo alternadamente a tensão proveniente da referência interna de tensão (1,45V) e do sensor de temperatura integrado. A tensão de alimentação e a temperatura ambiente são apresentadas no display LCD da placa RSK do RL78/G13. A tensão de alimentação é determinada através da medição da tensão da referência interna de 1,45V, utilizando os princípios apresentados no tópico 8.3. A medição da tensão de alimentação é necessária para correção do valor lido do sensor de temperatura, conforme mostrado no tópico 8.4. Este exemplo aproveita diversos conceitos apresentados neste livro e ilustra também uma técnica de formatação de dados para apresentação em display (ou outro meio) utilizando variáveis inteiras para representar valores fracionários. A aplicação utiliza um valor de offset fixo para a temperatura (variável “toff”). Este valor foi determinado através de ensaio, utilizando como referência um termômetro medindo a temperatura ambiente. Em aplicações profissionais cada placa deveria ser calibrada na linha de produção e o valor de calibração salvo na memória flash. #include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h" #include "lcd_8x2.c"

// Configura watchdog #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão

Exemplos de Aplicação 281

#pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;

/* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

volatile __saddr struct { unsigned char display_update : 1; unsigned char adc_channel : 1; } bits;

unsigned int acc_vref, vref, acc_vtemp, vtemp, vdd; int toff; unsigned long long_data;

#pragma vector = INTAD_vect __interrupt void trata_ADC(void) { unsigned int result; result = ADCR >> 6; // lê o resultado da conversão // o bit adc_channel controla qual o canal do ADC sendo convertido if (bits.adc_channel) { // conversão da referência interna de tensão acc_vref += result - vref; // acumula o novo valor, subtrai a média vref = acc_vref >> 6; // calcula a média dos 64 últimos valores ADS = ADC_CH_TEMP; // seleciona o sensor de temperatura bits.adc_channel = 0; } else { acc_vtemp += result - vtemp; // acumula o novo valor, subtrai a média vtemp = acc_vtemp >> 6; // calcula a média dos 64 últimos valores ADS = ADC_CH_REF; // seleciona a referência interna bits.adc_channel = 1; } }

#pragma vector = INTTM00_vect __interrupt void trata_TAU0_canal0(void) { bits.display_update = 1; // atualiza o display a cada 500ms }

void init(void) { ADPC = 0; // nenhum pino em modo analógico ADCEN = 1; // habilita o ADC // Configura o ADC (conversões múltiplas, um canal, disparo por software) ADM0 = ADCLK_DIV64 | ADC_LV0 | bADCE; ADM1 = ADC_TRIG_SOFT; ADS = ADC_CH_REF; // seleciona a referência interna como entrada do ADC ADMK = 0; // habilita interrupção do ADC

282 Microcontroladores RL78: Guia Básico

ADCS = 1; // inicia uma conversão TAU0EN = 1; // habilita a TAU0 TPS0 = TAU_CK0_DIV1024; // CK0=31250Hz, CK1=32MHz, CK2=16MHz e CK3=125kHz // configura o canal 0 da TAU0 no modo temporizador TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_TIMER; TDR00 = 15624; // uma interrupção a cada 500ms no canal 0 TMMK00 = 0; // habilita a interrupção do canal 0 da TAU0 TS0L = TAU_CH0; // Dispara o canal 0 LCD_init(DISPLAY_8x5|_2LINES,DISPLAY_ON|CURSOR_OFF|CURSOR_FIXED); acc_vref = vref = 0; acc_vtemp = vtemp = 0; bits.adc_channel = 1; // ADC convertendo tensão de referência __enable_interrupt(); // habilita as interrupções do RL78 }

/* Esta função escreve um valor inteiro no LCD. Ela utiliza uma formatação especial para representar um valor fracionário através de inteiros. Os dígitos de dezenas de milhares, milhares e centenas são impressos, seguidos do ponto decimal e dos dígitos de dezenas e unidades. Assim, o valor 1001 é apresentado como 10.01. */ void LCD_write_frac_int(unsigned int data) { unsigned char aux, space; unsigned int sub = 10000; aux = 0; space = 1; while (sub) { aux = 0; while (data>=sub) { data -= sub; aux++; space = 0; } if (!space) LCD_write_char(aux+'0'); sub /= 10; if (sub==10) { if (space) LCD_write_char('0'); LCD_write_char('.'); space = 0; } } if (space) LCD_write_char('0'); }

void main(void) { init(); LCD_write_char('\f'); // apaga o display toff = -500; // offset de temperatura (-5 graus) while(1) { // caso exista uma solicitação de atualização do display if (bits.display_update) {

Exemplos de Aplicação 283

bits.display_update = 0; // apaga o bit de atualização de display LCD_pos_xy(0,0); // cursor na linha 0, coluna 0 LCD_write_string("V="); long_data = 148480 / vref; // calcula o VDD vdd = long_data; LCD_write_frac_int(vdd); // imprime o VDD (5V = 5.00) LCD_write_string(" "); // apaga caracteres remanescentes LCD_pos_xy(0,1); // cursor na linha 1, coluna 0 LCD_write_string("T="); // calcula a temperatura atual long_data = 2500 - ((long)vtemp*(long)vdd*100 - 10752000)/368 + toff; LCD_write_frac_int(long_data); // imprime a temperatura LCD_write_string(" "); // apaga caracteres remanescentes } } }

Exemplo 11.3

11.4. Medidor de Distância por Ultrassom

Este exemplo demonstra como utilizar o modo de captura de nível da TAU para medir a largura de pulso de um sensor de distância ultrassônico (HC-SR04) e com isso determinar a distância de um objeto em relação ao sensor. O sensor HC-SR04 é um módulo de baixo custo e fácil utilização. Ele possui um conector de 4 pinos (VCC, Trig, Echo e GND), opera com tensão de 5V e fornece uma saída digital com largura proporcional a distância entre o sensor e o objeto posicionado a sua frente.

Figura 11.4

A operação do sensor é bastante simples: basta gerar um pulso de disparo no pino Trig (duração mínima de 10µs) e aguardar pelo retorno do eco do ultrassom. O próprio módulo irá gerar um trem de pulsos com frequência na faixa dos 40kHz e processar o sinal de retorno dos mesmos. O sinal de saída do sensor é apresentado no pino Echo e consiste num pulso ativo em nível lógico “1” com largura igual ao tempo entre a transmissão e a recepção do eco. O cálculo da distância pode ser facilmente realizado através da seguinte fórmula:

284 Microcontroladores RL78: Guia Básico

340 * pulso _ retorno DIST )m( = 2 Assim, se o pulso tiver uma largura de 1000µs, o alvo estará a 0,17m do sensor. Para obter a distância em cm: pulso _ retorno DIST )cm( = 58 Note que, para o cálculo, o pulso deverá sempre ser medido em µs. A seguir apresentamos a listagem do exemplo completo. O pino TRIG do módulo HC-SR04 deve ser conectado ao pino P4.1 do RL78 e o pino ECHO deve ser conectado ao pino P4.2 (entrada TI04) do RL78.

Figura 11.5

#include "ior5f100le.h" #include "ior5f100le_ext.h" #include "intrinsics.h" #include "myRL78.h" #include "lcd_8x2.c"

// Configura watchdog #pragma location = "OPTBYTE" __root __far const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root __far const char opbyte1 = LVD_OFF; // oscilador 32MHz flash high speed #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_HS | CLK_32MHZ; // debug ativado, com apagamento em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;

Exemplos de Aplicação 285

/* Configura security ID */ #pragma location = "SECUID" __root __far const char senha[10] = {0,0,0,0,0,0,0,0,0,0};

#define TRIGGER P4_bit.no1

volatile unsigned int interval; unsigned long distance; volatile __saddr struct { unsigned char display_update : 1; unsigned char echo_received : 1; unsigned char trig_mode : 1; unsigned char aux : 1; } bits;

#pragma vector = INTTM00_vect __interrupt void trata_TAU0_canal0(void) { if (bits.trig_mode) { TRIGGER = 1; TDR00 = 9; // intervalo de 10us para o disparo TS0L = TAU_CH0; bits.echo_received = 0; } else { TRIGGER = 0; TDR00 = 0xFFFF; TS0L = TAU_CH0; if (!bits.echo_received) interval=0xFFFF; } bits.trig_mode = !bits.trig_mode; } #pragma vector = INTTM04_vect __interrupt void trata_TAU0_canal4(void) { interval = TDR04; // salva o valor capturado bits.echo_received = 1; // sinaliza que recebeu um pulso de eco bits.aux = !bits.aux; if (bits.aux) bits.display_update = 1; // atualiza o display }

/* Esta função escreve um valor inteiro no LCD. Ela utiliza uma formatação especial para representar um valor fracionário através de inteiros. Os dígitos de dezenas de milhares, milhares e centenas são impressos, seguidos do ponto decimal e dos dígitos de dezenas e unidades. Assim, o valor 1001 é apresentado como 10.01. */ void LCD_write_frac_int(unsigned int data) { unsigned char aux, space; unsigned int sub = 10000; aux = 0; space = 1; while (sub) { aux = 0;

286 Microcontroladores RL78: Guia Básico

while (data>=sub) { data -= sub; aux++; space = 0; } if (!space) LCD_write_char(aux+'0'); sub /= 10; if (sub==10) { if (space) LCD_write_char('0'); LCD_write_char('.'); space = 0; } } if (space) LCD_write_char('0'); }

void TAU_init(void) { TAU0EN = 1; // habilita a TAU0 TPS0 = TAU_CK0_DIV32; // CK0=1MHz, CK1=32MHz, CK2=16MHz e CK3=125kHz // configura o canal 0 da TAU0 no modo temporizador TMR00 = TAU_CK0 | TAU_TRIG_SOFT | TAU_MD_ONECOUNT; TDR00 = 9; // intervalo inicial de 10us // configura o canal 4 da TAU0 no modo de captura de ciclo ativo TMR04 = TAU_CK0|TAU_EDGE_RISE_FALL|TAU_TRIG_BOTH_EDGE|TAU_MD_CAPTURE_LEVEL; TS0L = TAU_CH4 | TAU_CH0; // Arma os canais 0 e 4 TMMK00 = 0; // habilita a interrupção do canal 0 da TAU0 TMMK04 = 0; // habilita a interrupção do canal 4 da TAU0 }

void SYS_init(void) { PM4_bit.no1 = 0; // P41 como saída (TRIGGER) TAU_init(); // inicializa a TAU0 LCD_init(DISPLAY_8x5|_2LINES,DISPLAY_ON|CURSOR_OFF|CURSOR_FIXED); LCD_write_char('\f'); // apaga o display __enable_interrupt(); // habilita as interrupções do RL78 }

void main(void) { SYS_init(); LCD_pos_xy(0,0); // cursor na coluna 0 da linha 0 LCD_write_string("Distanc"); TRIGGER = 1; // inicia um pulso de disparo para o módulo de ultrassom bits.trig_mode = 0; TS0L = TAU_CH0; // Dispara o canal 0 while(1) { if (bits.display_update) { bits.display_update = 0; // apaga o bit de atualização LCD_pos_xy(0,1); // cursor na coluna 0 da linha 1 // calcula a distância em cm distance = ((long)interval*100)/58; if (distance<=40000) // se a distância for <= 400cm {

Exemplos de Aplicação 287

LCD_write_frac_int(distance); LCD_write_string("cm "); } else LCD_write_string("---.--cm"); } } } Exemplo 11.4

288 Microcontroladores RL78: Guia Básico

A

Tabela ASCII 12. Tabela ASCII

A tabela abaixo mostra o American Standard Code for Information Interchange (ASCII), um padrão internacional para codificação de texto e símbolos. A utilização da tabela é muito simples: supondo a letra “A”, basta localizá-la na tabela. Em seguida pegamos o valor da linha (64 decimal ou 4 hexadecimal) e o valor da coluna (1), assim, o código ASCII para “A” é 41 (hexadecimal) ou 64+1=65 (decimal), o código para DEL é 7F (hexadecimal) ou 112+15=127 (decimal) e assim por diante. Dec 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Hex 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 0 NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI 16 1 DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US 32 2 SP ! “ # $ % & ‘ ( ) * + , - . / 48 3 0 1 2 3 4 5 6 7 8 9 : ; < = > ? 64 4 @ A B C D E F G H I J K L M N O 80 5 P Q R S T U V W X Y Z [ \ ] ^ _ 96 6 ` a b c d e f g h i j k l m n o 112 7 p q r s t u v w x y z { | } ~ DEL

Tabela ASCII 289

290 Microcontroladores RL78: Guia Básico

Índice Remissivo

CCTIMER1...... 50 CISC ...... 17, 30, 55, 65 ! Clock fAD ...... 180 ! ...... 71 fCLK ...... 84 !! ...... 71 fIH ...... 83 fIL ...... 84 # fMAIN ...... 83 fMX ...... 83 # ...... 28 fSUB ...... 84 #pragma Gerenciamento ...... 95 bank...... 129 Saída ...... 98 location...... 75, 78 Conversor A/D ...... 177, 278, 281 vector...... 125 Clock...... 180 Comparador Digital...... 182 Disparo...... 184 $ Modo Snooze ...... 187 Pinagem ...... 179 $ ...... 71 Referência Interna ...... 186, 281 $! ...... 71 Sensor de Temperatura ...... 186, 281 Varredura ...... 184 CRC...... 235, 239 _ C-SPY...... 43 __asm...... 234 __callt...... 263 D __disable_interrupt() ...... 125 __enable_interrupt() ...... 125 Dataflash...... 240 __far...... 75, 79 Debug...... 43, 74, 78 __halt()...... 93 Disassembly...... 46 __saddr...... 64, 262 Display LCD ...... 271 __stop() ...... 94 CGRAM...... 273, 277 Comandos ...... 272 DDRAM...... 273 7 Pinagem ...... 271 DMA...... 253, 278 78K0R...... 55 DSP...... 252

A E

ADC...... Consulte Conversor A/D EEL...... 44, 240 API...... 240 EEPROM ...... 240 Applilet3...... 264 ELC...... 175, 192 CSI...... 215 2 Embedded Workbench ...... 41 I C...... 223, 226 EMI...... 108 UART...... 208 Endereço ilegal...... Consulte Reset:IAW ASCC ...... 16 ENIAC ...... 15 Assembly...... 46 EWRL78...... 41 AVREFM ...... 182 Criando um projeto...... 41 AVREFP ...... 182 Depuração ...... 51 Simulação...... 46 B

Big Endian...... 29 F Boot loader...... 63 FDL...... 44, 62, 240 Bootloader...... 240 Flag Breakpoint...... 47, 48 AC...... 57 Buzzer ...... 98 CY...... 57 Bytes de opção ...... 76 Z...... 57 Flash Apagamento ...... 240 C Gravação ...... 240 Carry ...... 57 FSL...... 44, 61, 62, 240 FSL_BlankCheck ...... 242

Microcontroladores RL78: Guia Básico 291

FSL_Close ...... 241 MULU...... 67 FSL_Erase ...... 61, 242 NOP...... 73 FSL_GetBlockEndAddr...... 244 NOT1...... 71 FSL_GetFlashShieldWindow...... 244 ONEB...... 65 FSL_Init...... 241 ONEW...... 65 FSL_InvertBootFlag ...... 63 OR...... 67 FSL_IVerify...... 242 OR1 ...... 71 FSL_Open...... 241 POP...... 73, 129 FSL_PrepareExtFunctions ...... 244 PUSH...... 59, 73, 129 FSL_PrepareFunctions...... 242 RET...... 73 FSL_StandBy...... 243 RETB...... 73, 123 FSL_StatusCheck...... 243 RETI...... 73, 123, 130 FSL_WakeUp ...... 244 ROL...... 70 FSL_Write ...... 243 ROLC...... 70 ROLWC ...... 71 ROR...... 70 H RORC...... 70 SAR...... 69 Halt...... Consulte Modo halt SARW...... 69 Harvard...... 16 SEL RBx...... 58, 73, 130 Hitachi ...... 30 SET1...... 71 SHL...... 69 SHLW...... 69 I SHR...... 68 IE ...... Consulte Interrupções: IE SHRW...... 69 IICA...... 224 SKC...... 73 Instruções SKH...... 73 ADD...... 66 SKNC...... 73 ADDC...... 66 SKNH...... 73 ADDW...... 66 SKNZ...... 73 AND...... 67 SKZ...... 73 AND1 ...... 71 STOP...... 74, 94 BC...... 72 SUB...... 66 BF...... 72 SUBC ...... 66 BH...... 72 SUBW ...... 66 BNC...... 72 Temporização ...... 74 BNH...... 72 XCH...... 65 BNZ...... 72 XCHW...... 65 BR...... 27, 72 XOR...... 67 BRK...... 59, 73, 123 XOR1 ...... 71 BT...... 72 Interrupções BTCLR ...... 65, 72 Bancos de Registradores ...... 129 BZ...... 27, 72 CSI...... 214 CALL...... 59, 72 DMA...... 256 CALLT ...... 59, 63, 64, 72, 263 Externas...... 130 CLR1 ...... 71 Flags ...... 122 CLRB...... 25, 65 IE...... 58, 122 CLRW...... 66 INTAD ...... 183 CMP...... 27, 67 INTCSI...... 214 CMP0...... 67 INTIIC...... 220 CMPS...... 67 INTIT ...... 136 CMPW...... 67 INTKR...... 133 DEC...... 68 INTMD...... 253 DECW ...... 68 INTPx...... 130 DI...... 58, 74 INTRTC ...... 141 DIVHU ...... 67 INTSREn...... 205 DIVWU ...... 68 INTSRn ...... 205 EI...... 58, 74 INTSTn...... 205 HALT ...... 74, 93 INTTMmn ...... 151 INC...... 27, 68 ISR...... 121, 123, 125, 129 INCW ...... 68 Latência ...... 128 MACH...... 57, 68 LVD...... 101 MACHU...... 57, 68 Mascaramento ...... 123 Modos de Endereçamento ...... 63 Prioridades...... 126 MOV...... 65 SAU...... 204, 214, 220 MOV1...... 71 Teclado...... 133 MOVS...... 65 Vetores ...... 63, 123 MOVW...... 65 Watchdog...... 105 MULH...... 67 ISP0...... 58 MULHU...... 67 ISP1...... 58

292 Microcontroladores RL78: Guia Básico

ISR...... Consulte Interrupções:ISR Pooling...... 106, 120 Princeton...... 16 PWM...... 149, 175 K Ki ...... 38 R KiB...... 38 Kibit ...... 38 R5F100LEA...... 35 RBS0...... 57 RBS1...... 57 L Registradores...... 55 A...... 55 Latch ...... 24 ADCR ...... 190 LIN...... 148 ADLL...... 190 Linker...... 43 ADM0 ...... 188 Little endian ...... 248 ADM1 ...... 189 Little Endian...... 29 ADM2 ...... 94, 189 LVD...... 77, 100, 103 ADPC...... 111, 114, 178 Interrupção ...... 101 ADS...... 190 Reset...... 100 ADTES...... 191, 238 ADUL...... 190 ALARMWH...... 145 M ALARMWM...... 144 Memória ALARMWW...... 145 Acesso ilegal ...... 62 AX...... 55 Bloco de boot...... 63 B...... 55 Blocos...... 61 Bancos...... 56, 57, 129 Dataflash ...... 62 BC...... 55 Espelhamento ...... 60 BCDADJ...... 233 Mapa ...... 61, 62 C...... 55 Modelo ...... 42 CKC...... 83, 84, 85, 87 Modelo Far ...... 42 CKSn...... 98 Modelo Near...... 42, 75, 79 CMC...... 84, 85, 88 Paridade...... 236 CRC0CTL...... 236 Mi ...... 38 CRCD ...... 239 MISO...... 211 CRCIN ...... 239 MISRA...... 235 CS...... 56, 60 Modo halt ...... 30, 93 CSC...... 84, 86, 88 Modo snooze ...... 94 D...... 55 Modo stop ...... 93 DAY...... 143 MOSI...... 211 DBCn ...... 256 Multiplicador por hardware ...... 251 DE...... 55 myRL78.h ...... 38 DMCn ...... 257, 258 DRAn...... 256 DRCn ...... 258 N DSAn ...... 256 E...... 55 N: ...... 28 EGN0 ...... 131 NEC...... 30 EGN1 ...... 131 Nibble...... 20 EGP0...... 131 EGP1...... 131 ES...... 56, 60 O GDIDIS...... 111, 115 H...... 55 OCD...... 74, 78, 108 HIOTRM...... 86, 91, 239 Opbyte0...... 76 HL...... 55 Opbyte1...... 77 HOCODIV ...... 81, 86, 90 Opbyte2...... 78 HOUR ...... 143 Opbyte3...... 78 IAWCTL...... 62, 237 Opcodes...... 25 IFxH...... 122 Option byte...... 48, 76 IFxL ...... 122 Oscilador ...... 78 IICAn ...... 228 HOCO ...... 86 IICCTLn0...... 228 LOCO...... 87 IICCTLn1...... 230 X1...... 84 IICCWHn...... 231 XT1 ...... 85 IICCWLn ...... 231 IICFn...... 230 IICSn...... 229 P ISC...... 173, 202, 208 Pipeline ...... 30, 74 ITMC...... 137

Microcontroladores RL78: Guia Básico 293

KRM...... 133 SSm ...... 199 L...... 55 SSmL...... 199 LVIM...... 100, 102 SSRmL ...... 199 LVIS...... 102 SSRmn...... 199 MACR...... 57, 68 STm...... 200 MACRH...... 57 STmL...... 200 MACRL...... 57 SUBCUD...... 144 MDAH...... 252 SVAn...... 228 MDAL...... 252 TEm...... 170 MDBH...... 252 TEmL ...... 170 MDBL...... 252 TIS0...... 171, 239 MDCH...... 252 TMRmn ...... 168 MDCL...... 252 TOEm...... 172 MDUC...... 253 TOEmL...... 172 MIN...... 142 TOLm...... 172 MKxH...... 123 TOLmL...... 172 MKxL ...... 123 TOm ...... 172 MONTH...... 144 TOmL...... 172 NFEN0...... 202 TOMm...... 173 NFEN1...... 173 TOMmL ...... 173 NFEN2...... 173 TPSm...... 167 OSMC...... 86, 87, 89 TSm...... 170 OSTC...... 85, 89 TSmL...... 170 OSTS...... 85, 89 TSRmn ...... 169 PC...... 56, 58 TSRmnL ...... 169 PER0...... 95, 136, 178, 202, 225 TTm...... 171 PGCRCL...... 235 TTmL ...... 171 PIMx...... 110 TXD0...... 204 PIOR...... 111, 116 TXD1...... 204 PMC...... 56, 60 TXD2...... 204 PMCx...... 110, 114, 179 TXD3...... 204 PMx ...... 110 Visualização ...... 47 POMx ...... 110 WDTE ...... 104 PR0xH ...... 126, 127 WEEK...... 143 PR0xL...... 126, 127 X...... 55 PR1xH ...... 126, 127 YEAR...... 144 PR1xL...... 126, 127 Regulador Interno de Tensão ...... 108 PSW...... 56, 57, 122, 130 Reset...... 81 PUx...... 110 IAW...... 62, 82, 238 Px...... 110 LVD...... 82 RESF...... 83, 100, 105, 238 Paridade...... 82, 236 RPECTL ...... 236 Pino ...... 81 RTCC0...... 141 POR...... 81 RTCC1...... 142 RPE...... 82 RXD0...... 204 Trap ...... 82, 238 RXD1...... 204 Vetor...... 81 RXD2...... 204 Watchdog...... 82, 104 RXD3...... 204 RFP...... 52, 79 SCRmn ...... 197 RISC...... 17, 65 SDRmn ...... 198 RL78/D1x...... 32 SEC...... 142 RL78/F1x ...... 32 SEm ...... 200 RL78/G12...... 31 SEmL...... 200 RL78/G13...... 31 SIOp...... 211 RL78/G14...... 31 SIRmn...... 198 RL78/G1A...... 31 SIRmnL ...... 198 RL78/G1C ...... 31 SMRmn...... 196 RL78/I1x ...... 32 SOEm ...... 200 RL78/L12 ...... 32 SOEmL ...... 200 RL78/L13 ...... 32 SOLm ...... 201 RTOS ...... 121 SOLmL ...... 201 SOm...... 201 SOmL ...... 201 S SP...... 56, 58 SPH...... 59 SAR...... 178 SPL...... 59 SAU...... 193 SPSm ...... 196 Canais...... 194 SPSmL...... 196 CSI...... 193, 211 SSCm...... 95, 201, 208 Baud rate ...... 214 SSCmL ...... 201 Modos ...... 213

294 Microcontroladores RL78: Guia Básico

FDC...... 206 RG...... 175 I2C ...... 193, 216 RJ...... 175 Baud rate ...... 221 RTC...... 138 Endereçamento...... 221 TAU...... 148 Parada ...... 223 Modo Contador de Eventos...... 156 Partida ...... 221 Modo de Captura de Ciclo...... 159 Partida Repetida ...... 222 Modo de Captura de Período...... 158 Recepção...... 222 Modo de Pulso Configurável...... 160 Transmissão ...... 222 Modo Disparo Único...... 154 Pinagem...... 194 Modo Divisor de Frequência ...... 157 UART...... 193, 203, 269 Modo Onda Quadrada ...... 151 Baud rate ...... 205 Modo PWM ...... 164 Erros...... 205 Modo Timer...... 151 LIN...... 208 Pinagem ...... 150 Snooze...... 208 SCK...... 211 Security ID ...... 63, 74, 266 U Semáforos...... 65 SI ...... 211 UART...... Consulte SAU:UART SO ...... 211 ULA...... 15 Somador ...... 23 SPI...... 193, 211 SSEC...... 16 V Stop ...... Consulte Modo stop Von Neumann ...... 16

T W TAU Watchdog...... 76, 104, 106 Modo de Captura de Ciclo ...... 284 Janela ...... 104 Timers WDT...... Consulte Watchdog Intervalo ...... 136, 267 Workspace ...... 42 IT...... 136 RD...... 175

Microcontroladores RL78: Guia Básico 295

296 Microcontroladores RL78: Guia Básico

Referências

1. DEAN, A. G., CONRAD J. M. Creating Fast, Responsive and Energy-Efficient Embedded Systems using the Renesas RL78 . USA: Micrium Press, 2012. 2. PEREIRA, F. HCS08 Unleashed: Designer’s Guide to the HCS08 Microcontrollers . USA: Booksurge, 2008. 3. PEREIRA, F. MSP430: Teoria e Prática . São Paulo: Érica, 2005. 4. BORGES DE LIMA, C. Técnicas de Projetos Eletrônicos com os Microcontroladores AVR . Florianópolis: Ed. Do autor, 2010. 5. GANSSLE, J. The Firmware Handbook: The Definitive Guide to Embedded Firmware Design and Applications. USA: Elsevier, 2004. 6. FUJISAWA, Y. The Introduction to the H8 Microcontroller . Japan: Ohmsha Ltd, 2003. 7. PREDKO, M. Handbook of Microcontrollers . USA: McGraw-Hill, 1999. Manuais (download em www.renesas.com) 8. RL78/G13 User’s Manual: Hardware . R01UH0146EJ0210 Rev.2.10, 2012 9. RL78 family User’s Manual: Software . R01US0015EJ0100 Rev.1.00, 2011 10. RL78/G12 User’s Manual: Hardware . R01UH0200EJ0110 Rev.1.10, 2012 11. RL78/G14 User’s Manual: Hardware . R01UH0186EJ0100 Rev.1.00, 2011 12. 78K0R User’s Manual: Instructions . R01US0029EJ0600 Rev.6.00, 2011 Notas de Aplicação (download em www.renesas.com) 13. AN0603: RL78 Window Watchdog Timer . R01AN0603ED0100, 2011 14. AN0749: RL78 Family VDE Certified IEC60730/60335 Self Test Library . R01AN0749EG0100, 2011 15. AN0814: Minimizing Power Consumption when Sensing Switch Inputs . R01AN0814EU0100, 2012 16. AN0956: RL78/G13 Safety Function (Frequency Detection) . R01AN0956EJ0100, 2012 17. AN0988: RL78 Internal Temperature Sensor Calibration . R01AN0988EU0100, 2012 Outros Documentos Eletrônicos 18. UM10204: I2C bus specification and user manual Rev. 5 . Disponível em: http://www.nxp.com/documents/user_manual/UM10204.pdf . NXP, 2012

Microcontroladores RL78: Guia Básico 297