Operácie

Zbernica i2c: Rozdiel medzi revíziami

Z SensorWiki

(Vytvorená stránka „Zbernica i2c Category:DVPS“)
 
(Reference)
 
(34 medziľahlých úprav od 2 ďalších používateľov nie je zobrazených)
Riadok 1: Riadok 1:
Zbernica i2c
+
{| class="wikitable" style="float:right"
 +
|colspan="2" style="text-align:center;" |'''I²C'''
 +
|-
 +
|colspan="2"|[[Image:logoI2C.svg|250px|frameless|center]]
 +
|-
 +
|'''Druh'''||[https://en.wikipedia.org/wiki/Serial_communication Sériová komunikačná zbernica]
 +
|-
 +
!colspan="2"|'''Production history'''
 +
|-
 +
|'''Designer'''|| [https://en.wikipedia.org/wiki/Philips Philips Semiconductor], known
 +
<BR> today as [https://en.wikipedia.org/wiki/NXP_Semiconductors NXP Semiconductors]
 +
|-
 +
|'''Designed'''||1982; 34 years ago
 +
|-
 +
!colspan="2"|'''Data'''
 +
|-
 +
|'''Signal'''    ||[https://en.wikipedia.org/wiki/Open_drain Open drain]
 +
|-
 +
|'''Width''' ||1 bit (SDA) + clock (SCL)
 +
|-
 +
|Bitrate || 0.1 / 0.4 / 1.0 / 3.4 / 5.0&nbsp;Mbit/s<br>(depending on mode)
 +
|-
 +
|Protocol  || [https://en.wikipedia.org/wiki/Serial_communication Serial], [https://en.wikipedia.org/wiki/Half_Duplex Half Duplex]
 +
|}
  
  
 +
Zbernica '''I²C'''  ('''Inter-Integrated Circuit''', výslovnosť ''I-squared-C'', prípadne ''I-two-C'') je multi-master počítačová sériová zbernica, ktorú vyvinula v roku 1982 firma Philips (v súčasnosti NxP).
 +
Ako už názov naznačuje, jej primárnym účelom bolo zabezpečiť komunikáciu medzi periférnymi obvodmi pre spotrebnú elektroniku (zosilňovače, rozhlasové prijímače, televízory) v rámci dosky s plošnými spojmi. Okrem toho sa používa najmä na prepojovanie nízkorýchlostných periférií v počitačoch, vnorených (embedded) systémoch alebo mobilných zariadeniach. Postupne vzniklo niekoľko vylepšení, najmä s vyššou prenosovou rýchlosťou. Používanie bolo spočiatku licencované, ale od r. 2006 sa licenčné poplatky nevyžadujú (s výnimkou poplatku za pridelenie špecifickej adresy zariadenia). Zbernica bola úspešne akceptovaná priemyslom a kompatibilné periférne obvody vyrába niekoľko desiatok výrobcov, vrátane napr. Siemens AG (neskôr Infineon), NEC, Texas Instruments, STMicroelectronics, alebo Motorola (neskôr Freescale, v súčasnosti spojená s NXP). Z licenčných dôvodov si vytvorili niektorí výrobcovia vlastnú, kompatibilnú verziu, ale s iným názvom. Preto sa táto zbernica v procesoroch Atmel AVR nazýva '''TWI''' (Two Wire Interface - dvojvodičové rozhranie). V PC priemysle sa zasa udomácnila zjednodušená verzia pod názvom '''SMBus''' (Intel, 1995).
  
[[Category:DVPS]]
+
<div style='text-align: center;'>
 +
[[Súbor:MIPS_I2C.svg|500px]]<BR>
 +
''Príklad zapojenia zbernice s jedným riadiacim mikropočítačom a troma perifériami - ADC, DAC a druhý mikropočítač - so zapojenými pull-up rezistormi R<sub>p</sub>.''
 +
</div>
 +
 
 +
 
 +
== Charakteristika ==
 +
Zbernica rozlišuhe zariadenia typu ''master'' (začína a končí komunikáciu a generuje aj taktovací signál SCL) a ''slave'' (s ktorými master komunikuje). Zbernica je rozšírená v mnohých oblastiach, niekoľko príkladov, s ktorými sme už v minulosti na cvičeniach pracovali zahŕňa napr.:
 +
* Pamäť EEPROM určená na ukladanie konfiguračných parametrov, napr. [[Zbernica i2c: EEPROM|Atmel M24C02]]
 +
* Rozhlasový [[Zbernica i2c: FM rádio|FM tuner RDA5807SS]] s možnosťou digitálneho ladenia staníc a predvolieb
 +
* Radič 4-miestneho 7-segmentového displeja [[Zbernica i2c: SAA1064|SAA1064]]
 +
* Snímač teploty a vlhkosti [[Zbernica i2c: SHT11|Sensirion SHT-11]] (zároveň príklad nekompatibilnej implementácie zbernice)
 +
* Hodiny reálného času [[Projekt: Zbernica i2c: hodiny RTC|Phillips PCF 8583]]
 +
* Obvod A/D a D/A prevodníka [[Zbernica i2c: PCF8591|Phillips PCF 8591]] s ktorým budeme pracovať aj na cvičeniach.
 +
 
 +
Kým sem neičo pribudne, tak aspoň stručný návod v češtine:
 +
 
 +
* https://navody.dratek.cz/technikuv-blog/zjisteni-adresy-i2c-twi-wire-zarizeni.html
 +
 
 +
== Fyzická vrstva ==
 +
Umožňuje propojení až 128 různých zařízení s pomocí pouze dvou obousměrných [[elektrický vodič|vodičů]]. Jeden tvoří [[hodinový signál]] SCL (Synchronous Clock) a druhý datový kanál SDA (Synchronous Data). Z elektrického hlediska jsou oba kanály zapojeny jako otevřený kolektor. Maximální délka vodičů je dána jejich nejvyšší přípustnou kapacitou 400 pF. Každý vodič musí být připojen jedním [[Pull up rezistor|pull-up]] [[rezistor]]em ke kladnému [[elektrické napětí|napětí]], což zajistí vysokou úroveň v klidovém stavu. Při probíhajícím přenosu jsou na SDA vysílány jednotlivé datové bity přičemž platí pravidlo, že logická úroveň na SDA se smí měnit pouze je-li SCL v úrovni L. Toto pravidlo je porušeno ve dvou speciálních případech. A to při vysílání podmínek START a STOP, které se používají k zahájení komunikace a k ukončení přenosu.
 +
 
 +
Maximální frekvence signálu SCL je podle verze I<sup>2</sup>C 100 kHz nebo 400 kHz. Pro obě frekvence je dána minimální povolená doba setrvání SCL v úrovni L a H. Při komunikaci i při přenosu dat si jednotlivé stanice synchronizují generátory hodin tak, že trvání úrovně H na SCL je odměřováno vnitřním časovačem každé stanice až od okamžiku, kdy SCL skutečně úrovně H dosáhne (protože je SCL typu otevřený kolektor, může být v úrovni L držen i v situaci kdy se daná stanice snaží nastavit úroveň H). Podobně je doba trvání úrovně L na SCL odměřována od sestupné hrany. Tento mechanismus umožňuje některé ze stanic zpomalit přenos: pomalá stanice může podržet po určitou dobu signál SCL v úrovni L a tím zabránit vysílající stanici ve vyslání dalšího bitu. Sběrnice I<sup>2</sup>C neumožňuje [[duplexní spojení|duplexní přenos]], v jednom okamžiku vysílá jen jedno zařízení. Všechna zařízení připojená na [[sběrnice|sběrnici]] musí mít individuální [[adresa (programování)|adresu]] o délce 7 nebo 10 bitů a implementovaný mechanizmus komunikace pomocí I²C sběrnice.
 +
 
 +
=== Časový diagram ===
 +
[[Soubor:I2C data transfer.svg|střed|600px|Sekvence přenosu dat]]
 +
 
 +
Přenos dat se zahajuje START bitem ('''S'''), když je SDA nízká, zatímco SCL zůstává vysoká. Pak, SDA nastaví přenášený bit zatímco SCL je nízká (modrá) a jsou odebrány vzorky dat (přijaté) při SCL stoupá (zelená). Když je přenos dokončen, je poslaný STOP bit ('''P''') pro uvolnění datové linky, změnou SDA na vysokou, zatímco SCL je trvale vysoký. Aby se zabránilo falešně detekci, je úroveň na SDA změněn na negativní hraně a je zachycen na kladné hrany SCL.
 +
[[Soubor:I2CByteSend M.jpg|náhled|630x630px]]
 +
 
 +
== Linková vrstva ==
 +
 
 +
Každému přenosu předchází vyslání podmínky START. Potom je vysílána 7bitová adresa příjemce a jeden bit R/W, který indikuje požadovanou operaci (čtení/zápis). Další bit ACK je vysílán s úrovní H a je určen k potvrzení přijímací stanice o připravenosti přijímat. Dále jsou přenášena data ve směru určeném předchozím bitem R/W. Každý byte je následován jedním bitem ACK. Po ukončení přenosu je vyslána podmínka STOP.
 +
 
 +
=== Řízení komunikace ===
 +
 
 +
Pro řízení komunikace se na I<sup>2</sup>C používá metoda s detekcí kolize. Každá ze stanic může zahájit vysílání, je-li předtím sběrnice v klidovém stavu. Během vysílání musí neustále porovnávat vysílané bity se skutečným stavem SDA. Je-li zjištěn rozdíl mezi očekávaným a skutečným stavem linky SDA, je to indikace kolize mezi několika stanicemi. Vzhledem k charakteru sběrnice (otevřené kolektory) může k této situaci dojít, pokud určitá stanice vysílá úroveň H, zatímco jiná stanice vysílá úroveň L. Stanice, která na lince zjistí úroveň L zatímco sama vysílá H musí vysílání okamžitě ukončit .
 +
K řízení komunikace většinou dochází během vyslání několika prvních bitů, kdy je vysílána adresa přijímací stanice. Pokud by se např. dvě stanice současně pokusily o zápis do stejného obvodu, nastane kolize až při přenosu vlastních zapisovaných dat. V krajním případě, kdy několik stanic současně zapisuje stejná data na stejnou adresu, nemusí být kolize vůbec detekována.
 +
 
 +
=== Adresování ===
 +
 
 +
Každá stanice připojená na I<sup>2</sup>C má přidělenou 7bitovou adresu. Po zachycení podmínky START, porovnávají všechny obvody svou adresu s adresou, která je vysílána na sběrnici. Zjistí-li některý z obvodů shodu, je vysílání určeno právě jemu a musí přijetí adresy potvrdit bitem ACK. Potom přijímá nebo vysílá další data. Několik adres je na I<sup>2</sup>C vyhrazeno pro speciální účely. Například adresa 0000000 je určena pro vysílání [[broadcast]] adresy 0000011, 00001XX a 11111XX jsou rezervovány pro další účely.
 +
 
 +
=== Potvrzování ===
 +
 
 +
Každý vysílaný byte a vyslaná adresa je následována vysláním jednoho bitu
 +
ACK. Vysílající stanice jej vysílá v úrovni H. Přijímající stanice potvrzuje přijetí tím, že
 +
v době vysílání ACK připojí SDA na úroveň L. Pokud vysílající stanice nedostane potvrzení příjmu, ukončí vysílání podmínkou STOP.
 +
 
 +
== Reference ==
 +
<references />
 +
 
 +
 
 +
 
 +
==='''Literatúra'''===
 +
 
 +
* https://rheingoldheavy.com/i2c-basics/
 +
* https://www.allaboutcircuits.com/technical-articles/introduction-to-the-i2c-bus/
 +
 
 +
* Official I2C Specification Version 6 http://www.nxp.com/documents/user_manual/UM10204.pdf
 +
* Official List of assigned NXP / Philips I2C addresses http://www.diolan.com/downloads/i2c-address-allocation-table.pdf
 +
 
 +
* Podrobný článok na Wikipedii: https://en.wikipedia.org/wiki/I%C2%B2C
 +
** Pseudokod bitbang i2c https://en.wikipedia.org/wiki/I%C2%B2C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
 +
** https://learn.sparkfun.com/tutorials/i2c Dobry tutorial
 +
** Procyon SW library http://www.procyonengineering.com/embedded/avr/avrlib/docs/html/i2csw_8c-source.html
 +
** Bitbanging by hand http://hackaday.com/2013/08/11/bitbanging-i2c-by-hand/
 +
** http://hackaday.com/2015/06/25/embed-with-elliot-i2c-bus-scanning/
 +
** http://howtomechatronics.com/tutorials/arduino/how-i2c-communication-works-and-how-to-use-it-with-arduino/
 +
 
 +
 
 +
* Arduino TWI Library  https://www.arduino.cc/en/Reference/Wire
 +
* http://playground.arduino.cc/Main/WireLibraryDetailedReference
 +
 
 +
 
 +
* http://fritzing.org/projects/readwrite-serial-eeprom-via-i2c  - DO PPT
 +
* https://learn.sparkfun.com/tutorials/i2c    - DO PPT
 +
 
 +
 
 +
* [http://www.st.com/internet/com/TECHNICAL_RESOURCES/TECHNICAL_LITERATURE/DATASHEET/CD00001163.pdf M24C02 Datasheet]
 +
* Mitchell Kahn: ''[http://ap.urpi.fei.stuba.sk/mmp/doc/prog_i2c.pdf Programming the i2c interface].'' Dr. Dobb's Journal, June 1992.
 +
* http://dsscircuits.com/articles/86-articles/47-effects-of-varying-i2c-pull-up-resistors
 +
* http://www.gammon.com.au/i2c
 +
* http://www.gammon.com.au/forum/?id=10896
 +
 
 +
=== Datasheets ===
 +
 
 +
* [http://www.atmel.com/images/doc0180.pdf AT24C02 EEPROM memory]
 +
* [http://thingm.com/fileadmin/thingm/downloads/BlinkM_datasheet.pdf BlinkM Smart RGB LED]
 +
 
 +
 
 +
Vsetko mozne k zbernici i2c (mozno presunut na stranku Category):
 +
 
 +
=== Tools ===
 +
 
 +
'''Bus Pirate'''
 +
 
 +
* [http://dangerousprototypes.com/docs/Bus_Pirate_101_tutorial Tutorial 101]
 +
* [http://dangerousprototypes.com/docs/Bus_Pirate_102_tutorial Tutorial 102]
 +
* [http://dangerousprototypes.com/2013/05/03/bus-pirate-console/ Bus Pirate Console] ([https://github.com/x893/BusPirateConsole/tree/master/bin/Debug download])
 +
 
 +
 
 +
[[Súbor:BusPirateConnection.png]]
 +
 
 +
Bus Pirate po pripojení sa nainštaluje FTDI serial port driver a OS mu pridelí nejaký port.
 +
Cez tento port sa terminálovým programom pripojíme k Bus Piratovi. Parametre portu sú
 +
115 200 bps / 8 / N / 1, no Flow control.
 +
 
 +
Prvý príkaz je obvykle otáznik, zobrazí sa celé menu.
 +
 
 +
Postup príkazov pre prácu s i2c zbernicou:
 +
 +
<source lang="teraterm" class="brush: js; ruler: true; first-line: 10; highlight: [2, 4, 6]">
 +
HiZ> ?
 +
 
 +
MENUS
 +
? Help
 +
I Status info
 +
M Bus mode
 +
B Terminal speed
 +
O Data display format
 +
V Check supply voltages
 +
F Frequency count on AUX
 +
G Frequency generator/PWM on AUX
 +
C AUX pin assignment
 +
L Bit order
 +
P Pullup resistors
 +
= HEX/DEC/BIN converter
 +
~ Self test
 +
# Reset
 +
$ Bootloader
 +
 
 +
SYNTAX
 +
A/a/@ AUX output toggle H/L/read
 +
W/w Power supply toggle on/off
 +
d (D) Measure voltage on ADC probe (continuous)
 +
[ ({) Start (with read)
 +
] or } Stop
 +
R or r Read byte
 +
0b Write BIN byte
 +
0h or 0x Write HEX byte
 +
0-255 Write DEC byte
 +
, Delimiter (also space)
 +
& 1uS delay
 +
: Repeat (r:2, 0x0a:4, &:20, ^:2, etc.)
 +
(#) Run macro, (0) for macro list
 +
 
 +
RAW BUS OPERATIONS
 +
/\ Clock H/L
 +
-/_ Data H/L
 +
. Read data input pin state
 +
^ Clock tick
 +
! Read bit
 +
 
 +
HiZ> M
 +
 
 +
1. HiZ
 +
2. 1-WIRE
 +
3. UART
 +
4. I2C
 +
5. SPI
 +
6. JTAG
 +
7. RAW2WIRE
 +
8. RAW3WIRE
 +
9. PC KEYBOARD
 +
10. LCD
 +
 
 +
(1) > 4
 +
Mode selected
 +
Set speed:
 +
1. ~5KHz
 +
2. ~50KHz
 +
3. ~100KHz
 +
4. ~400KHz
 +
(1) >4
 +
READY
 +
 
 +
I2C>
 +
 
 +
</source>
 +
 
 +
Teraz je Pirát pripravený pracovať so zbernicou i2c.
 +
Zapneme napájanie a Pull-Up rezistory:
 +
 
 +
<source lang="teraterm">
 +
I2C> w
 +
POWER SUPPLIES OFF
 +
 
 +
I2C> v
 +
Voltage monitors: 5V: 0.05 | 3.3V: 0.00 | VPULLUP: 0.01 |
 +
 
 +
I2C> W
 +
POWER SUPPLIES ON
 +
 
 +
I2C> v
 +
Voltage monitors: 5V: 6.59 | 3.3V: 3.88 | VPULLUP: 5.00 |
 +
 
 +
I2C> P
 +
  1. Pull-ups off
 +
  2. Pull-ups on
 +
(1) > 2
 +
Pull-up resistors ON
 +
 
 +
I2C>
 +
 
 +
</source>
 +
 
 +
Preskenujeme zbernicu, co je na nej pripojene:
 +
 +
  I2C> (1)                        <<< macro 1, I2C address search
 +
  Searching 7bit I2C address space.
 +
  Found devices at:
 +
  0xA0(0x50 W) 0xA1(0x50 R)
 +
   
 +
  I2C>
 +
 
 +
Now we can talk to the chip.
 +
I needed something very simple, only to verify that the chip is OK, so I wrote
 +
random byte (I chose 0xAA) to the address 0x00 and read it back.
 +
 
 +
To write a byte to memory we need to enter this [0xA0 0x00 0xAA]
 +
 
 +
  [        = Start bit
 +
  0xA0 = I2C address of the EEPROM with the WRITE bit
 +
  0x00 = Memory address
 +
  0xAA = Data
 +
  ]          = Stop bit
 +
 
 +
  I2C> [0xA0 0x00 0xAA]
 +
  I2C START BIT
 +
  WRITE: 0xA0 ACK
 +
  WRITE: 0x00 ACK
 +
  WRITE: 0xAA ACK
 +
  I2C STOP BIT
 +
 
 +
  I2C>
 +
 
 +
Now we need to set the read pointer to address we want to read. This
 +
is accomplished with this command [0xA0 0x00]
 +
 
 +
  I2C> [0xA0 0x00]
 +
  I2C START BIT
 +
  WRITE: 0xA0 NACK
 +
  WRITE: 0x00 NACK
 +
  I2C STOP BIT
 +
 
 +
  I2C>
 +
 
 +
And at last we can read the byte stored at the address. [0xA1 r:1]
 +
0xA1 = I2C address of the EEPROM with the READ bit set
 +
r:1      = tells the Bus Pirate to read 1 byte
 +
 
 +
  I2C> [0xA1 rrrrr]    alebo [0xA1 r:5]
 +
  I2C START BIT
 +
  WRITE: 0xA1 ACK
 +
  READ: 0x0B ACK
 +
  READ: 0xA0 ACK
 +
  READ: 0x03 ACK
 +
  READ: 0xAB ACK
 +
  READ: 0x55 NACK
 +
  I2C STOP BIT
 +
 
 +
  I2C>
 +
 
 +
Toto posledne sa ukazalo ze nefunguje, pretoze random read asi treba spravit takto [0xA0 0x1 0xA [0xA1 r] (opakovany start).
 +
 
 +
When you're done -  na konci:
 +
 
 +
  I2C> m                            <<<mode menu
 +
  1. HiZ
 +
  ...
 +
  10. LCD
 +
  (1) >                            <<<HiZ is the default
 +
  Mode selected
 +
 
 +
  HiZ>
 +
 
 +
 
 +
 
 +
* http://www.i2c-bus.org/
 +
* Analyzator: Bus Pirate + [https://www.lxtreme.nl/ols/ Logic Sniffer OLS]:
 +
** http://dangerousprototypes.com/docs/Logic_analyzer_mode
 +
** https://pixhawk.org/dev/bus_debugging_with_logic_analyzer
 +
** http://www.hobbytronics.co.uk/bus-pirate-logic-sniffer
 +
** http://www.hobbytronics.co.uk/bus-pirate
 +
 
 +
 
 +
 
 +
* http://dangerousprototypes.com/docs/Logic_Sniffer_101
 +
* http://dangerousprototypes.com/docs/Logic_Sniffer_102
 +
 
 +
 
 +
 
 +
Ukazkove programy (pre Arduino):
 +
* Jednoduchy zapis
 +
* Jednoduche citanie (vyzaduje aj zapis)
 +
* Jednoduchy scan zbernice  http://playground.arduino.cc/Main/I2cScanner
 +
* Komplexny i2c scanner https://github.com/RobTillaart/Arduino/tree/master/sketches/MultiSpeedI2CScanner
 +
 
 +
==='''K. Zbernica i2c:  EEPROM'''===
 +
 
 +
Prečítajte obsah predloženej pamäti EEPROM a zobrazte na PC.
 +
 
 +
[[Obrázok:i2c_M24C02.jpg]]
 +
 
 +
<source lang="c">
 +
 
 +
#include <avr/interrupt.h> 
 +
#include <stdlib.h>
 +
#include <avr/io.h>
 +
#include <util/delay.h>
 +
#include <util/twi.h>
 +
#include <stdio.h>
 +
 
 +
//#include "lcd.h"
 +
#include "Uart_ch.h"
 +
 
 +
unsigned char RD_EEprom(unsigned char adr_RAM);
 +
void WR_EEprom(unsigned char adr_IC,unsigned char adr_pocitadlo);
 +
void obsluha_Stav_Aut_I2C(void);
 +
 
 +
 
 +
 
 +
#define ADR_IC_WR 0xA0  // EEPROM Adresa IC+WR
 +
#define ADR_IC_RD 0xA1  // EEPROM Adresa IC+RD
 +
 
 +
 
 +
 
 +
volatile  unsigned char buffer_I2C[10]; // buffer pre obsluhu I2C
 +
 +
 
 +
 
 +
 
 +
 
 +
FILE mystdout_Uart = FDEV_SETUP_STREAM(sendchar, NULL, _FDEV_SETUP_WRITE);
 +
 
 +
 
 +
void WR_EEprom(unsigned char adr_IC,unsigned char adr_pocitadlo)
 +
{ // nastavenie globalnych premennych
 +
 
 +
buffer_I2C[0]=adr_IC; // Adr obvodu + wr
 +
buffer_I2C[1]=adr_pocitadlo;     // Nastavenie Adresneho citaca 24LC04 , Adresa (z ktorej citam)/(do ktorej zapisujem)
 +
// buffer_I2C[1]=<obsah>; // zapisovane data, byte,-ty
 +
 +
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition
 +
// a odovzdanie riadenia "preruseniu od I2C"
 +
obsluha_Stav_Aut_I2C();
 +
 
 +
}
 +
 
 +
 
 +
 
 +
unsigned char RD_EEprom(unsigned char adr_RAM)
 +
{
 +
// nastavenie globalnych premennych
 +
 
 +
buffer_I2C[0]=ADR_IC_RD; // Adr obvodu + rd
 +
buffer_I2C[1]=adr_RAM;     // Sem vrati obsah z nastavenej adresy 24LC04
 +
 
 +
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition
 +
// a odovzdanie riadenia "preruseniu od I2C"
 +
obsluha_Stav_Aut_I2C();
 +
return(buffer_I2C[1]);
 +
 +
}
 +
 
 +
// tato funkcia vyuziva globalne premenne
 +
// buffer_I2C[x]
 +
// Wr_data - tato premenna nadobuda vyznam az pri komunikacii s konkretnou premennou
 +
//          vid. "instrukcny subor" I2C periferie
 +
 
 +
// implementovany instrukcny subor pre seriovu EEPROM max 256 byte
 +
// S|adr_IO+wr|<AC>|P                -- nastavenie adresneho citaca pamate EEPROM
 +
// {nie je implementova} S|adr_IO+wr|<AC>|data|P          -- zapisanie dat na nastavenu adresu pamate EEPROM
 +
// S|adr_IO+rd|data|P                -- precitanie jedneho bytu z aktualne nastavenej adresy pamate EEPROM
 +
//                                      obsah adresneho citaca sa inkrementne
 +
 
 +
void obsluha_Stav_Aut_I2C(void)
 +
{ unsigned char pom_St_Aut=0;
 +
 +
 +
nav:while ((TWCR & _BV(TWINT)) == 0);  /* wait for transmission */
 +
 
 +
    {  pom_St_Aut=TWSR & 0xf8; // precitaj stav
 +
    printf(" %02x",pom_St_Aut);
 +
switch(pom_St_Aut)
 +
{ case TW_START:// = 0x08 // odvysielany start
 +
  case TW_REP_START:// = 0x10 // odvysielany repeated start
 +
                TWDR = buffer_I2C[0];// Adr+wr/rd, adresa IO
 +
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
 +
  break;
 +
 
 +
  case TW_MT_SLA_ACK: //        0x18  Data byte has been tramsmitted and ACK received
 +
                TWDR = buffer_I2C[1]; // tu konkretne, nastavenie Adreseho citaca pamate.
 +
  TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
 +
  break;
 +
 
 +
  case TW_MT_DATA_ACK: //        0x28  Data byte has been tramsmitted and ACK received
 +
  TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
 +
return; //  tento riadok v preruseni vypadne
 +
  break;
 +
 
 +
  case TW_MR_SLA_ACK: //  0x40  // Data byte has been tramsmitted and NACK received
 +
  TWCR = _BV(TWINT) | _BV(TWEN) ; // clear interrupt to start transmission
 +
  break;
 +
 
 +
  case TW_MR_DATA_NACK: // 0x58  // Data byte has been tramsmitted and ACK received
 +
      buffer_I2C[1]= TWDR;     // Vycitaj jeden byte z  24LC04.  Adresny citac sa posunie
 +
      TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); // send stop condition
 +
return; // tento riadok v preruseni vypadne
 +
  break;
 +
 
 +
  default:
 +
  TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
 +
return; // tento riadok v preruseni vypadne
 +
  break;
 +
}
 +
}
 +
goto nav; // toto v preruseni vypadne
 +
}
 +
 
 +
 
 +
 
 +
 
 +
int main(void)
 +
{ unsigned char znak;
 +
 
 +
unsigned int i=0;
 +
unsigned char poc_adresa_EEPROM=0;
 +
 +
 
 +
 
 +
inituart(); // inicializacia UARTU                      // inicializacia v 4-bitovom rezime
 +
                   
 +
 
 +
//  sei();                    // Enable ALL interrupts                     
 +
 
 +
// ini I2C
 +
 +
 
 +
  TWCR =  _BV(TWEN); /* send start condition */
 +
  TWBR = 72; // fi2c= fosc/(16 +2(preddelic=00=> 1)(<TWBR>)) = 100kHz
 +
  TWSR=1;
 +
}
 +
 
 +
 
 +
// TODO: to USART
 +
/* ************************************************************ */
 +
 
 +
stdout = &mystdout_Uart;
 +
 
 +
 
 +
printf("Nastavenie adresy EEPROM = %02x \n\r",poc_adresa_EEPROM);
 +
WR_EEprom(ADR_IC_WR,poc_adresa_EEPROM);
 +
 
 +
 
 +
printf("\n\r\rVypis EEPROM: \n\r");
 +
 
 +
// vypisme prvych 10 znakov
 +
    while (i<10) //256)// kapacita pamate 256 znakov, bytov,
 +
{
 +
znak = RD_EEprom(ADR_IC_RD); // obsah adresneho citaca EEPROM sa automaticky inkrementuje
 +
if(znak==0xff)i=256; // vymazane pametove miesto
 +
{
 +
printf("  %02d %02x %c\r",i++,znak,znak);
 +
}
 +
       
 +
}
 +
 +
for(;;);  // a cakam napr. na  "RESET"
 +
 +
}
 +
</source>
 +
 
 +
 
 +
[[Category:DVPS]][[Category:AVR]][[Category:MMP]][[Category:I2C]][[Category:MEMS]]

Aktuálna revízia z 20:48, 20. apríl 2021

I²C
LogoI2C.svg
Druh Sériová komunikačná zbernica
Production history
Designer Philips Semiconductor, known


today as NXP Semiconductors

Designed 1982; 34 years ago
Data
Signal Open drain
Width 1 bit (SDA) + clock (SCL)
Bitrate 0.1 / 0.4 / 1.0 / 3.4 / 5.0 Mbit/s
(depending on mode)
Protocol Serial, Half Duplex


Zbernica I²C (Inter-Integrated Circuit, výslovnosť I-squared-C, prípadne I-two-C) je multi-master počítačová sériová zbernica, ktorú vyvinula v roku 1982 firma Philips (v súčasnosti NxP). Ako už názov naznačuje, jej primárnym účelom bolo zabezpečiť komunikáciu medzi periférnymi obvodmi pre spotrebnú elektroniku (zosilňovače, rozhlasové prijímače, televízory) v rámci dosky s plošnými spojmi. Okrem toho sa používa najmä na prepojovanie nízkorýchlostných periférií v počitačoch, vnorených (embedded) systémoch alebo mobilných zariadeniach. Postupne vzniklo niekoľko vylepšení, najmä s vyššou prenosovou rýchlosťou. Používanie bolo spočiatku licencované, ale od r. 2006 sa licenčné poplatky nevyžadujú (s výnimkou poplatku za pridelenie špecifickej adresy zariadenia). Zbernica bola úspešne akceptovaná priemyslom a kompatibilné periférne obvody vyrába niekoľko desiatok výrobcov, vrátane napr. Siemens AG (neskôr Infineon), NEC, Texas Instruments, STMicroelectronics, alebo Motorola (neskôr Freescale, v súčasnosti spojená s NXP). Z licenčných dôvodov si vytvorili niektorí výrobcovia vlastnú, kompatibilnú verziu, ale s iným názvom. Preto sa táto zbernica v procesoroch Atmel AVR nazýva TWI (Two Wire Interface - dvojvodičové rozhranie). V PC priemysle sa zasa udomácnila zjednodušená verzia pod názvom SMBus (Intel, 1995).

MIPS I2C.svg
Príklad zapojenia zbernice s jedným riadiacim mikropočítačom a troma perifériami - ADC, DAC a druhý mikropočítač - so zapojenými pull-up rezistormi Rp.


Charakteristika

Zbernica rozlišuhe zariadenia typu master (začína a končí komunikáciu a generuje aj taktovací signál SCL) a slave (s ktorými master komunikuje). Zbernica je rozšírená v mnohých oblastiach, niekoľko príkladov, s ktorými sme už v minulosti na cvičeniach pracovali zahŕňa napr.:

  • Pamäť EEPROM určená na ukladanie konfiguračných parametrov, napr. Atmel M24C02
  • Rozhlasový FM tuner RDA5807SS s možnosťou digitálneho ladenia staníc a predvolieb
  • Radič 4-miestneho 7-segmentového displeja SAA1064
  • Snímač teploty a vlhkosti Sensirion SHT-11 (zároveň príklad nekompatibilnej implementácie zbernice)
  • Hodiny reálného času Phillips PCF 8583
  • Obvod A/D a D/A prevodníka Phillips PCF 8591 s ktorým budeme pracovať aj na cvičeniach.

Kým sem neičo pribudne, tak aspoň stručný návod v češtine:

Fyzická vrstva

Umožňuje propojení až 128 různých zařízení s pomocí pouze dvou obousměrných vodičů. Jeden tvoří hodinový signál SCL (Synchronous Clock) a druhý datový kanál SDA (Synchronous Data). Z elektrického hlediska jsou oba kanály zapojeny jako otevřený kolektor. Maximální délka vodičů je dána jejich nejvyšší přípustnou kapacitou 400 pF. Každý vodič musí být připojen jedním pull-up rezistorem ke kladnému napětí, což zajistí vysokou úroveň v klidovém stavu. Při probíhajícím přenosu jsou na SDA vysílány jednotlivé datové bity přičemž platí pravidlo, že logická úroveň na SDA se smí měnit pouze je-li SCL v úrovni L. Toto pravidlo je porušeno ve dvou speciálních případech. A to při vysílání podmínek START a STOP, které se používají k zahájení komunikace a k ukončení přenosu.

Maximální frekvence signálu SCL je podle verze I2C 100 kHz nebo 400 kHz. Pro obě frekvence je dána minimální povolená doba setrvání SCL v úrovni L a H. Při komunikaci i při přenosu dat si jednotlivé stanice synchronizují generátory hodin tak, že trvání úrovně H na SCL je odměřováno vnitřním časovačem každé stanice až od okamžiku, kdy SCL skutečně úrovně H dosáhne (protože je SCL typu otevřený kolektor, může být v úrovni L držen i v situaci kdy se daná stanice snaží nastavit úroveň H). Podobně je doba trvání úrovně L na SCL odměřována od sestupné hrany. Tento mechanismus umožňuje některé ze stanic zpomalit přenos: pomalá stanice může podržet po určitou dobu signál SCL v úrovni L a tím zabránit vysílající stanici ve vyslání dalšího bitu. Sběrnice I2C neumožňuje duplexní přenos, v jednom okamžiku vysílá jen jedno zařízení. Všechna zařízení připojená na sběrnici musí mít individuální adresu o délce 7 nebo 10 bitů a implementovaný mechanizmus komunikace pomocí I²C sběrnice.

Časový diagram

střed|600px|Sekvence přenosu dat

Přenos dat se zahajuje START bitem (S), když je SDA nízká, zatímco SCL zůstává vysoká. Pak, SDA nastaví přenášený bit zatímco SCL je nízká (modrá) a jsou odebrány vzorky dat (přijaté) při SCL stoupá (zelená). Když je přenos dokončen, je poslaný STOP bit (P) pro uvolnění datové linky, změnou SDA na vysokou, zatímco SCL je trvale vysoký. Aby se zabránilo falešně detekci, je úroveň na SDA změněn na negativní hraně a je zachycen na kladné hrany SCL. náhled|630x630px

Linková vrstva

Každému přenosu předchází vyslání podmínky START. Potom je vysílána 7bitová adresa příjemce a jeden bit R/W, který indikuje požadovanou operaci (čtení/zápis). Další bit ACK je vysílán s úrovní H a je určen k potvrzení přijímací stanice o připravenosti přijímat. Dále jsou přenášena data ve směru určeném předchozím bitem R/W. Každý byte je následován jedním bitem ACK. Po ukončení přenosu je vyslána podmínka STOP.

Řízení komunikace

Pro řízení komunikace se na I2C používá metoda s detekcí kolize. Každá ze stanic může zahájit vysílání, je-li předtím sběrnice v klidovém stavu. Během vysílání musí neustále porovnávat vysílané bity se skutečným stavem SDA. Je-li zjištěn rozdíl mezi očekávaným a skutečným stavem linky SDA, je to indikace kolize mezi několika stanicemi. Vzhledem k charakteru sběrnice (otevřené kolektory) může k této situaci dojít, pokud určitá stanice vysílá úroveň H, zatímco jiná stanice vysílá úroveň L. Stanice, která na lince zjistí úroveň L zatímco sama vysílá H musí vysílání okamžitě ukončit . K řízení komunikace většinou dochází během vyslání několika prvních bitů, kdy je vysílána adresa přijímací stanice. Pokud by se např. dvě stanice současně pokusily o zápis do stejného obvodu, nastane kolize až při přenosu vlastních zapisovaných dat. V krajním případě, kdy několik stanic současně zapisuje stejná data na stejnou adresu, nemusí být kolize vůbec detekována.

Adresování

Každá stanice připojená na I2C má přidělenou 7bitovou adresu. Po zachycení podmínky START, porovnávají všechny obvody svou adresu s adresou, která je vysílána na sběrnici. Zjistí-li některý z obvodů shodu, je vysílání určeno právě jemu a musí přijetí adresy potvrdit bitem ACK. Potom přijímá nebo vysílá další data. Několik adres je na I2C vyhrazeno pro speciální účely. Například adresa 0000000 je určena pro vysílání broadcast adresy 0000011, 00001XX a 11111XX jsou rezervovány pro další účely.

Potvrzování

Každý vysílaný byte a vyslaná adresa je následována vysláním jednoho bitu ACK. Vysílající stanice jej vysílá v úrovni H. Přijímající stanice potvrzuje přijetí tím, že v době vysílání ACK připojí SDA na úroveň L. Pokud vysílající stanice nedostane potvrzení příjmu, ukončí vysílání podmínkou STOP.

Reference



Literatúra




Datasheets


Vsetko mozne k zbernici i2c (mozno presunut na stranku Category):

Tools

Bus Pirate


BusPirateConnection.png

Bus Pirate po pripojení sa nainštaluje FTDI serial port driver a OS mu pridelí nejaký port. Cez tento port sa terminálovým programom pripojíme k Bus Piratovi. Parametre portu sú 115 200 bps / 8 / N / 1, no Flow control.

Prvý príkaz je obvykle otáznik, zobrazí sa celé menu.

Postup príkazov pre prácu s i2c zbernicou:

 HiZ> ?

 MENUS
 ? Help
 I Status info
 M Bus mode
 B Terminal speed
 O Data display format
 V Check supply voltages
 F Frequency count on AUX
 G Frequency generator/PWM on AUX
 C AUX pin assignment
 L Bit order
 P Pullup resistors
 = HEX/DEC/BIN converter
 ~ Self test
 # Reset
 $ Bootloader

 SYNTAX
 A/a/@ AUX output toggle H/L/read
 W/w Power supply toggle on/off
 d (D) Measure voltage on ADC probe (continuous)
 [ ({) Start (with read)
 ] or } Stop
 R or r Read byte
 0b Write BIN byte
 0h or 0x Write HEX byte
 0-255 Write DEC byte
 , Delimiter (also space)
 & 1uS delay
 : Repeat (r:2, 0x0a:4, &:20, ^:2, etc.)
 (#) Run macro, (0) for macro list

 RAW BUS OPERATIONS
 /\ Clock H/L
 -/_ Data H/L
 . Read data input pin state
 ^ Clock tick
 ! Read bit

HiZ> M

 1. HiZ
 2. 1-WIRE
 3. UART
 4. I2C
 5. SPI
 6. JTAG
 7. RAW2WIRE
 8. RAW3WIRE
 9. PC KEYBOARD
10. LCD

(1) > 4
Mode selected
Set speed:
 1. ~5KHz
 2. ~50KHz
 3. ~100KHz
 4. ~400KHz
(1) >4
READY

I2C>

Teraz je Pirát pripravený pracovať so zbernicou i2c. Zapneme napájanie a Pull-Up rezistory:

 I2C> w
 POWER SUPPLIES OFF

 I2C> v
 Voltage monitors: 5V: 0.05 | 3.3V: 0.00 | VPULLUP: 0.01 |

 I2C> W
 POWER SUPPLIES ON

 I2C> v
 Voltage monitors: 5V: 6.59 | 3.3V: 3.88 | VPULLUP: 5.00 |

 I2C> P
  1. Pull-ups off
  2. Pull-ups on
 (1) > 2
 Pull-up resistors ON

 I2C>

Preskenujeme zbernicu, co je na nej pripojene:

 I2C> (1)                         <<< macro 1, I2C address search
 Searching 7bit I2C address space.
 Found devices at:
 0xA0(0x50 W) 0xA1(0x50 R)
    
 I2C>

Now we can talk to the chip. I needed something very simple, only to verify that the chip is OK, so I wrote random byte (I chose 0xAA) to the address 0x00 and read it back.

To write a byte to memory we need to enter this [0xA0 0x00 0xAA]

 [         = Start bit
 0xA0 = I2C address of the EEPROM with the WRITE bit
 0x00 = Memory address
 0xAA = Data
 ]          = Stop bit
 I2C> [0xA0 0x00 0xAA]
  I2C START BIT
  WRITE: 0xA0 ACK
  WRITE: 0x00 ACK
  WRITE: 0xAA ACK
  I2C STOP BIT
  
 I2C>

Now we need to set the read pointer to address we want to read. This is accomplished with this command [0xA0 0x00]

 I2C> [0xA0 0x00]
  I2C START BIT
  WRITE: 0xA0 NACK
  WRITE: 0x00 NACK
  I2C STOP BIT
  
 I2C>

And at last we can read the byte stored at the address. [0xA1 r:1] 0xA1 = I2C address of the EEPROM with the READ bit set r:1 = tells the Bus Pirate to read 1 byte

 I2C> [0xA1 rrrrr]    alebo [0xA1 r:5]
  I2C START BIT
  WRITE: 0xA1 ACK
  READ: 0x0B ACK
  READ: 0xA0 ACK
  READ: 0x03 ACK
  READ: 0xAB ACK
  READ: 0x55 NACK
  I2C STOP BIT
  
 I2C>

Toto posledne sa ukazalo ze nefunguje, pretoze random read asi treba spravit takto [0xA0 0x1 0xA [0xA1 r] (opakovany start).

When you're done - na konci:

 I2C> m                            <<<mode menu
 1. HiZ
 ...
 10. LCD
 (1) >                             <<<HiZ is the default
 Mode selected
  
 HiZ>




Ukazkove programy (pre Arduino):

K. Zbernica i2c: EEPROM

Prečítajte obsah predloženej pamäti EEPROM a zobrazte na PC.

I2c M24C02.jpg

#include <avr/interrupt.h>  
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <util/twi.h>
#include <stdio.h>

//#include "lcd.h"
#include "Uart_ch.h"

unsigned char RD_EEprom(unsigned char adr_RAM);
void WR_EEprom(unsigned char adr_IC,unsigned char adr_pocitadlo);
void obsluha_Stav_Aut_I2C(void);



#define ADR_IC_WR		0xA0   	// EEPROM Adresa IC+WR
#define ADR_IC_RD		0xA1   	// EEPROM Adresa IC+RD



volatile  unsigned char	buffer_I2C[10];	// buffer pre obsluhu I2C
	




FILE mystdout_Uart = FDEV_SETUP_STREAM(sendchar, NULL, _FDEV_SETUP_WRITE);


void WR_EEprom(unsigned char adr_IC,unsigned char adr_pocitadlo)
{ 	// nastavenie globalnych premennych

	buffer_I2C[0]=adr_IC;	// Adr obvodu + wr
	buffer_I2C[1]=adr_pocitadlo;	    // Nastavenie Adresneho citaca 24LC04 , Adresa (z ktorej citam)/(do ktorej zapisujem)
//	buffer_I2C[1]=<obsah>;			// zapisovane data, byte,-ty
	
	TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition 
	// a odovzdanie riadenia "preruseniu od I2C"
	obsluha_Stav_Aut_I2C();

}



unsigned char RD_EEprom(unsigned char adr_RAM)
{ 	
	// nastavenie globalnych premennych

	buffer_I2C[0]=ADR_IC_RD;	// Adr obvodu + rd
	buffer_I2C[1]=adr_RAM;		    // Sem vrati obsah z nastavenej adresy 24LC04

	TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN); // send start condition 
	// a odovzdanie riadenia "preruseniu od I2C"
	obsluha_Stav_Aut_I2C();
	return(buffer_I2C[1]);
	
}

// tato funkcia vyuziva globalne premenne 
// buffer_I2C[x]
// Wr_data - tato premenna nadobuda vyznam az pri komunikacii s konkretnou premennou
//           vid. "instrukcny subor" I2C periferie

// implementovany instrukcny subor pre seriovu EEPROM max 256 byte
// S|adr_IO+wr|<AC>|P                -- nastavenie adresneho citaca pamate EEPROM
// {nie je implementova} S|adr_IO+wr|<AC>|data|P           -- zapisanie dat na nastavenu adresu pamate EEPROM
// S|adr_IO+rd|data|P                -- precitanie jedneho bytu z aktualne nastavenej adresy pamate EEPROM
//                                      obsah adresneho citaca sa inkrementne 

void obsluha_Stav_Aut_I2C(void)
{ unsigned char pom_St_Aut=0;
	
	
nav:while ((TWCR & _BV(TWINT)) == 0);  /* wait for transmission */

    {   pom_St_Aut=TWSR & 0xf8;		// precitaj stav 
	    printf(" %02x",pom_St_Aut); 
	 	switch(pom_St_Aut)		
	 	{ case TW_START:// = 0x08 // odvysielany start
		  case TW_REP_START:// = 0x10 // odvysielany repeated start
		                 	TWDR = buffer_I2C[0];// Adr+wr/rd, adresa IO
	  						TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
		  break;
		  
		  case TW_MT_SLA_ACK:	//        0x18   Data byte has been tramsmitted and ACK received
		                 	TWDR = buffer_I2C[1]; // tu konkretne, nastavenie Adreseho citaca pamate.
	  						TWCR = _BV(TWINT) | _BV(TWEN); /* clear interrupt to start transmission */
		  break;

		  case TW_MT_DATA_ACK:	//        0x28   Data byte has been tramsmitted and ACK received
		   					TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
							return; //  tento riadok v preruseni vypadne
		  break;

		  case TW_MR_SLA_ACK:	//   0x40  // Data byte has been tramsmitted and NACK received
		   					TWCR = _BV(TWINT) | _BV(TWEN) ; // clear interrupt to start transmission 							
		  break;

		  case TW_MR_DATA_NACK:	// 0x58  // Data byte has been tramsmitted and ACK received
		  				    buffer_I2C[1]= TWDR;	    // Vycitaj jeden byte z  24LC04.  Adresny citac sa posunie
				      		TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); // send stop condition 
							return; // tento riadok v preruseni vypadne
		  break;		 

		  default:
		  					TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN); /* send stop condition */
							return; // tento riadok v preruseni vypadne
		  break;
	 	}
	}
	goto nav; // toto v preruseni vypadne
}




int main(void)
{ 	unsigned char znak;

unsigned int i=0;
unsigned char poc_adresa_EEPROM=0;
	


	inituart();								// inicializacia UARTU                       // inicializacia v 4-bitovom rezime
   	                   

//  sei();                    // Enable ALL interrupts                      

// ini I2C
{  
   
   TWCR =  _BV(TWEN); /* send start condition */
   TWBR = 72; // fi2c= fosc/(16 +2(preddelic=00=> 1)(<TWBR>)) = 100kHz
   TWSR=1;
}


// TODO: to USART 
/* ************************************************************	*/

stdout = &mystdout_Uart;


printf("Nastavenie adresy EEPROM = %02x \n\r",poc_adresa_EEPROM);
WR_EEprom(ADR_IC_WR,poc_adresa_EEPROM);


printf("\n\r\rVypis EEPROM: \n\r");

	// vypisme prvych 10 znakov
    while (i<10) //256)// kapacita pamate 256 znakov, bytov, 
	{ 
		znak = RD_EEprom(ADR_IC_RD); // obsah adresneho citaca EEPROM sa automaticky inkrementuje
		if(znak==0xff)i=256; // vymazane pametove miesto
		{
			printf("   %02d %02x %c\r",i++,znak,znak);
		}
        
	}
	
 for(;;);  // a cakam napr. na  "RESET"
 
}