12.3.2. Пример программного кода

(Руководство разработчика по микроконтроллерам семейства HCS08)

В Примере 12.1 мы рассмотрим программный код, который позволяет записать и стереть собственные данные во флэш-памяти. Такие действия бывают необходимы, если пользователь какого-либо устройства производит дополнительную настройку этого устройства и желает, чтобы выбранная конфигурация сохранилась после отключения питания.

Ранее нами было отмечено, что МК семейства HCS08 не позволяют выполнять операции стирания и программирования флэш-памяти, исполняя программу управления этими режимами также из флэш-памяти. Обязательно следует сначала переписать программный код, отвечающий за операции стирания и программирования, в оперативную память, а затем запустить этот код на исполнение. В процессе стирания и программирования к модулю флэш-памяти будет приложено повышенное напряжение. Однако это не приведет к срыву работы программы, поскольку в данный момент времени она будет исполняться из ОЗУ.

Компания Freescale разработала набор утилит на ассемблере, который упрощает создание собственного программного кода для программирования флэш-памяти под управлением рабочей программы устройства. Эти утилиты размещены в файле doonstack.asm. Этот файл следует включить в проект, как показано на Рис.12.3.

Рис.12.3. Окно проекта с включенным файлом doonstack.asm.

Содержимое файла doonstack.asm представлено ниже. Приведен оригинальный текст используемого программного кода, поэтому комментарии переводу не подлежат.

;**************************************************************
;*Thisstationeryismeanttoserveastheframeworkfora*
;*userapplication.Foramorecomprehensiveprogramthat*
;*demonstratesthemoreadvancedfunctionalityofthis*
;*processor,pleaseseethedemonstrationapplications*
;*locatedintheexamplessubdirectoryofthe*
;*MetrowerksCodewarriorfortheHC08Programdirectory*
;**************************************************************
;exportsymbols
XDEFDoOnStack
XDEFFlashErase
XDEFFlashProg
;weuseexport'Entry'assymbol.Thisallowsusto
;reference'Entry'eitherinthelinker.prmfile
;orfromC/C++lateron

;includederivativespecificmacros
Include'MC9S08GB60.inc'

Две следующие строки следует раскомментировать и назначить желаемые значения.

;mPageEraseequ$40
;mByteProgequ$20
mFACCERRequ$10
mFPVIOLequ$20
mFCBEFequ$80
;variable/datasection
MY_ZEROPAGE:SECTIONSHORT
;Inserthereyourdatadefinition.Fordemonstration,temp_byteisused.
;temp_byteds.b1
;codesection
MyCode:SECTION
;**************************************************************
;thisassemblyroutineiscalledtheC/C++application
DoOnStack:pshx
pshh;savepointertoflash
psha;savecommandonstack
ldhx#SpSubEnd;pointatlastbytetomovetostack;
SpMoveLoop:lda,x;readfromflash
psha;moveontostack
aix#-1;nextbytetomove
cphx#SpSub-1;pastend?
bneSpMoveLoop;looptillwholesubonstack
tsx;pointtosubonstack
tpa;moveCCRtoAfortesting
and#$08;checktheImask
bneI_set;skipifIalreadyset
sei;blockinterruptswhileFLASHbusy
ldaSpSubSize+6,sp;preloaddataforcommand
jsr,x;executethesubonthestack
cli;oktoclearImasknow
braI_cont;continuetostackde-allocation
I_set:ldaSpSubSize+6,sp;preloaddataforcommand
jsr,x;executethesubonthestack
I_cont:ais#SpSubSize+3;deallocatesubbody+H:X+command
;H:XflashpointerOKfromSpSub
lsla;A=00&Z=1unlessPVIOLorACCERR
rts;toflashwhereDoOnStackwascalled
;**************************************************************
SpSub:ldhxLOW(SpSubSize+4),sp;getflashaddressfromstack
sta0,x;writetoflash;latchaddranddata
ldaSpSubSize+3,sp;getflashcommand
staFCMD;writetheflashcommand
lda#mFCBEF;masktoinitiatecommand
staFSTAT;[pwpp]registercommand
nop;[p]wantmin4~fromwcycletor
ChkDone:ldaFSTAT;[prpp]soFCCFisvalid
lsla;FCCFnowinMSB
bplChkDone;loopifFCCF=0
SpSubEnd:rts;backintoDoOnStackinflash
SpSubSize:equ(*-SpSub)
;**************************************************************
FlashErase:psha;adjustspforDoOnStackentry
lda#(mFPVIOL+mFACCERR);mask
staFSTAT;abortanycommandandclearerrors
lda#mPageErase;maskpatternforpageerasecommand
bsrDoOnStack;finishcommandfromstack-basedsub
ais#1;deallocatedatalocationfromstack
rts
;**************************************************************
FlashProg:psha;temporarilysaveentrydata
lda#(mFPVIOL+mFACCERR);mask
staFSTAT;abortanycommandandclearerrors
lda#mByteProg;maskpatternforbyteprogcommand
bsrDoOnStack;executeprogcodefromstackRAM
ais#1;deallocatedatalocationfromstack
rts
;**************************************************************

Также в тексте программного кода на С необходимо директивой #include подключить файл doonstack.h, текст которого представлен ниже.

/**********************************************************************/
/**/
/*ProjectName:doonstack.h*/
/*Lastmodified:04/11/2004*/
/*By:r60817*/
/**/
/**/
/**********************************************************************/
/**/
/*Description:MC9S08GB60_FLASH_DOONSTACK-demo*/
/**/
/**/
/*Documentation:MC9S08GB60/DRev.2.2*/
/*HCS08RMv1/DRev.1(4.8FLASHApplicationExamples)*/
/**/
/*ThissoftwareisclassifiedasEngineeringSampleSoftware.*/
/**/
/**********************************************************************/
/**/
/*ServicesperformedbyFREESCALEinthismatterareperformedASIS*/
/*andwithoutanywarranty.CUSTOMERretainsthefinaldecision*/
/*relativetothetotaldesignandfunctionalityoftheendproduct.*/
/*FREESCALEneitherguaranteesnorwillbeheldliablebyCUSTOMER*/
/*forthesuccessofthisproject.FREESCALEDISCLAIMSALL*/
/*WARRANTIES,EXPRESSED,IMPLIEDORSTATUTORYINCLUDING,BUTNOT*/
/*LIMITEDTO,IMPLIEDWARRANTYOFMERCHANTABILITYORFITNESSFORA*/
/*PARTICULARPURPOSEONANYHARDWARE,SOFTWAREOREADVISESUPPLIED*/
/*TOTHEPROJECTBYFREESCALE,ANDORNAYPRODUCTRESULTINGFROM*/
/*FREESCALESERVICES.INNOEVENTSHALLFREESCALEBELIABLEFOR*/
/*INCIDENTALORCONSEQUENTIALDAMAGESARISINGOUTOFTHISAGREEMENT.*/
/**/
/*CUSTOMERagreestoholdFREESCALEharmlessagainstanyandall*/
/*claimsdemandsoractionsbyanyoneonaccountofanydamage,or*/
/*injury,whethercommercial,contractual,ortortuous,rising*/
/*directlyorindirectlyasaresultoftheadviseorassistance*/
/*suppliedCUSTOMERinconnectionwithproduct,servicesorgoods*/
/*suppliedunderthisAgreement.*/
/**/
/**********************************************************************/
/*
-thisfileAPIbetweenmain.canddoonstack.asm
*/
#ifndef_doonstack
#define_doonstack
#ifdef__cplusplus
extern"C"{/*ourassemblyfunctionshaveCcallingconvention*/
#endif
voidDoOnStack(void);/*prototypeforDoOnStackroutine*/
voidFlashErase(unsignedchar*);/*prototypeforFlashEraseroutine*/
/*PageErasecommand*/
voidFlashProg(unsignedchar*,unsignedchar);/*prototypeforFlashProgroutine*/
/*ByteProgramcommand*/
#ifdef__cplusplus
}
#endif

#endif/*_doonstack*/
/**********************************************************************/

В нашем примере для записи энергонезависимых данных резервируется блок в 512 байт. Такой размер блока выбран потому, что это минимально разрешенный для стирания объем ячеек флэш-памяти в микроконтроллере MC9S08QG8. Выбранный блок будет располагаться в начале адресного пространства резидентной флэш-памяти МК: от 0xE000 до 0xE1FF. Программный код будет начинаться с адреса 0xE200 и может занимать адресное пространство вплоть до 0xFFFF.

Для того чтобы реализовать задуманное размещение кодов данных и программы, следует изменить установки компоновщика в файле project.prm.

В стандартном проекте была запись:

SEGMENTS/*HereallRAM/ROMareasofthedevicearelisted*/
ROM=READ_ONLY0xE000TO0xFFAD;

Ее следует заменить:

SEGMENTS/*HereallRAM/ROMareasofthedevicearelisted*/
ROM=READ_ONLY0xE200TO0xFFAD;

В нашем примере также использован режим защиты от записи области программного кода, т.е. адресного пространства от 0xF200 до 0xFFFF. На Рис.12.4 показан процесс формирования кода для регистра FPROT, который обеспечивает защиту адресного пространства 0xF200...0xFFFF от случайного стирания/записи. Семь старших битов последнего адреса 0xF1FF незащищенного адресного пространства должны быть записаны в регистр FPROT.

АдресA15A14A13A12A11A10A9A8A7A6A5A4A3A2A1A0
0xE1FF1110000111111111
FPROTFPS7FPS6FPS5FPS4FPS3FPS2FPS1FPDIS
0xE011100000

Рис.12.4. Формирование записи кода зашиты для регистра FPROT.

Пример 12.1. Операции с энергонезависимыми данными во флэш-памяти

//ДемонстрационнаяплатаDEMO9S08QG8
//стирание/запись/чтениерезидентнойфлэш-памяти
#include/*forEnableInterruptsmacro*/
#include"derivative.h"/*includeperipheraldeclarations*/
#include"hcs08.h"/*Этонашфайлсобъявлениями!*/
#include"doonstack.h"
#defineBUSCLK8000000
#definevFCDIV(BUSCLK/200000-1)
charfdata,operation;
unsignedintfaddress;
//Назначаетсяобластьзащищенныхотзаписиадресов:от0xE200до0xFFFF
constbyteNVPROT_INIT@0x0000FFBD=0xE0;
//ИнициализацияМК
voidmcu_init(void)
{
SOPT1=bBKGDPE;//РазрешениефункциилинииотладкиBKGD
ICSSC=NV_FTRIM;//ЗаписатьзначениеподстройкиFTRIM
ICSTRM=NV_ICSTRM;//ЗаписатьзначениеподстройкиTRIM
ICSC2=0;//ICSOUT=DCOOUT/1
//BUSCLK=8МГц
FCDIV=vFCDIV;//ЗаписатьзначениекодаделителядлячастотыFCLK
//(FCLK=200кГц)
}
#pragmainline
//Функциячтениябайтаизячейкипамятисзаданнымадресом
charflash_read(unsignedintaddress)
{
unsignedchar*pointer;
pointer=(char*)address;
return(*pointer);
}
//Функциязаписибайтавячейкупамятисзаданнымадресом
charflash_write(unsignedintaddress,unsignedchardata)
{
unsignedchar*pointer;
pointer=(char*)address;
FlashProg(pointer,data);//Вызовфункциипрограммированияфлэш-памяти
if(FSTAT_FACCERR)data=1;elsedata=0;
if(FSTAT_FPVIOL)data|=2;
return(data);
}
//Функциястираниязаданногоблокавобластифлэш-памяти
unsignedcharflash_sector_erase(unsignedintaddress)
{
unsignedchar*pointer,res;
pointer=(char*)address;
FlashErase(pointer);
if(FSTAT_FACCERR)res=1;elseres=0;
if(FSTAT_FPVIOL)res|=2;
return(res);
}
voidmain(void)
{
mcu_init();
fdata=0;
faddress=0xE000;
operation=0;
while(1)
{
switch(operation)
{
case1://Стираниеблока
fdata=flash_sector_erase(faddress);
operation=0;
break;
case2://Записьбайта
fdata=flash_write(faddress,fdata);
operation=0;
break;
case3://Чтениебайта
fdata=flash_read(faddress);
operation=0;
break;
}
}
}

Рассмотрим методику тестирования программного кода Примера 12.1. Для этого в окно отладчика Data добавим три переменные: faddress, fdata, operation. Также установим для окна режим периодического обновления, например, через 200мс.

Перед запуском на исполнение программного кода запишите в переменную faddress адрес для записи, а в переменную fdata — байт данных для записи. Далее в переменную operation запишите код 0x02. После запуска программного кода примера начнется запись байта данных в выбранную ячейку флэш-памяти. Обратите внимание, что выбранная ячейка должна находиться в стертом состоянии, т.е. в ней должен быть код 0xFF.

Для того чтобы стереть блок памяти 0xE00...0xE1FF, запишите в faddress любой адрес из указанного диапазона и установите переменную operation в 1. Далее запустите код снова на исполнение.

Прочитать данные из флэш-памяти тоже просто. Для этого запишите в переменную faddress код адреса, в переменную operation — код 0x03. Содержимое выбранной ячейки флэш-памяти отобразится в переменной fdata после исполнения программного кода.

Обратите внимание, что функции flash_write() и flash_sector_erase() возвращают переменную типа chare с кодом ошибки при выполнении действия: 0 — не было ошибки, 0x02 — была ошибка доступа, 0x04 — была попытка стирания/записи защищенного адресного пространства. Обе упомянутые функции требуют для своего исполнения около 35 байт стековой памяти. Если реальная область стека окажется меньше, то произойдет фатальная ошибка. Восстановить работоспособность программы можно будет только сбросом МК.

Для того чтобы посмотреть в отладчике изменения флэш-памяти, необходимо внести некоторые изменения в конфигурацию отладчика. Следуя установкам по умолчанию, отладчик считывает область флэш-памяти МК только один раз после запуска сессии отладки. Для изменения конфигурации выберите в главном меню отладчика опцию MultilinkCyclonPro > Debug Memory Map. Откроется окно, показанное на Рис.12.5,а. Выберите в этом окне memory block 3 и нажмите кнопку Modify/Details. В новом окне, показанном на Рис.12.5,б, выберите отмеченную опцию. Она позволит отладчику периодически обновлять окно памяти.

Рис.12.5. Изменение конфигурации отладчика для периодического обновления содержимого окна памяти.


Электронные компоненты Freescale >>>
Подробнее о компании Freescale >>>