STM32 - Migracja do Standard Peripheral Library wer. 3.1.0.pdf

(482 KB) Pobierz
652388963 UNPDF
kurs
Migracja do Standard
Peripheral Library wer. 3.1.0
We wcześniejszych numerach EP wielokrotnie przedstawiane były
aplikacje pisane dla mikrokontrolerów STM32 z  wykorzystaniem
biblioteki API dostarczanej przez ST Microelectronics. Jednak w  myśl
słów: kto nie idzie naprzód, ten się cofa – irma ST przygotowała
nową wersję biblioteki. W  artykule przedstawiono skrótowo
informacje dotyczące zarówno starszej wersji biblioteki (V2.0.3), oraz
– szczegółowej – nowej wersji 3.1.0. Omówiono ponadto sposób
migracji projektu ze starej wersji biblioteki do nowej.
szej części artykułu. Poniżej przedstawione
informacje mogą być przydatne podczas mi-
gracji do nowej wersji biblioteki.
Biblioteka FWLib jest podzielona na
wiele plików, każdy jest odpowiedzialny
na obsługę jakiegoś elementu systemu mi-
kroprocesorowego (układu peryferyjnego).
Na przykład plik stm32f10x_usart.c zawiera
wszystkie niezbędne funkcje do skonigu-
rowania portu USART oraz do nawiązania
komunikacji. Plików bibliotecznych nie
edytujemy, jedynie w nagłówkowym pliku
stm32f10x_conf.h , używając komentarzy
można włączać lub wyłączać obsługę po-
szczególnych urządzeń. Ważnym elemen-
tem biblioteki FWLib jest plik stm32f10x_
it.c , w którym umieszczane są wszystkie
funkcje obsługi przerwań.
Operowanie bezpośrednio na rejestrach
jakiekolwiek 32–bitowego procesora lub mi-
krokontrolera nie należy do zadań łatwych.
Mimo, iż samo napisanie (nawet stosunko-
wo zaawansowanych) aplikacji przy użyciu
nazw rejestrów jest możliwe, to wprowa-
dzanie zmian do istniejącego kodu po upły-
wie na przykład kilku miesięcy, dodatkowo
przez osobę, która nie jest autorem progra-
mu, jest w zasadzie niemożliwe do wyko-
nania w sensownym czasie. Z powyższych
względów, jeśli to możliwe, czyli np. czas
wykonania kodu nie jest krytyczny, pro-
gramiści wykorzystują funkcje o mniej, lub
bardziej kojarzących się nazwach, do opera-
cji często na zespołach wielu rejestrów.
Jeżeli mamy do czynienia z  bardzo
skomplikowanym projektem, wykorzystu-
jącym wiele peryferiów mikrokontrolera,
to napisanie stosownych funkcji jest praco-
i  czasochłonne, ponadto wymaga bardzo
dobrej znajomości architektury mikrokon-
trolera. Firma ST Microelectronics zauwa-
żyła ten problem i udostępnia kompletne
biblioteki API, które pozwalają na pełną
kontrolę nad mikrokontrolerami STM32.
W pewnych przypadkach może oczywiście
zajść potrzeba bezpośredniego odwołania
się do rejestru, we wszystkich pozostałych
funkcje API znacznie skracają czas potrzeb-
ny na napisanie i uruchomienie aplikacji.
CMSIS
Biblioteka STM32F10x Standard Periphe-
rals Library V3.1.0 wykorzystuje standard
CMSIS, a więc warto się nieco z nim zapo-
znać. Standard CMSIS ( Cortex Microcontrol-
ler Software Interface Standard ) jest to uni-
wersalny interfejs programowy, stworzony
przez irmę ARM, który umożliwia komuni-
kację z peryferiami i rdzeniem Cortex za po-
mocą ustandaryzowanych funkcji i deinicji.
CMSIS dostarcza mechanizmów do obsługi
układów peryferyjnych, systemów opera-
cyjnych czasu rzeczywistego oraz aplikacji
wykorzystujących interfejsy komunikacyjne:
Ethernet, UART oraz SPI.
Strukturę interfejsu CMSIS i jego miejsce
w aplikacji przedstawiono na rys.   1 . CMSIS
ma docelowo obejmować cała rodzinę rdze-
ni z grupy Cortex-M, natomiast na chwilę
obecną jest dostosowany do rdzeni Cortex
-M0, oraz Cortex-M3. Ustandaryzowane in-
terfejsu dostępu do układów peryferyjnych
oraz samego rdzenia ma na celu ułatwienie
przenoszenia aplikacji pomiędzy mikrokon-
trolerami różnych producentów, jak również
uproszczenie procesu tworzenia aplikacji.
Standard CMSIS został podzielony na
dwie podstawowe warstwy: Core Peripheral
Access Layer oraz Middleware Access Layer .
Pierwsza warstwa zawiera deinicje nazw
oraz umożliwia dostęp do rejestrów rdzenia
oraz urządzeń peryferyjnych, natomiast dru-
ga udostępnia mechanizmy do współpracy
z interfejsami komunikacyjnymi.
STM32F10x irmware library
V2.0.3
Biblioteka irmy STMicroelectronics dla
mikrokontrolerów STM32 w wersji V2.0.3
( FWLib ) została zastąpiona przez nowszą
wersję i nie jest już dalej rozwijana. Mimo to,
nadal można ze strony producenta pobrać tę
wersję biblioteki, jednak tworząc nowy pro-
jekt należy już raczej skorzystać z nowszej
wersji 3.1.0, która została omówiona w dal-
rys. 1. Budowa interfejsu CMSIS i jego miejsce w aplikacji
100
ELEKTRONIKA PRAKTYCZNA 10/2009
STM32
652388963.036.png 652388963.037.png 652388963.038.png 652388963.039.png 652388963.001.png 652388963.002.png 652388963.003.png 652388963.004.png 652388963.005.png 652388963.006.png
 
Migracja do Standard Peripheral Library
Rys. 2. Struktura plików środowiska
µVision dla projektu wykorzystującego
przetwornik A/C
zbudowanego w oparciu o szablon projektu dla
środowiska µVision przedstawiono na rys.   2 .
Jeśli szablon projektu zostanie skopiowa-
ny do innego katalogu, to należy poinformo-
wać kompilator, gdzie ma szukać stosownych
plików oraz należy dodać wykorzystywane
źródła do projektu. Dokonujemy tego (w śro-
dowisku µVision) poprzez prawe kliknięcie
na nazwie projektu i wybór z menu kontek-
stowego opcji „ Manage Components ” – patrz
rys. 2. Następnie odszukujemy na dysku wła-
ściwe pliki i je dodajemy.
Jak wyżej wspomniano, aby projekt
poprawnie się kompilował, należy zaktu-
alizować miejsca (ścieżeki), gdzie kompi-
lator będzie szukał plików nagłówkowych
*.h . W tym celu wybieramy menu „ Project/
Options for Target… ”, po czym otworzy się
okno, w którym na zakładce „ C/C++ ” edy-
tujemy ścieżkę poszukiwania plików na-
główkowych. W ten sposób przygotowany
projekt, jeśli kod aplikacji jest pozbawiony
błędów, powinien się bez błędów zbudować
i załadować do pamięci mikrokontrolera.
Szybkie rozpoczęcie pracy z mikrokon-
trolerami STM32 znacznie ułatwiają dołączo-
ne do biblioteki StdPeriph_Lib przykładowe
aplikacje, które pozwalają w krótkim czasie
zapoznać się z możliwościami tych układów.
Dodatkowo, wymienione wyżej warstwy
zostały rozszerzone przez producentów mi-
krokontrolerów, którzy współpracowali przy
tworzeniu CMSIS, o dwie „warstwy”: Device
Peripheral Access Layer oraz Access Func-
tions for Peripherals .
STM32F10x standard peripheral
library V3.1.0
Biblioteka STM32F10x Standard Periph-
erals Library v3.1.0. ( StdPeriph_Lib ) została
napisana zgodnie z formatem Doxygen , co
znacznie upraszcza proces tworzenia doku-
mentacji oraz jej używanie. Cala dokumenta-
cja omawianej biblioteki została umieszczo-
na w pliku pomocy, a nie, jak było to dotych-
czas praktykowane przez STMicroelectro-
nics, w pliku pdf. Nowy sposób dostarczania
dokumentacji ułatwił przeglądanie jej zawar-
tości, oraz wyszukiwanie informacji.
Wraz z archiwum biblioteki StdPeriph_Lib
otrzymujemy szablony projektów do trzech
najpopularniejszych kompilatorów (środo-
wisk), a są to: IAR, Keil oraz darmowy kompi-
lator GCC. Programista jest zatem zwolniony
z obowiązku samodzielnego tworzenia projek-
tu od podstaw. Struktura plików projektu, dla
przykładu wykorzystującego przetwornik A/C,
Rys. 4. Struktura modułu STM32F10x_
StdPeriph_Driver
Struktura biblioteki StdPeriph_
Lib
Pliki w bibliotece API zostały podzie-
lone na dwa bloki (moduły). Są to katalogi
STM32F10x_StdPeriph_Driver oraz CMSIS .
Drzewo plików i katalogów modułu CMSIS
biblioteki Standard Peripherals Library po-
kazano na rys.   3 , natomiast drzewo modułu
STM32F10x_StdPeriph_Driver na rys.   4 .
Dla każdej z rodzin mikrokontrolerów
STM32 zostały przygotowane oddzielne pli-
ki startowe. W  tab.   1 przedstawiono, który
plik startowy należy wykorzystać z jaką ro-
dziną STM32. Takich zestawów plików star-
towych otrzymujemy wraz z biblioteką API
trzy – dla trzech najpopularniejszych kompi-
latorów: Keil, IAR oraz GCC.
Plik system_stm32f10x.c zawiera dei ni-
cje i funkcje, które mogą być wykorzystane
do koni guracji sygnału zegarowego mikro-
kontrolera. Korzystając z funkcji zawartych
w pliku należy w pierwszej kolejności wy-
brać, używając komentarzy, z jaką częstotli-
wością MCU ma pracować. Fragment, który
należy w tym celu edytować został przed-
stawiony na list.   1 . W kodzie aplikacji wy-
starczy teraz wywołać funkcję SystemInit() ,
a jej wykonanie spowoduje skoni gurowanie
wszystkich sygnałów zegarowych (zegar sys-
temowy, HCLK, PCLK2, PCLK1).
Do modułu STM32F10x_StdPeriph_Dri-
ver należą pliki, które, wzorem starszej wer-
sji biblioteki V2.0.3, zgodnie ze swoją nazwą
zawierają funkcje API związane z poszcze-
gólnymi urządzeniami peryferyjnymi – patrz
rys.   4 . Tych plików bibliotecznych nie nale-
ży edytować.
Do każdego projektu są dołączone jesz-
cze dwa istotne pliki: stm32f10x_conf.h oraz
stm32f10x_it.c . W pierwszym pliku nagłów-
kowym za pomocą komentarzy włączamy
lub wyłączamy dołączanie do projektu pli-
ków nagłówkowych z modułu STM32F10x_
StdPeriph_Driver – patrz list.   2 .
Z punktu widzenia programisty jednym
z  najważniejszych plików jest stm32f10x_
it.c , w którym umieszcza się wszystkie funk-
cje obsługi przerwań. Jego nieco zedytowa-
ny fragment wraz z pustymi funkcjami jest
przestawiony na list.   3 . Jak widać, jest to
List. 1. Fragment pliku system_
stm32f10x.c – defi nicje częstotliwości
zegara systemowego, wykorzystywane
przez funkcję SystemInit()
/* #defi ne SYSCLK_FREQ_HSE HSE_
Value */
/* #defi ne SYSCLK_FREQ_24MHz
24000000 */
/* #defi ne SYSCLK_FREQ_36MHz
36000000 */
/* #defi ne SYSCLK_FREQ_48MHz
48000000 */
/* #defi ne SYSCLK_FREQ_56MHz
56000000 */
#defi ne SYSCLK_FREQ_72MHz 72000000
Tab. 1. Pliki startowe dla poszczegól-
nych rodzin mikrokontrolerów STM32
Plik
Rodzina STM32
startup_stm32f10x_cl.s
Connectivity line
startup_stm32f10x_hd.s
High Density
startup_stm32f10x_ld.s
Low Density
Rys. 3. Struktura modułu CMSIS
startup_stm32f10x_md.s
Medium Density
ELEKTRONIKA PRAKTYCZNA 10/2009
101
652388963.007.png 652388963.008.png 652388963.009.png 652388963.010.png 652388963.011.png
kurs
List. 2. Obszar pliku stm32f10x_conf.h ,
w którym za pomocą komentarzy
włącza się lub wyłącza dołączanie
plików nagłówkowych
/* #include „stm32f10x_adc.h” */
/* #include „stm32f10x_bkp.h” */
/* #include „stm32f10x_can.h” */
/* #include „stm32f10x_crc.h” */
/* #include „stm32f10x_dac.h” */
/* #include „stm32f10x_dbgmcu.h” */
#include „stm32f10x_dma.h”
/* #include „stm32f10x_exti.h” */
/* #include „stm32f10x_fl ash.h” */
/* #include „stm32f10x_fsmc.h” */
#include „stm32f10x_gpio.h”
/* #include „stm32f10x_i2c.h” */
/* #include „stm32f10x_iwdg.h” */
/* #include „stm32f10x_pwr.h” */
#include „stm32f10x_rcc.h”
/* #include „stm32f10x_rtc.h” */
/* #include „stm32f10x_sdio.h” */
#include „stm32f10x_spi.h”
/* #include „stm32f10x_tim.h” */
/* #include „stm32f10x_usart.h” */
/* #include „stm32f10x_wwdg.h” */
/* #include „misc.h” */
określonego zdarzenia. Takie podejście spra-
wiło, że projekt jest przejrzysty, a obsługa
wszystkich wyjątków znajduje się w jednym
pliku i nie ma potrzeby, jak to zwykle bywa,
samodzielnego dei niowania funkcji wy-
woływanych w chwili, gdy system wykryje
nadejście przerwania. Znacznie upraszcza
i przyśpiesza to prace nad projektem, jednak
nie należy zapominać, że aby tworzyć dobre
i niezawodne aplikacje to trzeba bardzo do-
brze rozumieć to, co się robi.
List. 5. Konfi guracja timera SysTick
z wykorzystaniem biblioteki STM32F10x
fi rmware library
// SysTick bedzie taktowany z f =
// 72MHz/8 = 9MHz
SysTick_CLKSourceConfi g(SysTick_
CLKSource_HCLK_Div8);
// Przerwanie ma byc co 1ms, f =
// 9MHz czyli liczy od 9000
SysTick_SetReload(9000);
// Odblokowanie przerwania od timera
// SysTick
SysTick_ITConfi g(ENABLE);
// Wlaczenie timera
SysTick_CounterCmd(SysTick_Counter_
Enable);
Migracja ze starszej wersji
biblioteki STM32F10x fi rmware
library
Najistotniejsze zmiany w stosunku do
poprzedniej wersji biblioteki API to kompa-
tybilność nowej wersji z omówionym wyżej
standardem CMSIS. Z punktu widzenia pro-
gramisty, który wcześniej pracował z biblio-
teką STM32F10x i rmware library ważne jest,
że nowa wersja (z perspektywy wykorzysta-
nia funkcji API) w sumie nie wiele różni się
od swojej poprzedniczki.
Biblioteka STM32F10x Standard Periphe-
rals Library została tak napisana, aby uaktu-
alnienie projektów wykorzystujących starszą
wersję biblioteki ( STM32F10x i rmware library )
nie nastręczało problemów. Ze strony interne-
towej i rmy STMicroelectronics można pobrać
archiwum o nazwie an2953 zawierające apli-
kację MigrationScript , która po uruchomieniu
automatycznie zmienia kod w  plikach tak,
aby był możliwie jak najbardziej kompatybil-
ny z nową biblioteką. Niestety te fragmenty
kodu, które wykorzystują funkcje całkowicie
zmienione, lub usunięte w  nowej bibliote-
ce STM32F10x Standard Peripherals Library
należy edytować ręcznie. Dotyczy to przede
wszystkim systemowego timera SysTick.
Zmiany, jakie zostaną wprowadzone do
kodu plików za pomocą aplikacji Migration-
Script , są opisane w pliku coni g.ini , a jego
fragment został przedstawiony na list. 4 .
Z perspektywy programisty wykorzystu-
jącego funkcje API, najistotniejszymi zmia-
nami są:
– inne dei nicje typów zmiennych, np. typ
u32 w nowej bibliotece jest reprezento-
wany przez uint32_t ,
– nowe nazwy funkcji obsługi przerwań
systemowych, np. NMIException() zosta-
ła zmieniona na NMI_Handler() ,
– funkcje i makra asemblerowe związane
z obsługą rdzenia, kontrolera przerwań
NVIC i timera SysTick zostały zmienio-
ne i zamieszczone w pliku misc.c , core_
cm3.c oraz core_cm3.h .
Ponadto zmienione zostały nazwy
związane z przerwaniami i tak na przykład
przerwanie EXTI0 nazywa się EXTI0_IRQn,
w miejsce EXTI0_IRQChannel. Aktualizacji
wymagają również pliki związane bezpo-
średnio z wykorzystywanym środowiskiem
programistycznym, ustawienia projektu oraz
List. 6. Konfi guracja timera SysTick
z wykorzystaniem biblioteki STM32F10x
Standard Peripherals Library
// SysTick bedzie taktowany
// z f = 72MHz/8 = 9MHz
SysTick_CLKSourceConfi g(SysTick_
CLKSource_HCLK_Div8);
// Przerwanie ma byc co 1ms,f =
// 9MHz / 1000, czyli liczy od 9000
if (SysTick_Confi g(SysTick_Frequency
/ 1000))
{
List. 3. Fragment pliku stm32f10x_it.c
void UsageFault_Handler(void)
{
while (1)
{}
}
void SVC_Handler(void)
{
}
void DebugMon_Handler(void)
{
}
void PendSV_Handler(void)
{
}
void SysTick_Handler(void)
{
}
// W razie bledu petla
// nieskonczona
while (1);
}
przeorganizowanie struktury plików biblio-
teki.
Przykładowy fragment kodu, napisa-
ny z  wykorzystaniem starszej biblioteki
STM32F10x i rmware library przedstawiono
na list.   5 , natomiast dla kontrastu na list.   6
przedstawiono program napisany przy uży-
ciu nowej biblioteki Standard Peripherals
Library . Zadanie obydwu programów jest
identyczne i polega na skoni gurowaniu do
pracy systemowy timer SysTick.
zestaw pustych funkcji, które jeżeli wystąpi
odpowiednie przerwanie, są wywoływane.
W stosunku do wersji tego pliku dostarczanej
przez i rmę STMicroelectronics zostały usu-
nięte komentarze, które jak pokazała prakty-
ka okazały się w tym miejscu zbędne. Nazwa
funkcji obsługi danego przerwania jest już
sama w sobie dość wymowna. W efekcie
uzyskano bardziej zwięzły kod, nie tracąc
tym samym na jego czytelności.
Zadaniem dewelopera jest umieszczenie
w odpowiedniej funkcji obsługi przerwania
kodu, jaki ma się wykonać po wystąpieniu
Koni guracja urządzeń
peryferyjnych
Dla każdego urządzenia, czy jest to
GPIO, kontroler przerwań, czy jakikolwiek
inny element systemu, są stworzone odrębne
typy danych. W przypadku portów wejścia/
wyjścia nazywają się one: GPIO_TypeDef ,
oraz wykorzystywany do inicjalizacji typ
GPIO_InitTypeDef . Dla programisty najwięk-
sze znaczenie ma typ inicjujący, ponieważ to
właśnie zmienną tego typu jawnie tworzymy
w pisanym kodzie.
Typ GPIO_TypeDef zapewnia dostęp do
poszczególnych rejestrów mikrokontrolera
i  jest wykorzystywany przede wszystkim
List. 4. Fragment pliku confi g.
ini , który opisuje zmiany, jakie
zostaną wprowadzone do kodu po
uruchomieniu aplikacji MigrationScript
u32<;,;>uint32_t
u16<;,;>uint16_t
u8<;,;>uint8_t
uc32<;,;>const uint32_t
uc16<;,;>const uint16_t
uc8<;,;>const uint8_t
volatile const<;,;>__I
volatile<;,;>__IO
NMIException<;,;>NMI_Handler
HardFaultException<;,;>HardFault_
Handler
MemManageException<;,;>MemManage_
Handler
BusFaultException<;,;>BusFault_
Handler
UsageFaultException<;,;>UsageFault_
Handler
SVCHandler<;,;>SVC_Handler
DebugMonitor<;,;>DebugMon_Handler
PendSVC<;,;>PendSV_Handler
List. 7. Wykorzystanie API – konfi guracja
portu GPIOB
// Wyprowadzenia PB8, PB9 jako
// wyjscia push - pull
GPIO_InitStructure.GPIO_Pin = GPIO_
Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_
Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed =
GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_
InitStructure);
102
ELEKTRONIKA PRAKTYCZNA 10/2009
652388963.012.png 652388963.013.png 652388963.014.png 652388963.015.png 652388963.016.png
Migracja do Standard Peripheral Library
przez funkcje API, natomiast zmienna typu
GPIO_InitTypeDef musi istnieć w każdej apli-
kacji wykorzystującej porty wejścia/wyjścia,
ponieważ jest wykorzystywana do inicjalizo-
wania i koni gurowania portów. Na list. 7 jest
przedstawiony kluczowy fragment kodu od-
powiedzialny za koni gurację portu GPIOB.
Utworzona na początku zmienna GPIO_
InitStructure jest, strukturą. Inicjowanie pi-
nów, lub w szczególnym przypadku całego
portu odbywa się w ten sposób, że wypełnia
się poszczególne pola struktury, a następ-
nie przekazuje się adres tak przygotowanej
zmiennej do funkcji inicjującej.
W  przedstawianej sytuacji w  naszym
kręgu zainteresowań leżą trzy pola struktury
GPIO_InitStructure . W pierwszej kolejności
ustalamy, które z pinów będą koni gurowa-
ne, następnie wybieramy żądany tryb pracy
– w tym przypadku będzie to wyjście typu
push-pull. Następnie ustalamy maksymalna
prędkość, z jaką będą mogły pracować piny.
Tak przygotowaną zmienną należy przeka-
zać przez podanie jej adresu w argumencie
do funkcji inicjującej GPIO_Init() . Drugim ar-
gumentem, jaki należy funkcji przekazać jest
nazwa portu, do jakiego mają być zastosowa-
ne wybrane ustawienia.
Podsumowanie
Wykorzystywanie gotowych bibliotek
jest bardzo przyjemne, ale nie zwalnia to
programisty z  obowiązku rozumienia, co
właściwie (i  w  jaki sposób) poszczególne
funkcje robią. Jest to bardzo ważne i zawsze
należy o tym pamiętać. Z tego powodu, je-
śli konstruktor chce w pełni panować nad
wszystkimi elementami systemu, to i  tak
musi dokładnie zapoznać się z dokumen-
tacją techniczną mikrokontrolera, a tym sa-
mym poznać jego architekturę.
Krzysztof Paprocki
paprocki.krzysztof@gmail.com
R
E
K
L
A
M
A
MIERNIKI SZKOLNE
ACA-1
AMPEROMIERZ ANALOGOWY AC
cena: 33,80 zł
zakresy pomiarowe: 0...500 mAAC, 0...1 AAC, 0...5 AAC
ACV-1
WOLTOMIERZ ANALOGOWY AC
cena: 26,70 zł
zakresy pomiarowe: 0...15 VAC, 0...150 VAC
DCG-1
GALWANOMETR ANALOGOWY DC
cena: 26,70 zł
zakresy pomiarowe: –35 M A...0...+35 M ADC
DCV-1
WOLTOMIERZ ANALOGOWY DC
cena: 26,70 zł
zakresy pomiarowe: 0...3 VDC, 0...30 VDC, 0...300 VDC
DCV-2
WOLTOMIERZ ANALOGOWY DC
cena: 26,70 zł
zakresy pomiarowe: 0...300 mVDC, 0...3 VDC, 0...30 VDC
DCA-1
AMPEROMIERZ ANALOGOWY DC
cena: 26,70 zł
zakresy pomiarowe: 0...50 mADC, 0...500 mADC, 0...5 ADC
www.sklep.avt.pl • tel 022 257 84 50
ELEKTRONIKA PRAKTYCZNA 10/2009
103
652388963.017.png 652388963.018.png 652388963.019.png 652388963.020.png 652388963.021.png 652388963.022.png 652388963.023.png 652388963.024.png 652388963.025.png 652388963.026.png 652388963.027.png 652388963.028.png 652388963.029.png 652388963.030.png 652388963.031.png 652388963.032.png 652388963.033.png 652388963.034.png 652388963.035.png
Zgłoś jeśli naruszono regulamin