Forum: Mikrocontroller und Digitale Elektronik Übersetzung C / ASM (PeDa's 124-BUS)


von M. P. (phpmysqlfreak)


Lesenswert?

Hallo Zusammen,

(Zu erst einmal: Ich hoffe, es ist der richtige Bereich. Einen anderes 
Thema zum Programmieren habe ich nach einem Tag hier und nicht mehr in 
der Codesammlung gefunden. Falls es falsch ist, bitte Verschieben.)

Nun zu meinem Vorhaben und dem Problem dabei:

Ich habe mir vorgenommen, ein LCD an einem 74164 über einen Tiny13 zu 
steuern. Der Tiny13 soll lediglich die erhaltenen Daten der seriellen 
Kommunikationsmöglichkeit an das Display weiterreichen.

Da ich das ganze in Assembler realisieren möchte, weil ich dort genug 
Erfahrung für das geplante vorgehen habe (wie ich denke), bin ich zur 
Zeit dabei, den 124Bus von PeDa in Assembler zu übersetzen. (Ich habe 
keine ASM-Version gefunden, oder habe den falschen Suchbegriff genutzt.) 
- Vorgestellt wird der Bus hier:
Beitrag "mehrere MC seriell über Datenbus verbinden (1Draht)"

Das Übersetzen macht mir bislang auch keine Probleme, da der Code auch 
ausreichend kommentiert ist. Jedoch habe ich ein Problem im 
Compare-Match-A Vektor seines Codes. Es geht um folgenden Ausschnitt:
1
ISR( TIMER2_COMPA_vect )                        // Transmit interrupt
2
{
3
  uint8_t *dp;          // locals for faster access
4
5
  if( tx_idx < DATA_SIZE * 8 ){
6
    OCR2A = BIT_TIME * 1 - 0.5;                 // 0-bit: 1T
7
    dp = &tx_buff[tx_idx++ / 8];                // get byte address
8
    if( *dp & 0x80 )                            // msb first
9
      OCR2A = BIT_TIME * 2 - 0.5;               // 1-bit: 2T
10
    *dp <<= 1;                                  // shift bits
11
  }else{
12
    OCR2A = BIT_TIME * 4 - 0.5;                 // stop:  4T
13
    if( DATA_PIN )                              // after output = high
14
      TCCR2B = 0;                               // then stop T1
15
  }
16
}

Umgesetzt habe ich bereits folgendes:
1
T0CMA:
2
  cpi TX_IDX, DATA_SIZE*8
3
  brlo GETDATA
4
  ;; Stop: 4T
5
  ldi iwr0, tBIT*4 - 0.5
6
  out OCR0A, iwr0
7
  ;; Nach Output=High
8
  in iwr0, DIN
9
  andi iwr0, (1 << DPIN)
10
  ldi iwr1, 0
11
  cpse iwr0, iwr1
12
  rjmp T0W
13
  ;; Wenn Bed. WAHR, Timer stoppen
14
  ldi iwr0, 0
15
  out TCCR0B, iwr0
16
  rjmp T0W
17
  GETDATA:
18
  ;; 0-Bit: 1T
19
  ldi iwr0, tBIT - 0.5
20
  out OCR0A, iwr0
21
22
  ; get byte address
23
  ; dp = &tx_buff[tx_idx++ / 8];
24
  ; if(*dp & 0x80)
25
  ;; 1-Bit: 2T
26
  ldi iwr0, tBIT*2-0.5
27
  out OCR0A, iwr0
28
  ; *dp <<=1;
29
30
  T0W:
31
  reti

Mein Problem ist jetzt aber der Pointer "dp". Wie wird mit diesem 
gearbeitet und wie wird er bearbeitet? Mein C-Verständnis hört an dieser 
Stelle leider auf.
Kann mir bitte einer erklären, was im WAHR-Zweig
der  " if( tx_idx < DATA_SIZE * 8 ){ " - Bedingung  Stück für Stück
bearbeitet wird?

OCR2A = BIT_TIME * 1 - 0.5;                 // 0-bit: 1T
Der OCR2A-Wert wird auf BIT_TIME - 0.5 gesetzt

dp = &tx_buff[tx_idx++ / 8];                // get byte address
Aber hier stehe ich auf dem Schlauch. TX_IDX wird um 1 erhöht, und als 
Index des TX_BUFF-Arrays wird ein 8tel des erhöhten TX_IDX-Wertes 
genutzt.
Aber welchen Wert nimmt "dp" in diesem Fall an? (Wg. _&_tx_buff)

Meine nächste Problem-Stelle -kommentiert mit "msb first" - ist:
if( *dp & 0x80 )
Was (Adresse oder Wert) wird hier mit 0x80 ver-und-et und geprüft?
Das Verständnis dieser Abfrage erschließt sich mit wahrscheinlich, wenn 
ich das vorhergehende Problem verstehe.

*dp <<= 1;
Was bedeutet _<<=_? Wird hier nach links verschoben, und mit einer 1 
aufgefüllt? Eine zyklische Verschiebung wäre doch nur _<<_?

Nach so viel Text erstmal recht herzlichen Dank, dass ihr Versucht, mein 
Problem zu verstehen. ;)

Gruß,
Marcel

von Karl H. (kbuchegg)


Lesenswert?

Marcel Papst schrieb:

> dp = &tx_buff[tx_idx++ / 8];                // get byte address
> Aber hier stehe ich auf dem Schlauch. TX_IDX wird um 1 erhöht, und als
> Index des TX_BUFF-Arrays wird ein 8tel des erhöhten TX_IDX-Wertes
> genutzt.
> Aber welchen Wert nimmt "dp" in diesem Fall an? (Wg. _&_tx_buff)

dp ist die Adresse dieses Bytes im Speicher

> Meine nächste Problem-Stelle -kommentiert mit "msb first" - ist:
> if( *dp & 0x80 )

Hier wird das Byte, dessen Adresse vorher ausgerechnet wurde mit 0x80 
und verknüpft.

> Das Verständnis dieser Abfrage erschließt sich mit wahrscheinlich, wenn
> ich das vorhergehende Problem verstehe.
>
> *dp <<= 1;
> Was bedeutet _<<=_? Wird hier nach links verschoben, und mit einer 1
> aufgefüllt? Eine zyklische Verschiebung wäre doch nur _<<_?

Selbiges.
Das ganze hat nur 'optimierende' Eigenschaften. Du kannst dp auch 
einfach loswerden (für deine Transkription) durch Rückübersetzung
1
  if( tx_idx < DATA_SIZE * 8 ){
2
    OCR2A = BIT_TIME * 1 - 0.5;                 // 0-bit: 1T
3
    if( tx_buff[tx_idx / 8] & 0x80 )                            // msb first
4
      OCR2A = BIT_TIME * 2 - 0.5;               // 1-bit: 2T
5
    tx_buff[tx_idx / 8] <<= 1;                                  // shift bits
6
    tx_idx++;
7
  }else{

und jetzt siehst du, dass hier in diesem Code um Grunde die 
Adressberechnung des Bytes an 2 Stellen gemacht werden müsste. Der 
Pointer hat hier einfach nur die Aufgabe, die Arrayindizierung an einer 
Stelle zusammenzuziehen und so zu garantieren, dass sie nur einmal 
gemacht wird.

von Stefan E. (sternst)


Lesenswert?

Marcel Papst schrieb:
> *dp <<= 1;
> Was bedeutet _<<=_? Wird hier nach links verschoben, und mit einer 1
> aufgefüllt? Eine zyklische Verschiebung wäre doch nur _<<_?

Nein. Die 1 bedeutet "um eine Stelle". Aufgefüllt wird immer mit 0.

von M. P. (phpmysqlfreak)


Lesenswert?

Hallo nochmal,

Erst mal an Stefan:

Stefan Ernst schrieb:
> Nein. Die 1 bedeutet "um eine Stelle". Aufgefüllt wird immer mit 0.

Das immer mit einer 0 aufgefüllt wird, war mir eigentlich klar, das 
zusätzliche "=" jedoch, machte mich nachdenklich bzgl. der Funktion 
dieses Operators. Ich habe es zuvor noch nie so bewusst gesehen. KHB hat 
dazu eine ausreichende Erklärung geliefert. Trotzdem vielen Dank für 
deine Antwort.


Karl Heinz Buchegger schrieb:
> Du kannst dp auch
> einfach loswerden (für deine Transkription) durch Rückübersetzung
>   if( tx_idx < DATA_SIZE * 8 ){
>     OCR2A = BIT_TIME * 1 - 0.5;                 // 0-bit: 1T
>     if( tx_buff[tx_idx / 8] & 0x80 )                            // msb first
>       OCR2A = BIT_TIME * 2 - 0.5;               // 1-bit: 2T
>     tx_buff[tx_idx / 8] <<= 1;                                  // shift bits
>     tx_idx++;
>   }else{
>
> und jetzt siehst du, dass hier in diesem Code um Grunde die
> Adressberechnung des Bytes an 2 Stellen gemacht werden müsste.

Ja, das sehe ich. Es hilft dem Code-Verständnis ungemein.

Ich habe mir zur weiteren Übersetzung auch das LST-File des 
Original-Codes angeschaut. Ich denke, dass es mir geholfen hat.

Analog zu Assembler:
Ist der folgende ASM-Code gleichwertig zu der oberen Vorgehensweise, 
oder habe ich noch Fehler eingebaut? (Ohne Beachtung von Push und Pop, 
welche ich noch nicht eingebaut habe.
Die Quelle der Übersetzung - um sie genauer zu bezeichnen - ist der 
Timer2-Compare-Match-A-Vector aus der "Slave1.c".
1
.def iwr0  = r16
2
.def iwr1  = r17
3
.def temp1  = r20
4
.def temp2  = r21
5
.def TX_IDX  = r22
6
.equ tBIT  = 1000 / 64
7
.equ DIN  = PINB
8
.equ DPIN  = PB0  ;; PB0 = OC0A
9
.equ DATA_SIZE  = 2
10
11
T0CMA:
12
  cpi TX_IDX, DATA_SIZE*8
13
  brlo GETDATA
14
  ;; Stop: 4T
15
  ldi iwr0, tBIT*4 - 0.5
16
  out OCR0A, iwr0
17
  ;; Nach Output=High
18
  in iwr0, DIN
19
  andi iwr0, (1 << DPIN)
20
  ldi iwr1, 0
21
  cpse iwr0, iwr1
22
  rjmp T0W
23
  ;; Wenn Bed. WAHR, Timer stoppen
24
  ldi iwr0, 0
25
  out TCCR0B, iwr0
26
  rjmp T0W
27
  GETDATA:
28
  ;; 0-Bit: 1T
29
  ldi iwr0, tBIT - 0.5
30
  out OCR0A, iwr0
31
  ;; TX_IDX sichern
32
  mov temp1, TX_IDX
33
  inc TX_IDX
34
  ;; Durch 8 Teilen
35
  lsr temp1
36
  lsr temp1
37
  lsr temp1
38
  ;; Zeiger einstellen:
39
  ldi ZL, LOW(TX_BUFF)
40
  ldi ZH, HIGH(TX_BUFF)
41
  ;; und "temp1" dazuaddieren
42
  ldi temp2, 0
43
  add ZL, temp1
44
  adc ZH, temp2
45
  ;; Wert laden
46
  ld iwr0, Z
47
  ;; Wert sichern und nach links verschieben
48
  mov temp2, iwr0
49
  lsl temp2
50
  ;; Wert mit 0x80 verknüpfen
51
  ldi iwr1, 0x80
52
  and iwr0, iwr1
53
  ;; OCR-Wert vorladen
54
  ldi temp1, tBIT*2-0.5
55
  ldi iwr1, 0
56
  ;; If-Bedingung ausführen
57
  cpse iwr0, iwr1
58
  ;; und wenn sie wahr ist, OCR laden
59
  out OCR0A, temp1
60
  ;; Wert zurückschreiben
61
  st Z, temp2
62
  ;; TX_IDX erhöhen
63
  inc TX_IDX
64
  T0W:
65
  reti
66
67
.dseg
68
TX_BUFF:  .byte DATA_SIZE

(Ich halte diese Routine noch für kurz, daher noch nicht als File 
angehängt.)

Gruß,
Marcel

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.