Forum: Mikrocontroller und Digitale Elektronik SMBUS Clock erzeugen


von SNEMEIS (Gast)


Lesenswert?

Hallo Community,


wie ist es eurer Meinung nach am einfachsten einen Clock für den SMBUS 
zu generieren hab schon über ein Timer Interrupt hinbekommen jedoch als 
Dauerschleife. Gibt es eine Möglichkeit den Interrupt zu stoppen sodass 
ich nur den Clock 9 mal erzeuge mit eine Frequenz von 100kHz.


hier ist die Funktion zum Timer Initialisieren:


#include "TimerInit.h"

void Timer0 (void)
{
TCCR0B |= (1<<CS00); /* Precaler auf 1 (µC-Frequenz) */
TIMSK0 |= (1<<TOIE0); /* Overflow Interrupt erlauben */
TCNT0 = 240; /* Timer mit 240 vorgeladen */

_asm_ volatile  ("sei"); /* Interrupt global aktivieren */


}



hier die Interrupt Routine:

#include "TimerInit.h"
#include <avr/io.h>




ISR (TIMER0_OVF_vect)
{

 TCNT0 = 240; /* Timer mit 240 vorgeladen */
 PORTD ^= (1 << PD7);

}


und main:


#include <avr/io.h>

/*Ende Include*/



int main( void )
{
    unsigned int i;


  DDRD = ( 1 << PD7 ); /* PORTD PIN7 als Ausgang definiert (SMB Clock) 
*/


  Timer0();/* Funktion Timer aufrufen */
;

    while( 1 ) {                /* Endlosschleife */

    }
    return 0;
}



oder ist es doch besser mit der bib. delay.h zu arbeiten und einfach 
entsprechend dem SMB-Protokoll die Ports zuschalten?


P.S der Controller ist ein Mega88 8Mhz interner Clock.

von SNEMEIS (Gast)


Lesenswert?

hat keiner ne Idee? über den SMBus soll ein Laderegler eingestellt 
werden. Wäre die Bibliothek delay.h genau genug um das richtige Timing 
hinzubekommen?

von SNEMEIS (Gast)


Lesenswert?

hat keine bisher was mit SMBUS gemacht oder warum gibt es gar keine 
Kommentare? Ja ich weiß es ist sehr ähnlich zum I2C-Bus... Wie würdet 
ihr es in C gestalten über delay.h oder doch timer intterrupt?


Über Anregungen  / Infos würde ich mich freuen :-)

von Achim S. (Gast)


Lesenswert?

Für SMBus und IIC habe ich schon diverses gebaut, aber ich habe mir noch 
nie so viel Gedanken über die Erzeugung der CLK gemacht ;-)

Falls es noch frei ist, kannst du ja das TWI/IIC Modul deines ATmega88 
die ganze Arbeit verrichten lassen. Dann passt auch das Timing exakt.

Ansonsten ist ein IIC-Master auch schnell programmiert, indem man die 
SDA und SCL-Pins "von Hand" toggelt. Um das Timing etwas zu bremsen 
setze ich dabei üblicherweise eine Schleife über ein paar NOPs ein. (Ich 
schätze mal,  _delay_us macht das selbe, oder?)

Damit triffst du zwar nicht exakt die 100kHz, aber der Bus funktioniert 
auch problemlos, wenn du ihn etwas langsamer. (Nur zu schnell könnte 
schlecht sein...)

von Radjesch (Gast)


Lesenswert?

Achim S. schrieb:
> Für SMBus und IIC habe ich schon diverses gebaut, aber ich habe
> mir noch
> nie so viel Gedanken über die Erzeugung der CLK gemacht ;-)
>
> Falls es noch frei ist, kannst du ja das TWI/IIC Modul deines ATmega88
> die ganze Arbeit verrichten lassen. Dann passt auch das Timing exakt.

nee, ist nicht frei muss auf software i2c ausweichen
>
> Ansonsten ist ein IIC-Master auch schnell programmiert, indem man die
> SDA und SCL-Pins "von Hand" toggelt. Um das Timing etwas zu bremsen
> setze ich dabei üblicherweise eine Schleife über ein paar NOPs ein. (Ich
> schätze mal,  _delay_us macht das selbe, oder?)

hast du mal in Beispiel in C hab schon über Timer interrupts versucht 
aber bekomme keine Start Bedingung hin die ja da heißt CLK high SDA Low 
oder? erst dann kommen die Daten bzw. muss ich erst die sende Adresse 
schicken?
>
> Damit triffst du zwar nicht exakt die 100kHz, aber der Bus funktioniert
> auch problemlos, wenn du ihn etwas langsamer. (Nur zu schnell könnte
> schlecht sein...)

von Achim S. (Gast)


Lesenswert?

Radjesch schrieb:
> hast du mal in Beispiel in C

Ich hätte zwar erwartet, dass das Netz voll mit Beispielen für IIC ist, 
aber bitteschön: hier die Erzeugung der Startcon:
1
   clr_sda();         //erzeuge Startcondition
2
   shortpause(IIC_PAUSE);
3
   clr_scl();
4
   shortpause(IIC_PAUSE);

Nicht zu kompliziert.

shortpause() ist wie gesagt eine Schleife über ein NOP und damit wohl 
ziemlich ähnlich zu _delay_us(). Müsste man viel länger warten, würde 
sich der Einsatz eines Timerinterrupts lohnen. Aber bei 5µs zwischen 
zwei Flanken...

Danach kommt die Übermittlung der Device-Adresse an und das Prüfen des 
Acknowledge:
1
   write8bitiic(devadr);    //Übertrage Device-Adresse
2
   if (!check_ack()) {return 0;};  //frage Acknowledge ab.

Wenn in check_ack() kein Acknowledge erkannt wird, wird eine Stopcon 
angelegt, damit der Bus wieder für die nächste Startcon vorbereitet ist.

Ansonsten gibt check_ack einfach einen CLK-Puls aus, um das 
Acknowledge-bit weiterzuschalten. Ganz zum Schluss überprüft die 
aufrufende Routine am Rückgabewert, ob die gewünschte Anzahl von Bytes 
geschrieben wurde.

die Routine zum Rausschieben der Adresse (und später der Daten) ist auch 
nicht zu kompliziert:
1
void write8bitiic(uint8_t data) //Rotiere Daten bitweise nach SDA. Hänge jeweils einen SCL-Puls an 
2
{
3
4
   for (int8_t i = 7;i>=0;i--) {
5
      if (data & (1 << 7)) set_sda();   else clr_sda(); 
6
      data = data << 1;
7
      shortpause(IIC_PAUSE);
8
      set_scl();
9
      shortpause(IIC_PAUSE);
10
      clr_scl();  
11
   }
12
}

Wie man die folgenden Acknowledges abfragt und wie am Ende die Stopcon 
erzeugt wird, überlasse ich deiner Kreativität ;-)

von Radjesch (Gast)


Lesenswert?

Achim S. schrieb:
> Radjesch schrieb:
>> hast du mal in Beispiel in C
>
> Ich hätte zwar erwartet, dass das Netz voll mit Beispielen für IIC ist,
> aber bitteschön: hier die Erzeugung der Startcon:
>    clr_sda();         //erzeuge Startcondition
>    shortpause(IIC_PAUSE);
>    clr_scl();
>    shortpause(IIC_PAUSE);
>

> Nicht zu kompliziert.
>
> shortpause() ist wie gesagt eine Schleife über ein NOP und damit wohl
> ziemlich ähnlich zu _delay_us(). Müsste man viel länger warten, würde
> sich der Einsatz eines Timerinterrupts lohnen. Aber bei 5µs zwischen
> zwei Flanken...
>
> Danach kommt die Übermittlung der Device-Adresse an und das Prüfen des
> Acknowledge:
>    write8bitiic(devadr);    //Übertrage Device-Adresse
>    if (!check_ack()) {return 0;};  //frage Acknowledge ab.
>
> Wenn in check_ack() kein Acknowledge erkannt wird, wird eine Stopcon
> angelegt, damit der Bus wieder für die nächste Startcon vorbereitet ist.
>
was steht in der Funktion check_ack()?

> Ansonsten gibt check_ack einfach einen CLK-Puls aus, um das
> Acknowledge-bit weiterzuschalten. Ganz zum Schluss überprüft die
> aufrufende Routine am Rückgabewert, ob die gewünschte Anzahl von Bytes
> geschrieben wurde.
>
> die Routine zum Rausschieben der Adresse (und später der Daten) ist auch
> nicht zu kompliziert:void write8bitiic(uint8_t data) //Rotiere Daten
> bitweise nach SDA. Hänge jeweils einen SCL-Puls an
> {
>
>    for (int8_t i = 7;i>=0;i--) {
>       if (data & (1 << 7)) set_sda();   else clr_sda();
>       data = data << 1;
>       shortpause(IIC_PAUSE);
>       set_scl();
>       shortpause(IIC_PAUSE);
>       clr_scl();
>    }
> }
>
die Schleife ist mit noch nciht ganz klar:

du toggelst die Datenleitung 8 mal auf high bei der steigenden Flanke 
vom Clock?
> Wie man die folgenden Acknowledges abfragt und wie am Ende die Stopcon
> erzeugt wird, überlasse ich deiner Kreativität ;-)

hast du vllt. ein Beispiel Quellcode denn ich müsste mir das ganze im 
gesamten mal anschauen und dann mit dem Oszi mal nachmessen und 
vergleichen.


Vielen Dank vorab!

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.