pcnerd
Take a parachute, and jump!
Hey,
Ik ben op dit moment weer wat met microcontrollers bezig en het leek me nu wel vitaal om het I2C proces onder de knie te krijgen. Ik heb dus 2 attiny2313's opgezet, 1tje met display en knopje uitgerust, interrupt achter het knopje.
Nu wil ik met een druk op het knopje de slave (uc zonder lcd) vragen om wat data, en die weergeven. Dit zou dus met i2c moeten gebeuren.
Ik ben de avr310, avr312 en de corresponderende pagina's van de attiny2313 aan het doorwerken, maar ik kom niet zo goed uit 1 ding, de clock.
Ze zijn met i2c de hele tijd met de SDA en SCL lijn aan het spelen, allebei laag trekken voor start, enzo, maar voor het verzenden van de data zal er toch een vaste klok puls moeten worden gegeven, hoe wordt dit gedaan? Stelt men deze pin eerst in als output en zet het naargelang het moet worden gezet, tot men data wil versturen en gaat men dan de 4-bit counter clock in de strijd gooien? Het lijkt mij namelijk het makkelijkst om de timoer/counter0 overflow te gebruiken. Vreemde is alleen dat de 4-bit counter/clock daarmee ook steeds omhooggaat. Waarvoor is die 4-bit counter? Hij zou moeten overflow'en als alles compleet is, maar ik zie nog niet hoe dat gebeurt aangezien er volgens mij per bit 1 clockpuls is, en als je dan 8 bits hebt gehad, de 4-bit clock counter nog niet is "geoverflowed".
Kan iemand helder maken hoe dit precies wordt gedaan? De voorbeelden die ik op internet vindt e.d. zijn allemaal nogal vaag, ik zoek gewoon een simpel voorbeeld voor het vragen van data, zonder knopjes or whatever met ledjes die oplichten.
mvg Pcnerdje
Peter Fleury heeft een tamelijk goede I2C library voor I2C geschreven.
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Ik ben niet erg gecharmeerd van dat I2C-gedoe. Het werkt allemaal wel, maar in tegenstelling tot SPI en RS232 komt het allemaal erg omslachtig over.
free_electron
Silicon Member
Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM
que ? I2C is zowat het meest elegante ding wat er is.
-netwerk .
- meerdere devices op dezelfde draden ( probeer dat maar eens met rs 233 .. )
- collision detection en arbitrage in hardware ...
- snel.
- in tegenstelling tot spi maar 2 draden -
- vast 2 draden ( bij SPI voor elk extra device komt er een extra chipselect kijken.)
i2c is heeeel simpel
Start - address + read/write bit - wacht op ack - lees of schrijf byte en genereer stop.
in rust zijn beide signalen hoog. ( SDA en SCL )
start : maak EERST SDA laag , dan pas SCL.
shuif je address op de bus : plaats bit , maak clock hoog en terug laag. volgende bit.
eenmaal klaar ; check de ACQ : maak SDA hoog.maak dan clock hoog. lees SDA. is die laag ? ja : device is daar en antwoordt. neen ? device is er niet of niet klaar : geef stop en probeer later opnieuw .
maak clock terug laag.
schuif nu data in of uit
als je klaar bent : gee fene stop
- zorg dat SDA laag is.
- maak clock hoog
- maak nu data hoog.
klaar
start
SDA ----____
SCL -----___
data sturen :
SDA_x==x==x==x==x==x==x==x==x_
SCL___-__-__-__-__-__-__-__-__
ack fase
SDA_---___
SCL__--___
|
\ hier kijk je of device antwoordt.
de tekening toont een device wat niet antwoordt.
als een device antwoordt zal je dit zien :
SDA_______
SCL__--___
jij MOET wel SDA eerst hoog maken anders kan een device niet antwoorden ( op de scoop zal je een heeeeeel smalle glitch zien. of geen glitch)
stop genereren
SDA____---
SCL__-----
het machinisme is simpel.
data is stabiel trwijl clock omhoog en terug omlaag gaat. data mag dus alleen veranderen als clock laag is.
als clock hoog is en er gebeurt iets met data :
als data van hoog naar laag gaat : START
als data van laag naar hoog gaat : STOP
heeeeeel eenvoudig. kinderspel.
ik ga niet alles opnieuw uitschrijven. google op i2c FAQ en je weet waar de mosterd vandaan komt ....
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Als ik de regels broncode, die nodig zijn om I2C te bedrijven, vergelijk met hetgeen nodig is voor RS232, komt het eerste me allesbehalve "elegant" over. De netwerk-achtige opzet is zonder twijfel een voordeel, maar je betaalt er wel een prijs voor.
pcnerd
Take a parachute, and jump!
Ik zal mijn best doen om de codes die je daar ziet wat eleganter te maken want die staan mij ook helemaal niet aan.
het protcol/principe i2c is het probleem niet, het is het implementeren met behulp van USI. Daarmee zou het makkelijker moeten worden geloof ik namelijk
.
Ik ben op zoek naar een fatsoenlijke beschrijving van het gebruik van de 4 bits counter en z'n overflow in combinatie met die 8 hoge pulsen die een overflow moeten genereren waaraan ik een interrupt vastknoopt die de data in een software-buffer gooi. Daarna de nieuwe data ontvangen.
Maar volgens mij gaat het ontvangen van de data van de slave als volgt (masters point of view):
-slave aanspreken met read bit
-clock genereren met timer/counter0 overflow
-wachten tot op de een of andere manier de 4-bit counter overflowed
-data in buffer gooien, ack geven
-herhalen tot stop signaal en daarna afsluiten en weer vrolijk met andere programma verder huppelen.
Klopt dit een beetje? En als pros wil helpen met het ontwerpen van fatsoenlijke TWI code is hij daartoe van harte uitgenodigt, mail maar ff
.
Ik zeg niet dat t niet kan maar ik heb eigenlijk nog nooit gezien dat de I2C clock gegeneerd werd met een Timer/counter, OF de hardware TWI interface wordt gebruikt OF ze bit-bangen gewoon. Clock mag namelijk best asynchroon zijn.
Het werkt allemaal wel, maar in tegenstelling tot SPI en RS232 komt het allemaal erg omslachtig over.
Dat heb ik nou met PIC'jes vs de 8051 core
Voor RS232 komt dat omdat hier meestal een hardware UART voor gebruikt wordt. Ga je RS232 bit-bangen wordt je code ook langer. Op bijvoorbeeld een 80552 met hardware I2C is dit ook al veel simpeler.
SPI en I2C ontloopt elkaar eigenlijk niet eens zo veel.
Hier staat er ook nog wat over :
http://www.nxp.com/acrobat_download/applicationnotes/AN10369_1.pdf
[Bericht gewijzigd door bprosman op (15%)]
free_electron
Silicon Member
Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM
Op 28 maart 2008 20:31:54 schreef pros:
Als ik de regels broncode, die nodig zijn om I2C te bedrijven, vergelijk met hetgeen nodig is voor RS232, komt het eerste me allesbehalve "elegant" over. De netwerk-achtige opzet is zonder twijfel een voordeel, maar je betaalt er wel een prijs voor.
code ? even uit de losse pols in Basic achtig taaltje rammen. zet het zelf over in je favoriete progtaal.
SCL en SDA zijn gewoon twee pinnen van procesoor. ( op een 8051 is io bit addresseerbaar dus das makkelijk meegenomen. geen gefoefel met and / or constructies )
sub start ()
scl = 1 ' we gaan ervan uit da de bus
sda = 1 ' in ongekende toestand is. dit forceert een stop als de bus bezig zou zijn.
sda = 0 ' we maken de start. eerst sda laag
scl = 0 ' dan scl laag.
end sub
sub stop ()
sda=0 ' kwestie van zeker te zijn . al mijn andere routines verlaten met clock laag.
scl=1 ' clock omhoog
sda=1 ' data omhoog en gedaan.
end sub
sub sendbyte(data as byte)
for x = 7 to 0 step -1
if data and (1<<x) then
sda =1 ' bit aan
else
sda = 0 ' bit af
end if
scl=1 ' clock omhoog
scl=0 ' clock omlaag
next x
sda=1 ' zorg dat we ALTIJD verlaten met sda hoog en SCL laag : voor ack en reads
end sub
function getbyte() as byte
dim x as byte = 0
for y as integer = 0 to 7 ' 8 keer
scl=1 ' clock up
x = (x <<1)
x=(x or sda) ' sample sda
scl=0 ' clock laag
next y
return x
end sub
function getack()
dim x as boolean = false
scl =1 ' clock up
x = not(sda) ' sample sda. als die laag is : ack
scl=0 ' clock laag
return x
return x
sub giveack
sda=0 ' trek sda laag
scl=1 ' clcok up
scl=0 ' clock down
sda=1 ' verlaten met sda hoog en clock laag
end sub
voila. daar staat al de code die je nodig hebt om i2c te doen
je kan eventueel nog een wrapper maken voor read/write
sub openwrite (address)
sendbyte (address <<1)
end sub
sub openread (address)
sendbyte ((address<<1) or 1)
end sub
byte AA naar address 64 sturen ?
start
openwrite (&h64)
if getack then sendbyte &hAA
stop
10 bytes lezen van address 12 ?
dim x() as byte = nothing
start
openread (&h12)
if getack then
for y= 0 to 8 ' eerste 9 lezen met daarnaa een ACK
x(y) = getbyte ' byte grabbelen
giveack ' ack geven aan slave
next y
x(y+1) = getbyte ' laatste zonder ACK
end if
stop
je kan gans die meuk in assembler schrijven in hoop en al 50 instructies .
probeer maar eens rs 232 te doen in 50 byte code.... als je in 'c' de seriele poort enabelt heb je al een runtime lib van 4 kilobyte aan je broek...
En als je een hardware i2c engine in je processor zitten hebt is het nog simpeler.
pcnerd
Take a parachute, and jump!
er zit usi, die behelst een buffer, counter, start en overflow etc. (zie pagina 's 139 en verder van attiny2313 datasheet). Ik had ongeveer hetzelfde idee in gedachten, ik ga bezig in GCC. Overigens is de rs232 iets makkelijker te implementeren in een microcontroller die al usart heeft maar dat terzijde, want het heeft toch een aantal beperkingen die ik niet kan gebruiken.
iig bedankt, hiermee komt het weer wat dichterbij. Nog ff researchen en dit volgen en dan deze week (weekend en verder) maar is aan de slag om 2 stukjes deftige code in elkaar te zetten.
[Bericht gewijzigd door pcnerd op (20%)]
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
sub sendbyte(data as byte)
for x = 7 to 0 step -1
if data and (1<<x) then
sda =1 ' bit aan
else
sda = 0 ' bit af
end if
scl=1 ' clock omhoog
scl=0 ' clock omlaag
next x
sda=1 ' zorg dat we ALTIJD verlaten met sda hoog en SCL laag : voor ack en reads
end sub
Ja, ik zie het nu. Dit is inderdaad heel wat eenvoudiger dan:
void uart_sendchar(char x)
{
loop_until_bit_is_set(UCSRA, UDRE);
UDR = x;
}

Uiteraard hangt veel af van de manier waarop je "ding" hardwarematig het gewenste protocol ondersteunt...
Ja, ik zie het nu. Dit is inderdaad heel wat eenvoudiger dan:
Dat komt omdat je een protocol geimplementeerd via SOFTWARE aan t vergelijken bent met een HARDWARE device. Da's Appels/Peren, Knollen/citroenen.
free_electron
Silicon Member
Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM
juist. als je een hardware i2c controller in je cpu hebt is het ook :
sub sendchar(x)
i2cbuf = x
while {not 'done'}
end sub
de meeste processors hebben tegenwoordig een i2c 'uart'.
enne : schrijf die seriele uart eens op een pic of avr die geen uart heeft waar je de uart gaat bitbangen .. veel success. het opwekken van de juiste baudrate is al een drama. bij i2c heb je dat probleem dan toch al niet. je kan zotraag of rap gaan als je wilt en je mag stotteren ...
vergelijk die i2c bitbang maar eens tegen een uart dei je bitbangt ... enne je mag geen timer gebruiken of interrupts om je baudrate te maken. mijn i2c code heeft niks nodig. 2 i/o poten.. das alles wat je krijgt
[Bericht gewijzigd door free_electron op (54%)]
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Op 28 maart 2008 22:17:13 schreef bprosman:
Dat komt omdat je een protocol geimplementeerd via SOFTWARE aan t vergelijken bent met een HARDWARE device. Da's Appels/Peren, Knollen/citroenen.
Uiteraard deed ik dat; ik heb nu eenmaal een slecht karakter. 
Maar dat neemt niet weg, dat de vraag een ATtiny2313 betrof, waar zowel USART als I2C (USI) hardwarematig ondersteund worden. En ook dan is I2C allesbehalve eenvoudig te noemen...
pcnerd
Take a parachute, and jump!
Het is niet zo eenvoudig als usart, maar wel beter, je kunt met 2 lijnen op hoge snelheid tussen meerdere controllers communiceren en ook met gemak de status daarvan controleren. Dat is met usart altijd een probleem, je kan altijd slecht controleren of je slave het heeft ontvangen. Als je het goed wilt doen moet je dan nog 1 i/o toepassen. Dan zit je op 4 lijnen met asynchronous usart, i2c doet dat met 2
.
Verder is de hardware matige ondersteuning juist genoeg om er redelijk makkelijk mee te communiceren, en het is ook niet genoeg geïmplementeerd om er aanpassingen op te maken als dat nodig blijkt te zijn (langere adressen, etc.)
In mijn ogen is het vooral veel betrouwbaarder dan USART.
Maargoed, daar gaat het in dit topic eigenlijk niet over, daar moet dan maar een nieuw topic over komen als het interessant blijkt te worden zoals nu, ik vraag nu alleen ff om een bevestiging van mijn eerdere post
Marcel
AVR C tutorial http://expand.xs4all.nl/avr
Op 28 maart 2008 22:40:58 schreef pros:
[...]
Uiteraard deed ik dat; ik heb nu eenmaal een slecht karakter.Maar dat neemt niet weg, dat de vraag een ATtiny2313 betrof, waar zowel USART als I2C (USI) hardwarematig ondersteund worden. En ook dan is I2C allesbehalve eenvoudig te noemen...
Hoewel je de USI kan gebruiken voor I2C is het geen dedicated I2C interface. Dat maakt het op de ATtiny2313 inderdaad nog lastiger. Op een AVR met echte TWI (bijv. ATmega88) gaat het alweer eenvoudiger. En ik moet zeggen dat ik het de eerste keer dat ik ermee werkte het ook vrij omslachtig vond. Het scheelt wanneer je eenmaal een library hebt gemaakt (je kan natuurlijk ook een bestaande gebruiken).
Op 28 maart 2008 22:40:58 schreef pros:
[...]
Uiteraard deed ik dat; ik heb nu eenmaal een slecht karakter.Maar dat neemt niet weg, dat de vraag een ATtiny2313 betrof, waar zowel USART als I2C (USI) hardwarematig ondersteund worden. En ook dan is I2C allesbehalve eenvoudig te noemen...
De gegeven implementatie is nog steeds een software bitbang constructie. Dus die vergelijking gaat nog steeds niet op.
Ik snap ook je probleem met I2C niet. Voor het doel waar het voor ontwikkeld is, is het in alle opzichten veruit superieur boven 'gewoon' serieel.
De vergelijking met RS232 gaat helemaal mank, RS232 is nou niet helemaal bedoeld voor 'on board' communication (dan houd je het wel gewoon TTL, of welke levels je chippies ook lekker vinden), net zo min als dat I2C bedoeld is om over 20 meter te trekken (al schijnen zelfs daar drivers voor te krijgen te zijn).
Waarom zou het ingewikkeld zijn? Als het volledig in hardware ingebakken zit, is het 1x config en daarna kletsen maar (en die config is eenvoudiger dan 'normaal' serieel, al is het maar omdat er veel minder aan te setten is). 'Kletsen' gaat ongeveer op dezelfde manier.
Als je μC het spul niet in hardware heeft, is het een eitje om in software te bit-bangen. Timing is geen issue (even er vanuit gaande dat je master bent), je kunt rustig tussendoor even een interrupt processen of de incomming data verwerken zoals je het leuk vindt zonder na te hoeven denken over bufferen ofzo. Doe dat maar eens met bit-banged serieel... SPI heeft overigens dezelfde voordelen, alleen heb je daar meer touw tussen je master en peripherals nodig en kost het dus meer pinnen van je master.
Je kunt zelfs multi-master. Dat zul je niet vaak nodig hebben, maar het is wel verrekte handig soms.
pcnerd
Take a parachute, and jump!
ik zoek gewoon een simpel voorbeeld voor het vragen van data
Dat antwoord had je al in mn eerste reactie.
pcnerd
Take a parachute, and jump!
Die library kende ik al, en vond ik niet zo verschrikkelijk handig, ik heb dus besloten zelf de boel in elkaar te knutselen. Ik ben al bezig, gaat tot nu toe wel aardig, ben maar begonnen met het implementeren van de slave...
Heb dit altijd wel een mooie implementatie gevonden. In asm, "helaas" wel 8051 core.
pcnerd
Take a parachute, and jump!
Helaas, asm is mij redelijk onbekend, wil ik nog wel is mee beginnen, maar C blijkt tot nu toe wel aardig toereikend.
pcnerd
Take a parachute, and jump!
Zo, ik heb het grootste gedeelter van de slave implementatie geschreven nu, nog niet getest (gaat moeilijk zonder master).
ontvangst routine moet ik ook nog doen, maar die heb ik op het moment niet direct nodig.
Kleine notitie: op PB4 zit een ledje
.
code hier:
http://pastebin.com/m201fb4e6
als er op of aanmerkingen zijn hoor ik het graag
.
//eindelijk goeie pastebin gevonden
.
[Bericht gewijzigd door pcnerd op (18%)]
free_electron
Silicon Member
Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM
pcnerd
Take a parachute, and jump!
Mij ook, maar veel makkelijker kon ik het zo 123 niet krijgen, en als ik naar de normale i2c libraries kijk wordt ik helemaal misselijk.
probleempje:
ik ben nu met de master implementatie bezig, maar ik vraag me af hoe ik dan ga zien of de data klaar is. Bij de slave was dat makkelijk want daar overflow'de die als hij van 15 naar 1 ging , wat betekent dat hij 16/2 = 8 klokpulsen heeft gehad (er werdt bij elke neergaande en opgaande flank van de SCL 1 bij opgeteld).
Echter, nu moet ik in de master zelf de klok genereren. Dit wil ik tijdens het zenden van gewone data simpel doen door de timer/counter0 instelling toe te passen. Maar dit betekent dat de counter bij 8 zal zijn als hij klaar is, en nog niet overflow'd. Verder kan ik nergens zien dat de SCL lijn ook wordt gepulst met die timer/counter0.
Iemand die daarover wat meer duidelijkheid kan verschaffen?
[Bericht gewijzigd door pcnerd op (73%)]