Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In an avr tiny, how is data meant to be stored in sram initialized when the microcontroler is powered up?

First some background. In an avr tiny, data can be stored in the registers, in the sram, in the eeprom or in the program space. Register and sram are volatile storage while the eeprom and program space are not. (ie: data stay when not powered.)

When programming in c(using the avr-gcc libraries), a typical code might look like :

#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){
    ;;
    }
}

Compiling with :

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

And extracting an intel .hex from the .elf :

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

We get the following test.hex :

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

And the following dissassembly :

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.

So how is the data (0xef) that we wanted to put in sram initialized ?
The answer is via a routine before main.

The data that should be stored in the sram is at address 0x5a, in the program space. It is put in the sram in the following way :

  1. The x register high and low byte are set to the address of where we want to put the data in the sram.(0x60) note that this address is not in the program memory but in the data memory.
  2. Same for the z register, but with the address of where the data is in the program space (0x5a)
  3. the content of the program memory at the adress stored in the z register is loaded into register r0 via the lpm opcode. Note that the z register value is incremented to point on the (eventual, here none) next data to load into the sram.
  4. the data in r0 is then stored in the sram at the address stored in the x register.
  5. Repeat until all data that should be in sram has been initialized.

This happens before a rcall to the main.

Is there a better/clearer answer ?

like image 640
user1443332 Avatar asked Nov 13 '22 04:11

user1443332


1 Answers

Right, in the gnu tools world and certainly similar ways with other tools.

the linker is given .text, .data, .bss data and has to place it in the binary. for a flash based system, nothing specific to avr, same for all platforms, all non-volatile information has to be on flash. The linker script tells the linker that the .data segment has two homes, one home is tacked in with .text and whatever else in the flash, and then a home in ram address space. You craft your linker script with some keywords that the linker will fill in to external variables in your boot code (the asm that calls main). This code uses these variables to copy .data to ram and to zero out .bss before calling main so that C language assumptions (unitialized variables are zero and initialized variables are what your code initialized them to). If you write your code so that you never assume a variable is initialized before main then you wont have to do any of this, your pre-main init code can simply set the stack pointer and branch to main.

like image 156
old_timer Avatar answered Dec 21 '22 00:12

old_timer