Serwis Edukacyjny
Nauczycieli

w I-LO w Tarnowie
obrazek

  Wyjście       Spis treści       Wstecz       Dalej  

obrazek

Autor artykułu
 mgr Jerzy Wałaszek
Konsultacje:
Wojciech Grodowski
mgr inż. Janusz Wałaszek

©2026 mgr Jerzy Wałaszek

obrazek

Mikrokontrolery

ATmega48A/PA/88A/PA/168A/PA/328/P

Samoprogramowanie FLASH, ATmega48A/48PA


obrazek

Educational and Non-Profit Use of Copyrighted Material:

If you use Microchip copyrighted material solely for educational (non-profit) purposes falling under the “fair use” exception of the U.S. Copyright Act of 1976 then you do not need Microchip’s written permission. For example, Microchip’s permission is not required when using copyrighted material in: (1) an academic report, thesis, or dissertation; (2) classroom handouts or textbook; or (3) a presentation or article that is solely educational in nature (e.g., technical article published in a magazine).

https://www.microchip.com/about-us/legal-information/copyright-usage-guidelines

SPIS TREŚCI KONSERWACJA
Podrozdziały

obrazek

Przegląd

Mikrokontroler ATmega 48A/48PA nie wspiera operacji RWW (ang. Read-While-Write – odczyt podczas zapisu) i nie posiada osobnej sekcji Boot-Loadera. Instrukcja SPM może być wykonywana z całego obszaru FLASH.

Mikrokontroler udostępnia mechanizm samoprogramowania do samodzielnego ładowania i odczytywania kodu programu. Samoprogramowanie może wykorzystywać dowolny z dostępnych interfejsów danych i związanych z nimi protokołów komunikacyjnych do odczytu i zapisu (programowania) tego kodu w pamięci programu.

Pamięć programu jest uaktualniana krokami strona po stronie. Przed zaprogramowaniem strony danymi umieszczonymi w tymczasowym buforze, strona musi zostać wymazana. Bufor tymczasowy wypełniany jest po jednym słowie naraz przy pomocy instrukcji SPM, a bufor można zapełnić albo przed rozkazem kasowania strony (ang. Page Erase command), albo pomiędzy kasowaniem strony a operacją zapisu strony (ang. Page Write command):

Alternatywa 1, wypełnienie bufora przed kasowaniem strony

Alternatywa 2: wypełnienie bufora po kasowaniu strony

Jeśli tylko część strony wymaga zmiany, reszta tej strony musi zostać zapamiętana (na przykład w tymczasowym buforze strony) przed kasowaniem, a następnie zapisana ponownie.

Jeśli jest wykorzystywana alternatywa 1, to program bootloadera może korzystać z użytecznej własności odczytu-modyfikacji-zapisu (ang. Read-Modify-Write), która pozwala oprogramowaniu użytkownika najpierw odczytać stronę, wykonać niezbędne zmiany, a następnie zapisać z powrotem zmodyfikowane dane.

Jeśli używana jest alternatywa 2, to nie można odczytać starych danych podczas ładowania, ponieważ strona została już skasowana. Tymczasowy bufor strony można zapisywać w dowolnej kolejności. Ważne jest, aby adres strony używany w obu operacjach Kasowania i Zapisu adresował tę samą stronę.

Wykonywanie kasowania strony (ang. Page Erase) przez instrukcję SPM

Aby wykonać operację kasowania strony pamięci FLASH, ustaw jej adres we wskaźniku Z (R30-31), wpisz “00000011” do rejestru SPMCSR i wykonaj instrukcję SPM w ciągu czterech taktów zegara po zapisie do SPMCSR. Dane w rejestrach R1 i R0 są ignorowane. Adres strony musi być wpisany do pola PCPAGE we wskaźniku Z. Pozostałe bity we wskaźniku Z będą zignorowane podczas tej operacji.

Uwaga: Jeśli w obrębie sekwencji czasowej wystąpi przerwanie, to nie można zapewnić dostępu w czterech taktach. Aby zapewnić operację atomową (niepodzielną czasowo), powinieneś zablokować przerwania przed zapisem do rejestru  SPMCSR.

Wypełnianie bufora tymczasowego strony (ang. Page Loading – ładowanie strony)

Aby wpisać słowo instrukcji, ustaw jego adres we wskaźniku Z i dane w rejestrach R1:R0, wpisz “00000001” do rejestru SPMCSR i w ciągu czterech taktów po zapisie rejestru SPMCSR wykonaj instrukcję SPM. Zawartość pola PCWORD w rejestrze Z jest używana do adresowania danych w buforze tymczasowym. Bufor tymczasowy wykasuje się automatycznie po operacji zapisu strony (ang. Page Write operation) lub przez zapis bitu RWWSRE w rejestrze SPMCSR. Jest również kasowany po resecie systemowym. Zauważ, iż nie można zapisać każdego adresu więcej niż raz bez skasowania bufora tymczasowego. Jeśli wystąpi zapis do pamięci EEPROM w środku operacji ładowania strony przez SPM, wszystkie załadowane dane będą stracone.

Wykonywanie zapisu strony (ang. Page Write)

Aby wykonać zapis strony, ustaw jej adres we wskaźniku Z, wpisz “00000101” do rejestru SPMCSR i w ciągu czterech taktów po zapisie do SPMCSR wykonaj instrukcję SPM. Dane w rejestrach R1 i R0 są ignorowane. Adres strony musi być zapisany w polu PCPAGE. Pozostałe bity we wskaźniku Z muszą być zapisane zerami podczas tej operacji.


do podrozdziału  do strony 

Adresowanie FLASH podczas samoprogramowania

Wskaźnik Z jest wykorzystywany w instrukcji SPM do adresowania.
Bit 15 14 13 12 11 10 9 8
ZH (R31) Z15 Z14 Z13 Z12 Z11 Z10 Z9 Z8
ZL (R30) Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0
Bit 7 6 5 4 3 2 1 0

Ponieważ pamięć FLASH jest zorganizowana w strony, to licznik programu (ang. Program Counter) można potraktować tak, jakby składał się z dwóch różnych sekcji. Jedna sekcja składająca się z najmniej znaczących bitów adresuje słowa wewnątrz strony, natomiast bity najbardziej znaczące adresują te strony. Pokazane to jest na poniższym rysunku. Zauważ, że operacje kasowania strony (ang. page erase) i zapisu strony (ang. page write) używają osobnych adresów. Dlatego jest bardzo ważne, aby oprogramowanie boot-loadera adresowało tę samą stronę w obu tych operacjach.

Instrukcja LPM również korzysta ze wskaźnika Z do przechowywania adresu. Ponieważ instrukcja ta adresuje pamięć FLASH bajt po bajcie, to również bit LSB (bit Z0) wskaźnika Z jest używany.

obrazek

Zapis pamięci EEPROM zapobiega zapisowi do SPMCR

Zauważ, iż operacja zapisu pamięci EEPROM zablokuje wszelkie programowanie pamięci FLASH. Odczyt bitów bezpiecznikowych i blokujących z poziomu oprogramowania jest również zablokowany podczas operacji zapisu EEPROM. Zaleca się sprawdzanie bitu stanu EEPE w rejestrze EECR i upewnieniu się, iż jest on wyzerowany, przed zapisywaniem rejestru SPMCR.

Programowy odczyt bitów bezpiecznikowych i blokujących

Możliwy jest programowy odczyt zarówno bitów bezpiecznikowych jak i bitów blokujących. Aby odczytać bity blokujące, załaduj wskaźnik Z wartością 0x0001 i ustaw bity BLBSET i SPMEN w rejestrze SPMCR. Gdy w ciągu trzech taktów mikroprocesora po tej operacji zostanie wykonana instrukcja LPM , to wartość bitów blokujących zostanie załadowana do rejestru docelowego. Bity BLBSET i SPMEN wyzerują się automatycznie po zakończeniu odczytu bitów blokujących lub jeśli  żadna instrukcja LPM nie będzie wykonana w ciągu trzech taktów mikroprocesora lub żadna instrukcja SPM nie będzie wykonana w ciągu czterech taktów mikroprocesora.  Gdy bity BLBSET i SPMEN wyzerują się, instrukcja LPM będzie działać zgodnie z opisem.

Bit 7 6 5 4 3 2 1 0
Rd  –   –   –   –   –   –   LB2  LB1

Algorytm odczytu dolnego bajtu bitów bezpiecznikowych jest podobny do algorytmu opisanego powyżej dla odczytu bitów blokujących. Aby odczytać dolny bajt bitów bezpiecznikowych, załaduj wskaźnik Z wartością 0x0000 i ustaw bity BLBSET i SPMEN w rejestrze SPMCR. Gdy instrukcja LPM zostanie wykonana w ciągu trzech taktów po ustawieniu bitów BLBSET i SPMEN w SPMCR, wartość dolnego bajtu bitów bezpiecznikowych (FLB) będzie załadowana do rejestru docelowego, jak pokazano poniżej.

Bit 7 6 5 4 3 2 1 0
Rd FLB7  FLB6 FLB5 FLB4 FLB3 FLB2 FLB1 FLB0

Podobnie przy odczycie górnego bajtu bitów bezpiecznikowych załaduj wskaźnik Z wartością 0x0003. Gdy instrukcja LPM zostanie wykonana w ciągu trzech taktów po ustawieniu bitów BLBSET i SPMEN w SPMCR, wartość górnego bajtu bitów bezpiecznikowych (FHB) będzie załadowana do rejestru docelowego, jak pokazano poniżej.

Bit 7 6 5 4 3 2 1 0
Rd FHB7  FHB6 FHB5 FHB4 FHB3 FHB2 FHB1 FHB0

Podobnie przy odczycie rozszerzonego bajtu bitów bezpiecznikowych załaduj wskaźnik Z wartością 0x0002. Gdy instrukcja LPM zostanie wykonana w ciągu trzech taktów po ustawieniu bitów BLBSET i SPMEN w SPMCR, wartość rozszerzonego bajtu bitów bezpiecznikowych (EFB) będzie załadowana do rejestru docelowego, jak pokazano poniżej.

Bit 7 6 5 4 3 2 1 0
Rd EFB7  EFB6 EFB5 EFB4 EFB3 EFB2 EFB1 EFB0

Zaprogramowane bity bezpiecznikowe i blokujące mają przy odczycie stan zero, natomiast bity niezaprogramowane dają przy odczycie stan jeden.

Zapobieganie uszkodzeniu danych w pamięci FLASH

W okresach spadku napięcia zasilającego VCC programowanie pamięci FLASH może zakończyć się błędami, ponieważ napięcie zasilające jest zbyt niskie, aby mikroprocesor i pamięć FLASH pracowały poprawnie. Problemy te są takie same jak w systemach z zewnętrzną pamięcią FLASH i należy stosować te same rozwiązania projektowe. Błędy programowania FLASH mogą pojawić się w dwóch sytuacjach, gdy napięcie jest za niskie. Po pierwsze standardowa sekwencja zapisu do FLASH wymaga minimalnego napięcia do poprawnej pracy. Po drugie, sam mikroprocesor może wykonywać instrukcje niepoprawnie, jeśli napięcie zasilające jest dla nich zbyt niskie.

Błędom w FLASH można łatwo zapobiec stosując się do następujących zaleceń projektowych (jedno jest wystarczające):

  1. Utrzymuj linię AVR RESET w stanie aktywnym (niskim) w okresach niewystarczającej wartości napięcia zasilającego. Można tego dokonać poprzez włączenie wewnętrznego detektora spadku napięcia zasilania (ang. internal Brown-out Detector, BOD), jeśli napięcie pracy pasuje do poziomu wykrywania. Jeśli nie, można użyć zewnętrznego układu resetowania przy niskim napięciu VCC. Jeśli reset wystąpi podczas wykonywania operacji zapisu, to operacja ta zostanie zakończona pod warunkiem, iż napięcie zasilające posiada wystarczającą wartość.
  2. Utrzymuj rdzeń AVR w trybie uśpienia z wyłączeniem zasilania (ang. Power-down sleep mode) w okresach niskiego VCC. Uniemożliwi to mikroprocesorowi próby dekodowania i wykonywania instrukcji, co skutecznie zabezpieczy rejestr SPMCSR, a co za tym idzie również pamięć FLASH, przed niezamierzonymi zapisami.

Czas programowania FLASH przy użyciu instrukcji SPM

Kalibrowany oscylator RC jest używany do odmierzania czasu dostępów do pamięci FLASH. Poniższa tabela pokazuje typowy czas programowania FLASH przy dostępie przez mikroprocesor.

Symbol Min. czas programowania Max. czas programowania
Zapis FLASH (wymazywanie strony, zapis strony i zapis bitów blokujących przez SPM) 3,7 ms 4,5 ms

Prosty przykład w asemblerze boot-loadera

  ;-Procedura zapisuje jedną stronę danych z RAM do FLASH
  ; Pierwszy adres danych w RAM jest wskazywany przez wskaźnik Y
  ; Pierwszy adres danych we FLASH jest wskazywany przez wskaźnik Z
  ;-Obsługa błędów nie została zrealizowana
  ;-Procedura musi się znaleźć w obszarze boot-loadera
  ; (przynajmniej podprogram Do_spm). Tylko kod wewnątrz sekcji NRWW może
  ; być odczytywany podczas samoprogramowania (wymazywania strony i zapisu strony).
  ;-Używane rejestry: r0, r1, temp1 (r16), temp2 (r17), looplo (r24),
  ; loophi (r25), spmcrval (r20)
  ; W procedurze nie zastosowano zachowywania i odtwarzania rejestrów.
  ; Wykorzystanie rejestrów można zoptymalizować kosztem rozmiaru kodu.
  ;-Zakłada się, iż albo tablica przerwań została przeniesiona do sekcji
  ; boot-loadera, albo przerwania są wyłączone.
.equ PAGESIZEB = PAGESIZE*2 ;PAGESIZEB jest rozmiarem strony w bajtach, nie w słowach
.org SMALLBOOTSTART
Write_page:
  ; Wymazywanie strony
  ldi spmcrval, (1<<PGERS) | (1<<SPMEN)
  rcall Do_spm
  ; Ponowne uaktywnienie sekcji RWW
  ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN)
  rcall Do_spm
  ; Przenieś dane z RAM do bufora strony FLASH
  ldi looplo, low(PAGESIZEB) ;Inicjuj zmienną pętli
  ldi loophi, high(PAGESIZEB) ;Niepotrzebne dla PAGESIZEB<=256
Wrloop:
  ld r0, Y+
  ld r1, Y+
  ldi spmcrval, (1<<SPMEN)
  rcall Do_spm
  adiw ZH:ZL, 2
  sbiw loophi:looplo, 2 ;Użyj subi dla PAGESIZEB<=256
  brne Wrloop
  ; Wykonaj zapis strony
  subi ZL, low(PAGESIZEB) ;Odtwórz wskaźnik
  sbci ZH, high(PAGESIZEB) ;Niepotrzebne dla PAGESIZEB<=256
  ldi spmcrval, (1<<PGWRT) | (1<<SPMEN)
  rcall Do_spm
  ; Ponowne uaktywnienie sekcji RWW
  ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN)
  rcall Do_spm
  ; Odczytaj z powrotem i sprawdź, opcjonalne
  ldi looplo, low(PAGESIZEB) ;Inicjuj zmienną pętli
  ldi loophi, high(PAGESIZEB) ;Niepotrzebne dla PAGESIZEB<=256
  subi YL, low(PAGESIZEB) ;Odtwórz wskaźnik
  sbci YH, high(PAGESIZEB)
Rdloop:
  lpm r0, Z+
  ld r1, Y+
  cpse r0, r1
  rjmp Error
  sbiw loophi:looplo, 1 ;Użyj subi dla PAGESIZEB<=256
  brne Rdloop
  ; Wróć do sekcji RWW
  ; Sprawdź, czy odczyt sekcji RWW jest bezpieczny
Return:
  in temp1, SPMCR
  sbrs temp1, RWWSB ;Jeśli bit RWWSB jest ustawiony, sekcja RWW nie jest jeszcze gotowa
  ret
  ; Ponowne uaktywnienie sekcji RWW
  ldi spmcrval, (1<<RWWSRE) | (1<<SPMEN)
  rcall Do_spm
  rjmp Return
Do_spm:
  ; Sprawdź zakończenie poprzedniej instrukcji SPM
Wait_spm:
  in temp1, SPMCR
  sbrc temp1, SPMEN
  rjmp Wait_spm
  ; Wejście: spmcrval określa działanie SPM
  ; Wyłącz przerwania, jeśli są włączone, zachowaj stan
  in temp2, SREG
  cli
  ; Sprawdź, iż nie następuje zapis do EEPROM
Wait_ee:
  sbic EECR, EEWE
  rjmp Wait_ee
  ; Sekwencja czasowa SPM
  out SPMCR, spmcrval
  spm
  ; Odtwórz SREG (aby włączyć przerwania, jeśli oryginalnie były włączone)
  out SREG, temp2
  ret

do podrozdziału  do strony 

Opis rejestrów

SPMCR – Store Program Memory Control Register – Rejestr kontroli instrukcji SPM

Bit 7 6 5 4 3 2 1 0  
0x37 (0x57) SPMIE RWWSB SIGRD RWWSRE BLBSET PGWRT PGERS SPMEN SPMCR
Zapis/Odczyt Z/O O ZO Z/O Z/O Z/O Z/O Z/O  
Wartość początkowa 0 0 0 0 0 0 0 0  

Bit 7 – SPMIE: SPM Interrupt Enable – Włączenie przerwania od instrukcji SPM

Gdy bit SPMIE zostanie zapisany jedynką i bit I w rejestrze stanu SREG jest ustawiony, to zostanie włączone przerwanie gotowości instrukcji SPM. Przerwanie to będzie wykonywane tak długo, jak bit SPMEN jest wyzerowany.

Bit 6 – RWWSB: Read-While-Write Section Busy – Zajętość sekcji RWW

Gdy zostanie zainicjowana operacja samoprogramowania (wymazywanie lub zapis strony) w sekcji RWW, bit RWWSB jest ustawiany (na jeden) sprzętowo. Gdy bit ten jest ustawiony, to nie ma dostępu do sekcji RWW. Bit RWWSB wyzeruje się, gdy do bitu RWWSRE zostanie wpisana jedynka po zakończeniu operacji samoprogramowania. Alternatywnie bit RWWSB jest automatycznie zerowany, gdy zostanie zainicjowana operacja ładowania strony.

Bit 5 – SIGRD: Signature Row Read – Odczyt wiersza sygnatury

Jeśli ten bit zostanie zapisany logiczną jedynką w tym samym czasie co bit SPMEN, to instrukcja LPM wykonana w ciągu następnych trzech taktów odczyta bajt z wiersza sygnatury i umieści go w rejestrze docelowym. Szczegóły znajdziesz w podrozdziale "Programowy odczyt wiersza sygnatury". Instrukcja SPM wykonana w ciągu czterech taktów po ustawieniu bitów SIGRD i SPMEN nie będzie miała żadnego efektu. Operacja ta jest zarezerwowana na przyszły użytek i nie powinna być wykorzystywana.

Bit 4 – RWWSRE: Read-While-Write Section Read Enable – Włączenie odczytu sekcji RWW

Funkcjonalność tego bitu w ATmega 48A/48PA jest podzbiorem funkcjonalności w ATmega88A/88PA/168A/168PA/328/328P. Jeśli bit RWWSRE zostanie zapisany podczas wypełniania tymczasowego bufora strony, bufor zostanie wymazany i dane będą utracone.

Bit 3 – BLBSET: Boot Lock Bit Set – Ustawianie bitów blokujących boot-loadera

Funkcjonalność tego bitu w ATmega 48A/48PA jest podzbiorem funkcjonalności w ATmega88A/88PA/168A/168PA/328/328P.  Instrukcja LPM wykonana w ciągu trzech taktów po ustawieniu bitów BLBSET i SPMEN odczyta albo bity blokujące, albo bity bezpiecznikowe (zależnie od Z0 we wskaźniku Z) do rejestru docelowego. Szczegóły znajdziesz w podrozdziale "Programowy odczyt bitów bezpiecznikowych i blokujących".

Bit 2 – PGWRT: Page Write – Zapis strony

Jeśli jedynka zostanie wpisana do tego bitu w tym samym czasie co do SPMEN, to następna instrukcja SPM w ciągu czterech taktów zegara wykona zapis strony danymi umieszczonymi w buforze tymczasowym. Adres strony zostanie pobrany z górnej części wskaźnika Z. Dane w rejestrach R1 i R0 są ignorowane. Bit PGWRT bit wyzeruje się automatycznie po zakończeniu zapisu strony lub jeśli żadna instrukcja SPM nie będzie wykonana w ciągu czterech taktów zegarowych. W czasie zapisu strony mikroprocesor jest zatrzymywany.

Bit 1 – PGERS: Page Erase – Kasowanie strony

Jeśli jedynka zostanie wpisana do tego bitu w tym samym czasie co do SPMEN, to następna instrukcja SPM w ciągu czterech taktów zegara wykona kasowanie strony. Adres strony zostanie pobrany z górnej części wskaźnika Z. Dane w rejestrach R1 i R0 są ignorowane. Bit PGERS bit wyzeruje się automatycznie po zakończeniu kasowania strony lub jeśli żadna instrukcja SPM nie będzie wykonana w ciągu czterech taktów zegarowych. Mikroprocesor jest wstrzymany przez całą operację kasowania strony.

Bit 0 – SPMEN: Store Program Memory Enable – Włączenie instrukcji SPM

Ten bit włącza instrukcję SPM przez następne cztery takty zegarowe. Jeśli jedynka logiczna zostanie umieszczona w nim oraz w jednym z bitów RWWSRE, BLBSET, PGWRT lub PGERS, to następna instrukcja SPM będzie miała specjalne znaczenie, zobacz na opisy umieszczone powyżej. Jeśli będzie zapisany tylko sam bit SPMEN, to następna instrukcja SPM umieści wartość R1:R0 w tymczasowym buforze strony adresowanym przez wskaźnik Z. Najmłodszy bit, LSB, wskaźnika Z jest ignorowany. Bit SPMEN wyzeruje się automatycznie po zakończeniu instrukcji SPM lub jeśli żadna instrukcja SPM nie będzie wykonana w ciągu kolejnych czterech taktów zegarowych. Podczas wymazywania strony i zapisu strony bit pozostaje w stanie wysokim aż do zakończenia operacji.

Zapis innej kombinacji bitów niż “10001”, “01001”, “00101”, “00011” lub “00001” w dolnych pięciu bitach rejestru SPMCR nie wywołuje żadnego efektu.   


do podrozdziału  do strony 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2026 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.

Informacje dodatkowe.