Forum: Mikrocontroller und Digitale Elektronik #define-Statements durch Variablen ersetzen


von Sonovice (Gast)


Lesenswert?

Hallo zusammen,

ich versuche gerade, eine SoftI2C Lib 
(http://homepage.hispeed.ch/peterfleury/avr-software.html bzw. direkt: 
http://homepage.hispeed.ch/peterfleury/i2cmaster.zip) so umzuschreiben, 
dass ich das ganze mehrfach (mit verschiedenen Pins) verwenden kann. Von 
Haus aus erlaubt die Library lediglich einen SoftI2C-Bus.

Leider bin ich keine große ASM-Leuchte und bin daher ein wenig ratlos: 
Im Quelltext werden die SDA- und SCL-Pins durch #define-Statemens 
gesetzt. Ich müsste das ganze jedoch durch Variablen ersetzen, um 
dynamisch auf die korrekten Pins zugreifen zu können.

Vermutlich ist die Sache mit etwas Erfahrung schnell gegessen, aber 
bevor ich jetzt für dieses Detail von GCC auf ASM umsteige, wollte ich 
doch lieber kurz nachfragen, ob jemand vllt eine Idee hat?

Gute Nacht
Sonovice

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Sonovice schrieb:
> (mit verschiedenen Pins)
An verschiedenen Ports?

> Vermutlich ist die Sache mit etwas Erfahrung schnell gegessen
Vermutlich nicht...
Hier mal ein Ausschnitt:
1
;***** Adapt these SCA and SCL port and pin definition to your target !!
2
#define SDA       4    // SDA Port D, Pin 4   
3
#define SCL    5    // SCL Port D, Pin 5
4
#define SDA_PORT        PORTD           // SDA Port D
5
#define SCL_PORT        PORTD           // SCL Port D         
6
;******
7
8
#define SDA_DDR    (_SFR_IO_ADDR(SDA_PORT) - 1)
9
#define SCL_DDR    (_SFR_IO_ADDR(SCL_PORT) - 1)
10
#define SDA_OUT    _SFR_IO_ADDR(SDA_PORT)
11
#define SCL_OUT    _SFR_IO_ADDR(SCL_PORT)
12
#define SDA_IN    (_SFR_IO_ADDR(SDA_PORT) - 2)
13
#define SCL_IN    (_SFR_IO_ADDR(SCL_PORT) - 2)
14
15
:
16
:
17
18
i2c_init:
19
  cbi SDA_DDR,SDA    ;release SDA
20
  cbi SCL_DDR,SCL    ;release SCL
21
  cbi SDA_OUT,SDA
22
  cbi SCL_OUT,SCL
23
  ret
Die Zugriffe erfolgen über IO-Bit-Befehle, deren Parameter zur 
Übersetzungszeit festgelegt sind. Das zu ändern ist eine Operation am 
offenen Herzen. Insbesondere das zeitliche Verhalten wird sich durch die 
dynamische Auswahl drastisch ändern. Denn dann können nicht mehr die 
schnellen cbi/sbi Befehle genommen werden, sondern es geht langsam über 
ld/st Befehle (bei denen zusätzlich noch der vorige Inhalt der 
X(YZ)-Register gesichert und wiederhergestellt werden muss) und 
Read-Modify-Write Abläufe, bei denen zudem Interrupts gesperrt werden 
müssen...

> so umzuschreiben, dass ich das ganze mehrfach (mit verschiedenen Pins)
> verwenden kann.
Wozu brauchst du mehrere Soft-I2C? Der Prozessor kann sowieso immer nur 
1 gleichzeitig bedienen...
Wenn du viele gleiche Slaves anschließen willst, die aber nur 1 
umschaltbare Adressleitung haben, dann könntest du diese Leitung evtl. 
als "Chip-Select" verwenden, und nur dem einen Slave, den du ansprechen 
willst, die richtige Adresse aufschalten.

: Bearbeitet durch Moderator
von Sonovice (Gast)


Lesenswert?

Herzlichen Dank für deine Antwort.

Lothar Miller schrieb:
> An verschiedenen Ports?
Ja, leider.

> Hier mal ein Ausschnitt:
>   #define SDA_DDR    (_SFR_IO_ADDR(SDA_PORT) - 1)
_SFR_IO_ADDR hat doch sicherlich ein C-Äquivalent, oder?

> i2c_init:
>   cbi SDA_DDR,SDA    ;release SDA
>   cbi SCL_DDR,SCL    ;release SCL
>   cbi SDA_OUT,SDA
>   cbi SCL_OUT,SCL
>   ret
> Die Zugriffe erfolgen über IO-Bit-Befehle, deren Parameter zur
> Übersetzungszeit festgelegt sind.
Dazu habe ich eine Frage. Am Ende jeder Funktion stehen ein paar Zeilen, 
die offensichtlich die Register auf andere "Variablen" mappen:
1
boolean i2c_init(void)
2
{
3
  __asm__ __volatile__ 
4
    (" cbi      %[SDADDR],%[SDAPIN]     ;release SDA \n\t" 
5
     " cbi      %[SCLDDR],%[SCLPIN]     ;release SCL \n\t" 
6
     " cbi      %[SDAOUT],%[SDAPIN]     ;clear SDA output value \n\t" 
7
     " cbi      %[SCLOUT],%[SCLPIN]     ;clear SCL output value \n\t" 
8
     " clr      r24                     ;set return value to false \n\t"
9
     " clr      r25                     ;set return value to false \n\t"
10
     " sbis     %[SDAIN],%[SDAPIN]      ;check for SDA high\n\t"
11
     " ret                              ;if low return with false \n\t"  
12
     " sbis     %[SCLIN],%[SCLPIN]      ;check for SCL high \n\t"
13
     " ret                              ;if low return with false \n\t" 
14
     " ldi      r24,1                   ;set return value to true \n\t"
15
     " ret "
16
     : :
17
       [SCLDDR] "I" (SCL_DDR), [SCLPIN] "I" (SCL_PIN), 
18
       [SCLIN]  "I" (SCL_IN),  [SCLOUT] "I" (SCL_OUT),
19
       [SDADDR] "I" (SDA_DDR), [SDAPIN] "I" (SDA_PIN), 
20
       [SDAIN]  "I" (SDA_IN),  [SDAOUT] "I" (SDA_OUT)); 
21
  return true;
22
}
Wäre es nicht möglich, SCL_DDR etc. als Variablen zu betrachten und 
entsprechend unten anzugeben?

> Wozu brauchst du mehrere Soft-I2C? Der Prozessor kann sowieso immer nur
> 1 gleichzeitig bedienen...
Ich entwickle gerade (unter C) ein Framework für den Anschluss 
verschiedener Sensoren an meine Platine. Der Clou ist, dass alle 
benutzbaren Pins frei in ihrer Funktion sind, sodass man sich erst in 
der Software um die "Pinbelegung" kümmern muss und nicht schon auf 
Hardwareebene. Dass immer nur ein Gerät zur gleichen Zeit bedient werden 
kann, ist mir klar. Bei mehreren Sensoren wäre es dennoch ungemein 
praktisch und eleganter, als 2 große Multiplexer für SDA bzw. SCL zu 
benutzen.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Sonovice schrieb:
> Ich entwickle gerade (unter C) ein Framework für den Anschluss
> verschiedener Sensoren an meine Platine

Für solch eine Aufgabe reicht es aber nicht einfach Code aus anderen 
Quellen zusammenzukopieren.
Es wird dir also nichts anderes übrig bleiben, als den Code zu verstehen 
und dir idealerweise eine C-Zugriffsfunktion mit inline ASM zu erzeugen, 
oder gleich in C zu schreiben.

Für den (statischen) Ansatz könnte man im AVR Assembler Macros benutzen, 
aber auch da: Vorher muss der Code verstanden werden.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Sonovice schrieb:
> _SFR_IO_ADDR hat doch sicherlich ein C-Äquivalent, oder?
Das ist irgend eine Konstante. Deren Wert findest du im Abschnitt 
"Register Description" und/oder "Register Summary" des Datenblatts.

> Wäre es nicht möglich, SCL_DDR etc. als Variablen zu betrachten und
> entsprechend unten anzugeben?
Nein, weil die Parameter von cbi/sbi/sbis/sbic zum 
Übersetzungszeitpunkt statisch sein müssen. Denn die werden ja fest 
als Maschinencode ins Flash assembliert.

: Bearbeitet durch Moderator
von Sonovice (Gast)


Lesenswert?

Lothar Miller schrieb:
> Nein, weil die Parameter von cbi/sbi/sbis/sbic zum
> Übersetzungszeitpunkt statisch sein müssen. Denn die werden ja fest
> als Maschinencode ins Flash assembliert.
Okay, wusste nicht, dass das "Mapping" auch vom Präprozessor verarbeitet 
wird.

Läubi .. schrieb:
> Für solch eine Aufgabe reicht es aber nicht einfach Code aus anderen
> Quellen zusammenzukopieren.
Das ist mir klar, aber ich ging davon aus, dass es bei diesem gezielten 
Problem kein großer Akt mit der Anpassung wäre. So kann man sich irren. 
Ich werde wohl doch meine eigene Lösung komplett in C schreiben, die 
Geschwindigkeit sollte eigentlich ausreichen, dafür ist kein ASM nötig.

Dennoch danke euch beiden, jetzt bin ich schlauer.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Sonovice schrieb:
> Ich werde wohl doch meine eigene Lösung komplett in C schreiben
Sieh dir den Beitrag "AVR: Pointer IO-Register" und den 
Beitrag "AVR Port und Pin in Array ablegen und dann per Schleife drauf zugreifen" an.

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.