quinta-feira, 14 de outubro de 2021

Acessando a memoria flash(ROM) do C8051F380 / C8051F382 usando o Simplicity Studio .

ACESSANDO A MEMÓRIA ROM(flash) DO C8051F380 / C8051F382   


     Olá, bom dia atualmente a maioria dos microcontroladores tem uma memória rom interna. Porém ao trabalhar com o C8051F382 percebi que não tem! isso me causou um certo desconforto. buscando por uma solução observei que é possível usar a memoria flash como se fosse uma memoria ROM.

   Porém o uso da flash apresenta algumas características relevantes, como o fato de só poder apagar blocos de memorias(512 bytes por vez) em vez de uma só posição, outro problema é que para escrever numa posição obrigatoriamente vc deve apagar aquele bloco de memoria, ou seja, supondo que eu queira escrever na posição 1024, precisarei apagar o bloco de memoria que vai de 512 a 1024, o que pode ser desastroso se não avaliar bem onde se vai mexer pois corre o risco de apagar trechos de memorias que fazem parte do programa principal, uma recomendação e dar uma olhada nos arquivos ".list" ,gerado após compilar o código fonte, para ver como esta a localização da áreas usadas.

     O motivo de obrigatoriamente ter que apagar a memoria flash antes de escrever um novo caracteres   é devido ao fato de que quando se trabalha na flash para escrever só aceita escrever "0" nas posições, isso se deve a arquitetura como foi projetado, descobri isso fazendo alguns testes aqui, ou seja supondo que eu queira escrever em hexadecimal o valor  "0X11" numa posição, e então eu decida escrever o valor "0X08" , o esperado era ler "0X08" porem isso não acontece e é lido "0X00" ou seja  onde é zero ele coloca mas onde é 1 não é colocado, descobri isso num código em assembly dai com esse entendimento apliquei ao código que eu fiz em C.

      Veja que é possível depois de apagado o bloco da memoria ir escrevendo nas posições, porém se precisar alterar valores já gravados, terá que apagar o bloco de memoria de 512 bytes, apesar de ser uma característica de alguns microcontroladores da Silicon Labs, pode-se recorrer também para o uso de uma memoria externa .

        Uma vez explicado os risco e a limitação de hardware podemos agora passar para o código fonte. Neste código são utilizados 2 leds, um para indicar processamento e outro pra indicar que houve uma gravação num trecho de memória, assim quando ligar pela primeira vez o led não acende e a partir da segunda vez ficara acesso indicando uma leitura valida na memória, apesar do código ser simples é uma mão na roda pra que está passando por este problema. Aqui está usando o PORT P0.

O código fonte :

// Target:         C8051F382
// Tool chain:     Simplicity Studio / Keil C51 9.51
// Command Line:   None
// Autor: Aguivone Moretti Fogia
// Data: 14/10/2021
//
//exemplo de como usar a memoria flash como uma memoria ROM, apesar de não ser muito bom essa ideia pois
//caso ocorra um ruido ele pode alterar outras areas de memoria.
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
#include <SI_C8051F380_Register_Enums.h>
#include "F380_FlashPrimitives.h"
#include "F380_FlashUtils.h"

//-----------------------------------------------------------------------------
// Global Constants
//-----------------------------------------------------------------------------

#define SYSCLK       12000000          // Internal oscillator frequency in Hz

//leds vermelho e sinal de saida
SI_SBIT(LED_gravado, SFR_P0, 0);                      // LED='0' Ligado
SI_SBIT(LED_pisca, SFR_P0, 1);                      // LED='1' Desligado


//-----------------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------------
SI_INTERRUPT_PROTO(PCA0_ISR, PCA0_IRQn);

void OSCILLATOR_Init (void);
void PORT_Init (void);
//-----------------------------------------------------------------------------
// SiLabs_Startup() Routine
// ----------------------------------------------------------------------------
// This function is called immediately after reset, before the initialization
// code is run in SILABS_STARTUP.A51 (which runs before main() ). This is a
// useful place to disable the watchdog timer, which is enable by default
// and may trigger before main() in some instances.
//-----------------------------------------------------------------------------
void SiLabs_Startup (void)
{
   PCA0MD = 0x00;                      // Disable watchdog timer
}

//-----------------------------------------------------------------------------
// main() Routine
//-----------------------------------------------------------------------------

void main (void)
{
  uint16_t LOOP;
  uint16_t LOOP_max =65000;
   PORT_Init ();                       // Initialize crossbar and GPIO
   OSCILLATOR_Init ();                 // Initialize oscillator
   LOOP =0;
   IE_EA = 0;
   if(FLASH_ByteRead(0x5FFE)== 0x12)  //olhe o datasheet para escolher um local de memoria existente,se for inexistente ele pode travar.
         {
            LED_gravado=0; //liga led indicando que posicão da memoria foi gravada
         }
     else
         {
            LED_gravado=1; //desliga led
            FLASH_PageErase(0x5FFE);//apaga bloco de 512bytes por vez (setando tudo para 1)
            // escreve valor na mmemoria - sempre deve apagar a memoria pois ele so escreve zero
            //é uma limitação do hardware.
            FLASH_ByteWrite(0x5FFE, 0x12); //grava 0X12H  na memoria
            //na proxima vez que ligar já busca na memoria este valor
         }

   while (1)
   {//pisca led
     LOOP++;
         if(LOOP>LOOP_max)
         {
             LED_pisca=0; //liga led (pois esta ligado ao vcc)
              LOOP=0;
         }
         if(LOOP ==(LOOP_max/2))
             {
             LED_pisca=1; //desliga led
             }
   }
}

//-----------------------------------------------------------------------------
// OSCILLATOR_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This function initializes the system clock to use the internal oscillator
// at 12 MHz.
//
//-----------------------------------------------------------------------------
void OSCILLATOR_Init (void)
{
   OSCICN = 0x83;                      // Set internal oscillator to run  (desabilitou osc interno)
                                       // at its maximum frequency(pois setou os 2 ultimos bit)
   CLKSEL = 0x00;                      // Select the internal osc. as (SYSCLK/4)
                                       // the SYSCLK source
}

//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters   : None
//
// This function configures the crossbar and GPIO ports.
//
// P0.0   digital   open-drain     PCA0 CEX0
// P0.1   digital   push-pull
//
//-----------------------------------------------------------------------------
void PORT_Init (void)
{
      OSCICN  = 0X81;                     // IHFOsc Enable, OpcDiv:3MHz
      CLKMUL  = 0XC0;                     // talvez nem precise neste microcontrolador -> habilita  e inicializa pll
      CLKSEL  = 0X03;                     // SYSCLK derived from the Internal High-Frequency Oscillator.
      PFE0CN  = 0X20;                     //(para High Speed) Prefetch Engine Control,otimiza tempo de execução lendo 2 bytes de execução por vez
      /* FLSCL.FOSE(7) = 0 for < 10MHz and 1 for SYSCLK > 10MHz
      FLSCL.FLRT(4) = 0 for < 25MHz and 1 for SYSCLK > 25MHz */
      FLSCL   = 0x90;
      CKCON   = 0x30;
      SPI0CN  = 0x02;                     //Select Mode 3-Wire pra liberar pino NSS

      P0MDIN  = 0xFF;                     //  are digital
      P1MDIN  = 0xFF;                     //  are digital
      P2MDIN  = 0xFF;                     //  are digital
      P3MDIN  = 0xFF;                     //  are digital
      P4MDIN  = 0xFF;                     //  are digital

      P0MDOUT = 0x10;                     // enable Switches as open-drain
      P1MDOUT = 0x00;                     // enable Switches as open-drain
      P2MDOUT = 0x00;                     // enable Switches as open-drain
      P3MDOUT = 0x00;                     // enable Switches as open-drain
      P4MDOUT = 0x04;                     // enable Switches as open-drain

      P0SKIP = 0xCF;                      // TXeRX precisa do Skip pra funcionar
      P1SKIP = 0xFF;
      P2SKIP = 0xFF;
      P3SKIP = 0xCF;

      XBR0   = 0x01;                     // CP1AE,CP1E,CP0AE,CP0E,SYSCKE,SMB0E,SPI0E,(UART0E)
      XBR2   = 0x00;                     // RESRV,RSRV,RESRV,RESRV,RESRV,RESRV,SMB1E, UART1E
      XBR1   = 0xC2;                     // WEAKPUD,(XBARE),T1E,T0E,ECIE,(PCA0ME):000:Nenhum,001:CEX0,010:CEX0eCEX1,...
      // VDM0CN -> monitor de tensão de reset
      VDM0CN = 0x80;                     //Colocado porque senão da problema na gravacao da flash(já estava isso)

       P4 = 0        ;  //portas de p4 desligadas
}




//-----------------------------------------------------------------------------
// End Of File

formatado por http://hilite.me/  14/10/2021