AVR Assembler handledning 10 (9 / 10 steg)
Steg 9: Hur fungerar på TWI avbryta?
Du bör först gå till nästa steg och hämta den final koden och sätta ihop det så att du kan använda det i det här steget (jag gillar att hålla den final koden och video i det sista steget för dem som vill bara hoppa över alla mitt babblande och bara köra koden.)
Det tolerabla VECKOINTAGET är förvirrande först eftersom det fungerar annorlunda än andra avbrott. Vanligtvis när ett avbrott inträffar och den motsvarande avbrottshanterare avrättas, jag flaggan i SREG automatiskt anges till 0 så att globala avbrott är inaktiverade, sen när det "RETI" utförs för att återgå från avbrottet, jag flaggan i SREG anges automatiskt 1 igen till re-möjliggöra globala avbrott och även enskilda avbrott flagg motsvarar avbrottet (dvs. biten i avstämningsregister för att avbryta) rensas så att den systemet svarar igen på den typen av avbrott (se status registrera beskrivning på sidan 11). Om vi tillät avbrott kvar på inuti ett avbrott skulle vi få "kapslade avbrott". Du kan göra detta genom faktiskt att aktivera dem inuti din avbrott rutin men du skulle inte normalt vill göra detta eftersom ett annat anrop till samma avbrott skulle då kasta ut dig från avbrott bara för att ange det igen på toppen.
Övning 3: Prova det! Aktivera global avbrott i början av din TWI rutin, då någonstans inuti uppsättning TWIE bet i TWCR registret och se vad som händer nästa gång flaggan TWINT har angetts.
Detta är dock inte hur på TWI avbryta fungerar! TWINT är avbrott flagga. I TWI inte återstår det in under avbrottshanterare, ändrar hela tiden. Det är därför det tolerabla VECKOINTAGET behöver använda flaggan avbrott för att kommunicera. Så vi inte kan bara lämna det på. I stället vi inaktivera avbrott med TWIE = 0 så att Processorn inte kasta ut oss tillbaka till avbrottsvektorn när TWINT ändras tillbaka till en 1. Detta kan ändå, fortfarande verka förvirrande så vi kommer att diskutera det i samband med vår kod. Exakt när är TWINT = 1 och då är TWINT = 0 i vår TWI rutin?
Låt oss lista ut.
Istället för att hoppa fram och tillbaka i databladet till räkna ut vad som pågår. Låt oss använda våra dice rulle och Visa. Då vi kommer att vara helt tydlig med vad bitarna anges och när.
Starta genom att lägga till följande definition till toppen av dice rulle koden:
def test = r23
Nu gå ner på tw_transmit rutin och rätt på toppen av det, när datorn först träder subrutinen, sätta följande rad
LDS test, SREG
Slutligen, gå till de två platserna i koden där vi överföra uppgifterna till displayen. Den andra en där vi överför den låga byten, ersätta dicetotal med test. När vi trycker på knappen, skickas nu innehållet i registret SREG, när vi först kom in subrutin, till displayen.
Nu, när vi monterar detta och kör det, finner vi att en 0000 visar upp på displayen. Detta innebär att jag flagga SREG inaktiveras som det ska vara eftersom vi inte aktiverar global avbrott i vår dice rulle.
Nu ändra koden så att testa laddar TWCR i stället för SREG och visa innehållet i TWCR.
Vi finner att och att TWEN flagga är enda på i TWCR. Vilket betyder att det tolerabla VECKOINTAGET aktiveras som det också ska vara eftersom vi använder det tolerabla VECKOINTAGET.
Nu kan flytta våra test linje till en annan plats. Flytta ner det till precis efter vi satt TWCR för första gången. Detta är när vi skickar startvillkoret. Resultatet är en 36 på vår bildskärm. Detta innebär att TWCR är 0b00100100.
TWCR = (TWINT, TWEA, TWSTA, TWSTO, TWWC, TWEN, -, TWIE) = (0,0,1,0,0,1,0,0)
Så är det TWSTA lite på som det ska vara eftersom vi precis laddat startvillkoret, och TWEN är på som det också ska vara. Men titta! I föregående rad vi lastade TWINT = 1 i TWCR register och när vi omedelbart kopieras registret och tittade på det finner vi att TWINT är 0! Varför är det? Du ser att "Ange TWINT = 1" gör något annat än bara ställa in det lite i TWCR lika med ett. Om du tittar längst ner på sidan 17 där de beskriver överföring en startvillkoret kommer du se att de säger, "TWINT måste skrivas till 1 för att avmarkera flaggan TWINT"... Så vad som faktiskt händer här är när du skriver en 1 till TWINT anges det värdet för TWINT lika med noll! Det beror på TWINT båda * kontroller * TWINT flagga och * är * flaggan TWINT. Det säger sedan att det tolerabla VECKOINTAGET testar 2-tråds USB-bussen och generera en startvillkoret så fort bussen blir fri. Efter en startvillkoret har överförts, ange sedan flaggan TWINT av hårdvara. Detta innebär att TWINT blir 1 när detta är färdigt. Vi vet redan att detta är fallet eftersom våra mycket nästa rad är en tw_wait subrutin som bara håller testa TWINT tills det blir 1 och därefter läser statusregistret. Det faktum att skicka en 1 till TWINT bara för att det anges till 0 är källan till massor av förvirring för människor som försöker förstå hur I2C-protokollet fungerar. Viktiga är att inse att TWCR är en aktiv "kontroll" registrera samt en massa vippströmbrytare. Skicka en 1 till TWINT rensar flaggan avbrott och denna flagga råkar vara den samma TWINT lite i TWCR register så resultatet är TWINT = 0.
Nu kan ändra våra testvariabeln så att det kopierar TWSR statusregistret istället. Flytta inte på plats ännu. Bara köra det som är och ta reda på vad som finns i statusregistret omedelbart när vi berättar TWCR att överföra en startvillkoret men innan detta villkor har överförts.
Jag får 251. Detta är binär 0b11111011. Databladet säger, i avsnittet 22.5.5 på sidan 213, att TWSR registrerar endast innehåller relevanta statusinformationen när flaggan TWINT har angetts (minns när vi talar om "flaggor" sedan orden "flaggan är inställd" medel TWINT = 1, när vi talar om "styra avbrott" då orden "ange flaggan" skulle innebära skriva 0 till TWINT, vilket resulterar i TWINT = 1... bisarrt men det är så dess arbeten). Eftersom vi läser TWSR när TWINT = 0, dvs avbrottet är avstängd och TWI är upptagen, innebär det att det inte bör innehålla relevanta statusinformation, i stället avsnittet fortsätter med för att säga att den bör innehålla "en särskild status kod som indikerar att det finns någon relevant information". Ja då. Jag antar att vi nu vet vad "särskild status code". Det är 248. Med andra ord ställs alla bitar utom 3 att vi oftast mask. Nu en fråga som du kan fråga är "hur är det med prescaler bitar i TWSR, påverkar de här speciell statuskoden?" kom ihåg att vi dölja dem när vi vill läsa statuskoder, så om det tolerabla VECKOINTAGET bara läser TWSR rakt upp skulle inte det visar dessa prescaler bitar? Tja, gå upp till toppen och anger de prescaler bitarna till ett annat värde. Du kommer att hitta det om vi iväg båda av prescaler bitar (så att prescaler värdet är nu 1 och SCL kör på en högre frekvens!) och köra den vi får 248, som är 0b11111000, om vi bara TWPS0 till 1 och köra det igen (denna gång precaler skulle vara 4) hittar du att det nu lyder 249. Om du anger bara TWPS1 till 1 (så prescaler är nu 16) får du 250 och med både som vi normalt har det vi har sett dig 251. Så vi ser att sanna "kod för särskilda status" är 248, vilket betyder att alla bitar av den "status" delen av TWSR har angetts till 1 och de andra 3 bitarna bo som de var.
Nu flyttar "lds test, TWSR" kommandot för att efter vi vänta på avbrottet (dvs. efter TWINT = 1).
När vi trycker på knappen ser vi 0011 Visa upp på displayen, dvs decimal nummer 11. Vad betyder statuskoden 11? Tja, minns att de sista två bitarna i TWSR register är våra prescaler bitar som i vårt fall är båda 1. Vi måste bli av med dem (minns hur vi dölja dem när vi vill kontrollera status?) så låter subtrahera 3 från våra resultat (3 är vad dessa två bitar ger konverteras till decimaltal). Så status är faktiskt 8, eller 0x08 i hexadecimalt. Vilket är exakt vad vi förväntar oss.
Nu flytta Testlinjen under den punkten där vi anger adressen till slav i registret TWDR. Hittar du att det fortfarande lyder 11. Så förblir den 11 tills vi faktiskt gör något annat med det tolerabla VECKOINTAGET. Dicking runt med register som TWDR inte påverkar statusregistret. Den ändras endast när TWI är aktiv.
Nu flytta det under nästa gång vi ladda kontroll registret och du kommer att finna att det blir "särställning" igen... du får bild.
Som en sista test, gå till avsnittet där vi skickar dicetotal display och lägga till de följande 3 raderna i början av avsnittet:
LDI temp, 0b00000100
STS TWCR, temp
LDS test, TWCR
Du ser vad detta innebär. Det håller TWEN på så att det tolerabla VECKOINTAGET förblir aktiv, men nu skriver vi TWINT = 0 i registret över kontrollen. Då läser vi ut värdet av kontroll registret. Vad får vi? Vi få 132 visar på displayen! Detta är binär 0b10000100. Med andra ord är TWEN lite på som vi det, men nu är det TWINT lite på. Vi skickade TWINT = 0 för att kontrollera register och resultatet är TWINT = 1. Du ser nu varför rätt? Skicka TWINT = 0 till kontrollen register faktiskt definierar flaggan avbrott. Så resultatet är avbrottet flaggan är på, är det en 1.
Okej. Nu vet vi vad som händer i dice rullen med TWINT bit av TWCR registret. Det bara potentiellt förvirrande var när vi satt TWINT = 1 och sedan läsa bara för att finna dess värde var 0, och när vi TWINT = 0 Vi hittade dess värde var 1. Jag tror att du nu se varför detta är och hur det fungerar. Ställa in värden till TWCR är samma som skickar kommandon till TWI. TWINT = 1 kommandot betyder "köra kommandot i TWCR", men det värde som få in i den TWINT bit när det kommandot utförs är "klartext flaggan avbrott" som betyder "starta upp det tolerabla VECKOINTAGET och skicka några data". När det gäller avbrott flagga (det faktiska värdet i lite) är berörda, TWINT = 0 betyder att avbryta flagga är avstängd, det tolerabla VECKOINTAGET är upptagen med något. När TWINT går tillbaka till 1 betyder avbryta flaggan är satt och du kan nu ändra saker igen. Å andra sidan, så långt den * kommandon * du skicka till TWCR, skriver TWINT = 0 * apparater * flaggan avbrott och resultat TWINT = 1, och det tolerabla VECKOINTAGET stängs av så att du kan ändra data registret. Har jag slå den döda hästen tillräckligt länge? Jag gör bara detta eftersom det är lika förvirrande som f... väl. du får idén. Om du fortfarande förvirrad bara leka med det ett tag.
Nu undersöka figur 22-10 som visar de saker som händer under en typisk överföring. Nu när vi förstår hur TWINT fungerar det är tydligt vad det faktiskt värdet i den biten är vid en given tidpunkt under överföringen. I vita avsnitten TWINT = 0, och i svarten avsnitten TWINT = 1. När beskrivningen säger att "se till att TWINT är skriven till en" du vet nu att detta leder till TWINT = 0, dvs de avbrott flagga är avstängd eller "ta bort". Det ovan citerade uttalandet om att se till att TWINT är skriven till en måste vara källan till inget annat än förvirring för människor när de försöker lista ut hur det tolerabla VECKOINTAGET fungerar. Det är irriterande att författarna av databladet inte tar sig tid att verkligen förklara vad som händer. Andra avbrott flaggor i AVR fungerar på samma sätt, till exempel Timer/Counter overflow flaggan som vi behandlat i tidigare tutorials. Skriver en 1 till TOV0 lite i TIFR0 Timer/Counter0 avbryta flagga Register också * Clear * flaggan och så resulterar i en logik 0 i den biten. Men i fallet med andra avbrott flaggor vi inte behöver oftast att ställa in och rensa dem med programvara, hårdvara tar hand om som. Det är bara för att vid det tolerabla VECKOINTAGET vi behöver installera och avmarkera flaggan medan inuti den faktiska avbrott rutin som vi behöver tänka på det och det finns potential för förvirring.
Låt oss nu återställa vår dice rulle kod till som det var och flytta över till våra 4-siffrig display.
Lägg till en ny generell Journal kallas "test" som vi gjorde med dice rullen i 4-siffriga-display koden. Sedan i våra tw_int avbrottshanterare, Lägg till följande två rader i början av vår tw_return etikett, dvs i slutet precis innan du går tillbaka till huvudsidan:
LDI playercashH, 0
MOV playercashL, test
så att displayen visar vad är i test registret. Kan nu testa några saker.
Första låt oss testa SREG på olika ställen i avbrottshanterare. Lägga "lds test, SREG" i rätt överst när avbrottet anropas först. Hittar att det lyder 0. Detta innebär att "I" flagga automatiskt är avmarkerad när vi går in i avbrottshanterare. Du hittar också att det förblir avstängd under hela avbrottet. Detta är det normala sättet som SREG fungerar.
Nu låt oss testa TWSR. Här är där vi hittar något som kan tyckas märkligt. Om vi testa den precis efter avbrottet kallas få vi 96 visar. Varför är detta? Tja, minns ni att TWSR statuskoder finns i hexadecimalt. Om du konverterar 96 till hexadecimalt hittar du att det är 60. Vilket är det värde som vi får när avbrottet anropas först.
Övning 4: Vad är "special statuskoden" används i slav mottagaren?
Nu titta på TWDR registret när du först ange avbrottet. Hittar du att det är lika med den adress som vi har satt upp för slav, som sig bör sedan behandlingen adressen från TWI in i data-registret är hur vi visste vi kallades.
Slutligen, låt oss titta på TWCR och TWINT lite. Om du sätter "lds test, TWCR" precis i början när hanteraren först anges får du 197 som är 0b11000101. Detta innebär att TWINT = 1, TWEA = 1, TWEN = 1 och TWIE = 1. Detta är exakt hur vi ställer saker in i våra Reset avsnitt av programmet (leta, se?) förutom att nu TWINT avbrott flaggan är på. Vilket är också normalt eftersom vi har just gått in på avbryta, vi skulle inte vara här om något inte ange att flagga.
Gå till toppen av din program i avsnittet Återställ nu och Lägg till följande två rader:
LDI temp, 0
STS TWDR, temp
som om vi skulle initiera registrera våra data TWDR till noll. Vad händer nu när du kolla TWCR registret i början av avbrottet? Du får 205.
Övning 5: Varför får man 205?
Nu kan du vilja testa värdena för register på andra ställen i koden. Jag tror hittar du att de är som förväntat.