Mega2560 чтение одного байта из eeprom с адреса > 255

Тема в разделе "Arduino & Shields", создана пользователем Vovka, 8 ноя 2020.

Метки:
  1. Vovka

    Vovka Гик

    Значит нужно мне считать 1 байт, допустим по адресу 300.
    Используем стандартную библиотеку EEPROM.h
    В ней есть функция
    Код (C++):
    uint8_t eeprom_read_byte (const uint8_t *__p) __ATTR_PURE__;
    Т.е. адрес задается 8-и битным значением, т.е. число, не более 255!!!
    Как быть?
     
  2. a1000

    a1000 Гуру

    А как вы его туда записали?
    Ну а если библиотека не поддерживает адреса старше 255 - сделайте это вручную.
     
  3. Vovka

    Vovka Гик

    Я не писал, просто для примера выбрал функцию чтения. Аналогично записана и функция записи.
    Так ведь это стандартная библиотека eeprom.h, которая идёт в комплекте с компилятором avr-gcc, который компилирует наши скетчи из под Arduino IDE. Т.е. сделали библиотеку, которую практически все используют, а она работает только с 256 байтами EEPROM? Что-то тут не то...
     
  4. a1000

    a1000 Гуру

    В описании написано что адрес интовый
    read()
    Описание
    Считывает байт из EEPROM. Те байты, которые никогда не подвергались записи, имеют значение 255.

    Синтаксис

    EEPROM.read(address)
    Параметры
    address: адрес байта, значение которого необходимо считать (int)

    Возвращаемые значения
    значение указанного байта (byte)
     
  5. Vovka

    Vovka Гик

    а в eeprom.h написано:
    Код (C++):
    uint8_t eeprom_read_byte (const uint8_t *__p) __ATTR_PURE__;
    Так кому верить: описанию или файлу, который использует компилятор???
     
  6. a1000

    a1000 Гуру

    Подскажите где лежит этот файл. Я его найти не могу.
     
  7. Vovka

    Vovka Гик

    Код (C++):
    ..\arduino-nightly\hardware\tools\avr\avr\include\avr\eeprom.h
     
  8. akl

    akl Гуру

    ваще, там есть и другие штуки
    Код (C++):
    /** \ingroup avr_eeprom
        Read one byte from EEPROM address \a __p.
    */

    uint8_t eeprom_read_byte (const uint8_t *__p) __ATTR_PURE__;

    /** \ingroup avr_eeprom
        Read one 16-bit word (little endian) from EEPROM address \a __p.
    */

    uint16_t eeprom_read_word (const uint16_t *__p) __ATTR_PURE__;

    /** \ingroup avr_eeprom
        Read one 32-bit double word (little endian) from EEPROM address \a __p.
    */

    uint32_t eeprom_read_dword (const uint32_t *__p) __ATTR_PURE__;

    /** \ingroup avr_eeprom
        Read one float value (little endian) from EEPROM address \a __p.
    */

    float eeprom_read_float (const float *__p) __ATTR_PURE__;

    /** \ingroup avr_eeprom
        Read a block of \a __n bytes from EEPROM address \a __src to SRAM
        \a __dst.
    */

    void eeprom_read_block (void *__dst, const void *__src, size_t __n);
     
    понятия не имею что это и как оно работает, но вроде оно работает и еще никто не жаловался. не факт ваще что это именно то что используется
     
    parovoZZ нравится это.
  9. Vovka

    Vovka Гик

    есть, но разговор о eeprom_read_byte()
    т.е. вы хотите сказать, что компилятор игнорирует это:
    Код (C++):
    #include <eeprom.h>
     
  10. Unixon

    Unixon Оракул Модератор

    С чего вы это решили? Указатель на uint8_t вовсе не обязан иметь размер 1 байта.
    Проверьте:

    Код (C++):
    Serial.print("sizeof(uint8_t*)=");
    Serial.println(sizeof(uint8_t*));

    Serial.print("sizeof(void*)=");
    Serial.println(sizeof(void*));
     
    parovoZZ и SergeiL нравится это.
  11. a1000

    a1000 Гуру

    Это всё заголовки. Самого тела функции нет. Не видно что пишется в EEAR. EEAR это двухбайтный регистр, так-что интовое значение в него влезет.
     
  12. Vovka

    Vovka Гик

    Для того, чтобы не было путаницы, специально были введены такие типы! Если написано 8 - значит число должно быть 8-и битным!
    https://ru.wikipedia.org/wiki/Stdint.h
     
  13. SergeiL

    SergeiL Оракул Модератор

    Это указатель на байт, и uint8_t с с разрядностью адреса ни как не связан.
     
    parovoZZ нравится это.
  14. Vovka

    Vovka Гик

    Указатель скольки битный?
     
  15. Unixon

    Unixon Оракул Модератор

    Вот код из библиотеки AVR GCC
    Код (Text):

    #include <avr/io.h>

    #if    E2END && __AVR_ARCH__ > 1

    #include <avr/eeprom.h>
    #include "asmdef.h"
    #include "eedef.h"

    /* uint8_t eeprom_read_byte (uint8_t EEMEM *addr);
    */

    #define ret_lo    r24
    #define    ret_hi    r25

    ENTRY    eeprom_read_byte

    #if    __AVR_XMEGA__    /* --------------------------------------------    */

        rcall    eeprom_mapen
        ld    ret_lo, Z
        clr    ret_hi
        ret

    ENTRY    eeprom_mapen

      ; It has to be noted that for some Xmega parts (Eg. Xmega E family) EEPROM
      ; is always memory mapped. So it is not required to  enable EEPROM mapping
      ; explicitly.
      ; The presence of NVM_EEMAPEN_bm macro (from the part header file) can be
      ; checked to find out whether the device supports enabling/disabling of
      ; EEPROM mapping. Absence of NVM_EEMAPEN_bm could be interpreted safely as
      ; EEPROM always memory mapped and explicit memory mapping of EEPROM is not
      ; required/invalid.
    #if     defined (NVM_EEMAPEN_bm)
      ; Load base address of NVM.
        ldi    ZL, lo8(NVM_BASE)
        ldi    ZH, hi8(NVM_BASE)

      ; Wait until NVM is not busy.
    1:    ldd    r19, Z + NVM_STATUS - NVM_BASE
        sbrc    r19, NVM_NVMBUSY_bp
        rjmp    1b

      ; Enable EEPROM mapping into data space.
        ldd    r19, Z + NVM_CTRLB - NVM_BASE
        ori    r19, NVM_EEMAPEN_bm
        std    Z + NVM_CTRLB - NVM_BASE, r19
    #endif

      ; Load Z with correct EEPROM address to read from data space.
        movw    ZL, addr_lo
        subi    ZL, lo8(-MAPPED_EEPROM_START)
        sbci    ZH, hi8(-MAPPED_EEPROM_START)

        ret

    #else            /* --------------------------------------------    */

    1:    sbic    _SFR_IO_ADDR (EECR), EEWE
        rjmp    1b
    # ifdef     EEARH
    #  if      E2END > 0xFF
        out    _SFR_IO_ADDR (EEARH), addr_hi
    #  else
        ; This is for chips like ATmega48: the EEAR8 bit must be cleaned.
        out    _SFR_IO_ADDR (EEARH), __zero_reg__
    #  endif
    # endif
        out    _SFR_IO_ADDR (EEARL), addr_lo
        sbi    _SFR_IO_ADDR (EECR), EERE
        clr    ret_hi
        in    ret_lo, _SFR_IO_ADDR (EEDR)
        ret

    #endif            /* --------------------------------------------    */

    ENDFUNC


    #endif    /* E2END && __AVR_ARCH__ > 1 */
     
    Код (Text):

    /* $Id$    */

    #ifndef    __DOXYGEN

    #include <avr/io.h>

    #if    E2END && __AVR_ARCH__ > 1

    #include <avr/eeprom.h>
    #include "asmdef.h"
    #include "eedef.h"

    ENTRY    eeprom_write_byte
        mov    r18, r22

    ENTRY    eeprom_write_r18

    #if  __AVR_XMEGA__    /* --------------------------------------------    */

    # ifndef CCP_IOREG_gc
    #  define CCP_IOREG_gc    0xD8    /* IO Register Protection    */
    # endif
    # ifndef NVM_CMD_READ_EEPROM_gc
    #  define NVM_CMD_READ_EEPROM_gc        0x06
    # endif
    # ifndef NVM_CMD_LOAD_EEPROM_BUFFER_gc
    #  define NVM_CMD_LOAD_EEPROM_BUFFER_gc        0x33
    # endif
    # ifndef NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc
    #  define NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc    0x35
    # endif
    # ifndef  NVM_CMD_ERASE_EEPROM_BUFFER_gc
    #  define NVM_CMD_ERASE_EEPROM_BUFFER_gc    0x36
    # endif

    #if    ! defined (NVM_EEMAPEN_bm)
      ; Saving X register because it might contain source address of block
        push XL
        push XH
    #endif

      ; Prepare base address of NVM.
        ldi    ZL, lo8(NVM_BASE)
        ldi    ZH, hi8(NVM_BASE)

      ; Wait until NVM is not busy.
    1:    ldd    r19, Z + NVM_STATUS - NVM_BASE
        sbrc    r19, NVM_NVMBUSY_bp
        rjmp    1b

      ; It has to be noted that for some Xmega parts (Eg. Xmega E family) EEPROM
      ; is always memory mapped. So it is not possible to disable EEPROM mapping
      ; explicitly.
      ; The presence of NVM_EEMAPEN_bm macro (from the part header file) can be
      ; checked to find out whether the device supports enabling/disabling of
      ; EEPROM mapping. Absence of NVM_EEMAPEN_bm could be interpreted safely as
      ; EEPROM always memory mapped and explicit memory mapping of EEPROM is not
      ; required/invalid.
    #if     defined (NVM_EEMAPEN_bm)
      ; Disable EEPROM mapping into data space.
        ldd    r19, Z + NVM_CTRLB - NVM_BASE
        andi    r19, ~NVM_EEMAPEN_bm
        std    Z + NVM_CTRLB - NVM_BASE, r19

      ; Check the clearance of EEPROM page buffer.
        ldd    r19, Z + NVM_STATUS - NVM_BASE
        sbrs    r19, NVM_EELOAD_bp
        rjmp    3f            ; erase is not required

      ; Note that we have only four clock cycles to write to the CCP
      ; protected register NVM_CTRLA, after writing to CCP.  The 'ldi'
      ; instruction always takes one clock to execute and 'std' instruction takes
      ; two clock cycles.  We fall within the four cycles that the CCP leaves
      ; us to write the command execution start bit to the NVM_CTRLA
      ; register.  Note that r18 must be preserved until written to NVM_DATA0

      ; Issue EEPROM Buffer Erase:
        ldi    r19, NVM_CMD_ERASE_EEPROM_BUFFER_gc
        std    Z + NVM_CMD - NVM_BASE, r19
        ldi    r19, CCP_IOREG_gc
        out    CCP, r19
        ldi    r19, NVM_CMDEX_bm
        std    Z + NVM_CTRLA - NVM_BASE, r19

      ; Wait until NVM is not busy.
    2:    ldd    r19, Z + NVM_STATUS - NVM_BASE
        sbrc    r19, NVM_NVMBUSY_bp
        rjmp    2b

      ; Issue EEPROM Buffer Load command.
    3:    ldi    r19, NVM_CMD_LOAD_EEPROM_BUFFER_gc
        std    Z + NVM_CMD - NVM_BASE, r19

        std    Z + NVM_ADDR0 - NVM_BASE, addr_lo
        std    Z + NVM_ADDR1 - NVM_BASE, addr_hi
        std    Z + NVM_ADDR2 - NVM_BASE, __zero_reg__

        std    Z + NVM_DATA0 - NVM_BASE, r18
    #else
          movw     XL, addr_lo
        subi    XL, lo8(-MAPPED_EEPROM_START)
        sbci    XH, hi8(-MAPPED_EEPROM_START)
        st    X, r18
    #endif

      ; Issue EEPROM Erase & Write command.
    #if defined(NVMCTRL_CTRLA)
        ldi    r18, CCP_SPM_gc
        out CCP, r18
        ldi    r18, NVMCTRL_CMD_PAGEERASEWRITE_gc
        std    Z + NVMCTRL_CTRLA - NVM_BASE, r18
    #else
        ldi    r18, NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc
        std    Z + NVM_CMD - NVM_BASE, r18
        ldi    r18, CCP_IOREG_gc
        ldi    r19, NVM_CMDEX_bm
        out    CCP, r18
        std    Z + NVM_CTRLA - NVM_BASE, r19
    #endif

      ; Increment address.
        adiw    addr_lo, 1

    #if    ! defined (NVM_EEMAPEN_bm)
      ; Restoring X register
        pop XH
        pop XL
    #endif  

        ret

    #else        /* ----------------------------------------------------    */

    1:    sbic    _SFR_IO_ADDR (EECR), EEWE
        rjmp    1b

    # if     defined (EEPM0) && defined (EEPM1)
        ; Set programming mode: erase and write.
        out    _SFR_IO_ADDR (EECR), __zero_reg__
    # elif     defined (EEPM0) || defined (EEPM1)
    #  error    /* Unknown EECR register.    */
    # endif

    # ifdef     EEARH
    #  if      E2END > 0xFF
        out    _SFR_IO_ADDR (EEARH), addr_hi
    #  else
        ; This is for chips like ATmega48: the EEAR8 bit must be cleaned.
        out    _SFR_IO_ADDR (EEARH), __zero_reg__
    #  endif
    # endif
        out    _SFR_IO_ADDR (EEARL), addr_lo
        out    _SFR_IO_ADDR (EEDR), r18
        in    __tmp_reg__, _SFR_IO_ADDR (SREG)
        cli
        sbi    _SFR_IO_ADDR (EECR), EEMWE
        sbi    _SFR_IO_ADDR (EECR), EEWE
        out    _SFR_IO_ADDR (SREG), __tmp_reg__
        adiw    addr_lo, 1
        ret

    #endif        /* ----------------------------------------------------    */

    ENDFUNC

    #endif    /* E2END && __AVR_ARCH__ > 1 */
     
     
  16. SergeiL

    SergeiL Оракул Модератор

    Все зависит от процессора и того к чему обращаемся.
    Компилятор сам выберет необходимую разрядность.
     
    parovoZZ нравится это.
  17. Vovka

    Vovka Гик

    Тогда зачем так адреса расписали:
    Код (C++):

    uint8_t eeprom_read_byte (const uint8_t *__p) __ATTR_PURE__;
    uint16_t eeprom_read_word (const uint16_t *__p) __ATTR_PURE__;
    uint32_t eeprom_read_dword (const uint32_t *__p) __ATTR_PURE__;
     
     
  18. SergeiL

    SergeiL Оракул Модератор

    Это не адреса, это размер данных, которые мы читаем из памяти.
     
    parovoZZ нравится это.
  19. Nekto_nikto

    Nekto_nikto Гик

    Ну вообще то ТОЛЬКО от разрядности процессора/контроллера.
     
    parovoZZ нравится это.
  20. Nekto_nikto

    Nekto_nikto Гик

    Это называется перегруженная функция, погуглите...
     
    parovoZZ нравится это.