TWI mit Xmega ohne Stop?

Lästige Stop Kondition verhindert lesen

RichardT
Benutzer
Avatar
Gender:
Age: 56
Posts: 19
Registered: 02 / 2013
Subject:

TWI mit Xmega ohne Stop?

 · 
Posted: 16.03.2017 - 07:27  ·  #1
@All

Nachdem ich seit 2 Tagen mit einem neuen Baustein via TWI Probleme habe und ich auch im Forum von Anderen ähnliches gelesen habe wollte ich mal nachfragen ob jemand eine Lösung gefunden hat.

Das Problem: Das Lesen via TWI funktioniert bei einigen Bausteinen nicht, da ein Stopbit immer nach dem Schreiben der (Device Adr. + W bit + Register Adr) eingefügt wird. Danach erfolgt dann eine Start Kondition, Device Adr + R bit + Byte zu lesen. Einige Bausteine funktionieren mit dem Stop / Start zwischen den Schreiben und Lesen, andere nicht. So auch der Beschleunigungssensor MMA 6853. Fúr solche Bausteine sollte das Protokol sein: Start, Dev Adr, W-bit, RegAdr, AK,Repeat Start,Dev Adr,Byte-lesen,NAK,Stop.

Mit scheint, laut Forum, das dieses Problem iZm XMega (bei mir XMega 128A4U) auftritt.

Irgend jemand eine Idee wie man das Stop bit mit einem Repeated Start ersetzt?

Ich wäre sehr dankbar. Habe leider schon die Platinen fertig und muss nun mit dem Baustein arbeiten.
Grüsse
Richard
RichardT
Benutzer
Avatar
Gender:
Age: 56
Posts: 19
Registered: 02 / 2013
Subject:

Re: TWI mit Xmega ohne Stop?

 · 
Posted: 17.03.2017 - 06:52  ·  #2
Hallo

Habe auch nach der Vorlage von Thomas AC eine kleine Routine geschrieben.

Funktioniert super.

Grüsse
Richard
Thomas.AC
Benutzer
Avatar
Gender: n/a
Age: 43
Posts: 308
Registered: 07 / 2013
Subject:

Re: TWI mit Xmega ohne Stop?

 · 
Posted: 22.03.2017 - 22:59  ·  #3
Ich vermisse diese Möglichkeit auch beim TWI Treiber von AVRco.
Genau aus diesem Grund konnte ich damals keine Daten aus einem ADAU1701 lesen und musste mir diesen Zugriff selber implementieren. (Bestimmte EEproms benötigen diese Zugriffsart auch)

Warnung:
Ich möchte aber unbedingt darauf hinweisen, dass meine Function 'twiCombinedRead' nicht umfangreich auf Robustheit getestet ist und nur zusammen mit einem importierten TWIE Treiber funktioniert. Die Schwierigkeit beim I2C ist eine gute und robuste Außnahmebehandlung. Meine Funktion 'twiCombinedRead' implementiert aber keine einzige Ausnahmebehandlung, sondern lediglich einen Timeout als Notausstieg. In meiner Applikation verlasse ich mich hoffnungsvoll
auf TwiOutE, dass Ausnahmesituation gelöst werden.

Timeout:
Hier benutze ich einen SysTimer8.
Meine Applikation verwendet kein Multithreading, so dass ein timeout von 20 ms bei einer I2C baudrate von 200kbaud hier okay ist.

function dspReadCapture:
Das ist ADAU1701 spezifisch. Zuerst muss ein bestimmter Wert in ein Register geschrieben werden, um anschließend daraus einen bestimmten Laufzeitwert lesen zu können.

Ausnahmesituationen bei I2C (soweit mir bekannt):
1.) bus state Logik hat fälschlicherweise eine Startbedingung detektiert. Die ist möglich bei einer EMV Störung. Hier hilft ein Reset der bus state logik.
2.) Ein Reset bei der Master-CPU während eines Lesezugriffs kann dazu führen, dass eine SCL Leitung vom Slave durch clock stretching dauerhaft auf 0-Pegel gezogen wird. Der Master hat dann keine Möglichkeit, eine neue Startbedingung zu erzeugen. Hier muss man die clock Leitung toggeln, bis diese wieder frei wird.
3.) bus error / arbitration error: Fehler, die durch EMV auftreten könnten könnten. In diesen Fällen würde der Master auf eine Stopp-Bedingung warten. Hier hilft wahrscheinlich die Kombination toggeln der SCL Leitung + bus state logic reset.
4.) Dauerkurzschluss auf einer Leitung:
Nach Aufhebung eines Kurzschlusses sollte I2C wieder funktionieren

Angst:
Meine größte Angst bei I2C sind Ausnahmefälle, die im schlimmsten Fall dazu führen, das die I2C Kommunikation für immer ausfällt oder sogar eine Endlosschleifenbedingung entsteht.
Beides Fälle, die selbst Hersteller von Mikrocontrollern in Ihren eigenen Treibern nicht im Griff haben. Ich glaube, dass deswegen auch die Slave Treiber beim xmega noch nicht implementiert wurden. Diese musste ich mir auch selber implementieren und im Sinne der Robustheit oft nachbessern. Ein guter Test ist das unkontrollierte Kurzschließen der I2C Leitungen SDA und SCL mit Litze. Prellt schön. Wenn die Kommunikation danach weiter funktioniert, ist man schon weit.

Codestyle:
Soweit ich mich erinnere ist mein Code lediglich eine 1:1 'user manual' Umsetzung für einen xmega32A4. Ohne user manual verstehe ich auch nur Bahnhof und fie Kommentare sind auch nicht hilfreich.

Schlussbemerkung:
Ich verwende meinen Code in einem Produkt mit einer zusätzlichen Vorsorgemaßnahmen. Im Falle eines I2C-Kommunikationsausfalls schaltet ich, einfach gesagt, ein Fehlerausgang.

Code

program UDSPM;

Device = xmega32A4, VCC=3.3;

Define_Fuses // set bits are zero
  Override_Fuses;
  NoteBook   = A;
  Supply     = 3.3, 0;   // no supply
  SPIclk     = 2000000; // programmer clock 2MHz
  COMport    = USB;
  LockBits0  = [];
  FuseBits0  = [];
  FuseBits1  = [];
  FuseBits2  = [];
  FuseBits5  = [BODLEVEL0, BODLEVEL2, BODACT0];  // BOD = 2.9V if XMEGA A
  //FuseBits5  = [BODLEVEL0, BODLEVEL1, BODLEVEL2, BODACT0]; //BOD = 3V if XMEGA AU

Import Systick, TWI_E;
from system import longword;

Define
  //OSCtype = int32MHz, PLLmul=4, prescA=1, prescB=1, prescC=1;
  OSCtype = extXTAL=16000000, PLLmul=2, prescA=1, prescB=1, prescC=1;
  SysTick        = 10;             {msec}
  StackSize      = 128, iData;
  FrameSize      = 128, iData;
  TWIprescE      = 75;   // TWI speed = 200kbit/s @32 MHz
  // TWIpresc = f_sys / (2*f_TWI) - 5;
  // 100 kbit/s @32Mhz -> TWIpresc = 155
  // 200 kbit/s @32Mhz -> TWIpresc = 75
  // 400 kbit/s @32Mhz -> TWIpresc = 35


Implementation

const
  DSPADDR           : byte = $68 shr 1;
  DATACAPTURE0      : word = $081A;    // data capture register 0
  
var
  twitimeout : sysTimer8;
  data : longword;
{$IDATA}

function twiCombinedRead (subaddress : Word; pData : pointer; bytesToRead : byte) : boolean;
begin
  SetSysTimer(twitimeout, 2); //

  // write I2C address Byte + RW = 0
  TWIEMASTERADDR := DSPADDR shl 1;
  repeat
  until Bit(TWIEMASTERSTATUS, 6) or isSysTimerZero(twitimeout);   // wif?
  if TWIEMASTERSTATUS <> $62 then     // return, if incorrect STATUS
    Return (false);
  endif;

  // write subaddress
  TWIEMASTERDATA := HI(subaddress); // write highbyte subaddress
  repeat
  until Bit(TWIEMASTERSTATUS, 6) or isSysTimerZero(twitimeout);     // wif?
  if TWIEMASTERSTATUS <> $62 then     // return, if incorrect STATUS
    Return (false);
  endif;
  TWIEMASTERDATA := LO(subaddress); // write lowbyte subaddress
  repeat
  until Bit(TWIEMASTERSTATUS, 6) or isSysTimerZero(twitimeout);     // wif
  if TWIEMASTERSTATUS <> $62 then     // return, if incorrect STATUS
    Return (false);
  endif;

  // bytesToRead?
  if bytesToRead = 0 then
    TWIEMASTERCTRLC := $07;                    // stop
    Return(true);
  endif;

  // read first byte (read access with repeated start condition)
  TWIEMASTERADDR := (DSPADDR shl 1) or $01;  // write I2C address + R/W = 1
  repeat
  until Bit(TWIEMASTERSTATUS, 7) or isSysTimerZero(twitimeout);    // rif?
  if TWIEMASTERSTATUS <> $A2 then           // return, if incorrect STATUS
    Return (false);
  endif;
  pData^++ := TWIEMASTERDATA;
  dec(bytesToRead);

  // read next bytes
  while bytesToRead > 0 do
    TWIEMASTERCTRLC := $02; // ack + read more byte
    repeat
    until Bit(TWIEMASTERSTATUS, 7) or isSysTimerZero(twitimeout); // rif?
    if TWIEMASTERSTATUS <> $A2 then // return, if incorrect STATUS
      Return (false);
    endif;
    pData^++ := TWIEMASTERDATA;
    dec(bytesToRead);
  endwhile;

  // send stop condition
  TWIEMASTERCTRLC := $07;
  Return(true);
end;

{------------------------------------------------------------------------------}
function dspReadCapture(address : word; var data : LongWord) : boolean;
begin
  if not TwiOutE(DSPADDR, DATACAPTURE0, swap(address)) then
    Return (false);
  endif;
  if not twiCombinedRead(DATACAPTURE0, @data, 3) then
    Return (false);
  endif;
   data := swapLong(data);
   data := data shr 8;
  Return (true);
end DspReadCapture;

{------------------------------------------------------------------------------}
{ Main Program }
begin
  loop
    dspReadCapture($0123, data);
  endloop;
end.
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 15 · Cache Hits: 14   66   80 · Page-Gen-Time: 0.02294s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI