Перейти к содержанию

Stm32: Cubemx+Uart_Dma


verlaty

Рекомендуемые сообщения

Есть такая задача. Надо организовать двухсторонний обмен данными между двумя устройствами по радиоканалу. Радиомодемы подключаются по UART. Решил использовать UART DMA режим. Настройку и сборку проекта делал через Cube. Проблема заключается в следующем: после некоторого времени работы устройства прекращается прием данных. В тоже время если на одном устройстве оставить только передающую, а на другом приемную часть программы – все прекрасно работает.

Прошу помощи в решении этого вопроса (к сожалению большого опыта в программировании этих процессоров не имею). Может подскажите готовое решение для двухстороннего обмена данными по UART.

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

Инициализация UART

/* USART1 init function */
void MX_USART1_UART_Init(void)
{
huart1.Instance = USART1;
huart1.Init.BaudRate = 19200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONEBIT_SAMPLING_DISABLED ;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
HAL_UART_Init(&huart1);}

Инициализация DMA

void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__DMA1_CLK_ENABLE();
__DMA2_CLK_ENABLE();
/* DMA interrupt init */
HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0); // DMA1_Channel4 - передача uart
HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);
HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0); // DMA1_Channel5 – прием UART
HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 0, 0);// DMA2_Channel1 – ADC
HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn);}

В main делаю отправку данных вот так:

if(TX_Ready == 1)
{
TX_Ready = 0;
HAL_UART_Transmit_DMA(&huart1, (uint8_t *)uartTX, 9);
}

Флаг сбрасывается вот здесь TX_Ready:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *UartHandle)
{
TX_Ready = 1;
}

Прием данных делаю вот здесь:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
if(huart1.RxXferSize == 1)
{
if(RXbyte[0] == START_BYTE)
HAL_UART_Receive_DMA(&huart1, (uint8_t *)uartRX, 3);
else
HAL_UART_Receive_DMA(&huart1, (uint8_t *)RXbyte, 1);
}
else
{
if (uartRX[2] == 2*START_BYTE)
IRdist = (uartRX[1] << 8) | uartRX[0];
HAL_UART_Receive_DMA(&huart1, (uint8_t *)RXbyte, 1);
}
}

Немного опишу теорию приема.

Запускаю прием одного байта командой HAL_UART_Receive_DMA(&huart1, (uint8_t *)RXbyte, 1).

Если принятый байт равен стартовому байту в отправленной пачке, то принимаю пачку из 3 байт HAL_UART_Receive_DMA(&huart1, (uint8_t *)uartRX, 3). Если не равен, снова принимаю байт (ожидаю нужный мне байт)

Если принял пачку и контрольный третий байт равен ожидаемому, то формирую сигнал IRdist и снова принимаю один байт. if(huart1.RxXferSize == 1) этим смотрю что я принимал один байт или пачку.

В ответном устройстве аналогично принимается пачка из 9 байт, а отправляется 3 байта.

Изменено пользователем verlaty
Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Если принятый байт равен стартовому байту в отправленной пачке, то принимаю пачку из 3 байт HAL_UART_Receive_DMA(&huart1, (uint8_t *)uartRX, 3). Если не равен, снова принимаю байт (ожидаю нужный мне байт)

Если принял пачку и контрольный третий байт равен ожидаемому, то формирую сигнал IRdist и снова принимаю один байт. if(huart1.RxXferSize == 1) этим смотрю что я принимал один байт или пачку.

В ответном устройстве аналогично принимается пачка из 9 байт, а отправляется 3 байта.

Зачем Вы так усложняете? Скорее всего у вас ошибка в коде.

Я обрабатываю немного не так данные:

Принимаю данные по ЮАРТ через прерывание , если принял то что надо - выполняю обработку и очищаю буфер приема. Если принял не то что ожидал - просто очищаю буфер , и выдаю ошибку.

Так у меня реализованы АТ команды .

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Да такую цель и преследовал. Принимать по байту, а если приходит нужный ( это или команда управления устройством или команда настройки устройства) то обрабатываю уже по типу входящей информации. Если я знаю что должно прийти 9 байт, то зачем по каждому байту обрабатывать в прерывании. Если есть код, покажи как ты принимаешь через прерывания. Повторюсь что в одну сторону обмен идет без проблем, а прием передача - подвисает.

Изменено пользователем verlaty
Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

а если к примеру один байт из пачки пропадет? Сколько времени приемник будет ждать завершения посылки?

Если пачка окажется битой по последовательности (а с радиомодемами это более чем реально), то вся канитель с приемом повиснет если не навсегда, то очень надолго. Надо мутить флуш по таймауту и ресетить всю процедуру принимающей стороны

И я бы еще не разрешал DMA принимать по 3 байта. Пускай лучше всегда по одному тянет. Так проще таймаут будет отработать если то.

Да и вообще при таких коротких посылках проще использовать функцию приема по прерываниям. Я понимаю если бы там скорость была мегабита 3-4 или поток, но тут то... 3 копейки на хромой телеге

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Вот откопал код. Когда то пробовал , работало в железе замечательно.

В архиве , полный рабочий проект под кейл. А вот "куски" кода:

void USART1_IRQHandler()
{
   //Проверяем, действительно ли прерывание вызвано приемом нового байта
char vuart_data;
if (USART1->SR & USART_SR_RXNE) { // ... не пришло ли что-то в UART ?
vuart_data=USART1->DR;

rx_buffer[rx_wr_index++]=vuart_data;
  if (rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
}
}
void USART2_IRQHandler()
{
   //Проверяем, действительно ли прерывание вызвано приемом нового байта
char vuart_data;
if (USART2->SR & USART_SR_RXNE) { // ... не пришло ли что-то в UART ?
vuart_data=USART2->DR;

rx_buffer2[rx_wr_index2++]=vuart_data;
  if (rx_wr_index2 == RX_BUFFER_SIZE) rx_wr_index2=0;
}
}
void clear_buffer()
{
for(unsigned char x=0; x<RX_BUFFER_SIZE; x++){rx_buffer[x]=0; rx_buffer2[x]=0;}
rx_wr_index=0;
rx_wr_index2=0;
}
char string_cmp(char *str1,char *str2)
{
unsigned int x=0;
str1+=0;
str2+=0;
while(str1[x]!=0)
{
if(str1[x] != str2[x])
{
 return 0;
}
x++;
}
return 1;
}
// принимаем строку , и передаем строку:

if(string_cmp("test_data", rx_buffer2))
{
Usart2_Send_String("test send data1!");
clear_buffer();
led_blink(3, 200);
}
else if(string_cmp("data send", rx_buffer2))
{
Usart2_Send_String("test send data2!");
clear_buffer();
led_blink(3, 200);
}

Таймаут пол секунды (настраивается индивидуально под размер принимаемой строки) примерно .

TEST_F100RBT6.rar

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

Литиевые аккумуляторы EVE Energy и решения для управления перезаряжаемыми источниками тока (материалы вебинара)

Опубликованы материалы вебинара Компэл, посвященного литиевым аккумуляторам EVE Energy и решениям для управления перезаряжаемыми источниками тока.

На вебинаре мы представили информацию не только по линейкам аккумуляторной продукции EVE, но и по решениям для управления ею, что поможет рассмотреть эти ХИТ в качестве дополнительной альтернативы для уже выпускающихся изделий. Также рассмотрели нюансы работы с производителем и сервисы, предоставляемые Компэл по данной продукции. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

а если к примеру один байт из пачки пропадет? Сколько времени приемник будет ждать завершения посылки?

Если пачка окажется битой по последовательности (а с радиомодемами это более чем реально), то вся канитель с приемом повиснет если не навсегда, то очень надолго. Надо мутить флуш по таймауту и ресетить всю процедуру принимающей стороны

И я бы еще не разрешал DMA принимать по 3 байта. Пускай лучше всегда по одному тянет. Так проще таймаут будет отработать если то.

Да и вообще при таких коротких посылках проще использовать функцию приема по прерываниям. Я понимаю если бы там скорость была мегабита 3-4 или поток, но тут то... 3 копейки на хромой телеге

если пропадет.... Он принимает допустим 9 байт, и 9 - это контрольный, если пачка целай и не битая он ее дешифрирует, иначе просто принимает след байт, в этом случае программа не зависнет. Но суть то вопроса в том что он просто зависает. Я принимал и в прерываниях и в дма....результат один и тот же. А протокол обмена - это просто одно из решений.

Вот откопал код. Когда то пробовал , работало в железе замечательно.

....

Спасибо. Попробую что нить использовать из него

Ссылка на комментарий
Поделиться на другие сайты

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

а если байт потеряет? примет то 8, а ДМА будет ждать 9-ый. Следующая пачка даже целая примется как поломанная и так далее. Для контроллера это будет фактически зависон, так как условий правильного пакета уже долго не будет, пока не накопится 9 ошибок.

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

Сейчас попробую объяснить идею. Я принимаю по одному байту. Если принятый байт будет равен START_BYTE, тогда принимаем пачку из трех байт. Если третий контрольный байт равен стоповому байту ( для упрощения я сделал так: if(uartRX[2]==2*START_BYTE, на самом деле этот контрольный байт можно рассчитывать по передаваемой информации) , то мы дешифрируем пачку. Допустим мы пропустили байт и третий принятый байт не равен стоповому байту, тогда мы начинаем снова ловить стартовый байт и просто пропускаем битую пачку. программа не зависнет. В моем проекте идет дистанционное управление исполнительным устройством, то есть постоянно передается информация для управления несколькими механизмами. Если я потеряю одну пачку, ничего страшного не произойдет. Дело в том что я пробовал все это реализовать и через прерывания и складывать в буфер по одному байту а уже в основной программе разбирать принятую информацию, но косячек все равно вылазил. Сейчас попробую работать напрямую с регистрами, так как посоветовал artos5. Повторюсь, если вы знаете уже готовые варианты двухстороннего обмена по уарт (что бы не изобретать велосипед), буду очень признателен.

Изменено пользователем verlaty
Ссылка на комментарий
Поделиться на другие сайты

можно порыть в кодах, но на ночь глядя долговато это все выковыривать

а что если поискать причину зависона? Скажем делать эхо всех принимаемых данных в отладочный уарт? Просто так же блоки контроллера не останавливаются. Будет понятно на каком месте затык, потому как данные там и там по идее пропасть должны. А если в отладочном не пропадут, то хоть будет видно что именно принимается. Я для таких целей всегда свободный уарт держу (железный ессно), благо их в стм-ке предостаточно

Вообще всегда предпочитаю дебажить через уарт + STLink. Гораздо удобнее выходит, особенно когда переменка вне области видимости стандартного отладчика. Слегка конечно догружает ядро, но ни разу небыло так чтобы существенно.

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

Приду домой - покажу как это делается .

Хотя , приведенный мною пример может это решить .

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

кстати очень поддерживаю, что используется именно HAL. Правильной дорогой идете, товарищ!

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

кстати очень поддерживаю, что используется именно HAL. Правильной дорогой идете, товарищ!

.

Я занялся STM буквально месяца 3 назад. Пришлось перейти с ARDUINO, так как STM гораздо функциональнее. И не смотря на то что многие Профи плюются на HAL, и Cube и HAL мне очень сильно упростили знакомство. Наверное UART первая проблема, которая заставила меня капнуть куда то глубже. В проекте использую I2C, USB, ADC, PWM, переписывал некоторые библиотеки с ARDUINO и в принципе посидев денек другой все нормально запускалось и работало. Без сомнения в дальнейшем придется разбираться и капать глубже.

Для отладки использую STLink (на базе STM32F3-Discovery) и STM Studio. А для проекта изготовил свои платы и устройства на том же процессоре.

Изменено пользователем verlaty
Ссылка на комментарий
Поделиться на другие сайты

я тоже сначала настороженно отнесся к HAL, но потом как то взялся и покопал либы. Пришел к выводу, что ничего там опасного нет, а вот удобства мегаочевидны. Просто вся возня с регистрами и зависимостями заменена макросами. Ошибки были в первых версиях, и изза них собсна и все вопли, но к версии 1.3.0 их почти все вычистили. Юзаю HAL уже примерно пол года и до их пор проблем не наблюдал. Все работает. Хотя по первости было трудновато привыкнуть к синтаксису и принципам работы. Колбэки вообще поначалу в ступор вводили, пока не нашел их обьявления и не выяснил механизм вызова.

И да - на сегодняшний день это единственная 100% поддерживаемая ST библиотека, остальное они сворачивают

Кстати, только обратил внимание. В коде приема функция HAL_UART_Receive_DMA вызывается без предварительной остановки DMA. Если DMA настроен в режим CIRCULAR, то это может вызывать ошибки. Самого блока настройки DMA не видно

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

Он не в CIRCULAR работает.

void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
 GPIO_InitTypeDef GPIO_InitStruct;
 if(huart->Instance==USART1)
 {
 /* USER CODE BEGIN USART1_MspInit 0 */
 /* USER CODE END USART1_MspInit 0 */
   /* Peripheral clock enable */
   __USART1_CLK_ENABLE();

   /**USART1 GPIO Configuration   
   PA9	 ------> USART1_TX
   PA10	 ------> USART1_RX
   */
   GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
   GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
   GPIO_InitStruct.Pull = GPIO_PULLUP;
   GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
   GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
   HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
   /* Peripheral DMA init*/

   hdma_usart1_rx.Instance = DMA1_Channel5;
   hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
   hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
   hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
   hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
   hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
   hdma_usart1_rx.Init.Mode = DMA_NORMAL;
   hdma_usart1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
   HAL_DMA_Init(&hdma_usart1_rx);
   __HAL_LINKDMA(huart,hdmarx,hdma_usart1_rx);
   hdma_usart1_tx.Instance = DMA1_Channel4;
   hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
   hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
   hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;
   hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
   hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
   hdma_usart1_tx.Init.Mode = DMA_NORMAL;
   hdma_usart1_tx.Init.Priority = DMA_PRIORITY_HIGH;
   HAL_DMA_Init(&hdma_usart1_tx);
   __HAL_LINKDMA(huart,hdmatx,hdma_usart1_tx);
 /* Peripheral interrupt init*/
   HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
   HAL_NVIC_EnableIRQ(USART1_IRQn);
 /* USER CODE BEGIN USART1_MspInit 1 */
 /* USER CODE END USART1_MspInit 1 */
 }
}

Ссылка на комментарий
Поделиться на другие сайты

Приду домой - покажу как это делается .

Хотя , приведенный мною пример может это решить .

Решил принимать один байт через прерывания, а распознав принятый байт как стартовый - принимать пачку через DMA. Передавать пачку тоже через DMA. За основу взял статьи http://dss-nk.ru/node/20 и http://dss-nk.ru/node/21. Твой пример похож на решение из этой статьи.Возник такой вопрос. При компиляции ругается на USART1->SR, USART_SR_RXNE и USART1->DR. В чем может быть проблема?

Ссылка на комментарий
Поделиться на другие сайты

подключение заголовочных файлов CMSIS надо проверить. Эти определения должны быть там

вообще затея так себе. Мешанина может быть из определений

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

если проект автоматом сгенерирован через куб, то таких слов и не будет

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

Ну он HAL и использует. Из другого проекта выдернуть CMSIS и подключить к своему, тогда должно собраться

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

Ссылка на комментарий
Поделиться на другие сайты

Приду домой - покажу как это делается .

Хотя , приведенный мною пример может это решить .

Решил принимать один байт через прерывания, а распознав принятый байт как стартовый - принимать пачку через DMA. Передавать пачку тоже через DMA. За основу взял статьи http://dss-nk.ru/node/20 и http://dss-nk.ru/node/21. Твой пример похож на решение из этой статьи.Возник такой вопрос. При компиляции ругается на USART1->SR, USART_SR_RXNE и USART1->DR. В чем может быть проблема?

Попробуй откомпилировать кейлом мой проект . Скорее всего в твоем проце по-другому регистры называются...

Кубом сгенерируй проект, и добавь функции , и все. Делов на вечер .Я за вечер смог читать / искать строки в буфере UART. Главное , буфер по больше выделить.

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

Попробуй откомпилировать кейлом мой проект . Скорее всего в твоем проце по-другому регистры называются...

Кубом сгенерируй проект, и добавь функции , и все. Делов на вечер .Я за вечер смог читать / искать строки в буфере UART. Главное , буфер по больше выделить.

Твой проект компилириуется. Видать вопрос в том, что у меня другой проц. Буду искать решение....

Ссылка на комментарий
Поделиться на другие сайты

Посмотри в даташит на проц как регистры называются , и все .

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...