Forum: Mikrocontroller und Digitale Elektronik .dseg am Ende oder auch Anfang?


von Lukas G. (lukas88)


Lesenswert?

Hallo zusammen,

Blieb bei meinem Projekt  grad bei SRAM hängen.

Zunächst mal möchte ich sagen, das ich das SRAM zum ersten mal nutze. 
Hab bis jetzt alles mit Registern gemacht. Aber da meine Projekte immer 
umfangreicher werden, muss ich nun das SRAM benützen, um etwas Übersicht 
zu gewinnnen.

Zur Frage:

Spielt generell es ein Rolle WO ich die Assemblerdirektive;

.dseg
count:  .BYTE 1

im Code selbst hinschreibe?

Also ich meine nicht direkt im Code, sondern dort wo ich die Register 
deklariere also Am Ganz am Anfang, oder erst am Schluss?

Ich hab bei den ersten Versionen, das Codesegment ganz am Anfang 
deklariert, dann hat aber das Programm nicht mehr Funktioniert.

Hab ich es entfernt ging wieder alles wunderbar.

Schreibe ich es am Schluss funktioniert alles wie gewünscht, waber warum 
ist das SO? Oder mache ich sonst was verkehrt.


Mein Code (der Funktionsfähige =)
1
.nolist
2
.include "/home/lukas/Dokumente/AVR/includes/m8def.inc"
3
.list
4
5
;Register
6
7
.def  t1    = r16 ; temp Register
8
.def   z1    = r17 ; Zähler 1 für die Zeitmessung 
9
.def  stat  = r18 ; Status
10
.def  z2    = r19 ; Timer für Warteschleifen
11
.def    z3    = r20 ; Impulszähler
12
13
;Konstanten
14
.equ  PD       = PORTD
15
.equ  DD       = DDRD
16
17
.equ  PB      = PORTB
18
.equ  DB      = DDRB
19
20
.equ   F_CPU     = 4000000 ; Systemtakt in Hz
21
.equ  BAUD     = 9600    ; Baudrate
22
23
24
; Berechnungen 
25
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
26
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
27
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
28
 
29
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
30
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
31
.endif
32
33
;Vektoren
34
.org 0x0000
35
  rjmp   configurations
36
.org 0x0001
37
  rjmp  int_1
38
.org 0x0009
39
  rjmp  timer0_overflow
40
  
41
;Interrupts
42
int_1:
43
44
  ldi    stat,1 ; Wenn Interrupt ausgelöst stat auf 1
45
reti
46
47
timer0_overflow:
48
49
  inc    z2
50
  inc    z1
51
  
52
reti
53
54
;Sprungprgramme:
55
56
57
58
59
configurations:
60
61
  ldi      t1,LOW(RAMEND)  ;Stackpointer LOW
62
  out      SPL,t1
63
64
  ldi      t1,HIGH(RAMEND) ;Stackpointer HIGH
65
  out      SPH,t1
66
67
  ldi      t1,0x00  ;PortD als Eingang
68
  out      DD,t1
69
70
  ldi      t1,0xFF  ;Pullups PortD aktivieren 
71
  out      PD,t1  
72
73
  ldi      t1,0xFF  ;PortB als Ausgang
74
  out      DB,t1
75
76
  ldi      t1,0xFF  ;PortB Pullups deaktiviert
77
  out      PB,t1
78
79
  ldi      t1,(1<<ISC01)|(1<<ISC00) ; Interrupt auf steigende flanke
80
  out      MCUCR,t1
81
82
  ldi      t1,(1<<INT0) ; Interrupt auf INT0 aka PortD 2
83
  out      GICR,t1
84
85
  ldi      t1,(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) ;Senden aktivieren UART
86
  out      UCSRC,t1
87
  
88
  sbi      UCSRB,TXEN
89
  
90
  ldi      t1,(0<<CS02)|(1<<CS01)|(1<<CS00) ; Timer teiler  64
91
  out      TCCR0,t1
92
  
93
  ldi      t1,(1<<TOIE0) ; Interrupt bei Timer Interrupt
94
  out      TIMSK,t1
95
  
96
  clr      stat  ; Alles auf null sezen 
97
  clr      z2
98
  clr      z1
99
  clr      z3
100
  
101
  sei  ; Aktiviere Interrupts
102
  
103
main:
104
105
  cpi      stat,1   ;Wenn interrupt hat ausgelöst!
106
  breq    i_1 
107
  rjmp    main
108
i_1:
109
  clr      stat   ; stat auf null setzen
110
  clr      z2    ; Timer auf null setzen für Wartezeit     
111
i_2:
112
  cpi      stat,1   ; Prüfen ob Interrupt wären der Wartezeit ausgelöst hat!
113
  breq    i_1    ; Wenn ausgelöst, springe zurück zu  i_1
114
  cpi      z2,10  ; Wenn  wärend der Wartezeit kein Interrupt stattfand, wird der Impuls registriert!
115
  breq    impuls
116
  rjmp    i_2    ;
117
impuls:
118
  cpi      z3,0
119
  breq    m_start
120
m_ret:
121
  cpi      z3,10  ; z3 Inkrementieren bis 10 Impulse
122
  brsh    end
123
  inc      z3  
124
  clr      stat  
125
  rjmp    main  ; Zurück zu Anfang
126
m_start:
127
  clr      z1    ; Beim start, Zeitmessung beginnen 
128
  rjmp    m_ret  ; Zurück zum Impuszähler
129
  
130
end:
131
  sts      count,z1
132
  cbi      PB,0
133
w_1:
134
  clr      z2
135
w_2:
136
  cpi      z2,10
137
  breq    w_3
138
  rjmp    w_2
139
w_3:
140
  sbi      PB,0
141
  clr      z3 ; Impulszähler auf null setzen
142
  clr      stat
143
  rjmp    main
144
  
145
.dseg 
146
count:  .BYTE 1

von Karl H. (kbuchegg)


Lesenswert?

Lukas G. schrieb:

> Spielt generell es ein Rolle WO ich die Assemblerdirektive;
>
> .dseg
> count:  .BYTE 1
>
> im Code selbst hinschreibe?

Vom Prinzip her ist es wurscht.
Alles was unter .dseg kommt wird gesammelt und dem SRAM zugewiesen (in 
der Reihenfolge in der es von oben nach unten auftaucht)
Alles was unter .csef definiert wird, wird genaso gesammelt und dem 
Flash zugewiesen (wieder von oben nach unten).

.dseg bzw. .cseg sind also so ähnlich wie Umschalter, die bestimmen 
wohin das Nachfolgende gehört. Entweder SRAM oder Flash.

> Also ich meine nicht direkt im Code, sondern dort wo ich die Register
> deklariere also Am Ganz am Anfang, oder erst am Schluss?

Die Register definierst du sowieso nicht. Die gibt es schon. Was du 
vereinbarst, das sind andere Namen für die Register. Da geht es aber 
nicht darum, dass dafür irgendwelcher Code generiert werden soll oder 
dass irgendwelche Speicherreservierungen im SRAM gemacht werden sollen, 
sondern es geht einzig und alleine um eine Vereinabarung zwischen dir 
und dem Assembler-Übersetzungspogramm "Hör mal. Wenn ich in Zukunft 
'hamstibamsti' schreibe, dann meine ich damit das Register r18". Das 
kann daher stehen wo es will, solange es nur vor der ersten Verwendung 
des somit neu bekannt gemachten Namens passiert.

> Ich hab bei den ersten Versionen, das Codesegment ganz am Anfang
> deklariert, dann hat aber das Programm nicht mehr Funktioniert.

Was jetzt. Codesegment (.cseg) oder Datensegment (.dseg). Wenn weder das 
eine noch das andere angegeben ist, dann ist automatisch das Codesegment 
erst mal das 'aktive Segment'.

> Schreibe ich es am Schluss funktioniert alles wie gewünscht, waber warum
> ist das SO?

Weil du irgendeinen Fehler gemacht hast. Dann kann man aber nicht 
eruieren, wenn du die Version zeigst, die dann letzten Endes 
funktioniert.

von Michael U. (amiga)


Lesenswert?

Hallo,

.dseg ist das Datensegment, also der Ram. Kannst Du prinzipiell an 
beliebige Stelle schreiben, Du mußt nur daran denken, wieder auf .cseg 
(Codesegmeht) zu schalten, bevor Du wieder mit Programmcode schreibst.

Bei mir landen die .dseg-Sachen auch bei den Registerdefinitionen, vor 
dem Begin der Vektoren steht dann generll bei mir

.cseg

;Vektoren
.org 0x0000
  rjmp   configurations
.org 0x0001
  rjmp  int_1
.org 0x0009
  rjmp  timer0_overflow

um bei Deinem Progarmm zu bleiben.

Gruß aus Berlin
Michael

von Lukas G. (lukas88)


Lesenswert?

Ich glaub ich weis vo der Hund begraben liegt.

.cseg


Muss ich also in demfall anwenden wie .nolist & .list

Habs gerade ausprobiert, und es hat Funktioniert!

Komischerweise steht davon im Tutorial nichts. Aber dort ist .dseg ja 
auch am Schluss...

Besten dank für die Hilfe

mfg Lukas

von Michael U. (amiga)


Lesenswert?

Hallo,

Karl Heinz war wieder ausführlicher sehe ich gerade.

Ein Tipp von mir ganz allgemein:
verfalle nicht in den Trend, wenig tippen zu wollen.
Dann über lieber den Umgang nit Ctrl-c/ctrl-v, also kopieren/einfügen.

.equ  PD       = PORTD
.equ  DD       = DDRD

.equ  PB      = PORTB
.equ  DB      = DDRB

wenn schon, dann bei Deinem Programm:

.equ  KEY_PORT = PORTD
.equ  KEY_DDR  = DDRD
.equ  KEY_PIN  = PIND

.equ  LED_PORT  = PORTB
.equ  LED_DDR   = DDRB
.equ  LED_PIN   = PB0

...

  ldi      t1,0x00  ;PortD als Eingang
  out      KEY_DDR,t1

  ldi      t1,0xFF  ;Pullups PortD aktivieren
  out      KEY_PORT,t1

  ldi      t1,0xFF  ;PortB als Ausgang
  out      LED_DDR,t1

  ldi      t1,0xFF  ;PortB Pullups deaktiviert
  out      LED_PORT,t1

...

  sts      count,z1
  cbi      LED_PORT,LED_PIN
w_1:
  clr      z2
w_2:
  cpi      z2,10
  breq    w_3
  rjmp    w_2
w_3:
  sbi      LED_PORT,LED_PIN
  clr      z3 ; Impulszähler auf null setzen
  clr      stat

Ich habe nur eine Beispielstelle genommen.

Wenn Du jetzt die LED statt an PB0 an PC2 hängst, muß Du nur
.equ  LED_PORT  = PORTB
.equ  LED_DDR   = DDRB
.equ  LED_PIN   = PB0

in

.equ  LED_PORT  = PORTC
.equ  LED_DDR   = DDRC
.equ  LED_PIN   = PC2

"Spechende Namen" sind eine sehr praktische Hilfe, wenn man was ändern 
will oder nach 2 Jahren wieder in das Programm schaut.

Gruß aus Berlin
Michael

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.