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
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
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
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
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
Plik z chomika:
bulwion
Inne pliki z tego folderu:
Wentylatory.pdf
(1666 KB)
Star Wars. Katalizator. Wprowad - James Luceno.pdf
(1665 KB)
Gordon R. Dickson - Smoczy rycerz T2.pdf
(1663 KB)
LOKOMOTYWA TOWAROWA EMD JT42CWRM(Class66).pdf
(1662 KB)
Greer Luanshya - Kto sieje wiatr 02 - Po burzy spokój.pdf
(1660 KB)
Inne foldery tego chomika:
- - 1024--Fillm
- - 2024--FULL---
- - 2K wallpapers
- - ART PICS
- - FILMY 2023-2025 WSZYSTKIE NOWOŚCI
Zgłoś jeśli
naruszono regulamin