Estou trabalhando num projeto utilizando o RL78/G12 de 20 pinos (R5F10367, com 4KiB de flash e sem dataflash) e precisei configurar o oscilador interno de alta velocidade (HOCO) para operar a 1MHz. Abaixo está a configuração que utilizei nos bytes de configuração:
// Watchdog desligado #pragma location = "OPTBYTE" __root const char opbyte0 = WDT_OFF; // Configura detector de baixa tensão #pragma location = "OPTBYTE" __root const char opbyte1 = LVD_RESET_MODE | LVD_VMODE2; // oscilador 1MHz flash low voltage #pragma location = "OPTBYTE" __root const char opbyte2 = FLASH_LV | CLK_1MHZ; // debug ativado, apaga a flash em caso de falha de autenticação #pragma location = "OPTBYTE" __root const char opbyte3 = DEBUG_ON_ERASE;
Pois bem, ao rodar o programa da aplicação, percebi que os atrasos de tempo estavam muito rápidos. Verifiquei a configuração do timer TAU, tudo certo. Parti então para observar o código na memória flash, fui direto nos endereços 0x000C0 a 0x000C3, onde são armazenados os bytes de configuração. Fiquei pasmo: estavam todos em 0xFF!!!! O quê estaria acontecendo?
Com certeza alguma coisa com o compilador ou linker. Ativei a geração do MAP file e fui procurar onde estavam sendo armazenados os bytes de configuração (já que obviamente eles não haviam sido armazenados no local correto)…
Gotcha! Eles estavam sendo armazenados nos endereços 0xFFD00 a 0xFFD03! Esta área é memória RAM e nada tem a ver com a área dos bytes de configuração!!! O quê estaria acontecendo?
A explicação está na forma como o compilador trata as constantes conforme o modelo de memória e de microcontrolador. Alguns RL78 possuem a facilidade de espelhar uma área da flash (do primeiro segmento da memória) no último de segmento, de forma que o programa pode acessar as constantes em flash e dados em RAM utilizando apenas endereçamento near, o que acelera o código.
No entanto, nos modelos G12 com 8KiB de flash ou menos, esta facilidade de espelhamento não está disponível e o compilador assume que deve copiar as constantes near da flash para a RAM. O problema é que as constantes near terminam por ser alocadas na faixa do último segmento, o que, no caso dos bytes de opção e security ID, inviabiliza totalmente a operação do chip!
A solução para isso é simples: basta declarar estes símbolos utilizando o modificador __far:
// Watchdog desligado #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_RESET_MODE | LVD_VMODE2; // oscilador 1MHz flash low voltage #pragma location = "OPTBYTE" __root __far const char opbyte2 = FLASH_LV | CLK_1MHZ; // debug ativado, apaga a flash em caso de falha de autenticação #pragma location = "OPTBYTE" __root __far const char opbyte3 = DEBUG_ON_ERASE;
Desta forma o linker armazena os bytes de configuração nos endereços corretos e tudo funciona perfeitamente! Ahh e tem mais: você pode utilizar o modificador __far na declaração dos bytes de configuração e security ID inclusive dos outros modelos de RL78, pois ele não produz nenhum efeito colateral nos outros chips e modelos de memória!