Operace nad flash prováděné za běhu aplikace v mikrokontroleru MC9S08x

Několik funkcí v C a v Asembleru do předmětu Mikroprocesorové a vestavěné systémy, které implementují některé operace prováděné s pamětí flash mikrokontrolérů rodiny MC9S08 firmy Freescale. Na požádání k nim můžu zaslat i česky psané vývojové diagramy.

POZN.: Všechny uvedené funkce předpokládají na začátku programu správně inicializovanou paměť Flash nastavením správné frekvence hodin paměti v registru FCDIV.
Funkce nejsou řádně otestované přímo na kontroléru a kód uvedený v této zprávě se může lišit od kódu v odevzdaných zdrojových souborech, protože jej často bylo nutno krátit či pro názornost jinak upravit.

Ověření prázdnosti (BlankCheck)

Funkce vykoná příkaz ověření prázdnosti nad pamětí Flash a nastaví příslušný bit stavového registru Flash jako výsledek. Hodnota tohoto bitu je předána volajícímu programu jako návratová hodnota a jedná se tak o jedinou funkci s návratovou hodnotou jinou než udávající, zda došlo k chybě či nikoliv.
Funkce nemá žádné parametry a žádné specifické počáteční podmínky pro své volání. Při operaci se sice zapisuje do bufferu paměti, ale adresa ani data nemají vliv na průběh operace.
Návratová hodnota je buď paměť je prázdná nebo paměť není prázdná nebo chyba. V jazyce symbolických instrukcí je návratová hodnota předána volajícímu programu skrze střadač.

byte
BlankCheck(void)
{
  if (FSTAT_FACCERR)
      FSTAT_FACCERR = 1;
  while (!FSTAT_FCBEF);
  *((word *)0xDD00) = 0;
  FCMD = mBlank;
  FSTAT_FCBEF = 1;
  _asm NOP; // 4x
  if (FSTAT_FACCERR || FSTAT_FPVIOL)
      return FAILURE;
  while (!FSTAT_FCCF);
  return FSTAT_FBLANK;
}

blank_check:
    lda    #(mFSTAT_FPVIOL+mFSTAT_FACCERR)
    sta    FSTAT
    ldhx   #$AFBE
    sta    0,x
    lda    #mBlank
    sta    FCMD
    lda    #mFSTAT_FCBEF
    sta    FSTAT
    nop
    brset  FSTAT_FACCERR, FSTAT, error
    brset  FSTAT_FPVIOL,  FSTAT, error
done:
    lda    FSTAT
    lsla
    bpl    done
error:
    RTS

Programování bytu (ByteProgram)

Funkce zapisující právě jeden byte do paměti Flash vykonáním specifického příkazu. Zápis je možný pouze do nechráněné části paměti. Také není dovoleno přepsat jakýkoliv byte paměti, aniž by zápis nepředcházelo jeho smazání k tomu určenou operací.
První ze dvou parametrů udává adresu ve Flash, kam se mají data uložit, zatímco druhým parametrem jsou právě tato data.
V asemblerovské verzi rutiny je adresa místa v paměti předána v registru H:X. Byte dat určený k zápisu je předán přes zásobník.
Návratovou hodnotou funkce je úspěšnost operace zápisu.

byte
ByteProgram(byte*addr,byte data)
{
  if (FSTAT_FACCERR
    FSTAT_FACCERR = 1;
  while (!FSTAT_FCBEF);
  *addr = data;
  FCMD = mByteProg;
  FSTAT = 0x80;
  _asm NOP; // 4x
  if (FSTAT_FACCERR || FSTAT_FPVIOL)
    return FAILURE;
  while (!FSTAT_FCCF);
  return SUCCESS;
}

byte_program:
    lda    #(mFSTAT_FPVIOL+mFSTAT_FACCERR)
    sta    FSTAT
    lda    3,SP
    sta    ,X
    lda    #mByteProg
    sta    FCMD
    lda    #mFSTAT_FCBEF
    sta    FSTAT
    nop
    brset  FSTAT_FACCERR, FSTAT, error
    brset  FSTAT_FPVIOL,  FSTAT, error
done:
    lda    FSTAT
    lsla
    bpl    done
error:
    RTS

Smazání stránky (PageErase)

U kontrolérů řady MC9S08 je nejmenší možná jednotka pro operaci mazání Flash paměti jedna stránka, tedy 512 bytů. Je-li požadováno smazání jednoho bytu, není jiná možnost než smazat celou stránku, ve které se tento byte nachází. Funkce PageErase vymaže obsah stránky identifikované adresou jakéhokoli bytu, který obsahuje. Není možno smazat stránku v chráněném bloku paměti.
Parametrem funkce je adresa libovolné slabiky nacházející se ve stránce, která je určena ke smazání.
V jazyce symbolických instrukcí je adresa předána uložením do registru H:X před rozvětvením do rutiny.
Návratová hodnota udává úspěšnost operace mazání stránky.

byte
PageErase(byte*addr)
{
  if (FSTAT_FACCERR
    FSTAT_FACCERR = 1;
  while (!FSTAT_FCBEF);
  *addr = 0;
  FCMD = mPageErase;
  FSTAT_FCBEF = 1;
  _asm NOP; // 4x
  if (FSTAT_FACCERR || FSTAT_FPVIOL)
    return FAILURE;
  while (!FSTAT_FCCF);
  return SUCCESS;
}

page_erase:
    lda    #(mFSTAT_FPVIOL+mFSTAT_FACCERR)
    sta    FSTAT
    sta    0,X
    clr    ,X
    lda    #mPageErase
    sta    FCMD
    lda    #mFSTAT_FCBEF
    sta    FSTAT
    nop
    brset  FSTAT_FACCERR, FSTAT, error
    brset  FSTAT_FPVIOL,  FSTAT, error
done:
    lda    FSTAT
    lsla
    bpl    done
error:
    RTS

Smazání celé FLASH (MassErase)

Operace smazání celé paměti Flash.
Nejsou specifikovány žádné vstupní parametry. Součástí operace je sice také zápis do paměti, ale podobně jako u ověření prázdnosti tento zápis nijak neovlivní její obsah ani průběh operace.
Funkce vrací úspěšnost operace jako návratovou hodnotu.

byte
MassErase(void)
{
  if (FSTAT_FACCERR
    FSTAT_FACCERR = 1;
  while (!FSTAT_FCBEF);
  *((word*)0xDD00) = 0;
  FCMD = mMassErase;
  FSTAT_FCBEF = 1;
  _asm NOP; // 4x
  if (FSTAT_FACCERR || FSTAT_FPVIOL)
    return FAILURE;
  while (!FSTAT_FCCF);
  return SUCCESS;
}

mass_erase:
    lda #(mFSTAT_FPVIOL+mFSTAT_FACCERR)
    sta    FSTAT
    ldhx   #$AFBE
    sta    0,X
    lda    #mMassErase
    sta    FCMD
    lda    #mFSTAT_FCBEF
    sta    FSTAT
    nop
    brset  FSTAT_FACCERR, FSTAT, error
    brset  FSTAT_FPVIOL,  FSTAT, error
done:
    lda    FSTAT
    lsla
    bpl    done
error:
    RTS

Programování v burst režimu (BurstProgram)

Obdobně jako u ByteProgram se jedná o funkci zprostředkující zápis do paměti Flash, avšak s tím rozdílem, že je možno zapsat více bytů během jednoho volání. Zapisovaná data musí ležet v paměti za sebou. Funkce je složitější o smyčku, ve které jsou zapisovány jednotlivé byty tak, jak jdou za sebou. Počet iterací je dán parametrem length.
Funkce má tři parametry a všechny jsou předány přes zásobník (i v asembleru). Těmito parametry jsou počáteční adresa zdroje dat, počáteční adresa místa paměti Flash, kam se data mají uložit a počet zapisovaných bytů.
Návratová hodnota je stejná jako u funkce zápisu jednoho bytu, tedy úspěch či případný neúspěch operace.

byte
BurstProgram(byte*addr,
             byte*data,
             word length)
{
  if (FSTAT_FACCERR
    FSTAT_FACCERR = 1;
  do {
    while (!FSTAT_FCBEF);
    *addr = *data++;
    FCMD = mBurstProg;
    FSTAT_FCBEF = 1;
    _asm NOP; // 4x
    if (FSTAT_FACCERR||FSTAT_FPVIOL)
      return FAILURE;
    addr++;
  } while (--length);
  while (!FSTAT_FCCF);
  return SUCCESS;
}

burst_program:
    lda    #(mFSTAT_FPVIOL+mFSTAT_FACCERR)
    sta    FSTAT
loop:
    lda    FSTAT
    and    #mFSTAT_FCBEF
    beq    loop
    ldhx   5,SP
    lda    ,X
    aix    #1
    sthx   5,SP
    ldhx   3,SP
    lda    ,X
    aix    #1
    sthx   3,SP
    lda    #mBurstProg
    sta    FCMD
    lda    #mFSTAT_FCBEF
    sta    FSTAT
    nop
    brset  FSTAT_FACCERR, FSTAT, error
    brset  FSTAT_FPVIOL,  FSTAT, error
    lda    7,SP
    deca
    sta    7,SP
    cmp    #0
    bne    loop
done:
    lda    FSTAT
    lsla
    bpl    done
error:
    RTS

Vypnutí zabezpečení paměti (DisengageSecurity)

Paměť Flash u kontrolérů řady MC9S08 má svou vlastní ochranu před neoprávněným přepsáním. Tato ochrana se dá vypnout pouze buď v režimu background debug nebo za běžného chodu aplikace zadáním bezpečnostního kódu. Jedná se o osmi-bytový bezpečnostní kód uložený programátorem na jistém místě v paměti. Umožňuje-li aplikace uživateli vypínat ochranu paměti Flash, musí uživatel zadat bezpečnostní kód přes nějaké vstupní rozhraní. V této implementaci funkce vypnutí ochrany je použito rozhraní SCI, které po zavolání funkce očekává jednotlivé byty bezpečnostního kódu a pokud je všech osm slabik kódu správně zadáno, je zabezpečení vypnuto až do následujícího resetu.
Funkce nepřebírá žádné parametry, ale má specifické podmínky použití. Pokud není nastaven bit KEYEN registru FOPT paměti Flash, nemůže být zabezpečení vypnuto. Dále musí být umožněn uživatelský vstup přes rozhraní SCI.
Funkce nic nevrací, proto jediným způsobem, jak programově poznat, zda je ochrana vypnuta, je kontrola bitů SEC01:SEC00 registru NVOPT, které jsou vypnutím zabezpečení automaticky nastaveny na 1:0.

void
DisengageSecurity(void) {
  if (FOPT_KEYEN == 0) return;
  _asm {
    mov  #$00, SCI1BDH
    mov  #$34, SCI1BDL
    mov  #$04, SCI1C2
  }
  FCNFG_KEYACC = 0x1;
  while (SCI1S1_RDRF != 1);
  *(byte *)0xFFB0 = SDI1D;
 
  // . . . 0xFFB1 – 0xFFB6 . . .
 
  while (SCI1S1_RDRF != 1);
  *(byte *)0xFFB7 = SDI1D;
  FCNFG_KEYACC = 0x0;
}

disengage_security:
  lda   NVOPT
  and   #mNVOPT_KEYEN
  beq   error
  mov   #$00, SCI1BDH
  mov   #$34, SCI1BDL
  mov   #$04, SCI1C2
 
  bset  FCNFG_KEYACC,FCNFG
  brclr 5,SCI1S1,*
  lda   SCI1D
  sta   NVBACKKEY0
; . . .  NVBACKKEY1 -  NVBACKKEY6
  brclr 5,SCI1S1,*
  lda   SCI1D
  sta   NVBACKKEY7
  bclr  FCNFG_KEYACC,FCNFG
  RTS

Ochrana bloků paměti (FlashBlockProtection)

Programátor může zabezpečit určitou část paměti Flash, avšak vždy se jedná o část paměti od určité, programátorem zadané adresy, po konec adresového prostoru (adresa FFFF). Dá se tedy určit pouze začátek chráněného bloku paměti a to adresou. Funkce tuto adresu vezme, upraví na adresu posledního nechráněného bytu, z ní vezme nejvyšších osm bitů, přičemž jejich nejnižší bit vynuluje a takto upravenou adresu uloží do registru FPROT, čímž se ochrana aktivuje.
Jako parametr do funkce vstupuje adresa začátku chráněného bloku paměti Flash.
Funkce nemá žádnou návratovou hodnotu.

Kód v jazyce C
void
FlashBlockProtection(byte*addr) {
  byte tmp;
  --addr;
  tmp=(byte)(((word)addr&0xFE00)>>8);
  FPROT = tmp;
}

flash_block_protection:
   ;address is in H:X register
   decx
   pshh
   pula
   and   #%11111110
   sta   FPROT
   RTS