Sida 1 av 1

I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 12:03:06
av Korken
Godagens!

Jag har ett problem som kommer och det kommer väldigt sporadiskt på en LPC1768.
Jag har en lite kodsnutt som läser av en sensor på I2C bussen och ibland så fastnar den i en av wait-looparna.
Det jag då lyckas få ut av statuskoden (0x38) är "Arbitration lost in SLA+R/W or Data bytes." och det händer var 1 på 10 000 - 100 000 transfers (väldigt sporadiskt).
Jag kör bussen i 400kHz, vilket både sensorer och MCU klarar utan problem enligt databladet.

Frågan är, vad kan göra att detta händer?
Och hur löser jag detta enklast?
Som lösning tänkte jag ha en liten if-sats som kollar om statuskoden är 0x38 och i så fall starta om läsningen, det tycks vara den enklaste lösningen.
Alternativt dra ned hastigheten, men det har andra problem med sig.

Edit:
Detta är en ganska öppen fråga som har lite hårda fakta, det vet jag.
Jag är mest ute efter vad de mer erfarna har att säga om vad som kan ha åstadkommit detta.

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 12:44:31
av sodjan
> Som lösning tänkte jag ha en liten if-sats som kollar om statuskoden är 0x38
> och i så fall starta om läsningen, det tycks vara den enklaste lösningen.

Är det något problem med att göra så ?
Om inte så låter det som en standardlösning...

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 14:00:54
av labmaster
Ibland kan det uppstå störningar på alla typer av kommunikationskanaler och en del hårdvara finns det felrättning men det är inte alla fel som kan rättas. Därför finns statusregister och/eller checksumma. Det är alltid viktigt att kontrollera att data som kommer från en kommunikationskanal är korrekt och i ditt fall handlar det om att kontrollera en statuskod. Speciellt viktigt verkar det vara i din applikation eftersom programmet verkar fastna i din wait-loop. Varför detta sker kan jag naturligtvis inte svara på eftersom jag inte studerat din programkod.

Din idé om att alltid kontrollera om du får status == 0x38 och starta om sekvensen verkar vara den rätta lösningen. Om detta fel inte dyker upp mer än var tiotusende gång och det inte får några speciella konsekvenser för funktionen behöver du inte bry dig om detta mer än att du måste kolla att statuskoden inte är 0x38 eller någon annan kod som gör att ditt program loopar.

Generellt sett brukar jag alltid implementera en "state machine" om det handlar om att läsa datapaket med flera seriella poster. Programkoden blir effektivare med en sådan på flera sätt och fram för allt är det lätt att ändra och underhålla programkoden. Säg att du exempelvis kan styra sändaren och mottagaren och du kommer på att det behövs ytterligare en slot med 8 bitar med någon typ av information i paketet. Det enda du då behöver göra är att lägga till en handler för den sloten och ändra pekaren i föregående handler till den nya och i den nya handlern peka på den som kommer efter i sekvensen.

Nåväl, det är ju inte "state machine" vara eller icke vara i din aplikation som det handlar om i denna tråd men jag tänkte att det kunde vara en värdefull input för dig.

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 15:22:29
av Korken
Ah, jag förstår! Tackar för den utförliga förklaringen! :tumupp:
Det du skriver om, en "state machine", låter precis som det jag behöver skriva för att göra mina läsningar interruptdrivna.
För nästa steg är att ta bort väntlooparna och låta interrupts sköta jobbet.
Dock så har jag aldrig skrivit en state machine men jag har googlat ganska mycket på det. Dock så undrar jag om du har lust att förklara det lite bättre hur du går till väga när du designar en sådan? :)

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 15:32:22
av sodjan
I grunden är det hela väldigt enkelt. Säg att ditt program kan befinna
sig i två olika "lägen", "wait" eller "processing". Det enda som en "state-
machine" betyder är att du har en variabel som är antingen "wait" eller
"processing". Det kan vara enumererarde som 1 och 2 eller vad du vill.

Det är i princip allt. Du kan ha flera olika "states" så klart. Och man kan
bygga programlogiken lite olika kring det hela. Men poängen är att du vid
behov alltid kan kolla state-variablen för att se vilket "state" applikationen
för tillfället befinner sig i. Det är inget magiskt alls... :-)

Men å andra sidan så har state-machine inte mycket med din fråga att göra.
Lite grundläggande felhantering kan/ska man ha oavsett hur applikationen
för övrigt är konstruerad. Om det räcker med att testa på just kod "38" eller
om det finns andra tänkbara fel har jag inte en susning om, men felkoderna
finns där av en anledning !

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 16:05:54
av Korken
En till bra förklaring, tackar sodjan! :)
Som du säger så måste man alltid ha felhantering, det kommer man aldrig undan.

>>Men å andra sidan så har state-machine inte mycket med din fråga att göra.
Sant så sant. Jag ramlade över info som jag inte sätt förut så vart väldigt nyfiken.

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 16:19:56
av sodjan
Se även t.ex :
http://en.wikipedia.org/wiki/Finite-state_machine
http://sv.wikipedia.org/wiki/Tillst%C3%A5ndsmaskin

Allt går att göra komplicerat oavsett hur enkelt det är... :-)

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 19:10:39
av labmaster
Länkarna som Sodjan postade berättar det mesta om teorin. Precis som Sodjan skriver så går det att implementera en state machine på många olika sätt.

Det passar utmärkt med en "state machine implementering" ifall man skall läsa sekvensiell data i samband med interrupt. Följande principkod kan symbolisera ett sätt:

Kod: Markera allt


// --------- State machine ----------
int (*stateFunc)() = NULL;

interruptHandler () {

  if (stateFunc) {
    stateFunc();
  }

}

void rxWait() {

     uchar s;

     s = readData();

     if (s == SYNC) {
       stateFunc = rxType;
     }
}

void rxType() {

  stateFunc = rxDstAddressLow;

}

void rxDstAddressLow() {

  addr = readData();

  if (addr == MYADDRLow) {
    stateFunc = rxDstAddressHigh;
  } else {
    stateFunc = rxWait;
  }
}
 
void rxDstAddressHigh() {

  addr = readData();

  if (addr == MYADDRHigh) {
    stateFunc = rxCRC;
  } else {
    stateFunc = rxWait;
  }

}

void rxCRC() {

  stateFunc = rxDstAddressFirst;

  if (crc(readData())) {
     // set stateFunc to next handler
  } else {
     stateFunc = rxWait;
  }
}

// --------- End of State machine ----------

viod startRX() {
    stateFunc = rxWait;
    enableInterrupt();
}

viod stopRX() {
    disableInterrupt();
    stateFunc = NULL;
}


Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 19:22:37
av sodjan
För att dra det lite längre så går det knappt att skriva någon applikation
alls utan att hålla reda *något* slags "status" på/i applikationen.

Just vid läsning från ett kommunikationsinterface är det ju utmärkt.
"Väntar på start", "har fått start, väntar på data", "data OK, väntar på slutkod"
o.s.v. På så sätt behöver man inte "hänga" i mottagningsrutinen hela tiden
utan kan plocka upp tråden igen vid nästa (t.ex) USART interrupt och
fortsätta där man slutade vid föregående interruptet. I mellantiden kan
man göra helt andra saker...

Sen om man kallar det "state-machine" eller inte är mer en smaksak... :-)
En del vill enbart använda uttrycket när *allt* i applikationen styrs på
det sättet. D.v.s att hela appliktionen är en "state-machine". Men, som
sagt, även enskilda delar av en applikation kan vara implementerade på
det sättet. Och USART'ens "state-machine" kan ju vara en del i hela
applikationens "state-machine" som t.ex har "väntar på paket", "behandlar
paket". I "väntar på paket" rullar USART'en genom sina egna "states".

O.s.v...

Re: I2C problem: Arbitration lost in transfer

Postat: 18 juli 2011, 19:39:48
av labmaster
Mycket bra och pedagogisk beskrivning Sodjan.

Re: I2C problem: Arbitration lost in transfer

Postat: 19 juli 2011, 09:17:48
av Korken
Underbar beskrivning! :tumupp:
Tackar för de få men extremt informativa svaren. :) Jag börjar förstå det här nu.

Jag hittade ett bra blockschema på hur man kan designa en I2C Master Interrupt Handler.
Kolla sista figuren i dokumentet AVR315.

Re: I2C problem: Arbitration lost in transfer

Postat: 21 juli 2011, 14:24:34
av Korken
Jag vill tacka er än en gång!
Tack vare er så har jag lyckats skriva min första (som jag iaf vet) state machine för interruptdriven läsning av I2C bussen! :D
Och den hänger sig aldrig igen, vilket är grymt skönt.

Jag tackar igen och slår mig vidare in i nästa kommunikationsprotokoll! :)