Linux_embedded_cz4.pdf

(678 KB) Pobierz
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
KURS
Wprowadzenie do
Linuksa embedded (4)
Obsługa interfejsu I 2 C
Dodatkowe materiały
na CD/FTP
W  systemach z  mikrokontrolerem często zachodzi potrzeba transmisji
danych pomiędzy układami zewnętrznymi. Popularnym standardem
jest interfejs I 2 C. W  artykule zaprezentowano, jak do jego obsługi
zaprząc system operacyjny Linux embedded.
Dodatkowe materiały na CD/FTP:
ftp://ep.com.pl , user: 10925 , pass: 87thc181
• wszystkie poprzednie części kursu
w jaki sposób uzyskać dostęp do magistrali I 2 C
z aplikacji użytkownika, na przykładzie czujnika
temperatury MCP9803 (moduł KAMOD-TEM),
bez konieczności pisania sterowników jądra.
W systemach mikroprocesorowych komu-
nikacja z urządzeniami peryferyjnymi odbywa
się za pomocą magistral szeregowych lub rów-
noległych. W wypadku magistral równoległych
najczęściej mamy do czynienia z  magistralą
systemową. Urządzenie takie jest wówczas do-
stępne jako fragment pamięci (np. architektu-
ra ARM) lub może być dostępne w specjalnej
przestrzeni IO (np. architektura x86). Naturalnie
w przypadku systemów wykorzystujących MMU
obszar ten jest dostępny tylko dla jądra systemu
operacyjnego. Wykorzystanie magistral równo-
ległych wymaga wielu linii, skomplikowanych
połączeń i generalnie jest zbyt niewygodne. Dla-
tego najczęściej w ten sposób podłączone są tyl-
ko wewnętrzne układy peryferyjne, wbudowane
w mikrokontroler. Zewnętrzne układy najczę-
ściej dołączane są za pomocą interfejsów szere-
gowych. Najpopularniejsze interfejsy szeregowe
współczesnych systemów mikroprocesorowych
to: SPI, I 2 C, USB, RS232/RS485, ETHERNET.
I 2 C oraz SPI są używane najczęściej do dołą-
czania układów peryferyjnych, takich jak: zegary
RTC, pamięci EEPROM itp., znajdujących się
w obrębie płytki drukowanej z mikrokontrole-
rem. Interfejs USB jest stosowany do dołączania
urządzeń zewnętrznych. Natomiast interfejsy
RS232 i RS485 są używane zwykle do komuni-
kacji z urządzeniami zdalnymi.
W przypadku mikrokontrolerów jednoukła-
dowych oraz rozwiązań bez systemu operacyj-
nego stosunkowo proste do opanowania są in-
terfejsy SPI, I 2 C i RS232. Dużo bardziej skompli-
kowana jest obsługa USB, przez co producenci
mikrokontrolerów, aby ułatwić zadanie użytkow-
nikom, dostarczają gotowe biblioteki programo-
we. Po zapoznaniu się z obsługą portów GPIO
w Linuksie skupimy się ma obsłudze urządzeń
peryferyjnych dołączanych za pomocą interfejsu
I 2 C. Większość współczesnych mikrokontrole-
rów ma wbudowany sprzętowy kontroler I 2 C,
którego programowanie jest stosunkowo łatwe,
nawet bez pomocy gotowych bibliotek, nato-
miast w mikrokontrolerach niemających sprzę-
towego kontrolera I 2 C można bez większych
trudności wykonać programowy interfejs pracu-
jący w trybie master, korzystając z funkcji obsłu-
gi GPIO. Niestety, podczas tworzenia programów
pracujących pod kontrolą systemu Linux meto-
dy, których używamy do pisania oprogramowa-
nia dla mikrokontrolerów jednoukładowych, nie
są odpowiednie, z uwagi na ochronę pamięci
oraz wielozadaniowość. Zatem należy skorzy-
stać z pośrednictwa jądra systemu, gdzie istnieje
gotowa architektura programowa przeznaczona
do obsługi interfejsu I 2 C. W przykładzie poka-
żemy sposób obsługi za pomocą sterowników
dostępnych w jądrze interfejsu I 2 C sprzęgające-
go mikrokontroler z układem zegarka PCF-8563
dostępnego na płycie BF210. Pokażemy również,
Podsystem I 2 C
W Linuksie implementacja wszelkich pod-
systemów realizowana jest w sposób warstwowy,
zapewniając maksymalną uniwersalność oraz
przenośność na wszystkie platformy wspierane
przez jądro. Podobnie jest w przypadku podsys-
temu I 2 C. Podsystem ten umożliwia obsługę ma-
gistral I 2 C/SMBUS oraz wielu urządzeń do nich
dołączonych. Na rysunku   6 przedstawiono mo-
del programowy podsystemu I 2 C/SMBUS.
Sercem podsystemu jest moduł jądra i2c-co-
re , który komunikuje się z modułem sterownika
izycznego kontrolera magistrali oraz zapewnia
Rysunek 6. Model programowy podsystemu I 2 C/SMBUS na podstawie i2c.wiki.kernel.
org
98
ELEKTRONIKA PRAKTYCZNA 7/2011
883836528.443.png 883836528.454.png 883836528.464.png 883836528.475.png 883836528.001.png 883836528.012.png 883836528.023.png 883836528.033.png 883836528.044.png 883836528.055.png 883836528.066.png 883836528.077.png 883836528.088.png 883836528.099.png 883836528.110.png 883836528.121.png 883836528.132.png 883836528.143.png 883836528.154.png 883836528.165.png 883836528.176.png 883836528.187.png 883836528.198.png 883836528.209.png 883836528.220.png 883836528.231.png 883836528.242.png 883836528.253.png 883836528.264.png 883836528.275.png 883836528.286.png 883836528.297.png 883836528.308.png 883836528.319.png 883836528.330.png 883836528.341.png 883836528.352.png 883836528.363.png 883836528.374.png 883836528.385.png 883836528.396.png 883836528.407.png 883836528.418.png 883836528.429.png 883836528.433.png 883836528.434.png 883836528.435.png 883836528.436.png 883836528.437.png 883836528.438.png 883836528.439.png 883836528.440.png 883836528.441.png 883836528.442.png 883836528.444.png 883836528.445.png 883836528.446.png 883836528.447.png 883836528.448.png 883836528.449.png 883836528.450.png 883836528.451.png 883836528.452.png 883836528.453.png 883836528.455.png 883836528.456.png 883836528.457.png 883836528.458.png 883836528.459.png
 
Wprowadzenie do Linuksa embedded
wiedzialnym za inicjalizację maszyny ( arch/arm/
mach-at91/board-boff210.c ).
Struktura i2c_gpio_platform zawiera in-
formację o tym, które linie będą pełnić funk-
cję linii interfejsowych SDA (PA25) oraz SCL
(PA26), informację o tym, czy linie GPIO są
typu Open-Drain i czas trwania sygnału SCK,
który ustawiono na 2 Ms, co odpowiada trybowi
standard ( 100 kHz ). Tak przygotowana struktu-
ra następnie jest wpisywana do struktury plat-
form_device , która jest rejestrowana w systemie
za pomocą funkcji platform_device_register()
listing   9 .
Przed rejestracją struktury linie PA25 i PA26
są konigurowane jako wyjściowe z otwartym
drenem. Tak zarejestrowana struktura umożli-
wia sterownikowi i2c-gpio odczytanie struktury
poszczególnych magistral I 2 C oraz przyporząd-
kowanych im linii GPIO.
Uwaga! W wypadku typowego adresowania 7-bitowego magistrali I 2 C, najmłodszy bit określa
kierunek transmisji. Zwyczajowo adres I 2 C danego układu przedstawiamy w postaci liczby 8-bito-
wej z wyzerowanym najmłodszym bitem R/ W =0 (rys. n)
A6
A5
A4
A3
A2
A1
A0
R/ W
7
6
5
4
3
2
1
0
W podsystemie I 2 C Linuksa adres sprzętowy I 2 C przedstawiany inaczej, mianowicie jest to liczba
pozbawiona bitu R/ W przez przesunięcie bitowe o 1 w prawo (rys. n)
0
A6
A5
A4
A3
A2
A1
A0
7
6
5
4
3
2
1
0
Na przykład, jeżeli urządzenie ma adres 0x90, w Linuksie należy użyć adresu 0x48
jednolite API, niezależne od sprzętu, umożliwia-
jące innym modułom korzystanie z I 2 C. Moduł
sterownika kontrolera magistrali (Adapter) od-
powiada za izyczną komunikację z kontrolerem
I 2 C, który jest zależny od platformy. Moduł ten
może wykorzystywać kod pomocniczy z modu-
łów Alghoritm. Moduł Alghoritm deiniuje spo-
sób, w kontroler odwołuje się do interfejsu I 2 C,
ale bez wykonywania izycznego dostępu do re-
jestrów kontrolera sprzętowego. Na przykład ten
sam kontroler sprzętowy I 2 C może być w wypad-
ku jednej architektury dołączony do magistrali
PCI, natomiast w innym może być dołączony
do magistrali systemowej. Z tego powodu różny
będzie sposób dostępu do rejestrów tego kontro-
lera. Innym przykładem jest moduł i2c-algo-bit ,
który zawiera opis sterowania magistralą I 2 C za
pomocą operacji bitowych, ale nie zawiera kodu
bezpośrednio sterującego liniami GPIO. Za i-
zyczne sterowanie liniami jest odpowiedzialny
moduł i2c-gpio .
Bardzo często moduły sterowników mają
zdeiniowany własny algorytm dostępu do ma-
gistrali i nie używają dodatkowych modułów
Alghoritm . Podystem i2c-core zapewnia jednolite
API, dzięki którym użytkownik może tworzyć
oprogramowanie w oderwaniu od obsługi sa-
mego interfejsu I 2 C. Urządzenia są mapowane
przez system operacyjny i dostępne jako zasoby
standardowe. Na przykład zegar RTC jest obsłu-
giwany przez sterownik jądra i udostępnia urzą-
dzenie /dev/rtc0, a aplikacja korzystająca z RTC
„nie wie”, do jakiego rodzaju interfejsu jest on
dołączony.
Istnieje również wydajny sposób dostępu
do magistrali I 2 C z aplikacji użytkownika, reali-
zowany przez moduł I2c-dev , który umożliwia
dostęp do I 2 C za pomocą pliku urządzenia /dev/
i2c-x (gdzie x to kolejny numer interfejsu). Dzięki
dostępowi do I 2 C z poziomu aplikacji użytkow-
nika istnieje możliwość bezpośredniej obsługi
urządzenia z pominięciem sterowników prze-
strzeni jądra. Jest to bardzo wygodne rozwiąza-
nie, które może być wykorzystane, gdy nie ma
potrzeby użycia funkcjonalnych sterowników,
na przykład w wypadku, gdy układ I 2 C będzie
używany jedynie przez pojedynczą aplikację.
Może to być bardzo wygodne, ponieważ zwalnia
użytkownika z konieczności tworzenia stosunko-
wo skomplikowanych i trudnych w uruchamia-
niu sterowników jądra czy konieczności jego re-
kompilacji oraz tworzenia wpisów w strukturach
platform-device .
Implementacja kontrolera I 2 C na
platformie BF210. Konigurowanie
platform-device
Mikrokontroler AT91RM9200 stanowiący
serce Armputera BF210 ma zintegrowany kon-
troler magistrali I 2 C, który jest nazwany TWI.
Z uwagi na liczne błędy sprzętowe kontrolera,
a w szczególności brak możliwości generowa-
nia ponownej sekwencji Start przed wysłaniem
sekwencji Stop , jest on w zasadzie bezużytecz-
ny i jego obsługa nie jest dostępna w standardo-
wym kodzie jądra. Implementacja protokołu I 2 C
przy pojedynczym układzie master jest łatwa do
wykonania z użyciem operacji na liniach GPIO.
W systemie Linux istnieje implementacja ob-
sługi I 2 C realizowana przez moduł i2c-gpio przy
współpracy z modułem algorytmu i2c-algo-bit .
Użycie sterownika GPIO jest okupione nieco
większym obciążeniem CPU. Dzięki zastosowa-
niu tego sterownika istnieje możliwość imple-
mentacji w zasadzie dowolnej liczby niezależ-
nych interfejsów I 2 C ograniczonych jedynie licz-
bą dostępnych linii GPIO. Informowanie o tym,
które linie GPIO będą magistralą I 2 C, jest reali-
zowane przez odpowiednie wpisy w strukturach
platform-device ( listing   8 ) w kodzie jądra odpo-
Użycie sterowników
funkcjonalnych wbudowanych
w jądro
W jądrze istnieje wiele gotowych sterow-
ników dla układów peryferyjnych dołączanych
za pomocą I 2 C. Komunikują się one z magistralą
poprzez wewnętrzne API podsystemu i2c-core ,
natomiast aplikacji udostępniają interfejs funk-
cjonalny reprezentujący funkcję pełnioną przez
dany układ. Takim przykładem w BF210 jest
układ zegara PCF8563, który jest obsługiwany
przez moduł jądra, a w przestrzeni użytkowni-
ka jest widoczny w postaci urządzenia /dev/rtc .
To, że jest on dołączony akurat do I 2 C, jest nie-
istotne dla użytkownika, ważna jest jego funk-
cjonalność. Użycie sterowników dostępnych
w jądrze jest zgodne z ilozoią Linuksa, dlatego
przed podjęciem decyzji o zastosowaniu API
bezpośredniego dostępu do magistrali I 2 C należy
upewnić się, że nie istnieje gotowy sterownik ją-
dra dla danego układu.
W  przeciwieństwie do SMBUS, interfejs
I 2 C nie ma zdeiniowanego mechanizmu ska-
Listing 8. Wpisy w strukturze platform-device zawierające konigurację linii
interfejsowych I 2 C/GPIO
//I2c In gpio Mode
static struct i2c_gpio_platform_data i2c_gpio_data =
{
.sda_pin = AT91_PIN_PA25,
.scl_pin = AT91_PIN_PA26,
.sda_is_open_drain = 1,
.scl_is_open_drain = 1,
.udelay = 2, /* ~100 kHz */
};
static struct platform_device i2c_gpio_device =
{
.name = “i2c-gpio”,
.id = 0,
.dev =
{
.platform_data = &i2c_gpio_data,
}
};
Listing 9. Przygotowanie struktury z koniguracją I 2 C
//I2C code
at91_set_GPIO_periph(AT91_PIN_PA25, 1); /* TWD (SDA) */
at91_set_multi_drive(AT91_PIN_PA25, 1);
at91_set_GPIO_periph(AT91_PIN_PA26, 1); /* TWCK (SCL) */
at91_set_multi_drive(AT91_PIN_PA26, 1);
i2c_register_board_info(0, bf210_i2c_devices, ARRAY_SIZE(bf210_i2c_devices));
platform_device_register(&i2c_gpio_device);
99
ELEKTRONIKA PRAKTYCZNA 7/2011
883836528.460.png 883836528.461.png 883836528.462.png 883836528.463.png 883836528.465.png 883836528.466.png 883836528.467.png 883836528.468.png 883836528.469.png 883836528.470.png 883836528.471.png 883836528.472.png 883836528.473.png 883836528.474.png 883836528.476.png 883836528.477.png 883836528.478.png 883836528.479.png 883836528.480.png 883836528.481.png 883836528.482.png 883836528.483.png 883836528.484.png 883836528.485.png 883836528.002.png 883836528.003.png 883836528.004.png 883836528.005.png 883836528.006.png 883836528.007.png 883836528.008.png 883836528.009.png 883836528.010.png 883836528.011.png 883836528.013.png 883836528.014.png 883836528.015.png 883836528.016.png 883836528.017.png 883836528.018.png 883836528.019.png 883836528.020.png 883836528.021.png 883836528.022.png 883836528.024.png 883836528.025.png 883836528.026.png 883836528.027.png 883836528.028.png 883836528.029.png
 
KURS
Rysunek 7. Sekwencje odczyt/zapis bez bitu stopu
nowania dołączonych urządzeń, dlatego jedy-
nym sposobem poinformowania o  obecności
danego układu na magistrali jest wykorzystanie
mechanizmu Platform Device . Na przykład, aby
poinformować o dołączeniu układu PCF8563
do wcześniej utworzonej magistrali I2C0, należy
zdeiniować następującą strukturę w kodzie ją-
dra odpowiedzialnym za inicjalizację maszyny:
//I2C device map
static struct i2c_board_info __
initdata bf210_i2c_devices[] =
{
{
I2C_BOARD_INFO(“pcf8563”, 0x51),
}
};
projektu, zamiast pisania sterownika w prze-
strzeni jądra warto rozważyć możliwość użycia
bezpośredniego dostępu do magistrali I 2 C oraz
bezpośredniej obsługi układu z poziomu apli-
kacji. Funkcjonalność taką zapewnia moduł
i2c-dev , którego zadaniem jest udostępnianie in-
terfejsów I 2 C za pomocą plików urządzeń ( /dev/
i2c-x , gdzie x oznacza kolejny numer porząd-
kowy). Aby uzyskać dostęp do API I 2 C w prze-
strzeni użytkownika, należy załadować moduł
i2c-dev (modprobe i2c-dev) , a w programie dołą-
czyć pliki nagłówkowe <linux/i2c-dev.h> oraz
<linux/i2c.h> . Przed skorzystaniem z funkcjo-
nalności dostępu do I 2 C trzeba otworzyć plik
reprezentujący daną magistralę (dla 0 magi-
strali /dev/i2c-0), za pomocą wywołania open
(...,O_RDWR). Po otwarciu pliku należy poin-
formować sterownik o sprzętowym adresie I 2 C,
z którym chcemy się komunikować za pomocą
wywołania systemowego ioctl: ioctl(ile, I2C_
SLAVE, i2c_addr) , w którym jako i2c_addr nale-
ży podać sprzętowy adres I 2 C układu. Po wyko-
naniu tej czynności możemy odczytywać dane
z urządzenia o adresie sprzętowym i2c_add r za
pomocą wywołania systemowego read() oraz
zapisywać dane za pomocą wywołania systemo-
wego write() .
Każda operacja odczytu lub zapisu spo-
woduje wygenerowanie bitu startu, po którym
nastąpi wysłanie lub odczytanie danych, a na
zakończenie zostanie wysłany bit stopu. Jeżeli
chcemy komunikować się z różnymi układami
dołączonymi do magistrali, należy za każdym ra-
zem przed wywołaniem funkcji read/write zmie-
nić adres docelowy poprzez ponownie wywoła-
nie funkcji ioctl(ile,I2C_SLAVE,new_i2c_addr) ,
w którym new_i2c_addr to adres sprzętowy no-
wego układu.
Taki prosty sposób sterowania za pomocą
wywołań read/write , choć dla wielu urządzeń
może być wystarczający, nie odzwierciedla spe-
cyiki magistrali I 2 C. Bardzo często układy I 2 C
mają dodatkowy adres wewnętrzny, określający
wewnętrzny rejestr układu i w przypadku żąda-
nia odczytu wymagają sekwencji odczyt/zapis
bez generowania bitu stopu ( rysunek   7 )
W  takim przypadku sekwencja wywołań
systemowych write()/read() będzie nieodpowied-
nia, ponieważ pomiędzy wysłaniem adresu reje-
stru a odczytem danych będzie wygenerowany
dodatkowy bit stopu. Aby uzyskać pożądaną
sekwencję, należy zastosować wywołanie sys-
temowe ioctl(ile, I2C_RDWR, struct i2c_rdwr_
ioctl_data *msgset) , które umożliwia wykonanie
dowolnych transakcji na magistrali I 2 C jako poje-
dynczej sekwencji bez generowania bitu stopu.
Wywołanie to jako trzeci argument przyjmuje
wskaźnik do struktury i2c_rdwr_ioctl_data , która
zdeiniowana jest następująco:
struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* pointers
to i2c_msgs */
__u32 nmsgs; /* number
of i2c_msgs */
};
Pole msgs zawiera wskaźnik do tablicy
struktur opisujących sekwencję transakcji I 2 C,
natomiast pole nmsgs zawiera liczbę transakcji.
Strukturę transakcji I 2 C (wiadomości) zdeinio-
wano jak na listingu   10 .
Pole addr zawiera adres sprzętowy I 2 C, dla
którego jest przeznaczona transakcja. Pole lags
zawiera lagi transakcji umożliwiające sterowa-
nie daną transakcją zgodnie z deinicjami (np.
laga I2C_M_RD informuje, że jest to sekwencja
odczytu; laga I2C_M_RD informuje, że adres
jest 10-bitowy). Pole len określa długość bufora
z danymi do wysłania/odebrania, natomiast pole
*buf zawiera wskaźnik do bufora danych. Budu-
jąc odpowiednią tablice składającą się z trans-
akcji zapisu jednego bajtu, a następnie odczytu
zadanej liczby bajtów, mamy możliwość wyge-
nerowania prawidłowej sekwencji odczytu.
W strukturze i2c_board_info trzeba zdeinio-
wać typ układu dołączonego do I 2 C oraz poinfor-
mować o jego adresie sprzętowym. Następnie tak
przygotowaną strukturę należy zarejestrować za
pomocą wywołania:
i2c_register_board_info(0,
bf210_
i2cdevices,
ARRAY_SIZE(bf210_i2c_
devices));
Wywołanie to jako pierwszy argument przyj-
muje numer porządkowy magistrali, do której
zostało dołączone urządzenie, natomiast jako
kolejne argumenty przyjmuje wskaźnik do opi-
sanej wcześniej struktury oraz liczbę wpisów
w strukturze. Tak zarejestrowana struktura po-
zwoli kernelowi na automatycznie załadowanie
i inicjalizację odpowiedniego sterownika dla da-
nego układu.
Dostęp do magistrali I 2 C z wiersza
polecenia
Pakiet i2c-tools umożliwia dostęp do magi-
strali I 2 C z poziomu shella (wiersza polecenia).
Wykorzystuje on opisany wcześniej moduł do-
stępu do magistrali I 2 C z aplikacji użytkownika
i2c-dev . Pakiet składa się z szeregu poleceń,
z których najistotniejsze to:
i2cdetect [-y] [-a] [-q|-r] I2CBUS [FIRST
LAST] – polecenie umożliwiające przeskanowa-
nie dostępnych urządzeń dołączonych do ma-
gistrali I 2 C. Na przykład wywołanie polecenia
i2cdetect -y 0 w BF210 powoduje wyświetlenie
tablicy wszystkich adresów wraz z listą dostęp-
nych urządzeń na danej magistrali ( listing   11 ).
Możemy zauważyć, że widoczne są dwa
urządzenia: pod adresem 0x51 (zegar PCF8563)
oraz pod adresem 0x48 (moduł KAMOD-TEM).
Literki UU dla adresu 0x48 oznaczają, że dane
urządzenie jest dołączone, ale jest niedostępne
Obsługa urządzeń I 2 C z poziomu
aplikacji z użyciem API
bezpośredniego dostępu do
magistrali
Brak zdeiniowanego mechanizmu auto-
detekcji układów dołączonych do magistrali I 2 C
skutkuje koniecznością zarejestrowania układu
w podsystemie platform-device , co jest związane
z koniecznością modyikacji kodu jądra. Mody-
ikacja i ponowna rekompilacja jądra może być
kłopotliwa dla początkujących użytkowników.
Brak dołączanego układu na liście dostępnych
sterowników skutkuje koniecznością napisania
sterownika jądra, co może być zadaniem jeszcze
bardziej skomplikowanym. W  wypadku, gdy
nie potrzebujemy sterownika funkcjonalnego
dostępnego z poziomu systemu, a dany układ
będzie używany w obrębie jednej aplikacji lub
100
ELEKTRONIKA PRAKTYCZNA 7/2011
883836528.030.png 883836528.031.png 883836528.032.png 883836528.034.png 883836528.035.png 883836528.036.png 883836528.037.png 883836528.038.png 883836528.039.png 883836528.040.png 883836528.041.png 883836528.042.png 883836528.043.png 883836528.045.png 883836528.046.png 883836528.047.png 883836528.048.png 883836528.049.png 883836528.050.png 883836528.051.png 883836528.052.png 883836528.053.png 883836528.054.png 883836528.056.png 883836528.057.png 883836528.058.png 883836528.059.png 883836528.060.png 883836528.061.png 883836528.062.png 883836528.063.png 883836528.064.png 883836528.065.png 883836528.067.png 883836528.068.png 883836528.069.png 883836528.070.png 883836528.071.png 883836528.072.png 883836528.073.png
Wprowadzenie do Linuksa embedded
Listing 10. Struktura transakcji I 2 C
struct i2c_msg {
__u16 addr; /* slave address */
__u16 lags;
#deine I2C_M_TEN 0x0010 /* this is a 10-bit chip address */
#deine I2C_M_RD 0x0001 /* read data, from slave to master */
#deine I2C_M_NOSTART 0x4000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#deine I2C_M_REV_DIR_ADDR 0x2000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#deine I2C_M_IGNORE_NAK 0x1000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#deine I2C_M_NO_RD_ACK 0x0800 /* if I2C_FUNC_PROTOCOL_MANGLING */
#deine I2C_M_RECV_LEN 0x0400 /* length will be irst received byte */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
Listing 11. Tablica wszystkich adresów wraz z listą dostępnych urządzeń na danej
magistrali
root@bf210-at91:~# i2cdetect -y 0
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Listing 12. Składnia polecenia i2cget
root@bf210-at91:~# i2cget
Usage: i2cget [-f] [-y] I2CBUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77)
MODE is one of:
b (read byte data, default)
w (read word data)
c (write byte/read byte)
Append p for SMBus PEC
Listing 13. Składnia polecenia i2cset
i2cset [-f] [-y] [-m MASK] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] [MODE]
I2CBUS is an integer or an I2C bus name
ADDRESS is an integer (0x03 - 0x77)
MODE is one of:
c (byte, no value)
b (byte data, default)
w (word data)
Append p for SMBus PEC
z poziomu aplikacji użytkownika, ponieważ jest
kontrolowane przez sterownik jądra systemu
operacyjnego. Natomiast urządzenie pod adre-
sem 0x48 (KAMOD-TEM) jest dostępne, co w od-
powiednim polu oznaczono cyfrą 48.
Polecenie i2cget umożliwia odczytanie da-
nych z urządzenia dołączonego do magistrali
I 2 C. Składnię tego polecenia umieszczono na
listingu   12 . Jako argumenty przyjmuje ono odpo-
wiednio numer interfejsu I 2 C, numer sprzętowy
urządzenia, adres rejestru do odczytania oraz
długość słowa danych (8 lub 16 bitów).
Polecenie i2cset umożliwia wpisanie danych
do układu podłączonego do magistrali I 2 C. Jego
składnię umieszczono na listingu   13 . Jako pierw-
szy argument polecenie przyjmuje, odpowied-
nio: numer interfejsu I 2 C, adres układu, adres re-
jestru, wartość do zapisania oraz długość danych
do zapisania.
płycie CD i serwerze FTP ). Dostęp do magistra-
li I 2 C będzie realizowany z użyciem opisanego
wcześniej API. Do uruchomienia przykładu jest
potrzebny moduł KAMOD-TEM. Sposób podłą-
czenia modułu do płytki prototypowej BF210
przedstawiono na rysunku 7 .
Moduł KAMOD-TEM zawiera czujnik tem-
peratury MCP2301 , który ma następujące para-
metry:
– jest wyposażony w interfejsy I 2 C/SMBUS
pracujące z  maksymalną częstotliwością
taktowania 400 kHz,
– napięcie zasilania 2,7...5,5 V,
– rozdzielczość pomiaru temperatury ustalaną
od 9 do 12 bitów,
– zakres pomiary temperatury
–55...+125ºC z dokładnością ±1ºC.
Adres bazowy układu to (1001xxx)b. Jego
najmłodsze bity możemy ustalić za pomocą
zwór koniguracyjnych. Układ może generować
sygnał alarmujący o przekroczeniu zadanej tem-
peratury.
Po dołączeniu modułu należy upewnić się,
że zwory A0...A2 koniguracji adresu zostały
ustawione w pozycji „0” (adres sprzętowy czuj-
nika 0x90h). Czujnik zawiera kilkanaście reje-
strów kontrolnych i konigurujących umożliwia-
jących między innymi: ustalenie rozdzielczości
pomiaru, ustawianie alarmów itp. W przykła-
Rysunek 7. Schemat dołączenia modułu
KAMOD-TEM do płytki prototypowej
dzie nie będziemy wykorzystywać alarmów,
więc konieczna będzie znajomość tylko dwóch
rejestrów: ATR umożliwiającego odczyt aktual-
nej temperatury (0x00h) oraz CONFIG (0x01),
który umożliwia ustalenie rozdzielczości po-
miaru temperatury. Na rysunku   8 zamieszczono
strukturę rejestru CONFIG (0x01h), natomiast
na rysunku   9 16-bitowego rejestru ATR (0x00h)
zawierającego wynik pomiaru temperatury.
Starsza połowa rejestru ATR zawiera wartość
całkowitą temperatury wyrażoną w stopniach
Celsjusza, a młodsza ułamkową. Po włączeniu
czujnik jest skonigurowany w trybie 9-bitowym.
Aby uzyskać większą rozdzielczość, należy od-
powiednio ustawić bity resolution w rejestrze
CONFIG .
Przykład praktyczny
Jako przykład demonstrujący użycie układu
dołączonego do magistrali I 2 C z wykorzystaniem
dostępu za pomocą i2c-dev pokazano aplikację,
która będzie odczytywać temperaturę z modułu
KAMOD-TEM, a następnie prezentować aktual-
ny wynik z odświeżaniem co 1 s na standardo-
wym wyjściu (konsoli). (k od źródłowy aplikacji
znajduje się w pliku i2ctemp.c umieszczonym na
Opis aplikacji
Aby zademonstrować przykład użycia in-
terfejsu I 2 C, napisano program i2ctemp , którego
zadaniem jest cykliczne odczytywanie aktual-
nej temperatury z modułu KAMOD-TEM oraz
prezentacja wyniku na standardowym wyjściu
(terminal). Program rozpoczyna się od pokazanej
na listingu 14 funkcji main(). Na jej początku jest
101
ELEKTRONIKA PRAKTYCZNA 7/2011
883836528.074.png 883836528.075.png 883836528.076.png 883836528.078.png 883836528.079.png 883836528.080.png 883836528.081.png 883836528.082.png 883836528.083.png 883836528.084.png 883836528.085.png 883836528.086.png 883836528.087.png 883836528.089.png 883836528.090.png 883836528.091.png 883836528.092.png 883836528.093.png 883836528.094.png 883836528.095.png 883836528.096.png 883836528.097.png 883836528.098.png 883836528.100.png 883836528.101.png 883836528.102.png 883836528.103.png 883836528.104.png 883836528.105.png 883836528.106.png 883836528.107.png 883836528.108.png 883836528.109.png 883836528.111.png 883836528.112.png 883836528.113.png 883836528.114.png 883836528.115.png 883836528.116.png 883836528.117.png 883836528.118.png 883836528.119.png 883836528.120.png 883836528.122.png 883836528.123.png 883836528.124.png 883836528.125.png 883836528.126.png 883836528.127.png 883836528.128.png 883836528.129.png 883836528.130.png 883836528.131.png 883836528.133.png 883836528.134.png 883836528.135.png 883836528.136.png 883836528.137.png 883836528.138.png 883836528.139.png 883836528.140.png 883836528.141.png 883836528.142.png 883836528.144.png 883836528.145.png 883836528.146.png 883836528.147.png 883836528.148.png 883836528.149.png 883836528.150.png 883836528.151.png 883836528.152.png 883836528.153.png 883836528.155.png 883836528.156.png 883836528.157.png 883836528.158.png 883836528.159.png 883836528.160.png 883836528.161.png 883836528.162.png 883836528.163.png 883836528.164.png 883836528.166.png 883836528.167.png 883836528.168.png 883836528.169.png 883836528.170.png 883836528.171.png 883836528.172.png 883836528.173.png 883836528.174.png 883836528.175.png 883836528.177.png 883836528.178.png 883836528.179.png 883836528.180.png 883836528.181.png 883836528.182.png 883836528.183.png 883836528.184.png 883836528.185.png 883836528.186.png 883836528.188.png 883836528.189.png 883836528.190.png 883836528.191.png 883836528.192.png 883836528.193.png 883836528.194.png 883836528.195.png 883836528.196.png 883836528.197.png 883836528.199.png 883836528.200.png 883836528.201.png 883836528.202.png 883836528.203.png 883836528.204.png 883836528.205.png 883836528.206.png 883836528.207.png 883836528.208.png 883836528.210.png 883836528.211.png 883836528.212.png 883836528.213.png 883836528.214.png 883836528.215.png 883836528.216.png 883836528.217.png 883836528.218.png 883836528.219.png 883836528.221.png 883836528.222.png 883836528.223.png 883836528.224.png 883836528.225.png 883836528.226.png 883836528.227.png 883836528.228.png 883836528.229.png 883836528.230.png 883836528.232.png 883836528.233.png 883836528.234.png 883836528.235.png 883836528.236.png 883836528.237.png 883836528.238.png 883836528.239.png 883836528.240.png 883836528.241.png 883836528.243.png 883836528.244.png 883836528.245.png 883836528.246.png 883836528.247.png 883836528.248.png 883836528.249.png 883836528.250.png 883836528.251.png 883836528.252.png 883836528.254.png 883836528.255.png 883836528.256.png 883836528.257.png 883836528.258.png 883836528.259.png 883836528.260.png 883836528.261.png 883836528.262.png 883836528.263.png
KURS
wywoływana funkcja i2c_bus_open() , która jako
argument przyjmuje numer porządkowy interfej-
su I 2 C, a zwraca uchwyt do pliku reprezentują-
cego daną magistralę . Kod funkcji zamieszczono
na listingu   15 .
Działanie tej funkcji sprowadza się do utwo-
rzenia w buforze nazwy pliku odpowiadającego
interfejsowi (w  naszym przypadku /dev/i2c-0 ),
a następnie otwarcia pliku reprezentującego kon-
kretny interfejs I 2 C do odczytu i zapisu za pomocą
wywołania systemowego open(). Następnie jest
wywoływana funkcja [2] , której zadaniem jest
ustalenie adresu sprzętowego, którego będą doty-
czyć wywołania systemowe read(), write() . W  [3]
za pomocą wywołania systemowego write() , do re-
jestru CONFIG układu MCP2301 jest wpisywana
wartość #deine MCP9800_RES_12BIT (3<<5) ,
co powoduje ustawienie 10-bitowej rozdzielczo-
ści pomiaru temperatury. Po zakończeniu inicja-
lizacji program wchodzi do pętli nieskończonej,
w której dzięki wywołaniu funkcji tempsensor_
get() [4] jest odczytywana temperatura z czujnika
MCP2301 , a następnie w  [5] jest ona wyświetlana
na standardowym wyjściu (konsola).
Na listingu   16 zamieszczono funkcję odpo-
wiedzialną za odczyt temperatury z czujnika. Aby
odczytać temperaturę, należy odczytać liczbę
16-bitową z rejestru ATR , co jest wykonywane za
pomocą sekwencji zapis/odczyt bez generowania
bitu stopu. Aby wygenerować taką sekwencję,
należy użyć wywołania systemowego ioctl(han-
dle, I2C_RDWR) oraz zdeiniować strukturę, która
w pojedynczej transakcji spowoduje wysłanie baj-
tu danych z adresem rejestru ATR , a następnie, po
wygenerowaniu ponownego bitu startu, odczyta
16 bitów danych będących zawartością rejestru
ATR. Jest to realizowane przez utworzenie tablicy
składającej się z dwóch struktur i2c_msgs repre-
zentujących transakcje zapisu pojedynczego bajtu
oraz odczytu dwóch bajtów. Następnie adres ta-
blicy temp_msgs oraz liczba jej elementów prze-
kazywana jest do struktury i2c_rdwr_ioctl_data ,
która z kolei jest przekazywana jako argument wy-
wołania ioctl(handle,I2C_RDWR, msg); Wywoła-
nie tej funkcji spowoduje wysłanie odpowiedniej
sekwencji przez magistralę I 2 C bez generowania
bitu stopu pomiędzy zapisem a odczytem.
Bit 7
Bit 0
R/W-0
R/W-0
R/W-0
R/W-0
R/W-0
R/W-0
R/W-0
R/W-0
One-Shot Resolution
Fault Queue
ALERT
Polarity
COMP/INT Shutdown
bit 7: 1 – tryb jednokrotnego pomiaru, 0 – tryb ciągłego pomiaru (domyślny)
bity 6–5: rozdzielczość pomiaru: 00b – 9 bit (0,5°C) 01b – 10 bit (0,25°C) 10b – 11 bit (0,125°C)
11b – 12 bit (°C)
bity 4–3: Określa, ile przekroczeń pomiarów wyzwala alarm (dla nas nieistotne)
bit 2: Określa polaryzację linii alarmu (dla nas nieistotne)
bit 1: Określa tryb pracy linii wyjściowej alarmu (dla nas nieistotne)
bit 0: 1 – układ uśpiony, 0 – układ aktywny
Rysunek 8. Opis bitów rejestru CONFIG (0x1h)
Bit 15
Bit 8
R-0
R-0
R-0
R-0
R-0
R-0
R-0
R-0
Sign
2 6 [°C]
2 5 [°C]
2 4 [°C]
2 3 [°C]
2 2 [°C]
2 1 [°C]
2 0 [°C]
Bit 7
Bit 0
R-0
R-0
R-0
R-0
R-0
R-0
R-0
R-0
2 -1 [°C/bit] 2 -2 [°C]
2 -3 [°C]
2 -4 [°C]
0
0
0
0
Rysunek 9. Opis bitów rejestru ATR (0x0h)
Listing 14. Program główny
int main(void)
{
//Initialize i2c bus
int handle = i2c_bus_open( 0 ); [1]
error(handle<0);
//Set destination device address
int err = ioctl(handle, I2C_SLAVE, MCP_SLAVE_ADDR); [2]
error(err<0);
//Write init string to temp sensor
static const char mcp_init[] = { MCP9800_CONFIG_REG , MCP9800_RES_12BIT };
err = write( handle, mcp_init, sizeof(mcp_init) ); [3]
error(err!=sizeof(mcp_init));
//Main loop for read sensor temp
for(;;)
{
//Read the temp
loat temp = tempsensor_get(handle); [4]
//Print temp
printf(“%.1f \r”,temp); [5]
flush(stdout);
//Sleep one sec
sleep(1);
[6]
}
//Close handle
close(handle);
return 0;
}
Listing 15. Funkcja i2c_bus_open
static int i2c_bus_open(int i2cbus)
{
char ilename[65];
snprintf(ilename, sizeof(ilename), “/dev/i2c-%d”, i2cbus);
return open(ilename, O_RDWR);
}
Listing 16. Odczyt temperatury z czujnika
loat tempsensor_get(int handle)
{
unsigned char tempreg_addr = MCP9800_TEMP_REG; //Temp sensor rego
unsigned char temp_regs[2];
struct i2c_msg temp_msgs[] = //I2c msgs
{
{
MCP_SLAVE_ADDR, //Slave addres
0, //Flags
sizeof(tempreg_addr), //transfer sizze
&tempreg_addr //Reg address
},
{
MCP_SLAVE_ADDR, //Slave adddres
I2C_M_RD, //Read lag
sizeof(temp_regs), //transfer size
temp_regs //Reg address
}
};
struct i2c_rdwr_ioctl_data msg =
{
temp_msgs, //Address of messages
sizeof(temp_msgs)/sizeof(struct i2c_msg) //Number of messages
};
int err = ioctl(handle, I2C_RDWR, &msg); //WRWR ioctl
error(err<0); //Check error
return (loat)((signed char)temp_regs[0])+ (temp_regs[1]>>4)/16.0f;
}
Uruchomienie przykładu na
BF210
Skompilowany przykład wraz z komplet-
nym systemem Linux jest dostępny w postaci
obrazu example3.img . Przykład należy nagrać
na kartę SD, tak jak to zostało opisane w pierw-
szym odcinku. Po nagraniu karty, włożeniu jej do
BF210 oraz uruchomieniu systemu, należy zalo-
gować się do konsoli jako root, a następnie uru-
chomić przykład, wpisując polecenie i2ctemp ,
co spowoduje uruchomienie programu. Jeżeli
moduł KAMOD-TEM jest dołączony, to na termi-
nalu (konsoli) powinna być widoczna aktualna
temperatura aktualizowana co 1 s. Zakończenie
działania programu jest możliwe przez wciśnię-
cie kombinacji klawiszy CTRL+C.
Lucjan Bryndza, EP
102
ELEKTRONIKA PRAKTYCZNA 7/2011
883836528.265.png 883836528.266.png 883836528.267.png 883836528.268.png 883836528.269.png 883836528.270.png 883836528.271.png 883836528.272.png 883836528.273.png 883836528.274.png 883836528.276.png 883836528.277.png 883836528.278.png 883836528.279.png 883836528.280.png 883836528.281.png 883836528.282.png 883836528.283.png 883836528.284.png 883836528.285.png 883836528.287.png 883836528.288.png 883836528.289.png 883836528.290.png 883836528.291.png 883836528.292.png 883836528.293.png 883836528.294.png 883836528.295.png 883836528.296.png 883836528.298.png 883836528.299.png 883836528.300.png 883836528.301.png 883836528.302.png 883836528.303.png 883836528.304.png 883836528.305.png 883836528.306.png 883836528.307.png 883836528.309.png 883836528.310.png 883836528.311.png 883836528.312.png 883836528.313.png 883836528.314.png 883836528.315.png 883836528.316.png 883836528.317.png 883836528.318.png 883836528.320.png 883836528.321.png 883836528.322.png 883836528.323.png 883836528.324.png 883836528.325.png 883836528.326.png 883836528.327.png 883836528.328.png 883836528.329.png 883836528.331.png 883836528.332.png 883836528.333.png 883836528.334.png 883836528.335.png 883836528.336.png 883836528.337.png 883836528.338.png 883836528.339.png 883836528.340.png 883836528.342.png 883836528.343.png 883836528.344.png 883836528.345.png 883836528.346.png 883836528.347.png 883836528.348.png 883836528.349.png 883836528.350.png 883836528.351.png 883836528.353.png 883836528.354.png 883836528.355.png 883836528.356.png 883836528.357.png 883836528.358.png 883836528.359.png 883836528.360.png 883836528.361.png 883836528.362.png 883836528.364.png 883836528.365.png 883836528.366.png 883836528.367.png 883836528.368.png 883836528.369.png 883836528.370.png 883836528.371.png 883836528.372.png 883836528.373.png 883836528.375.png 883836528.376.png 883836528.377.png 883836528.378.png 883836528.379.png 883836528.380.png 883836528.381.png 883836528.382.png 883836528.383.png 883836528.384.png 883836528.386.png 883836528.387.png 883836528.388.png 883836528.389.png 883836528.390.png 883836528.391.png 883836528.392.png 883836528.393.png 883836528.394.png 883836528.395.png 883836528.397.png 883836528.398.png 883836528.399.png 883836528.400.png 883836528.401.png 883836528.402.png 883836528.403.png 883836528.404.png 883836528.405.png 883836528.406.png 883836528.408.png 883836528.409.png 883836528.410.png 883836528.411.png 883836528.412.png 883836528.413.png 883836528.414.png 883836528.415.png 883836528.416.png 883836528.417.png 883836528.419.png 883836528.420.png 883836528.421.png 883836528.422.png 883836528.423.png 883836528.424.png 883836528.425.png 883836528.426.png 883836528.427.png 883836528.428.png 883836528.430.png 883836528.431.png 883836528.432.png
 
Zgłoś jeśli naruszono regulamin