Forum: Mikrocontroller und Digitale Elektronik SPI selbst generieren


von Jason (Gast)


Lesenswert?

Hi

Folgendes ich arbeite mit dem ATMEGA128 und benutze das SPI.
Nun benötige ich aber zum programmieren eines DAC eine weitere SPI
Schnittstelle. Da ich hier immer nur 16 Bit an Daten an den DAC
schicken muss nehm ich also 3 I/Os - eine CLK, ein CS und ein DataOut.
Soweit so gut aber irgendwie krieg ich die 16 Bit nicht einzeln auf den
DataOut Pin, bzw. rausgeschiftet.
Arbeite zudem mit CVAVR also wenn dann in C bidde.
 dachte eigentlich es würde so funktionieren:

#define SDOUT PORTB.7

...

unsigned char control;

for(j=0;j<8;j++)
{
   ...
   SDOUT= (control>>(7-j));
   ...
}
...

Schonmal danke im vorraus.

von mthomas (Gast)


Lesenswert?

Ein Codefragment. Vielleicht hilft's:

void softspi_W(uint8_t data)
{
  uint8_t i;
  i = 0x80;
  do {
    if (data & i) SPIPORT |= (1<<SPIMOSI);
    else SPIPORT &= ~(1<<SPIMOSI);
    pulse_sck();
    i>>=1;
  } while (i);
}

von Rufus T. Firefly (Gast)


Lesenswert?

In Deiner Schleife shiftest Du einerseits nur ein Byte, andererseits
solltest Du -sicherheitshalber- noch eine verANDung mit 1 vornehmen:

   SDOUT= (control>>(7-j)) & 1;

Mit Takt könnte das dann so aussehen:

#define SDOUT PORTB.7
#define CLOCK PORTB.6
#define CHIPSEL PORTB.5
...

unsigned char control;

CHIPSEL = 0;  // active-Low-CS

for (j = 0; j < 8; j++)
{
   ...
   CLOCK = 0;
   SDOUT = (control >> (7 - j)) & 1;
   CLOCK = 1;
   ...
}

CHIPSEL = 1;
..

Du musst Dir noch Gedanken über die Polarität des Taktsignales machen
und wann in Relation zu den Daten das Taktsignal umschalten soll.
Außerdem musst Du überlegen, ob Du das LSB (wie in Deinem Quelltext)
oder das MSB als erstes übertragen willst; es gibt beide Varianten.

Wie hier vor einiger Zeit bereits diskutiert wurde, ist das Konstrukt
mit dem Shiftoperator ein relativ ineffizientes, da der AVR über keinen
sog. "Barrel Shifter" verfügt.

Besser wäre daher eine Variante wie


unsigned char control;
unsigned char temp;


temp = control;

CHIPSEL = 0;  // active-Low-CS

for (j = 0; j < 8; j++)
{
   ...
   CLOCK = 0;
   SDOUT = temp & 1;
   temp >>= 1;  // oder temp /= 2;
   CLOCK = 1;
   ...
}

CHIPSEL = 1;

von Rufus T. Firefly (Gast)


Lesenswert?

Nachtrag:
Das ganze für 16-Bit-SPI:


unsigned short control;
unsigned short temp;


temp = control;

CHIPSEL = 0;  // active-Low-CS

for (j = 0; j < 16; j++)
{
   ...
   CLOCK = 0;
   SDOUT = temp & 1;
   temp >>= 1;  // oder temp /= 2;
   CLOCK = 1;
   ...
}

CHIPSEL = 1;

von Jason (Gast)


Lesenswert?

Das ich nur ein Byte shifte und somit nur 8 Bit und nicht 16 war mir
schon klar. Und ob bei steigender oder fallender Flanke übernomen
werden soll auch, deshalb ja die vielen ... "pünktchen" ;-)
Wollte nur nicht den ganzen Code posten.

Das einzige was mir theoretisach fehlte war die Ausmaskierung mit & 1
Und ein wenig umgestrickt damit ich das MSB zuerst sende und nicht das
LSB sieht das ganze jetzt so aus und funzt auch:

void WriteDAC(unsigned char control, unsigned char wert)
{
unsigned char j= 0;
unsigned char temp_control, temp_wert;

cs = 0;  // active-Low-CS

for (j=0;j<16;j++)
{
   sclk = 1;
   if(j<8)
   {
        temp_control = control;
        temp_control >>= (7-j);
        sdin = temp_control & 1;

   }
   else
   {
        temp_wert= wert;
        temp_wert >>= (15-j);
        sdin = temp_wert & 1;
   }
   sclk = 0;
}

cs = 1;
}


In diesem Sinne dankeschön für die Mühe

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.