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.

http://homepage.hispeed.ch/peterfleury/avr-software.html

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.

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 ....

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.

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 :P.

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%)]

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.

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%)]

ik ga bezig in GCC.

Ehhh als je toch GCC gaat doen waarom gebruik je dan Peter Fleury zn lib niet ?


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.

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%)]

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...

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

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.

Darn, jullie wijken van topic af zeg, kan de discussie misschien ergens anders worden voortgezet?

ik zoek gewoon een simpel voorbeeld voor het vragen van data

Dat antwoord had je al in mn eerste reactie.

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.

http://www.smartdata.com.au/8051/i2c_asm.zip

Helaas, asm is mij redelijk onbekend, wil ik nog wel is mee beginnen, maar C blijkt tot nu toe wel aardig toereikend.

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 :P.

[Bericht gewijzigd door pcnerd op (18%)]

dat lijkt me verschrikkelijk complexe code om iets heel simpel te doen....

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%)]