ARM: Laikmačio pertraukimas

Posted: 2014-09-08 in Darbeliai
Žymos:,

Praėjo daugiau, kaip pusė metų nuo mano paskutinio ARM pakrapštymo. Tai laiko nebuvo, tai noro, tai ten vienas bandymas su ARM neišdegė… kurio ir neaprašiau, beje.

Bet štai praėjusią savaitę užėjo mirtinas noras kažkiek ARM pakrapštyt. Motyvacija yra tame, kad man jau beveik mirtinai reikia gudraus skydelio savo Avietei, o AVR procesoriaus tam tinkamo neturiu. Na, galėčiau Atmega2560 ar panašų nusigriebt, bet ten irgi ne viskas taip, kaip man norėtųsi. Todėl nusprendžiau, kad bent jau šiek tiek pasikapstysiu po ARM galimybes.

Dabartinis mano tikslas yra panašus į JeeLabs programinių laikmačių biblioteką. Tai pirmas dalykas, kurį noriu pasidaryti savo STM32 procesoriukui. Be abejo, iki to reikia prieiti ir išsiaiškinti daug nežinomųjų. Bet, manau, pavyks. Na, ir dar reikės patyrinėti SysTick laikmatį, kuris yra „tūpas“ ir labiausiai tinka visokiems laiko skaičiavimams ir mažų OS dispečerių baksnojimui. Šiandien, tuo tarpu, apie „normalius“ 16 bitų laikmačius… kurių šitas procesoriukas turi, regis, tris ir kiekvienas iš jų turi keturis aparatūrinius kanalus, galinčius valdyti kad ir PWM. Dvylika PWM kojų — visai nėr blogai pigiam mažam procesoriukui, ane?

Perskaitęs keliolika puslapių STM32 specifikacijų lakšto supratau, kad laikmačių per registrus konfigūruoti nenoriu. Bjauriai sudėtinga ten. Todėl apsisprendžiau naudotis STM Standard Peripherals bibliotekomis, kurios visus tuos registrus ne tik gražiai, bet ir be papildomo apkrovimo optimaliai paslepia. Aš prieš tą gerą pusmetį kiek pasimokiau GPIO valdyti su registrais ir manau, kad man to užteks. Bendrą supratimą, kaip sakoma, įgijau.

Ką gi, nuo paskutinio ARM pakrapštymo praėjo nemažai laiko. Visų pirma, pakeičiau kompiuterį, o visų antra — jame perinstaliavau OS. Tad jau supratau, kad teks pakelti savo paties senus užrašėlius ir visokius ten toolchain’us ir gdb serverius persikonfigūruot.

Atsikėliau savaitgalį ryte, įsijungiau kompiuterį ir supratau, kad viskas blogai. Kompiuteris neužsikrovė. Tiksliau, kraudamasis pastrigo ties „Restoring resolver state“. Kitaip sakant, prieš pat grafinio prisijungimo langelio pasirodymą. Įdomus dalykas: tas grafinis langelis pasirodė vėliau prijungtame antrajame monitoriuje. Taigi kažkas (spėju po kažkokio atnaujinimo) susibliovė su mano Nvidia Optimus palaikymu. Po kelių pasikrapštymų BIOS’e įjungiau „Discrete Video“ ir tam kartui galiu dirbti. O kaip reikės išspręsti Optimus problemą — kol kas neįsivaizduoju. Nebent su kokiu kitu atnaujinimu vėl viskas susitvarkys. Va ir nesidaryk savo root skirsnio atsarginių kopijų… paskutinė kopija tiek pasenus, kad nesiryžau prie jos grįžti. Šiuo dabar turėsiu motyvacijos užsiimti. Tiesa, problemą pavyko išspręsti vėliau: užteko nudobti lightdm ir ištrinti /etc/X11/xorg.conf failą. Kažkas ten buvo pridirbta po šviežio atnaujinimo, jaučiu, Intel vaizdo plokštės adresas suveltas… bet kokiu atveju, vaizdas grįžo į ekraną, nors sunervino gan smarkiai… akivaizdu, kad dalinis atnaujinimas kažką labai suvėlė, nes prasidėjo ACPI problemos, garso problemos ir šiaip visokie keisti netikėtumai… nx tą Linuxą kartais.

ARM aplinką susitvarkiau, nors ir nelabai sklandžiai, bet pavyko. Dar pasisekė, kad radau paprastą pavyzduką su laikmačiais. Vienas pavyzdukas, kuriame nuolat buvo apklausinėjamos laikmačio skaitliuko reikšmės, nesuveikė. Greičiausiai ten dėl palyginimo programėlė vis nepataikydavo į laikmačio reikšmę. Prastas pavyzdys, iš karto matosi.

Antras pavyzdys — sugeneruojantis laikmačio atnaujinimo įvykį. Jį irgi galima pagrindiniame programos cikle patikrinti bei laikmatį vėl perstatyti suktis iš naujo.

Daug čia nepaistysiu, štai kodo pavyzdukas. Jame GPIOA nulinė koja prijungta, kaip Active Low. Na, mano kaištukinė plokštelė su šviesos diodu taip ir pragulėjo pusmetį be didelių judinimų. Laikmatukas nustatomas su maždaug milisekundės prescale reikšme, skaičiuojama didėjimo linkme ir „persverčia“ sukapsėjus 500 vienetų — apie pusę sekundės. Toliau dar visų reikšmių neapžiūrėjau, bet kažkas tokio…

#include "stm32f10x.h"

/* Mirksiuko konstantos */
#define BLINK_PORT      GPIOA
#define BLINK_PIN       0
#define BLINK_RCC_BIT   RCC_APB2Periph_GPIOA

int main(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* Įjungiam taktavimą */
  RCC_APB2PeriphClockCmd(BLINK_RCC_BIT, ENABLE);

  /* Diodo elektrodą nustatom į push/pull režimą */
  GPIO_InitStructure.GPIO_Pin = (1 << BLINK_PIN);
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(BLINK_PORT, &GPIO_InitStructure);

  /* Įjungiam laikmačio taktavimą */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  TIM_TimeBaseInitTypeDef timerInitStructure;
  /* Nustatom laikmatį atnaujinti skaitliuką kas milisekundę */
  timerInitStructure.TIM_Prescaler = 40000;
  timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
  timerInitStructure.TIM_Period = 500;
  timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  timerInitStructure.TIM_RepetitionCounter = 0;
  TIM_TimeBaseInit(TIM2, &timerInitStructure);
  TIM_Cmd(TIM2, ENABLE);

  /* Įjungiam TIM_IT_Update įvykio generavimą */
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

  /* Mirksiuko „apvertimo“ kintamasis */
  int bit = 0;

  while (1) {
          /* Tikrinam, ar atnaujinimo įvykio nereikia nuRESETinti, 
             t.y. ar nesukapsėjo norimas laikas */
	  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
	  {
                  /* Indikuojam, kad sutvarkėm įvykį ir leidžiam laikmačiui kapsėti toliau */
		  TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
                  /* Junginėjam mirksiuką */
		  if (bit) {
			  GPIO_ResetBits(BLINK_PORT, (1 << BLINK_PIN));
			  bit = 0;
		  } else {
			  GPIO_SetBits(BLINK_PORT, (1 << BLINK_PIN));
			  bit = 1;
		  }
	  }
    }

  return 0;
}

Toks gan paprastas pavyzdukas. Tačiau taip nėra labai įdomu, nes pagrindiniame programos cikle tikrinama laikmačio būsena. Jei daug priprogramuosim, tai tas tikrinimas gali „vėluoti“. O ten, kur reikia apdoroti kritiškai svarbius įvykius, tokie uždelsimai gali būti negerai. Tad toliau reikia pabandyti susikurti ir suvaldyti laikmačio pertraukimo vektorių ir pasirašyti paprogramę, kuri būtų iškviečiama aparatūriniu būdu — kad įvyktų procesoriaus pertraukimas.

Pastabėlė. Jau prie GPIO įrašo minėjau, kad visokie ARM daikčiukai viduje yra pririšti prie keleto dažnių magistralių. Kiek jų yra, aš nepamenu, bet svarbu žinoti, kad kelios. Laikmačiai irgi prikabinti prie skirtingų magistralių. Vienas prie vienos ir du — prie kitos (jei nepainioju). Todėl kode ir yra toks „taktavimo įjungimas“ — įjungiam laikmatį ir magistralę, kuri jam atraminį dažnį duoda. Magistralių dažniai skiriasi, tad skiriasi ir laikmačių daugikliai (prescale). Visa TIM_TimeBaseInitTypeDef struktūra plius-minus atitinka laikmatuko registrus, kuriuos reikėtų užpildyti.

Apskritai, priešingai nei AVR, ARM orientuoti į energijos taupymą „pagal nutylėjimą“. AVR įjungei, nustatei kokios kojos režimą ir makaluok ja. O ARM pirma reikia įjungti reikalingas magistrales, dažnomačius ir panašiai, o tik tada jau kojom makaluoti. Bo kitaip kojos nesimakaluos — viskas išjungta iki negaliu.

Tąsomės toliau. Pertraukimų valdymas ARM architektūroje bjauriai sudėtingas. Su AVR nepalyginsi. Pasėdėjęs ant ištiesto specifikacinio lakšto susiėmiau už galvos ir nėriau internetan ieškoti kokio pavyzduko. Vualia, radau.

Ir štai, ARM programėlė, kuri junginėja mirksiuką su tikru pertraukimu:

#include "stm32f10x.h"

/* Mirksiuko konstantos */
#define BLINK_PORT      GPIOA
#define BLINK_PIN       0
#define BLINK_RCC_BIT   RCC_APB2Periph_GPIOA

/* Mirksiuko „apvertimo“ kintamasis */
int bit = 0;

/* Sukuriam pertraukimo apdorojimo paprogramę */
void TIM2_IRQHandler()
{
	/* Indikuojam, kad sutvarkėm įvykį ir leidžiam laikmačiui kapsėti toliau */
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	/* Junginėjam mirksiuką */
	if (bit) {
		GPIO_ResetBits(BLINK_PORT, (1 << BLINK_PIN));
		bit = 0;
	} else {
		GPIO_SetBits(BLINK_PORT, (1 << BLINK_PIN));
		bit = 1;
	}
}

int main(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/* Įjungiam taktavimą */
	RCC_APB2PeriphClockCmd(BLINK_RCC_BIT, ENABLE);

	/* Diodo elektrodą nustatom į push/pull režimą */
	GPIO_InitStructure.GPIO_Pin = (1 << BLINK_PIN);
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(BLINK_PORT, &GPIO_InitStructure);

	/* Įjungiam laikmačio taktavimą */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

	TIM_TimeBaseInitTypeDef timerInitStructure;
	/* Nustatom laikmatį atnaujinti skaitliuką kas milisekundę */
	timerInitStructure.TIM_Prescaler = 40000;
	timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	timerInitStructure.TIM_Period = 500;
	timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	timerInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM2, &timerInitStructure);
	TIM_Cmd(TIM2, ENABLE);

	/* Įjungiam TIM_IT_Update įvykio generavimą */
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

	/* Konfigūruojam laikmačio petraukimo vektorių */
	NVIC_InitTypeDef nvicStructure;
	nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
	nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
	nvicStructure.NVIC_IRQChannelSubPriority = 1;
	nvicStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&nvicStructure);

	while (1) {

	}

	return 0;
}

Va ir viskas. Pastabėlė: jeigu darytumėt C++ projektą (o ne C, kaip aš čia), tai priešais pertraukimo paprogramę dar reikėtų extern “C” pridėti. Man šiam kartui pažinties su laikmačiais užteks, o kitu kartu bandysiu prie SysTick kokią nors naudingą bibliotekėlę prikabinti.

Advertisements
Komentarai
  1. dmb220 parašė:

    sveiki, bandau mokytis arm, stm32f103 ir tavo kad paimu nukopijuoju, sukompiliuoju, naudoju eclipse, jokiu error viskas pavyksta ikeliu i mikrovaldikli koda, ir niekas nevyksta, joks led nemirksi, nereguoja. antra diena ieskau saknu. jei pasirenki blink sablona is eclipse nustatymu kuriant projekta o ne emp
    ty projekta, tas kodas veikia ikelus i mikrovaldikli.

    • Darau, Blė parašė:

      Na, aš siūlyčiau padaryti taip. Paimti veikiantį mirksiuko kodą (blinky) ir jį papildyti mano pavyzdžiu. Ir tada žiūrėt, ar mano pavyzdį įklijavus į veikiantį mirksiuką tas neužsilenkia, t.y. toliau tebemirksi. Bent jau aš pats taip darau, kai tingiu normaliai debugintis. Paleidžiu softwarinį mirksiuką ir jei jis veikia, ieškau problemų kitur. Beje, Empty projcet su Eclipse niekada nekuriu, jei ruošiuosi ARM kodyt. Visada pradedu nuo mirksiuko.

      • Andrius parašė:

        Bandau taip daryti kaip tu patari, bet man nekompiliuoja, meta error del visu naudojamu TIM_ClearITPendingBit, TIM_Cmd(TIM2, ENABLE);, TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);, TIM_TimeBaseInit(TIM2, &timerInitStructure); cia reik kazka ijungti ar header includinti, tik, nesuprantu ka, ar kur padaryti.?
        naudojant System Workbench for STM32 programa, eclipse pagrindu sukompiliuoja, bet neveikia ant mikrovaldiklio kai ikeli.

        • Darau, Blė parašė:

          Jo, čia reikia Standard Peripherals includų. Kurių tiksliai, nepasakysiu, aš vieną bendrą includinu (stm32f10x.h). Skiriasi šiaip visi tie IDE, ką by default įkiša…

          • Andrius parašė:

            stm32f10x.h sita includinu, bet jo nepakanka. reiks ieskoti saknu

            • Darau, Blė parašė:

              Jo, aš dabar ne prie kompo, negaliu tiksliai pažiūrėt.

            • n\a parašė:

              tai rodyk kokias klaidas meta, nes kitaip tai spelioti galima iki begalybes

                • Andrius parašė:

                  https://drive.google.com/file/d/0B7l6SxJ3dkyCcGdlNTdZZVpvSGM/view?usp=sharing cia naudoju eclipse +GCC taip kaip pas taves, tik gal kazko nenustatu ar neparasau i koda papildomai

                  • Darau, Blė parašė:

                    Ai viskas čia maždaug aišku, bent aš jau taip manau. Žiūrėk, išsiskleisk katalogėlį system/src/stm32f1-stdperiph/ savo projekte ir pažiūrėk, ar *.c failiukai neperbraukti įstrižu pilku brūkšniu 🙂 Tai reikštų, kad jų nekompiliuoja.

                    Vaistukas paprastas: ant projekto spaudi „Properties“, toliau naviguoji iki C/C++ General > Paths and Symbols, ten įsijungi tabuką Source Locations. Išsiskleisk system ir ten turėtų Filter būt uždėtas. Paspausk tą Filter, o šone — Edit Filter… mygtuką ir viską išmesk lauk.

                    • Andrius parašė:

                      labai aciu, viskas veikia dabar puikiai, pats buciau nerades kur ka pakeisti

                    • Darau, Blė parašė:

                      Čia kažkokia nesąmonė su nauju Eclipse pluginu. Turiu įtarimą, kad bandoma prastumti naują HAL biblioteką vietoj Standard Peripherals ir dėl to pastarasis kodas yra nufiltruojamas, tipo deprecated. Arba priešingai, nori, kad programuotojai atsifiltruotų tik jiems reikalingą kodą…

                    • n\a parašė:

                      Kažkodėl neleidžia į du paskutinius komentarus atsakyti tai rašau čia 🙂
                      Tie filtrai tai jau pamenu iš senovės buvo uždėti, tik ten nebuvo visi failai sukišti (gal kokie 4-5 pagrindiniai nebuvo sukišti, gal ir dabar tas pats?), tai manau čia alles in Ordnung ir padaryta, kad developeriai patys įsitrauktų ko jiems reikia

  2. Andrius parašė:

    o tas HAL library kazkuo geresni? siaip ka naudoti o ko nenaudoti gali sitame faile stm32f10x_conf uzkomentuoti ar atkomentuoti kurias library nori kad uzsikrautu. ar as klystu?

  3. dmb220 parašė:

    sveiki dar karta, vel su durnu klausimu, reikia man nusistatyti timer pertraukima, kuris suveiktu apie 400-500 kartu per sukunde, reik isvedinet duomenis i LEd matrix 96×64. vienu metu rodomos 2 eilutes, pilnas kadras kad butu reik 16 kartu iskviesti pertraukima, o kad butu per skunde 24 kadrai reik 384 pertarukimu per 1 sekunde maziausiai. viska buvau pasidares ant arduino, bet jei bandai papildomai koki DHT ar 433 mhz imtuvu priimti duomenis ar IR nuotulinis pultelis ir nebespeja, i led matrix atnaujinti duomenu. nusprenciau pereiti ant galingesnio daikto, gal pavyks. 😀

    • dmb220 parašė:

      gal koki tutorial zinai ar programike kuri paskaiciuotu man timer. keliu kartu per sekunde timer pvz randu o kad man reik tokiu dazniu nerandu, arba nemoku ieskoti.

      • Darau, Blė parašė:

        Yra vienas labai geras kalkuliatorius, kurį pats naudoju. Jis ir kodo gabalus sugeneruoja, tik juos paskui prie savo naudojamo frameworko reikia prisitaikyt: http://www.mikroe.com/timer-calculator/

        Dėl ekrano tai nežinau. Jei jis paišomas pertraukimais, tai kiti reikalai neturėtų labai maišyt. Visada galima atskirą procesoriuką vien ekranui dedikuoti.

        • dmb220 parašė:

          darant su arduino galvojau kabinti atskira arduino koki mini, bet RAm mazoka, norisi daugiau sriftu isikelti ir pan, ir jau meta kad neuztenka. pabandysiu su STM32 jei nepavyks, teks gryzti prie arduino. dekui uz nuoroda

          • dmb220 parašė:

            pabandziau pasiskaiciuoti: //Timer2 Prescaler :2; Preload = 62499; Actual Interrupt Time = 2,604166667 ms tai prescaler kaip ir asiku, kode 2 irasyti, o tas preload tai period?

            • Darau, Blė parašė:

              Jo, preload turbūt bus skaitliukas, ties kuriuo laikmatis persivers. Prescaleris tai nurodo, kas kiek procesoriaus taktų skaitliuką vienetu padidinti.

              Dėl RAM tai visada kokį XMega galima pasiimti, su juo ir dažnį galima didesnį, nei 16 MHz turėt. Bet panašus ARM gal tiesiog pigiau. Viskas ten su jais gaunasi, tik kantrybės biškutuko reikia — kaip ir visur 🙂

  4. dmb220 parašė:

    pasileidau savo led matrix, kad rodytu vaizda, su stm32f103, rodo gerai, bent pakolkas, jokiu papildomu darbu nedaviau, tai neaisku kaip eis apkrovus ji. tik man keistai pasirode kad timer pertarukimas turi 1000hz dazniu dirbti, kad normaliai rodytu, nors arduino uzteko ir 400hz daznio. kodel taip idomiai? gal kazka ne iki galo timer nustatymuose nusistatau? pagal ta programike kuria pasiuliai, i tavo timer, kuri same straipsnyje ppateki, idedu reiksmes kurias sugeneruoja.

    • Darau, Blė parašė:

      Dėl 1000 Hz ir 400 Hz kažkaip abejoju, kad skirtumas būtų… nebent tas skirtumas atsiranda dėl maitinimo įtampos. Ar savo LED matricą maitini 3,3 V ar 5?
      Šiaip 16 bitų laikmačiui gali pasiskaičiuoti prescalerį ir periodą pats, tai nėra sunku. Procesoriaus dažnis yra 72 MHz, o laikmačius valdo APB1 magistralė, ji yra pusės procesoriaus dažnio, t.y. 36 MHz. Padalini 36 000 000 iš prescalerio, iš periodo ir žinai suveikimo dažnį. Pasitikrink tokiu būdu, ar atitinka.

      • dmb220 parašė:

        LEd matrix maitinu 5v 15A, mikrovaldiklis uzsimaitina pakolkas nuo pc per st-link. 36MHz dalinu is Prescaler = 1; ir tada dalinu is Period = 35999; gaunu apie 1000Hz, tiek kiek ir paskaiciuoja ta programa. siaip idomu kodel ta programa prescaler maza skaiciu pateikia. kiek pavizdziu ziurejau tai visalai prescaler didesnis skaiciu uz period, o ta programa atvirsciai skaiciuoja

        • Darau, Blė parašė:

          Na, priklauso, į ką ta programa orientuota. Kai reikia PWM impulsus generuot, tai tada kaip tik svarbiau turėti kuo didesnį diapazoną keičiamų reikšmių su mažesniu prescaleriu. Nes, sakykim, prescaleris 1, o period 35999, tai lieka labai daug reikšmių tarpiniams PWM intervalams. Aišku, kai tas nėra aktualu, tai galima ir atvirkščiai daryt, užsikelt prescalerį. Bet didelis prescaleris paprastai naudojamas, kai intervalas siekia sekundės dalis ar net kelias sekundes.

          O, aš kažkaip galvojau, kad kokį LED ekraniuką junginėji 🙂 15 A tai jau žvėris 🙂

          Na, lauksiu tolimesnių komentarų, kaip seksis procesorių papildomais darbais apkraut. Šiaip tarp milisekundės pirstelėjimų tikrai turėtų nemažai spėt nuveikt, klausimas, kiek laiko matricos atnaujinimas užims.

  5. dmb220 parašė:

    https://drive.google.com/file/d/0B7l6SxJ3dkyCLVJpYi1xV0pKdzQ/view?usp=sharing kol junginejau GPIO kojas viskas ok, norejau I2C ir error poto ziuriu kad library perbraukti yra. pagal tavo paasikinima, filtras tuscias, tai nesuprantu kaip pasidaryt kad tos duotos library veiktu

    • Darau, Blė parašė:

      Hmm. Gal failai ne src kataloge? Arba kokiam nors, kuris neįtrauktas į kompiliavimą?

    • Darau, Blė parašė:

      Jo, pas tave pagal paveiksliuką kažkaip source katalogai sugadinti atrodo. Neištrynei netyčia?

      • dmb220 parašė:

        failai visi yra savo vietose, paspaudud ant tu perbrauktu, jie atsidaro ir gali koreguoti, tik kazko kompiliatorius ju nemato

        • dmb220 parašė:

          tas eclipse durniuoja, nieko nekeiciau, keleta kartu kompiliuojant pradejo mesti error:
          fatal error: misc.h: No such file or directory misc.c tiesiog is oro error atsiranda, dabar sugebejo dar ir CAn library faile rasti klaidu. beveik 200 error is oro atsirado.

Parašykite komentarą

Įveskite savo duomenis žemiau arba prisijunkite per socialinį tinklą:

WordPress.com Logo

Jūs komentuojate naudodamiesi savo WordPress.com paskyra. Atsijungti / Keisti )

Twitter picture

Jūs komentuojate naudodamiesi savo Twitter paskyra. Atsijungti / Keisti )

Facebook photo

Jūs komentuojate naudodamiesi savo Facebook paskyra. Atsijungti / Keisti )

Google+ photo

Jūs komentuojate naudodamiesi savo Google+ paskyra. Atsijungti / Keisti )

Connecting to %s