Пятница, 13 мая 2011 23:32

Flash память программ МК PIC18XXXX

Written by
Rate this item
(0 votes)

Все микроконтроллеры семейства  PIC18XXXX  имеют встроенную  энергонезависимую Flash память программ, доступную для чтения, записи и стирания. В отличии от  EEPROM памяти данных, память программ побайтно можно только считать. Запись можно производить только блочно, по 8 байт т.е. записывать нужно не менее 8 байт данных.

 

А операция стирания выполняется блоками по 64 байта.

На время выполнения процесса записи/стирания памяти программ, выполнение текущей программы приостанавливается, пока не закончится цикл записи/стирания (приблизительно 18 мс., выполняется от отдельного таймера). Что конечно вызывает определенные трудности при написание программ, где есть необходимость в точном временном интервале. Вообще в пользовательских программах процесс   записи/стирания   Flash память программ  довольно редкое явление. Очень мало программистов кто этим пользуется и не только из-за приблизительного времени записи/стирания,  но и по количественному ограничению самих процессов до 100 000 циклов. Что не скажешь про операцию чтения Flash память программ, которая наоборот очень часто используется программистами (необходимые данные (шрифт, текстовая информация и др. данные) записанные в Flash память программ на стадии "прошивки" впоследствии передаются при помощи специальной операции  (команды) в память данных).


Чтение памяти программ.

 Для чтения содержимого памяти программ используется инструкция (команда) TBLRD. Она имеет несколько разновидностей, которые мы сейчас рассмотрим:

  • TBLRD*  - происходит чтение  байта таблицы, указанного по адресу регистра TBLPTR (TBLPTRU:TBLPTRH:TBLPTRL), адрес после выполнения не меняется, т.е. при повторном выполнении команды (при условии  адрес TBLPTR программно не менялся) получим те же данные.
  • TBLRD*+ - происходит чтение  байта таблицы, указанного по адресу регистра TBLPTR (TBLPTRU:TBLPTRH:TBLPTRL),после чтения таблицы адрес увеличивается на 1 (инкремент), т.е. при повторном выполнении команды получим значение следующего байта в таблице.
  • TBLRD*- - происходит чтение  байта таблицы, указанного по адресу регистра TBLPTR (TBLPTRU:TBLPTRH:TBLPTRL),после чтения таблицы адрес уменьшается на 1 (декремент), т.е. при повторном выполнении команды получим значение предыдущего  байта в таблице.
  • TBLRD+* - происходит чтение  байта таблицы, указанного по адресу регистра TBLPTR (TBLPTRU:TBLPTRH:TBLPTRL), адрес увеличивается на 1 (преинкремент) перед выполнением команды.

  Результат выполнения команды будет находиться  в регистре TABLAT, который является "посредником" между 16-разрядной памятью программ и 8-разрядной памятью данных. Для доступа к памяти используется указатель TBLPTR  (TBLPTRU:TBLPTRH:TBLPTRL-21 битный указатель), с помощью которого можно обратиться к любому байту адресного пространства памяти программ.

Для удобства можно  указывать метки (названия таблиц ) таблицы данных в памяти программ, воспользовавшись  операторами  low,  high,  upper, в принципе от последнего, (если объем памяти программ не превышает 64 КБ) можно и отказаться, просто сбросив TBLPTRU в "0".

Рассмотрим пример:

У нас есть таблица данных в области памяти программ под  меткой "TEST" и нам необходимо ее прочитать . Для этого задаем указатель TBLPTR:

            clrf           TBLPTRU ; Cбрасываем верхний байт
            movlw       high (TEST); =Задание адреса "TEST"
            movwf          TBLPTRH ;  старшего байта=
            movlw        low (TEST); =Задание адреса "TEST"
            movwf          TBLPTRL ;  младшего байта=

           
Естественно,  если у вас другое название таблиц(и), вместо TEST необходимо написать их названия (метки).

Далее в зависимости от задачи выполняем  подпрограммы (ПП) чтения, как показано здесь...

Важно:

Если таблица данных состоит из нескольких строк, то  количество байт в каждой строке, кроме последней строки, должны быть четными.  Это объясняется тем, что  память программ 16-разрядная (2 байта), а  строки в MPLAB  всегда начинается соответственно с четного адреса. Прочитав младший байт, мы перескочили старший (нечетный). Но во время инкремента (декремента) этот байт будет считываться, что приведет к ошибке. Надеюсь, понятно объяснил....

Если что не понятно, то можно посмотреть видеоурок по теме.....

Переходим к рассмотрению записи в память программ.


Запись в память программ.

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

  • TBLWT*   - происходит запись в промежуточный регистр  , указанного по адресу регистра С (TBLPTRL, трех последних бит), адрес после выполнения не меняется,.
  • TBLWT*+ - происходит запись в промежуточный регистр  , указанного по адресу регистра С (TBLPTRL, трех последних бит),после чтения таблицы адрес увеличивается на 1 (инкремент).
  • TBLWT*- - происходит запись в промежуточный регистр  , указанного по адресу регистра С (TBLPTRL, трех последних бит), после чтения таблицы адрес уменьшается на 1 (декремент).
  • TBLWT+* - происходит запись в промежуточный регистр  , указанного по адресу регистра С (TBLPTRL, трех последних бит), адрес увеличивается на 1 (преинкремент) перед выполнением команды.

По выполнению команд TBLWT содержимое регистра TABLAT переносится в промежуточный регистр. Три младших разряда регистра (указателя)  TBLPTR определяют в какой (из восьми), промежуточный регистр будет записано значение. По заполнению всех восьми регистров можно начать процесс записи.

В операции стирания и записи необходимо задействовать два регистра специального назначения:

  • EECON1 - регистр управления для доступа к памяти.
  • EECON2 - не физический регистр.

Рекомендованная последовательность действий для записи блока Flash памяти программ:

  1.  Прочитать 64 байта блока в память данных.
  2. Обновить необходимые регистры с информацией из памяти программ.
  3.  Загрузить в указатель адрес стираемого блока Flash памяти программ.
  4. Выполнить процедуру стирания.
  5. Загрузить в указатель адрес первого байта.
  6. Записать первые 8 байт с автоинкрементом указателя в промежуточные регистры.
  7. Установить  бит EEPGD для  выбора Flash памяти  программ;сбросить бит CFGS  для обращения к памяти программ;установить  бит WREN для      разрешения записи.
  8. Выключить прерывания.
  9. Записать 55h в регистр EECON2.
  10. Записать AAh в регистр EECON2.
  11. Установить бит WR для инициализации цикла записи блока.
  12. CPU остановит выполнение программы до завершения цикла записи (ориентировочно 2мс).
  13. Выполнить команду NOP.
  14. Разрешить прерывания.
  15. Повторить шаги 6-14 семь раз для записи 64 байт.
  16. Выполнить контрольное чтение.

 

Из практики  можно сказать: " То что рекомендовано разработчиком лучше соблюдать".  Так или иначе, рекомендации возникают не на пустом месте...  По этому,  мы не будем отступать от "правил"? , но есть уточнения ...

Очень многие допускают ошибку, предполагая что раз написано 64 байта значит ни больше не меньше записывать нельзя. На самом деле это не так. Записывать можно разное количество блоков по 8 байт (хоть один). А вот процедура стирания действительно блоками по 64 байта.  Опять же не стоит путать табличную процедуру стирания  с процедурой стирания памяти программ. В табличной процедуре стираются только по 8 байт. Единственное "неудобство"  при табличной записи, необходимо следить за расположением таблицы, которая должна начинаться по адресу кратным  "8", т.е. 0,8,16,32 и т.д. до 248. 

 В примере, после записи необходимых данных,  выполним ПП проверки   записанных данных в память программ.

Хотя запись и производится блоками по 8 байт, при желании можно записать всего один байт, верней изменить один байт из восьми, и записать блок  обратно в память программ. . В этом примере   мы разберем таблицу из  64 байт, которую скопируем в память данных (ОЗУ) и  внесем изменения в значения некоторых регистров. После внесенных изменений запишем весь блок (64 байта) в память программ, соответственно в то же место.  А после записи проверим на ошибку. Кроме всего, мы еще получим возможность применения данной подпрограммы в своих приложениях, практически без изменения кода, за исключением некоторых переменных.

Очень важно не "наехать" и не стереть программный код (саму программу). На стадии разработки и отладки MBLAB выдаст вам ошибку, а вот в процессе эксплуатации" программы такое возможно. Для исключения такой ситуации желательно работать с метками,  особенно для новичков,  метки (названия) таблиц , необходимо располагать в конце программного кода, с учетом сказанного выше (кратность 0,8...) тем самым исключается возможность "наезда". Конечно,  это относится к изменению таблиц с данными и если есть необходимость в изменении программного кода, то здесь сам программист должен предусмотреть все возможные ситуации.

Приступим  к реализации :

В качестве примера рассмотрим ситуацию, когда необходимо переписать 15 байт в таблице данных "TEST". Естественно можно применить другое название таблицы и другое количество данных.

  • Первое действие чтение таблицы.(к примеру 64 байта.) (рассматривали в первой части)
  • Для упрощения примера сбросим 15 байт начиная с адреса  0107h (14) и 013Сh  (1 байт).

{showhide title="Смотреть код ПП" template="strong" changetitle="Свернуть код ПП" mousetitleistitle=true closeonclick=true titleasspan=true}

;-------------------------------------
; ПП предварительной записи в ОЗУ необходимых
; данных, с последующей записью в таблицу
; в примере изменяются значения 15 байтов.
;-------------------------------------
 ZAP_data  lfsr        FSR0,0x0107 ; Адрес первого регистра для изменения.
           movlw               .14 ; Всего 14 байт
           movwf              Temp ;
           clrf              INDF0 ; Очистить регистр
           movf           POSTINC0 ; Увеличиваем адрес FSR0L на 1
           decfsz             Temp ; Все очищены?
           bra                $-.6 ; нет,следующий
           lfsr        FSR0,0x013C ; Адрес  регистра для изменения.
           clrf              INDF0 ; Очистить регистр
           return                  ; Да, возврат из ПП
{/showhide}

 

В результате в ОЗУ у нас будут  вот такие данные:

 

alt

 

Т.е. мы изменили значения 15 регистров (сбросили в "0") и теперь  перезапишем в таблицу "TEST" блоками по 8 байт. Сначала "короткая" запись в промежуточные регистры (8 байт)..

;-----------------------------------
; Короткая запись  8 байт
;-----------------------------------
Counter_8  movlw                 8 ; Задание количества
           movwf           Counter ; байтов в одном блоке.
           nop
           movf         POSTINC0,0 ; =Копируем в W значение регистра.    
           movwf            TABLAT ;  в регистр TABLAT=
           tblwt*+                 ; Запись в защелку
           decfsz          Counter ; Все байты блока записаны?
           bra                $-.8 ; нет,следующий.

 

Далее  , записываем блок в память программ ( "длинная" запись).

 

;-----------------------------------
; Длинная запись
;-----------------------------------
           bsf        EECON1,EEPGD ; Работа с Flash-памятью программ.
           bcf         EECON1,CFGS ; Обращение к Flash памяти программ
           bsf         EECON1,WREN ; Разрешение записи.
           bcf          INTCON,GIE ; Запрет прерывания
           movlw              055h ; =
           movwf            EECON2 ; Обязательная
           movlw              0AAh ; процедура.
           movwf            EECON2 ; =
           bsf           EECON1,WR ; Инициализация цикла записи.
           nop                     ; 
           bsf          INTCON,GIE ; Разрешение прерывания.
           decfsz       Count_Blok ; Кол-во блоков по 8 байт
           call          Counter_8 ;  
           bcf         EECON1,WREN ; Запрет записи.
           return                  ; Возврат из прерывания

 

Для записи более одного блока (8 байт) повторяем процедуру записи столько раз, сколько необходимо записать блоков. В данном примере 8 блоков или 64 байта. После завершения записи проверяем значение соответствующего регистра памяти программ со значением в ОЗУ, тем самым проверяем на ошибку.  Если хоть один записанный в памяти программ  байт не совпадет с содержимым соответствующих регистров в ОЗУ,  установится  флаг ошибки (Flag,0).

{showhide title="Смотреть код ПП записи в память программ" template="strong" changetitle="Свернуть код ПП записи в память программ" mousetitleistitle=true closeonclick=true titleasspan=true}

           list          p=18F252 ; Используется микроконтроллер PIC18F252.
            #include   p18F252.inc ; Подключение INC-файла PIC18F252.
;***************************************************************************
; Конфигурирование.
;***************************************************************************
            CONFIG      OSC=XT     ; кварц.резонатор
            CONFIG      BOR=OFF    ; Сброс по снижению питания выключен
            CONFIG      WDT=OFF    ; WDT выключен.
            CONFIG      LVP=OFF    ; Режим низковольтного програм. выкл.
;-----------------------------------
; Регистры общ. назначения
;-----------------------------------
            cblock             00h ;
            Flag                   ; Флаг ошибки
            R_Bute_L               ; младший байт кол-ва данных таблицы.  
            R_Bute_H               ; старший байт кол-ва данных таблицы.
            ProvEE_L               ; младший байт
            ProvEE_H               ; младший байт
            Temp                   ;
            Counter                ; количество байт (всегда 8)
            Count_Blok             ; количество блоков по 8 байт
            endc                   ;
            org                  0 ;
            goto             START ;
;-----------------------------------

START       call            W_DATA ; Вызов ПП
            clrf              Flag ; Сброс флага ошибки
            goto             START ; зацикливаем.
   
;-----------------------------------
; ПП записи в память программ.           
;-----------------------------------
W_DATA      movlw               .8 ;
            movwf       Count_Blok ; количество байт (всегда 8)
            call            Ukaz_1 ; TBLPTR на начало таблицы
            movlw               .8 ; количество блоков по 8 байт
            MULWF       Count_Blok ; высчитаваем общее количество байт
            movff   PRODH,R_Bute_H ; Кол-во байт (старший, для коп. в ОЗУ
            movff   PRODL,R_Bute_L ; Кол-во байт (младший),для коп. в ОЗУ
            movff   PRODH,ProvEE_H ; Кол-во байт (старший) для проверки записи
            movff   PRODL,ProvEE_L ; Кол-во байт (младший) для проверки записи
            incf          R_Bute_H ; Коррекция.
            incf          ProvEE_H ; Коррекция.
            call            Ukaz_1 ; TBLPTR на начало таблицы
            call            R_DATA ; Вызов ПП чтения.
            call          ZAP_data ; Тестовая - для демонстрации (удалить)
            call            Ukaz_1 ; TBLPTR на начало таблицы
            movlw               .8 ; =Коррекция
            subwf        TBLPTRL,F ; =
            movlw                0 ; =
            subwfb       TBLPTRH,F ; =
            call         Counter_8 ; Запись новых данных
            call            Ukaz_1 ; TBLPTR на начало таблицы
            call           PROV_EE ; Проверка записи
            return

;-----------------------------------
; проверка записи
;-----------------------------------
PROV_EE    TBLRD*+                 ; Чтение байта +1 адрес
           movf         POSTINC0,0 ;
           CPFSEQ           TABLAT ;
           bsf              Flag,0 ; Флаг ошибки.
           decfsz         ProvEE_L ; Все прочитаны?
           bra             PROV_EE ; нет,следующий
           decfsz         ProvEE_H ; Все прочитаны?
           bra             PROV_EE ; нет,следующий   
           return                  ; Да, возврат из ПП  

;-----------------------------------
; Короткая запись  8 байт
;-----------------------------------
Counter_8  movlw                 8 ; Задание количества
           movwf           Counter ; байтов в одном блоке.
           nop
           movf         POSTINC0,0 ; =Копируем в W значение регистра.    
           movwf            TABLAT ;  в регистр TABLAT=
           tblwt*+                 ; Запись в защелку
           decfsz          Counter ; Все байты блока записаны?
           bra                $-.8 ; нет,следующий.
;-----------------------------------
; Длинная запись
;-----------------------------------
           bsf        EECON1,EEPGD ; Работа с Flash-памятью программ.
           bcf         EECON1,CFGS ; Обращение к Flash памяти программ
           bsf         EECON1,WREN ; Разрешение записи.
           bcf          INTCON,GIE ; Запрет прерывания
           movlw              055h ; =
           movwf            EECON2 ; Обязательная
           movlw              0AAh ; процедура.
           movwf            EECON2 ; =
           bsf           EECON1,WR ; Инициализация цикла записи.
           nop                     ;
           bsf          INTCON,GIE ; Разрешение прерывания.
           decfsz       Count_Blok ; Кол-во блоков по 8 байт
           call          Counter_8 ;  
           bcf         EECON1,WREN ; Запрет записи.
           return                  ; Возврат из прерывания                      
;-------------------------------------
; Указаталь TBLPTR на начало таблицы
; FSR0,0x0100 ; Начальный адрес В ОЗУ
;-------------------------------------
Ukaz_1      clrf           TBLPTRU ; Cбрасываем верхний байт
            movlw       high (TEST); =Задание адреса "TEST"
            movwf          TBLPTRH ;  старшего байта=
            movlw        low (TEST); =Задание адреса "TEST"
            movwf          TBLPTRL ;  младшего байта=
            lfsr       FSR0,0x0100 ; Начальный адрес В ОЗУ
            return
;-------------------------------------
; ПП чтения данных из памяти программ
;-------------------------------------
R_DATA     TBLRD*+                 ; Чтение байта +1 адрес
           movff      TABLAT,INDF0 ; Результат в ОЗУ
           movf           POSTINC0 ; Увеличиваем адрес FSR0L на 1
           decfsz         R_Bute_L ; Все прочитаны?
           bra              R_DATA ; нет,следующий
           decfsz         R_Bute_H ; Все прочитаны?
           bra              R_DATA ; нет,следующий   
           return                  ; Да, возврат из ПП
;-------------------------------------
; ПП предварительной записи в ОЗУ необходимых
; данных, 15 байт. ПРИМЕР !!!
;-------------------------------------
 ZAP_data  lfsr        FSR0,0x0107 ; Адрес первого регистра для изменения.
           movlw               .14 ; Всего 14 байт
           movwf              Temp ;
           clrf              INDF0 ; Очистить регистр
           movf           POSTINC0 ; Увеличиваем адрес FSR0L на 1
           decfsz             Temp ; Все очищены?
           bra                $-.6 ; нет,следующий
           lfsr        FSR0,0x013C ; Адрес  регистра для изменения.
           clrf              INDF0 ; Очистить регистр
           return                  ; Да, возврат из ПП
;--------------------------------------------------------
;ТАБЛИЦА ДАННЫХ 64 БАЙТА (ПРИМЕР)
;--------------------------------------------------------
          org                0100h ; размещение таблицы начиная с 0100h

TEST
    db     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,  
    db     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x06, 0x0F, 0x10,  
    db     0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,  
    db     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,  
    db     0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,  
    db     0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x06, 0x0F, 0x10,  
    db     0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,  
    db     0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,

end

 

{/showhide}

 

Видеоурок по теме...

 


 

Стирание Flash памяти программ производится блоками по 64 байта, последние 6 бит регистра TBLPTR (TBLPTRL) сбрасываются и соответственно в адресации не участвуют, а значит граница стираемого блока всегда на границе  адреса мл.байта  TBLPTRL  ХХ00 0000. Для стирания блока необходимо выполнить следующие действия:

  1. Загрузить в указатель адрес стираемого блока
  2. Установить  бит EEPGD для  выбора Flash памяти  программ; сбросить бит CFGS  для обращения к памяти программ; установить  бит WREN для  разрешения записи; установить бит FREE для разрешения стирания 
  3. Выключить прерывания 
  4. Записать 55h в регистр EECON2
  5. Записать AAh в регистр EECON2
  6. Установить бит WR для инициализации цикла стирания
  7. CPU о становит выполнение программы до завершения цикла стирания (ориентировочно 2мс)
  8. Выполнить команду NOP
  9. Разрешить прерывания

В даташитах при переводе бывают "опечатки". Так и в нашем случае бит  WR  регистра EECON1 приписали  к EECON2 и практически везде пропущена команда сброса бита CFGS , для обращения к памяти программ. Дело в том, что при сбросе бит принимает неизвестное состояние и ПП стирания как и записи, чтения может просто не работать.

Вот так выглядит ПП стирания Flash памяти программ.

;-----------------------------------
; ПП стирания  памяти программ.           
;------------------ -----------------
Clr_TAB    bsf        EECON1,EEPGD ; Работа с Flash-памятью программ.
           bcf         EECON1,CFGS ; Обращение к Flash памяти программ
           bsf         EECON1,WREN ; Разрешение записи.
           bsf         EECON1,FREE ; Разрешение стирания.
           bcf          INTCON,GIE ; Запретить прерывания
           movlw               55h ; =
           movwf            EECON2 ; Обязательная
           movlw              0AAh ; процедура.
           movwf            EECON2 ; =         
           bsf           EECON1,WR ; Инициализация стирания
           nop                     ; Обязательная процедура
           bsf          INTCON,GIE ; Разрешить прерывания
           return                  ; Возврат из ПП.

 

Смотреть видеоурок по теме....


Регистр EECON1.

 

Регистр содержит биты управления EEPROM памяти данных.

 

Важно:

Сброс по включению питания   микроконтроллера (POR) и сброс по снижению питания (BOR) приводит к сбросу  битов управления регистра EECON1, за исключением битов 3,6,7,  которые принимают неизвестное состояние.

R/W-X R/W-X U-0 R/W-0 R/W-X R/W-0 R/S-0 R/S-0
EEPGD CFGS - FREE WRERR WREN WR RD
Бит7 Бит6 Бит5 Бит4 Бит3 Бит2 Бит1 Бит0

Бит7   EEPGD:  Обращение к Flash памяти программ или EEPROM памяти данных

 

           1= Обращение к Flash памяти программ

           0= Обращение к EEPROM памяти данных

 

Бит6   CFGS: Обращение к Flash памяти программ /EEPROM памяти данных или

                           к регистрам конфигурации

 

           1= Обращение к регистрам конфигурации

           0= Обращение к Flash памяти программ/EEPROM памяти данных

 

Бит5  Не используется. Читается как 0

 

       

Бит4   FREE: Разрешение стирания Flash  памяти программ

 

           1= стереть блок памяти программ начиная с адреса TBLPTR при следующей

                  команде WR (сбрасывается аппаратно при окончании стирания)

           0= Только запись данных

 

Бит3   WRERR: Флаг ошибки записи в память

 

           1= Запись прервана (произошел один из сбросов во время исполнения записи)

           0= Запись завершена

             Примечание. При установке бита WRERR биты EEPGD,CFGS не сбрасываются, что позволяет определить

                                       условные ошибки.

 

Бит2  WREN: Разрешение записи в память

 

           1= Запись разрешена

           0= Запись запрещена

 

Бит1 WR: Управляющий бит записи

 

           1= Инициализация цикла стирания/запись в EEPROM память данных.

                Для памяти программ инициализация цикла записи или стирания. Бит сбрасывается

                     аппаратно по завершении операции стирания/записи, программно он может быть только установлен в "1"

           0= цикл стирание/запись завершен

 

 

Бит0  RD: Управляющий бит чтения

1= Инициализация чтения   EEPROM памяти данных. Чтение выполняется за один цикл.

       Бит RD сбрасывается аппаратно. программно он может только установлен в "1" . RD  не

       устанавливается  в "1", если EEPGD=1

      

          0= Чтение EEPROM памяти данных не инициализировалось

Read 6055 times Last modified on Четверг, 04 сентября 2014 11:51

Все права принадлежат ChipMK.ru. При копировании материала ссылка обязательна. 2011-2017 © ChipMK.ru

ChipMk.ru Яндекс.Метрика
PRCY.ru