niedziela, 3 września 2017

[9] Atmega328p - Dostęp do pamięci EEPROM

Ten post chciałbym poświęcić na opisanie sposobu zapisywania danych do EEPROMu.

[Źródło: https://en.wikipedia.org/wiki/ATmega328]

Rejestry:


Dane do pamięci EEPROM wprowadza się poprzez odpowiednie ustawienie trzech rejestrów. 

Pierwszy z nich jest EEDR. Zawiera on dane jakie mają zostać wpisane bądź odczytane z pamięci. Rejestr ten jest 8 bitowy. Bit 7 ma przypisaną wartość MSB, bit 0 wartość LSB.

Drugi to EECR czyli rejestr kontrolny. Jest to także rejestr 8 bitowy jego struktura wygląda następująco:


  • Bit 7 - zarezerwowane
  • Bit 6 - zarezerwowane
  • Bit 5 - zarezerwowane
  • Bit 4 - zarezerwowane
  • Bit 3 - EERIE - włączenie informacji o gotowości eepromu. Za każdym razem gdy bit EEWE jest czyszczony następuje generowanie przerwania. 
  • Bit 2 - EEMWE - wpisanie wartości 1 uruchamia możliwość wpisywania danych do pamięci.
  • Bit 1 - EEPE - jest to rejestr odpowiedzialny za wpisywanie danych do pamięci. Wartość powinna być ustawiona po wprowadzeniu informacji odnośnie adresu oraz wprowadzanych danych.
  • Bit 0 - EERE - włączenie możliwości odczytu danych. W celu odczytu wpisuje się do rejestru wartość 1, po wpisaniu adresu do rejestru EEAR. Spowoduje to uruchomienie procedury odczytu.


Trzecim rejestrem jest 16 bitowy EEAR czyli rejestr adresu. 

Bity od 15 do 10 są zarezerwowane. Prz próbie odczytania ich wartość będzie zawsze wynosiła 0.

Bity od 9 do 0 przechowują adres z którego dane będą odczytywane.

Procedury zapisu:

Na początku trzeba odczekać aż poprzednia procedura zapisu/odczytu zostanie zakończona. Można to sprawdzić poprzez sprawdzenie stanu bitu EEPE. Gdy procedura się zakończy to jego wartość będzie wynosiła 0. Kolejnym krokiem jest załadowanie adresu do rejestru EEAR. Dane wprowadza się do EEAD. Następnie należy ustawić bit EEMWE. Po czterech cyklach zegarowych należy ustawić EEWE. Po takiej procedurze dane zostają automatyczne wpisywane w odpowiednie miejsce.

Procedury odczytu:

Tutaj podobnie jak poprzednio czeka się na zakończenie zapisu/odczytu danych. Następnie ładuje się adres z którego ma nastąpić odczytanie danych. Procedurę odczytu rozpoczyna się poprzez wpisanie jedynki do rejestru EERE. Odczytane dane będą przechowywane w rejestrze EEDR. 

Przykładowy program:

Do operacji na pamięci EEPROM można wykorzystać bibliotekę udostępnioną przez producenta. Wtedy wykorzystuje się następuje funkcje umożliwiające zapis oraz odczyt:

  1. #define eeprom_read_byte      _EEPROM_CONCAT2 (__eerd_byte, _EEPROM_SUFFIX)
  2. #define eeprom_read_word      _EEPROM_CONCAT2 (__eerd_word, _EEPROM_SUFFIX)
  3. #define eeprom_read_dword     _EEPROM_CONCAT2 (__eerd_dword, _EEPROM_SUFFIX)
  4. #define eeprom_read_float     _EEPROM_CONCAT2 (__eerd_float, _EEPROM_SUFFIX)
  5. #define eeprom_read_block     _EEPROM_CONCAT2 (__eerd_block, _EEPROM_SUFFIX)
  6.  
  7. #define eeprom_write_byte     _EEPROM_CONCAT2 (__eewr_byte, _EEPROM_SUFFIX)
  8. #define eeprom_write_word     _EEPROM_CONCAT2 (__eewr_word, _EEPROM_SUFFIX)
  9. #define eeprom_write_dword    _EEPROM_CONCAT2 (__eewr_dword, _EEPROM_SUFFIX)
  10. #define eeprom_write_float    _EEPROM_CONCAT2 (__eewr_float, _EEPROM_SUFFIX)
  11. #define eeprom_write_block    _EEPROM_CONCAT2 (__eewr_block, _EEPROM_SUFFIX)
  12.  
  13. #define eeprom_update_byte    _EEPROM_CONCAT2 (__eeupd_byte, _EEPROM_SUFFIX)
  14. #define eeprom_update_word    _EEPROM_CONCAT2 (__eeupd_word, _EEPROM_SUFFIX)
  15. #define eeprom_update_dword   _EEPROM_CONCAT2 (__eeupd_dword, _EEPROM_SUFFIX)
  16. #define eeprom_update_float   _EEPROM_CONCAT2 (__eeupd_float, _EEPROM_SUFFIX)
  17. #define eeprom_update_block   _EEPROM_CONCAT2 (__eeupd_block, _EEPROM_SUFFIX)

Poniżej przykładowe funkcje do odczytu i zapisu pojedynczych danych, większej ilości danych oraz ciągów znaków:

  1. #include <avr\io.h>
  2. #include "eep.h"
  3. //--------------------------------------------------------------------------
  4. void eepromWriteByteNoInter(uint16_t addresToWrite, uint8_t *dataToWrite)
  5. {
  6.     /* disable interrupts */
  7.     cli();
  8.    
  9.     /* wait till operation are finished */
  10.     while(EECR & (1<<EEPE)) { ; }
  11.        
  12.     /* writes data into EEDR and adres into EEAR */
  13.     EEAR = addresToWrite;
  14.     EEDR = dataToWrite;
  15.    
  16.     /* set bits */
  17.     EECR |= (1<<EEMPE);
  18.     EECR |= (1<<EEPE);
  19.    
  20.     /* wait till operation is finished,
  21.         used here to e*/
  22.     while(EECR & (1<<EEPE)) { ; }
  23.    
  24.     sei();
  25. }
  26. //--------------------------------------------------------------------------
  27. uint8_t eepromReadByteNoInter(uint16_t addresToRead)
  28. {
  29.     /* disable interrupts */
  30.     cli();
  31.        
  32.     /* wait till operation are finished */
  33.     while(EECR & (1<<EEPE)) { ; }
  34.    
  35.     /* writes data into EEDR */
  36.     EEAR = addresToRead;
  37.    
  38.     /* start read sequence */
  39.     EECR |= (1<<EERE);
  40.    
  41.     /* wait till operation are finished */
  42.     while(EECR & (1<<EEPE)) { ; }
  43.    
  44.     /* disable interrupts */
  45.     sei();
  46.    
  47.     return EEDR;
  48. }
  49. //--------------------------------------------------------------------------
  50. void writeMultiBytes(uint16_t startAddress, uint8_t *dataBuffer, uint16_t numberBytesToWrite)
  51. {
  52.     uint16_t i = 0;
  53.    
  54.     while(!=  numberBytesToWrite){
  55.         eepromWriteByteNoInter(startAddress, *dataBuffer);
  56.         startAddress++;
  57.         dataBuffer++;                        
  58.         i++;           
  59.     }  
  60. }
  61. //--------------------------------------------------------------------------
  62. void readMultiBytes(uint16_t startAddress, uint8_t *dataBuffer, uint16_t numberBytesToWrite)
  63. {
  64.     uint16_t i = 0;
  65.    
  66.     while(!=  numberBytesToWrite){
  67.         *(dataBuffer + i) = eepromReadByteNoInter(startAddress);
  68.         startAddress++;
  69.         dataBuffer++;
  70.         i++;
  71.     }
  72. }
  73. //--------------------------------------------------------------------------
  74. void eepromWriteStringNoInter(uint16_t startAddress, char *buffer)
  75. {
  76.   while(*buffer){
  77.       eeprom_write_byte1(startAddress, *buffer);
  78.       buffer++;
  79.       startAddress++;
  80.   }
  81. }
  82. //--------------------------------------------------------------------------
  83. void eepromReadStringNoInter(uint16_t startAddress, char *buffer, uint8_t bufferLength)
  84. {
  85.     uint8_t i = 0;
  86.    
  87.     while(!= bufferLength){
  88.       *buffer = eepromReadByteNoInter(startAddress);
  89.      
  90.       if( *buffer == '\0' ){      break;    }
  91.       i++;
  92.       buffer++;
  93.     }
  94.     *buffer = '\0';
  95. }
  96. //--------------------------------------------------------------------------
  97. void eepromErase()
  98. {
  99.     uint16_t eepromAdress = 0;
  100.    
  101.     /* Go for whole memmory, to clear write 0xff */
  102.     while(eepromAdress<1024)
  103.     {
  104.         eepromWriteByteNoInter(eepromAdress, 0xFF);
  105.         eepromAdress++;
  106.     }
  107. }
  108. //--------------------------------------------------------------------------