Как в avr tiny данные должны храниться в sram, инициализированном при включении микроконтроллера?

Сначала немного предыстории. В avr tiny данные могут храниться в регистрах, в sram, в eeprom или в программном пространстве. Регистр и sram являются энергозависимой памятью, в то время как eeprom и пространство программы - нет. (т.е. данные остаются, когда питание не подается.)

При программировании на c (используя библиотеки avr-gcc) типичный код может выглядеть так:

#define F_CPU 8000000UL
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>

//This data is put in the eeprom
const uint8_t dat_eeprom EEMEM= 0xab;
//This data is put in the program space
const uint8_t dat_pgm_space PROGMEM= 0xcd;
//This data is stored in the sram
uint8_t dat_sram = 0xef;

int main(){
    while(1){
    ;;
    }
}

Компиляция с:

avr-gcc -g -mmcu=attiny44 -o test.elf test.c

И извлечение intel .hex из .elf :

avr-objcopy -j .text -j .data -O ihex test.elf test.hex

Получаем следующий test.hex:

:1000000011C023C022C021C020C01FC01EC01DC0FF
:100010001CC01BC01AC019C018C017C016C015C01C
:1000200014C0CD0011241FBECFE5D1E0DEBFCDBF8F
:1000300010E0A0E6B0E0EAE5F0E002C005900D9225
:10004000A236B107D9F702D006C0DACFCF93DF933B
:0A005000CDB7DEB7FFCFF894FFCF65
:02005A00EF00B5
:00000001FF

И следующая разборка:

00000000 <.sec1>:
0:  11 c0           rjmp    .+34        ;  0x24
      <...skipped interrupt vector table...> 
20: 14 c0           rjmp    .+40        ;  0x4a
22: cd 00           .word   0x00cd  ; this is our data stored in the program mem.
24: 11 24           eor r1, r1  
26: 1f be           out 0x3f, r1    ; 63
28: cf e5           ldi r28, 0x5F   ; 95
2a: d1 e0           ldi r29, 0x01   ; 1
2c: de bf           out 0x3e, r29   ; 62
2e: cd bf           out 0x3d, r28   ; 61
30: 10 e0           ldi r17, 0x00   ; 0
32: a0 e6           ldi r26, 0x60   ; X register low byte ; address of dest. in
34: b0 e0           ldi r27, 0x00   ; X register high byte; sram
36: ea e5           ldi r30, 0x5A   ; z register low byte ; address of data in 
38: f0 e0           ldi r31, 0x00   ; z register high byte; program memory
3a: 02 c0           rjmp    .+4         ;  0x40
3c: 05 90           lpm r0, Z+
3e: 0d 92           st  X+, r0
40: a2 36           cpi r26, 0x62   ; 98
42: b1 07           cpc r27, r17
44: d9 f7           brne    .-10        ;  0x3c
          <...skipped rcall to main...>
5a: ef 00           .word   0x00ef  ; this is our data that
                                      should be stored in the sram.

Так как же инициализируются данные (0xef), которые мы хотели поместить в sram?
Ответ — через подпрограмму перед main.

Данные, которые должны храниться в оперативной памяти, находятся по адресу 0x5a в программном пространстве. Он помещается в срам следующим образом:

  1. Старший и младший байт регистра x устанавливаются на адрес, куда мы хотим поместить данные в sram. (0x60) обратите внимание, что этот адрес находится не в памяти программ, а в памяти данных.
  2. То же самое для регистра z, но с адресом, где данные находятся в пространстве программы (0x5a)
  3. содержимое памяти программ по адресу, хранящемуся в регистре z, загружается в регистр r0 с помощью кода операции lpm. Обратите внимание, что значение регистра z увеличивается, чтобы указать на (возможные, здесь нет) следующие данные для загрузки в sram.
  4. данные в r0 затем сохраняются в sram по адресу, хранящемуся в регистре x.
  5. Повторяйте до тех пор, пока все данные, которые должны быть в sram, не будут инициализированы.

Это происходит перед повторным вызовом на главную.

Есть ли лучший / более ясный ответ?


person user1443332    schedule 08.06.2012    source источник


Ответы (2)


Правильно, в мире инструментов gnu и, конечно же, аналогичным образом с другими инструментами.

компоновщик получает данные .text, .data, .bss и должен поместить их в двоичный файл. для системы на основе флэш-памяти ничего особенного для avr, одинаково для всех платформ, вся энергонезависимая информация должна быть на флэш-памяти. Сценарий компоновщика сообщает компоновщику, что у сегмента .data есть два дома, один дом связан с .text и чем-то еще во флэш-памяти, а затем дом в адресном пространстве оперативной памяти. Вы создаете свой скрипт компоновщика с некоторыми ключевыми словами, которые компоновщик заполнит внешними переменными в вашем загрузочном коде (asm, который вызывает main). Этот код использует эти переменные для копирования .data в ram и для обнуления .bss перед вызовом main, чтобы предположения языка C (неинициализированные переменные равны нулю, а инициализированные переменные — это то, чем их инициализировал ваш код). Если вы пишете свой код так, что вы никогда не предполагаете, что переменная инициализируется до main, вам не нужно будет делать ничего из этого, ваш pre-main код инициализации может просто установить указатель стека и ветвь на main.

person old_timer    schedule 08.06.2012

Если вам нужны данные в SRAM, ваша программа должна поместить их туда.

Вот, сделал это для тебя.

person starbolin    schedule 08.06.2012
comment
Да, теперь это очевидно для меня, но я потратил немного времени на то, чтобы понять, почему данные, которые я хотел в sram, были в конце .hex . Надеюсь, это поможет кому-то. - person user1443332; 08.06.2012