Теоретические сведения

Структурная схема ЦСП семейства C28x приведена на рис. 2.1. Память и все периферийные модули объединены системой шин по модифицированной гарвардской архитектуре.

 

Рис. 2.1. Структурная схема ЦСП семейства C28x

 

Карта адресного пространства ЦСП C28x показана на рис. 2.2. В качестве памяти данных используется исключительно ОЗУ быстрого доступа (Single Access RAM – SARAM, доступ возможен в течение каждого машинного цикла) общим объёмом 18 Кслов, состоящее из нескольких банков – М0, M1 (2x1К), L0, L1 (2x4К) и Н0 (8К). Каждый банк отображается и на память программ, и на память данных, т.е. эту память можно использовать и в качестве памяти программ, и в качестве памяти данных. В сигнальных процессорах F2812 объём встроенной флэш-памяти составляет 128 Кслов (4 сектора по 8К и 6 секторов по 16К).

В процессоре C28x, помимо центрального процессорного устройства (CPU) имеется внутренняя периферия (АЦП, таймеры, встроенные интерфейсы и пр.), которая также располагается на кристалле. ЦСП семейства С28x содержат регистры модуля центрального процессора (регистры CPU), необходимые для арифметической/логической обработки данных и три сегмента (фрейма) регистров встроенной периферии, предназначенных для управления режимами и хранения данных внутренних периферийных устройств. Эти регистры расположены прямо в адресном пространстве памяти, т.е. доступны не только как регистры с именами, но и как ячейки памяти с определенными адресами (см. рис. 2.2).

 

 

 


Рис. 2.2. Карта адресного пространства ЦСП семейства C28x

 

Peripheral Frame 0 (PF0, объем 2K, адреса 0x00 0800…
0x00 0FFF) – включает в себя регистры внешнего интерфейса памяти XINTF, модуля расширения прерываний PIE, модуля Flash-памяти, модуля таймеров ядра, модуля ключа защиты CSM;

Peripheral Frame 2 (PF2, объем 4K, адреса 0x00 6000…0x00 6FFF) – включает в себя регистры интерфейса eCAN;

Peripheral Frame 1 (PF1, объем 4K, адреса 0x00 7000…
0x00 7FFF) – включает в себя регистры модуля управления системой, модуля ввода-вывода GPIO, модуля менеджеров событий EVA/EVB, модуля последовательного интерфейса McBSP, модуля последовательного интерфейса SCI, модуля последовательного интерфейса SPI, модуля АЦП.

Все программно доступные цифровые выводы сгруппированы в порты GPIOA, GPIOB, GPIOD, GPIOE, GPIOF, GPIOG. GPIO (general purpose input/output) означает «линии ввода/вывода общего назначения».

Периферия имеет выводы, использующиеся для ввода/вывода сигналов. Чтобы не загромождать ЦСП дополнительными выводами, используют мультиплексирование: на одном выводе могут быть реализованы две и более различные функции, которые выбираются программным путем. На рис. 2.3 приведены основные и альтернативные функции портов.

 

Рис. 2.3. Основные и альтернативные функции портов ввода-вывода F2812

Все 6 портов управляются своими мультиплексирующими регистрами (GPxMUX, здесь и далее в именах регистров, относящихся к портам, x – имя порта). Если бит сброшен в 0, то данный вывод работает как обычная линия порта; установкой бита в 1 выбирается альтернативная функция, т.е. линия порта (pin) подключается к соответствующему периферийному устройству (см. рис. 2.4). К регистрам данных относятся:

- регистры GPxDAT (в них непосредственно хранятся данные порта, которые могут быть изменены записью в данные регистры);

- регистры GPxSET (служат для установки соответствующих разрядов порта);

- регистры GPxCLEAR (служат для сброса соответствующих разрядов порта);

- регистры GPxTOGGLE (служат для переключения соответствующих разрядов порта в альтернативное логическое состояние).

 


 

Рис. 2.4. Функциональная схема линии GPIO

 

Каждый вывод порта может работать на ввод или вывод. Направление передачи данных задается битами в регистрах  GPxDIR:
0 – линия работает на ввод, 1 – на вывод данных. При работе портов A, B, D и E на ввод для увеличения помехозащищенности можно настроить функцию задержки ввода (Input Qualification feature) установкой битов 7-0 в соответствующем регистре GPxQUAL. После этого импульсы на линиях соответствующих портов, имеющие максимальную длительность от 2 (GPxQUAL=0x01) до 510 (GPxQUAL=0xFF) периодов частоты тактирования ядра SYSCLKOUT, не будут распознаваться ядром процессора.

Перед началом работы необходимо настроить модуль тактирования. Как и многие современные процессоры, ЦСП семейства С28х используют внешний резонатор или генератор с частотой более низкой, чем максимальная тактовая. Это позволяет уменьшить влияние электромагнитных помех, понизить требования к разводке печатной платы и повысить надежность работы схемы. Частота тактового генератора OSCCLK, расположенного на плате эмулятора, составляет
30 МГц. Максимальная тактовая частота процессора 150 МГц получается путем умножения внешней частоты на 5 (OSCCLK*10/2, см. рис. 2.5). Коэффициент деления задается программно в регистре PLLCR.

 

Рис. 2.5. Тактовый модуль и регистр PLLCR

 

Помимо формирователя тактовой частоты ядра, тактовый модуль содержит предделители: низкоскоростной LOSPCP и высокоскоростной HISPCP (рис. 2.6), которые используются для тактирования периферийных устройств.

Известно, что потребляемая мощность микропроцессорных элементов возрастает пропорционально тактовой частоте. Снижая тактовую частоту, можно снизить энергопотребление и определенного модуля, и всего ЦСП в целом. Коэффициенты деления задаются программно в регистрах LOSPCP и HISPCP.

Рис. 2.6. Формат регистров HISPCP и LOSPCP

В ЦСП семейства С28х реализована возможность не только изменять, но и полностью запрещать/разрешать тактирование различных периферийных модулей при помощи регистра PCLKCR (рис. 2.7).

 

 

EVAENCLK Разрешение HSPCLK в EVA
EVBENCLK Разрешение HSPCLK в EVВ
ADCENCLK Разрешение HSPCLK в АЦП (ADC)
SPIAENCLK Разрешение LSPCLK в SPI
SCIAENCLK Разрешение LSPCLK в SCI-A
SCIBENCLK Разрешение LSPCLK в SCI-B
MCBSPENCLK Разрешение LSPCLK в McBSP
ECANENCLK Разрешение тактирования eCAN

Рис. 2.7. Формат регистра PCLKCR: 1 – разрешить тактирование периферийного модуля; 0 – запретить.

Сторожевой таймер (Watchdog timer или WDT, рис. 2.8) предназначен для предотвращения «зависания» ядра ЦСП и реализован на основе суммирующего счетчика WDCNTR, который тактируется через счетчик-делитель от внешнего генератора и при переполнении вырабатывает сигнал прерывания WDINT либо сброса ядра ЦСП WDRST (задается программно). WDT работает независимо от ядра ЦСП и должен сбрасываться программно для предотвращения сброса процессора.

Сторожевой таймер защищен ключом «101», и, в случае записи в биты WDCHK 2–0 регистра WDCR (рис. 2.9) любой иной кодовой комбинации, в следующем машинном цикле происходит генерация выходного сигнала (такого же, как и при переполнении). Для предотвращения сброса ЦСП необходимо периодически программно сбрасывать счетчик WDCNTR при помощи записи последовательности кодов «0x55 + 0xAA» в специальный регистр WDKEY.

 

 

Рис. 2.8. Функциональная схема сторожевого таймера

 

 

Рис. 2.9. Формат регистра управления сторожевого таймера WDCR

 

Бит WDFLAG используется для того, чтобы указать источник сброса: обычный сброс (WDFLAG=0) или сброс по сторожевому таймеру (WDFLAG=1). Биты WDPS 2–0 позволяют выбрать необходимый коэффициент деления частоты для работы сторожевого таймера. Бит WDDIS служит для запрета работы (блокировки) WDT.

Регистр управления и состояния (System Control and Status
Register – SCSR, рис. 2.10) управляет сбросом сторожевого таймера. Бит WDINTS отражает текущее состояние сигнала WDINT. Бит WDENINT – выбор режима действия от WDT (сброс или прерывание). Если WDENINT=0 – разрешен сигнал сброса WDRST, если WDENINT=1 – разрешен сигнал прерывания WDINT.

Если бит WDOVERRIDE установлен в 1, то пользователь может изменять состояние сторожевого таймера, т.е. запрещать или разрешать его работу с помощью бита WDDIS в регистре управления WDCR. Особенностью является то, что пользователь может только сбросить бит WDOVERRIDE, записав в него «1», установить бит программно нельзя.

 

 

Рис. 2.10. Формат регистра управления и состояния SCSR








Ход работы

 

Часть I

 

В части I лабораторной работы необходимо разработать программу «бегущие огни», задавая направление движения: сначала – от края к краю (см. рис. 2.11, а), а потом, зажигая по два светодиода, – от периферии к центру (см. рис. 2.11, б). Светодиоды подключены к линиям порта GPIOB7 – GPIOB0 (1 – горит, 0 – погашен), а линии порта GPIOB15 – GPIOB8 соединены с ключами (1 – ключ замкнут, 0 – разомкнут).

 

 

 


Рис. 2.11. Направление движения светодиодов: а) – слева направо и наоборот; б) – от периферии к центру и наоборот.

 

1. Создание нового проекта.

В Code Composer Studio создаем новый проект Lab2.pjt. В поле Project Name записываем название проекта «Lab2». В поле Location указывается путь, по которому будет находиться проект – E:\DspUser\Lab2.

1.1. Для упрощения работы файл под именем «_lab2_.c» с заготовкой текста программы имеется на диске в папке «E:\DspUser\Templates». Знаками «?» в исходном тексте программы отмечены значения, которые необходимо будет заменить на требуемые для правильной работы программы (рис. 2.12). Копируем данный файл в папку проекта E:\DspUser\Lab2 и переименовываем в «Lab2.c». Добавляем в проект и открываем в окне редактора данный файл:
Project → Add files to Project. 

1.2. Добавляем в проект управляющий файл линкера, командные файлы, библиотеки, необходимые внешние программные модули (рекомендуется для исключения ошибок пути к файлам, указанные ниже, копировать в диалоговое окно «Add files to Project»):

 

C:\tidcs\c28\dsp281x\v100\DSP281x_common\cmd\F2812_EzDSP_RAM_lnk.cmd

C:\tidcs\c28\dsp281x\v100\DSP281x_headers\cmd\DSP281x_Headers_nonBIOS.cmd

C:\CCStudio_v3.3\C2000\cgtools\lib\rts2800_ml.lib

C:\tidcs\c28\dsp281x\v100\DSP281x_headers\source\DSP281x_GlobalVariableDefs.c

 

2. Настройка параметров проекта.

2.1. Включаем в проект заголовочные файлы, для этого выбираем Project → Build Options, в закладке Compiler выбираем Preprocessor и в поле Include Search Path (-i) вводим:

C:\tidcs\C28\dsp281x\v100\DSP281x_headers\include;..\include

2.2. Добавление библиотек и создание стека.

Подключаем Си-библиотеки:

Project → Build Options → Linker → Libraries → Search Path: C:\CCStudio_v3.3\C2000\cgtools\lib

Project → Build Options → Linker → Libraries → Search Path Linker → Incl. Libraries: rts2800_ml.lib

Задаем глубину стека 0х400:

Project → Build Options → Linker → Basic → Stack Size (-stack): 0x400


//##################################################################

// Имя файла: _Lab2_.c

//

// Описание: С помощью 8 светодиодов, подключенных к линиям

// порта GPIOB0 - GPIOB7, формируются "бегущие огни".

// Направление движения справа - налево и наоборот

//##################################################################

 

#include "DSP281x_Device.h" // Включение заголовочного файла

 

void delay_loop(long);

void Gpio_select(void);

void InitSystem(void);

 

void main(void)

{

unsigned int i;

unsigned int LED[8]= {0x0001,0x0002,0x0004,0x0008,

                 0x0010,0x0020,0x0040,0x0080}; 

     

InitSystem();      // Инициализация регистров ЦСП

Gpio_select();     // Инициализация линий ввода/вывода

     

while(1)

{  

    for(i=0;i<14;i++)

     {

     if(i<7) GpioDataRegs.GPBDAT.all = LED[i];

     else GpioDataRegs.GPBDAT.all = LED[14-i];

     delay_loop(?);

 }

}

}    

 

//##################################################################

// Подпрограмма: delay_loop

//

// Описание: Формирование временной задержки горения светодиодов

//##################################################################

 

void delay_loop(long end)

{

long i;

for (i = 0; i < end; i++);

EALLOW; // Сброс сторожевого таймера

//SysCtrlRegs.WDKEY = 0x?;

//SysCtrlRegs.WDKEY = 0x?;

EDIS;

}

 

//##################################################################

// Подпрограмма: Gpio_select

//

// Описание: Настройка линий порта GPIO B15-8 на ввод, а линий

// B7-0 на вывод. Настройка всех линий портов A, D, F, E, G на

// ввод. Запрещение работы входного ограничителя

//##################################################################

 


void Gpio_select(void)

{

EALLOW;

GpioMuxRegs.GPAMUX.all = 0x?; // Настройка линий ввода/вывода на

GpioMuxRegs.GPBMUX.all = 0x?; // работу в качестве портов  

GpioMuxRegs.GPDMUX.all = 0x?;

GpioMuxRegs.GPFMUX.all = 0x?;       

GpioMuxRegs.GPEMUX.all = 0x?;

GpioMuxRegs.GPGMUX.all = 0x?;       

GpioMuxRegs.GPADIR.all = 0x?; // Настройка портов А, D, E, F, G

// на ввод

GpioMuxRegs.GPBDIR.all = 0x?; // Настройка линий 15-8 на ввод,

GpioMuxRegs.GPDDIR.all = 0x?; // а линий 7-0 на вывод

GpioMuxRegs.GPEDIR.all = 0x?; 

GpioMuxRegs.GPFDIR.all = 0x?; 

GpioMuxRegs.GPGDIR.all = 0x?; 

 

GpioMuxRegs.GPAQUAL.all = 0x?; // Запрещение входного ограничителя

GpioMuxRegs.GPBQUAL.all = 0x?;

GpioMuxRegs.GPDQUAL.all = 0x?;

GpioMuxRegs.GPEQUAL.all = 0x?;

EDIS;

}    

 

 

//#####################################################################

// Подпрограмма: InitSystem

//

// Описание: Настройка сторожевого таймера на работу,

//     предделитель = 1. Выработка сброса сторожевым

//     таймером. Внутренняя частота работы ЦСП 150 МГц.

//     Запись в предделитель высокоскоростного таймера

//     коэффициента деления 2, а в предделитель

//     низкоскоростного таймера - 4. Запрещение работы

//     периферийных устройств

//#####################################################################

 


void InitSystem(void)

{

EALLOW;

SysCtrlRegs.WDCR= 0x?;  // Разрешение работы сторожевого                           // таймера, предделитель = 64

                              // или запрещение работы сторо-

                              // жевого таймера, предделитель = 1

 

SysCtrlRegs.SCSR =?;   // Конфигурирование сброса ЦСП от WDT   

SysCtrlRegs.PLLCR.bit.DIV =?;// Настройка блока умножения частоты

 SysCtrlRegs.HISPCP.all = 0x?;// Задание значений высокоскоростного

SysCtrlRegs.LOSPCP.all = 0x?; // и низкоскоростного предделителей

    

 


SysCtrlRegs.PCLKCR.bit.EVAENCLK=?; // Запрещение работы

SysCtrlRegs.PCLKCR.bit.EVBENCLK=?; // периферийных устройств

SysCtrlRegs.PCLKCR.bit.SCIAENCLK=?;

SysCtrlRegs.PCLKCR.bit.SCIBENCLK=?;

SysCtrlRegs.PCLKCR.bit.MCBSPENCLK=?;

SysCtrlRegs.PCLKCR.bit.SPIENCLK=?;

SysCtrlRegs.PCLKCR.bit.ECANENCLK=?;

SysCtrlRegs.PCLKCR.bit.ADCENCLK=?;

EDIS;

}

     
 

 


Рис. 2.12. Заготовка текста программы «бегущие огни»

 

3. Инициализация системы.

Открываем файл Lab2.c и переходим к подпрограмме
«InitSystem()».

    3.1. Присваивая необходимое значение регистру WDCR (см. рис. 2.9), запрещаем работу сторожевого таймера (WDDIS=0), сбрасываем бит WDFLAG, задаем коэффициент деления частоты тактирования Watchdog-таймера, равный 1 (WDPS0, WDPS1, WDPS2=0). Указанные значения нужно  внести в область 1 программы
(см. рис. 2.12).

    3.2. Программируем регистр SCSR (см. рис. 2.10) на сброс процессора при переполнении Watchdog-таймера. В бит WDENINT записываем «0», в бит WDOVERRIDE также записываем «0» для того, чтобы оставить его в единичном состоянии (см. область 2 на
рис. 2.12).

    3.3. В регистр PLLCR (см. рис. 2.5) заносим код, необходимый для преобразования частоты кварцевого резонатора 30 МГц во внутреннюю частоту SYSCLKOUT работы процессора 150 МГц (см. область 3 на рис. 2.12).

    3.4. Заносим в высокоскоростной предделитель HISPCP
(см. рис. 2.6) коэффициент деления 2, а в низкоскоростной (LOSPCP) – 4 (см. область 3 на рис. 2.12).

    3.5. Установкой-сбросом бит в регистре PCLKCR (см. рис. 2.7) запрещаем работу всех периферийных устройств (см. область 4 на рис. 2.12).

 

    4. Настройка портов.

Переходим к подпрограмме «Gpio_select()».

    4.1. Установкой-сбросом бит в регистрах GPxMUX настраиваем все выводы на работу в качестве портов (см. область 5 на рис. 2.12).

    4.2. Установкой-сбросом бит в регистрах GPxDIR настраиваем все линии портов A, D, E, F, G на ввод (см. область 5 на рис. 2.12).
В порту GPIOB настраиваем линии порта GPIOB15 – GPIOB8 на ввод, а GPIOB7 – GPIOB0 на вывод (см. область 5 на рис. 2.12).

    4.4. Сбрасываем все биты регистров GPxQUAL портов A, B, D, E в ноль (см. область 5 на рис. 2.12).

 

5. Расчет и задание временной задержки

В строке «delay_loop()» (см. область 6 на рис. 2.12) в скобках указываем число n – параметр задержки. Длительность задержки будет пропорциональна данному числу и рассчитывается по формуле (в секундах):

 

.

 

6. Компиляция, компоновка и загрузка выходного файла в отладочный модуль ЦСП.

6.1. Компилируем программу: Project → Compile File. При наличии ошибок, исправляем их.

6.2. Компонуем проект: Project → Build. При наличии ошибок, исправляем их.

6.3. Загружаем выходной файл: File → Load Program → Debug\ lab2.out (в случае, если данная функция сконфигурирована для выполнения автоматически, выполнять данный пункт не нужно).

 

    7. Тестирование программы.

7.1. Сбрасываем ЦСП: Debug → Reset CPU, Debug → Restart.

    7.2. Устанавливаем программный счетчик на точку «void main (void)» основной программы: Debug → Go main.

7.3. Запускаем программу: Debug → Run. Проверяем правильность работы, наблюдая за светодиодами.

Имеется возможность отслеживать правильность выполнения логики программы, просматривая в отдельном окне, как изменяется содержимое выводов порта GPIOB. Для этого необходимо:

- остановить выполнение программы;

- установить точку останова на строку программы, отмеченную знаком «●»;

- выделить мышью в любом месте текста программы название «GpioDataRegs.GPBDAT», нажать правую кнопку мыши и в открывшемся окне выбрать «Add to Watch Window»;

- щелкнуть по значку «+» напротив имени «GpioDataRegs.GPBDAT» в окне Watch Window, далее выбрать «bit», после чего в данном окне будут выведены в столбик двоичные состояния разрядов порта GPIOB (рис. 2.13);

- исключить из программы (закомментировать) задержку, вставив символы «//» в начало строки delay_loop(?);

- сохранить проект (Project → Save), выполнить компиляцию и линковку измененного проекта;

- запустив программу в режиме «Animate», наблюдать последовательность изменения логических уровней на линиях порта GPIOB.

 

8. Работа со сторожевым таймером.

8.1. Останавливаем выполнение программы.

8.2. В подпрограмме «InitSystem()» изменением содержимого регистра WDCR разрешаем работу сторожевого таймера (см. область 1 на рис. 2.12). В битовом поле WDPS этого регистра задаем коэффициент деления программного предделителя равным 64 (см. рис. 2.8, 2.9).

8.3. В подпрограмме временной задержки «delay_loop()» удаляем символы «//» перед двумя строками программы, в которых должна производиться запись в регистр WDKEY (см. область 7 на рис. 2.12), и записываем кодовую комбинацию для сброса Watchdog-таймера:SysCtrlRegs.WDKEY = 0x55, SysCtrlRegs.WDKEY = 0xAA.

Расчетное время до формирования импульса сброса /WDRST от Watchdog-таймера в выбранном режиме составит:

 

 

Для того чтобы сброс WDT происходил раньше (т.е. сброса ЦСП не происходило), нужно обеспечить соотношение tздtWDRST.

8.4. Компилируем, компонуем проект и тестируем программу.

 

 

Рис. 2.13. Просмотр состояния двоичных разрядов порта GPIOB в окне Watch Window

 

9. Работа с двумя светодиодами.

    9.1. Копируем содержимое файла «Lab2.c» в новый файл, который называем «Lab2a.c».

9.2. Преобразуем программу Lab2a.c так, чтобы одновременно зажигались два светодиода в направлении от периферии к центру
(см. рис. 2.11, б).

9.3. Добавляем в проект «Lab2a.c» и удаляем «Lab2.c» (щелкаем правой клавишей мышки и выбираем Remove from project).

9.4. Компилируем, компонуем проект и тестируем программу.

 

Часть II

        

В части II лабораторной работы необходимо положение ключей отражать на светодиодах (ключ замкнут – светодиод горит, разомкнут – погашен), а также положением ключей задавать длительность свечения светодиодов.

1. Отображение состояния ключей на светодиодах.

1.1. Копируем содержимое файла «Lab2а.c» в новый файл, который называем «Lab2b.c».

1.2. Преобразуем программу Lab2b.c. Состояние (двоичный код), установленный ключами, должен индицироваться на светодиодах. С учетом того, что для подключения и светодиодов, и ключей используется один и тот же порт (GPIOB), состояние ключей можно индицировать, введя в основную программу команду циклического сдвига содержимого порта GPIOB на 8 бит:

 

GpioDataRegs.GPBDAT.all = GpioDataRegs.GPBDAT.all >> 8

 

Удаляем таблицу состояния светодиодов, а подпрограммы
«InitSystem()» и «Gpio_select()» оставляем без изменений.

1.3. Добавляем в проект «Lab2b.c» и удаляем «Lab2a.c».

1.4. Компилируем, компонуем проект и тестируем программу.

 

2. Формирование длительности свечения светодиодов в зависимости от состояния ключей.

2.1. Копируем содержимое файла «Lab2.c» в новый файл, который называем «Lab2c.c».

2.2. Преобразуем программу Lab2c.c. Задаем длительность задержки при  переключении  светодиодов  согласно рис. 2.11, а,  равную (0,1*N+0,001) сек, где N – код, заданный переключателями на линиях B15–B8. Подпрограммы «InitSystem()» и «Gpio_select()» оставляем без изменений.

2.3. Добавляем в проект «Lab2c.c» и удаляем  «Lab2b.c».

2.4. Компилируем, компонуем проект и тестируем программу.

Содержание отчета:

 

Отчет должен содержать цель работы, краткие теоретические сведения по теме работы, тексты исследуемых программ, результаты их выполнения, выводы.

 

 

Контрольные вопросы:

 

1. Структурная схема ЦСП семейства C28x.

2. Карта адресного пространства ЦСП C28x.

3. Структура портов ввода/вывода, режимы работы, регистры управления.

4. Вывод простейших управляющих сигналов через порты TMS320F2812.

5. Система тактирования TMS320F2812. Структура, особенности, назначение регистров высокоскоростного и низкоскоростного предделителей.

6. Watchdog timer: назначение, принцип действия, особенности.

7. Какие изменения необходимо внести в исходный текст, чтобы программа «бегущие огни» запускалась по нажатию кнопки, присоединенной к линии порта GPIOD1, а останавливалась – по нажатию кнопки, присоединенной к линии порта GPIOD6
(«0» – соответствующая кнопка нажата, «1» – кнопка отжата)?
В исходном состоянии обе кнопки отжаты.

8. Модифицируйте исходную программу таким образом, чтобы происходило движение одного «погашенного» светодиода среди остальных «горящих».




















Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: